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