Improved completion processor
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / viewsupport / ContainerCheckedTreeViewer.java
1 package net.sourceforge.phpdt.internal.ui.viewsupport;
2
3 import java.util.ArrayList;
4
5 import org.eclipse.jface.viewers.CheckStateChangedEvent;
6 import org.eclipse.jface.viewers.CheckboxTreeViewer;
7 import org.eclipse.jface.viewers.ICheckStateListener;
8 import org.eclipse.jface.viewers.ITreeViewerListener;
9 import org.eclipse.jface.viewers.TreeExpansionEvent;
10 import org.eclipse.swt.widgets.Composite;
11 import org.eclipse.swt.widgets.Item;
12 import org.eclipse.swt.widgets.Tree;
13 import org.eclipse.swt.widgets.TreeItem;
14 import org.eclipse.swt.widgets.Widget;
15
16 /**
17  * CheckboxTreeViewer with special behaviour of the checked / gray state on 
18  * container (non-leaf) nodes:
19  * The grayed state is used to visualize the checked state of its children.
20  * Containers are checked and non-gary if all contained leafs are checked. The
21  * container is grayed if some but not all leafs are checked.
22  */
23 public class ContainerCheckedTreeViewer extends CheckboxTreeViewer  {
24
25         /**
26          * Constructor for ContainerCheckedTreeViewer.
27          * @see CheckboxTreeViewer#CheckboxTreeViewer(Composite)
28          */
29         public ContainerCheckedTreeViewer(Composite parent) {
30                 super(parent);
31                 initViewer();
32         }
33
34         /**
35          * Constructor for ContainerCheckedTreeViewer.
36          * @see CheckboxTreeViewer#CheckboxTreeViewer(Composite,int)
37          */
38         public ContainerCheckedTreeViewer(Composite parent, int style) {
39                 super(parent, style);
40                 initViewer();
41         }
42
43         /**
44          * Constructor for ContainerCheckedTreeViewer.
45          * @see CheckboxTreeViewer#CheckboxTreeViewer(Tree)
46          */
47         public ContainerCheckedTreeViewer(Tree tree) {
48                 super(tree);
49                 initViewer();
50         }
51
52         private void initViewer() {
53                 setUseHashlookup(true);
54                 addCheckStateListener(new ICheckStateListener() {
55                         public void checkStateChanged(CheckStateChangedEvent event) {
56                                 doCheckStateChanged(event.getElement());
57                         }
58                 });
59                 addTreeListener(new ITreeViewerListener() {
60                         public void treeCollapsed(TreeExpansionEvent event) {}
61                         public void treeExpanded(TreeExpansionEvent event) {
62                                 Widget item = findItem(event.getElement());
63                                 if (item instanceof TreeItem) {
64                                         initializeItem((TreeItem) item);
65                                 }
66                         }
67                 });
68         }
69
70         protected void doCheckStateChanged(Object element) {
71                 Widget item = findItem(element);
72                 if (item instanceof TreeItem) {
73                         TreeItem treeItem = (TreeItem) item;
74                         treeItem.setGrayed(false);
75                         updateChildrenItems(treeItem);
76                         updateParentItems(treeItem.getParentItem());
77                 }
78         }
79
80         /**
81          * The item has expanded. Updates the checked state of its children. 
82          */
83         private void initializeItem(TreeItem item) {
84                 if (item.getChecked() && !item.getGrayed()) {
85                         updateChildrenItems((TreeItem) item);
86                 }
87         }
88
89         /**
90          * Updates the check state of all created children
91          */
92         private void updateChildrenItems(TreeItem parent) {
93                 Item[] children = getChildren(parent);
94                 boolean state = parent.getChecked();
95                 for (int i = 0; i < children.length; i++) {
96                         TreeItem curr = (TreeItem) children[i];
97                         if (curr.getData() != null && ((curr.getChecked() != state) || curr.getGrayed())) {
98                                 curr.setChecked(state);
99                                 curr.setGrayed(false);
100                                 updateChildrenItems(curr);
101                         }
102                 }
103         }
104
105         /**
106          * Updates the check / gray state of all parent items
107          */
108         private void updateParentItems(TreeItem item) {
109                 if (item != null) {
110                         Item[] children = getChildren(item);
111                         boolean containsChecked = false;
112                         boolean containsUnchecked = false;
113                         for (int i = 0; i < children.length; i++) {
114                                 TreeItem curr = (TreeItem) children[i];
115                                 containsChecked |= curr.getChecked();
116                                 containsUnchecked |= (!curr.getChecked() || curr.getGrayed());
117                         }
118                         item.setChecked(containsChecked);
119                         item.setGrayed(containsChecked && containsUnchecked);
120                         updateParentItems(item.getParentItem());
121                 }
122         }
123
124         public boolean setChecked(Object element, boolean state) {
125                 if (super.setChecked(element, state)) {
126                         doCheckStateChanged(element);
127                         return true;
128                 }
129                 return false;
130         }
131
132         public void setCheckedElements(Object[] elements) {
133                 super.setCheckedElements(elements);
134                 for (int i = 0; i < elements.length; i++) {
135                         doCheckStateChanged(elements[i]);
136                 }
137         }
138
139         protected void setExpanded(Item item, boolean expand) {
140                 super.setExpanded(item, expand);
141                 if (expand && item instanceof TreeItem) {
142                         initializeItem((TreeItem) item);
143                 }
144         }
145
146         public Object[] getCheckedElements() {
147                 Object[] checked = super.getCheckedElements();
148                 // add all items that are children of a checked node but not created yet
149                 ArrayList result = new ArrayList();
150                 for (int i = 0; i < checked.length; i++) {
151                         Object curr = checked[i];
152                         result.add(curr);
153                         Widget item = findItem(curr);
154                         if (item != null) {
155                                 Item[] children = getChildren(item);
156                                 // check if contains the dummy node
157                                 if (children.length == 1 && children[0].getData() == null) {
158                                         // not yet created
159                                         collectChildren(curr, result);
160                                 }
161                         }
162                 }
163                 return result.toArray();
164         }
165
166         private void collectChildren(Object element, ArrayList result) {
167                 Object[] filteredChildren = getFilteredChildren(element);
168                 for (int i = 0; i < filteredChildren.length; i++) {
169                         Object curr = filteredChildren[i];
170                         result.add(curr);
171                         collectChildren(curr, result);
172                 }
173         }
174
175 }