KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > viewers > CheckboxTreeViewer


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jface.viewers;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.List JavaDoc;
15
16 import org.eclipse.core.runtime.ListenerList;
17 import org.eclipse.core.runtime.Assert;
18 import org.eclipse.jface.util.SafeRunnable;
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.events.SelectionEvent;
21 import org.eclipse.swt.widgets.Composite;
22 import org.eclipse.swt.widgets.Control;
23 import org.eclipse.swt.widgets.Item;
24 import org.eclipse.swt.widgets.Tree;
25 import org.eclipse.swt.widgets.TreeItem;
26 import org.eclipse.swt.widgets.Widget;
27
28 /**
29  * A concrete tree-structured viewer based on an SWT <code>Tree</code>
30  * control with checkboxes on each node.
31  * <p>
32  * This class is not intended to be subclassed outside the viewer framework.
33  * It is designed to be instantiated with a pre-existing SWT tree control and configured
34  * with a domain-specific content provider, label provider, element filter (optional),
35  * and element sorter (optional).
36  * </p>
37  */

38 public class CheckboxTreeViewer extends TreeViewer implements ICheckable {
39
40     /**
41      * List of check state listeners (element type: <code>ICheckStateListener</code>).
42      */

43     private ListenerList checkStateListeners = new ListenerList();
44
45     /**
46      * Last item clicked on, or <code>null</code> if none.
47      */

48     private TreeItem lastClickedItem = null;
49
50     /**
51      * Creates a tree viewer on a newly-created tree control under the given parent.
52      * The tree control is created using the SWT style bits: <code>CHECK</code> and <code>BORDER</code>.
53      * The viewer has no input, no content provider, a default label provider,
54      * no sorter, and no filters.
55      *
56      * @param parent the parent control
57      */

58     public CheckboxTreeViewer(Composite parent) {
59         this(parent, SWT.BORDER);
60     }
61
62     /**
63      * Creates a tree viewer on a newly-created tree control under the given parent.
64      * The tree control is created using the given SWT style bits, plus the <code>CHECK</code> style bit.
65      * The viewer has no input, no content provider, a default label provider,
66      * no sorter, and no filters.
67      *
68      * @param parent the parent control
69      * @param style the SWT style bits
70      */

71     public CheckboxTreeViewer(Composite parent, int style) {
72         this(new Tree(parent, SWT.CHECK | style));
73     }
74
75     /**
76      * Creates a tree viewer on the given tree control.
77      * The <code>SWT.CHECK</code> style bit must be set on the given tree control.
78      * The viewer has no input, no content provider, a default label provider,
79      * no sorter, and no filters.
80      *
81      * @param tree the tree control
82      */

83     public CheckboxTreeViewer(Tree tree) {
84         super(tree);
85     }
86
87     /* (non-Javadoc)
88      * Method declared on ICheckable.
89      */

90     public void addCheckStateListener(ICheckStateListener listener) {
91         checkStateListeners.add(listener);
92     }
93
94     /**
95      * Applies the checked and grayed states of the given widget and its
96      * descendents.
97      *
98      * @param checked a set of elements (element type: <code>Object</code>)
99      * @param grayed a set of elements (element type: <code>Object</code>)
100      * @param widget the widget
101      */

102     private void applyState(CustomHashtable checked, CustomHashtable grayed,
103             Widget widget) {
104         Item[] items = getChildren(widget);
105         for (int i = 0; i < items.length; i++) {
106             Item item = items[i];
107             if (item instanceof TreeItem) {
108                 Object JavaDoc data = item.getData();
109                 if (data != null) {
110                     TreeItem ti = (TreeItem) item;
111                     ti.setChecked(checked.containsKey(data));
112                     ti.setGrayed(grayed.containsKey(data));
113                 }
114             }
115             applyState(checked, grayed, item);
116         }
117     }
118
119     /**
120      * Notifies any check state listeners that the check state of an element has changed.
121      * Only listeners registered at the time this method is called are notified.
122      *
123      * @param event a check state changed event
124      *
125      * @see ICheckStateListener#checkStateChanged
126      */

127     protected void fireCheckStateChanged(final CheckStateChangedEvent event) {
128         Object JavaDoc[] array = checkStateListeners.getListeners();
129         for (int i = 0; i < array.length; i++) {
130             final ICheckStateListener l = (ICheckStateListener) array[i];
131             SafeRunnable.run(new SafeRunnable() {
132                 public void run() {
133                     l.checkStateChanged(event);
134                 }
135             });
136         }
137
138     }
139
140     /**
141      * Gathers the checked and grayed states of the given widget and its
142      * descendents.
143      *
144      * @param checked a writable set of elements (element type: <code>Object</code>)
145      * @param grayed a writable set of elements (element type: <code>Object</code>)
146      * @param widget the widget
147      */

148     private void gatherState(CustomHashtable checked, CustomHashtable grayed,
149             Widget widget) {
150         Item[] items = getChildren(widget);
151         for (int i = 0; i < items.length; i++) {
152             Item item = items[i];
153             if (item instanceof TreeItem) {
154                 Object JavaDoc data = item.getData();
155                 if (data != null) {
156                     TreeItem ti = (TreeItem) item;
157                     if (ti.getChecked()) {
158                         checked.put(data, data);
159                     }
160                     if (ti.getGrayed()) {
161                         grayed.put(data, data);
162                     }
163                 }
164             }
165             gatherState(checked, grayed, item);
166         }
167     }
168
169     /* (non-Javadoc)
170      * Method declared on ICheckable.
171      */

172     public boolean getChecked(Object JavaDoc element) {
173         Widget widget = findItem(element);
174         if (widget instanceof TreeItem) {
175             return ((TreeItem) widget).getChecked();
176         }
177         return false;
178     }
179
180     /**
181      * Returns a list of checked elements in this viewer's tree,
182      * including currently hidden ones that are marked as
183      * checked but are under a collapsed ancestor.
184      * <p>
185      * This method is typically used when preserving the interesting
186      * state of a viewer; <code>setCheckedElements</code> is used during the restore.
187      * </p>
188      *
189      * @return the array of checked elements
190      *
191      * @see #setCheckedElements
192      */

193     public Object JavaDoc[] getCheckedElements() {
194         ArrayList JavaDoc v = new ArrayList JavaDoc();
195         Control tree = getControl();
196         internalCollectChecked(v, tree);
197         return v.toArray();
198     }
199
200     /**
201      * Returns the grayed state of the given element.
202      *
203      * @param element the element
204      * @return <code>true</code> if the element is grayed,
205      * and <code>false</code> if not grayed
206      */

207     public boolean getGrayed(Object JavaDoc element) {
208         Widget widget = findItem(element);
209         if (widget instanceof TreeItem) {
210             return ((TreeItem) widget).getGrayed();
211         }
212         return false;
213     }
214
215     /**
216      * Returns a list of grayed elements in this viewer's tree,
217      * including currently hidden ones that are marked as
218      * grayed but are under a collapsed ancestor.
219      * <p>
220      * This method is typically used when preserving the interesting
221      * state of a viewer; <code>setGrayedElements</code> is used during the restore.
222      * </p>
223      *
224      * @return the array of grayed elements
225      *
226      * @see #setGrayedElements
227      */

228     public Object JavaDoc[] getGrayedElements() {
229         List JavaDoc result = new ArrayList JavaDoc();
230         internalCollectGrayed(result, getControl());
231         return result.toArray();
232     }
233
234     /* (non-Javadoc)
235      * Method declared on StructuredViewer.
236      */

237     protected void handleDoubleSelect(SelectionEvent event) {
238
239         if (lastClickedItem != null) {
240             TreeItem item = lastClickedItem;
241             Object JavaDoc data = item.getData();
242             if (data != null) {
243                 boolean state = item.getChecked();
244                 setChecked(data, !state);
245                 fireCheckStateChanged(new CheckStateChangedEvent(this, data,
246                         !state));
247             }
248             lastClickedItem = null;
249         } else {
250             super.handleDoubleSelect(event);
251         }
252     }
253
254     /* (non-Javadoc)
255      * Method declared on StructuredViewer.
256      */

257     protected void handleSelect(SelectionEvent event) {
258
259         lastClickedItem = null;
260         if (event.detail == SWT.CHECK) {
261             TreeItem item = (TreeItem) event.item;
262             lastClickedItem = item;
263             super.handleSelect(event);
264
265             Object JavaDoc data = item.getData();
266             if (data != null) {
267                 fireCheckStateChanged(new CheckStateChangedEvent(this, data,
268                         item.getChecked()));
269             }
270         } else {
271             super.handleSelect(event);
272         }
273     }
274
275     /**
276      * Gathers the checked states of the given widget and its
277      * descendents, following a pre-order traversal of the tree.
278      *
279      * @param result a writable list of elements (element type: <code>Object</code>)
280      * @param widget the widget
281      */

282     private void internalCollectChecked(List JavaDoc result, Widget widget) {
283         Item[] items = getChildren(widget);
284         for (int i = 0; i < items.length; i++) {
285             Item item = items[i];
286             if (item instanceof TreeItem && ((TreeItem) item).getChecked()) {
287                 Object JavaDoc data = item.getData();
288                 if (data != null) {
289                     result.add(data);
290                 }
291             }
292             internalCollectChecked(result, item);
293         }
294     }
295
296     /**
297      * Gathers the grayed states of the given widget and its
298      * descendents, following a pre-order traversal of the tree.
299      *
300      * @param result a writable list of elements (element type: <code>Object</code>)
301      * @param widget the widget
302      */

303     private void internalCollectGrayed(List JavaDoc result, Widget widget) {
304         Item[] items = getChildren(widget);
305         for (int i = 0; i < items.length; i++) {
306             Item item = items[i];
307             if (item instanceof TreeItem && ((TreeItem) item).getGrayed()) {
308                 Object JavaDoc data = item.getData();
309                 if (data != null) {
310                     result.add(data);
311                 }
312             }
313             internalCollectGrayed(result, item);
314         }
315     }
316
317     /**
318      * Sets the checked state of all items to correspond to the given set of checked elements.
319      *
320      * @param checkedElements the set (element type: <code>Object</code>) of elements which are checked
321      * @param widget the widget
322      */

323     private void internalSetChecked(CustomHashtable checkedElements,
324             Widget widget) {
325         Item[] items = getChildren(widget);
326         for (int i = 0; i < items.length; i++) {
327             TreeItem item = (TreeItem) items[i];
328             Object JavaDoc data = item.getData();
329             if (data != null) {
330                 boolean checked = checkedElements.containsKey(data);
331                 if (checked != item.getChecked()) {
332                     item.setChecked(checked);
333                 }
334             }
335             internalSetChecked(checkedElements, item);
336         }
337     }
338
339     /**
340      * Sets the grayed state of all items to correspond to the given set of grayed elements.
341      *
342      * @param grayedElements the set (element type: <code>Object</code>) of elements which are grayed
343      * @param widget the widget
344      */

345     private void internalSetGrayed(CustomHashtable grayedElements, Widget widget) {
346         Item[] items = getChildren(widget);
347         for (int i = 0; i < items.length; i++) {
348             TreeItem item = (TreeItem) items[i];
349             Object JavaDoc data = item.getData();
350             if (data != null) {
351                 boolean grayed = grayedElements.containsKey(data);
352                 if (grayed != item.getGrayed()) {
353                     item.setGrayed(grayed);
354                 }
355             }
356             internalSetGrayed(grayedElements, item);
357         }
358     }
359
360     /* (non-Javadoc)
361      * Method declared on Viewer.
362      */

363     protected void preservingSelection(Runnable JavaDoc updateCode) {
364
365         int n = getItemCount(getControl());
366         CustomHashtable checkedNodes = newHashtable(n * 2 + 1);
367         CustomHashtable grayedNodes = newHashtable(n * 2 + 1);
368
369         gatherState(checkedNodes, grayedNodes, getControl());
370
371         super.preservingSelection(updateCode);
372
373         applyState(checkedNodes, grayedNodes, getControl());
374     }
375
376     /* (non-Javadoc)
377      * Method declared on ICheckable.
378      */

379     public void removeCheckStateListener(ICheckStateListener listener) {
380         checkStateListeners.remove(listener);
381     }
382
383     /* (non-Javadoc)
384      * Method declared on ICheckable.
385      */

386     public boolean setChecked(Object JavaDoc element, boolean state) {
387         Assert.isNotNull(element);
388         Widget widget = internalExpand(element, false);
389         if (widget instanceof TreeItem) {
390             ((TreeItem) widget).setChecked(state);
391             return true;
392         }
393         return false;
394     }
395
396     /**
397      * Sets the checked state for the children of the given item.
398      *
399      * @param item the item
400      * @param state <code>true</code> if the item should be checked,
401      * and <code>false</code> if it should be unchecked
402      */

403     private void setCheckedChildren(Item item, boolean state) {
404         createChildren(item);
405         Item[] items = getChildren(item);
406         if (items != null) {
407             for (int i = 0; i < items.length; i++) {
408                 Item it = items[i];
409                 if (it.getData() != null && (it instanceof TreeItem)) {
410                     TreeItem treeItem = (TreeItem) it;
411                     treeItem.setChecked(state);
412                     setCheckedChildren(treeItem, state);
413                 }
414             }
415         }
416     }
417
418     /**
419      * Sets which elements are checked in this viewer's tree.
420      * The given list contains the elements that are to be checked;
421      * all other elements are to be unchecked.
422      * Does not fire events to check state listeners.
423      * <p>
424      * This method is typically used when restoring the interesting
425      * state of a viewer captured by an earlier call to <code>getCheckedElements</code>.
426      * </p>
427      *
428      * @param elements the array of checked elements
429      * @see #getCheckedElements
430      */

431     public void setCheckedElements(Object JavaDoc[] elements) {
432         assertElementsNotNull(elements);
433         CustomHashtable checkedElements = newHashtable(elements.length * 2 + 1);
434         for (int i = 0; i < elements.length; ++i) {
435             Object JavaDoc element = elements[i];
436             // Ensure item exists for element
437
internalExpand(element, false);
438             checkedElements.put(element, element);
439         }
440         Control tree = getControl();
441         tree.setRedraw(false);
442         internalSetChecked(checkedElements, tree);
443         tree.setRedraw(true);
444     }
445
446     /**
447      * Sets the grayed state for the given element in this viewer.
448      *
449      * @param element the element
450      * @param state <code>true</code> if the item should be grayed,
451      * and <code>false</code> if it should be ungrayed
452      * @return <code>true</code> if the gray state could be set,
453      * and <code>false</code> otherwise
454      */

455     public boolean setGrayed(Object JavaDoc element, boolean state) {
456         Assert.isNotNull(element);
457         Widget widget = internalExpand(element, false);
458         if (widget instanceof TreeItem) {
459             ((TreeItem) widget).setGrayed(state);
460             return true;
461         }
462         return false;
463     }
464
465     /**
466      * Check and gray the selection rather than calling both
467      * setGrayed and setChecked as an optimization.
468      * Does not fire events to check state listeners.
469      * @param element the item being checked
470      * @param state a boolean indicating selection or deselection
471      * @return boolean indicating success or failure.
472      */

473     public boolean setGrayChecked(Object JavaDoc element, boolean state) {
474         Assert.isNotNull(element);
475         Widget widget = internalExpand(element, false);
476         if (widget instanceof TreeItem) {
477             TreeItem item = (TreeItem) widget;
478             item.setChecked(state);
479             item.setGrayed(state);
480             return true;
481         }
482         return false;
483     }
484
485     /**
486      * Sets which elements are grayed in this viewer's tree.
487      * The given list contains the elements that are to be grayed;
488      * all other elements are to be ungrayed.
489      * <p>
490      * This method is typically used when restoring the interesting
491      * state of a viewer captured by an earlier call to <code>getGrayedElements</code>.
492      * </p>
493      *
494      * @param elements the array of grayed elements
495      *
496      * @see #getGrayedElements
497      */

498     public void setGrayedElements(Object JavaDoc[] elements) {
499         assertElementsNotNull(elements);
500         CustomHashtable grayedElements = newHashtable(elements.length * 2 + 1);
501         for (int i = 0; i < elements.length; ++i) {
502             Object JavaDoc element = elements[i];
503             // Ensure item exists for element
504
internalExpand(element, false);
505             grayedElements.put(element, element);
506         }
507         Control tree = getControl();
508         tree.setRedraw(false);
509         internalSetGrayed(grayedElements, tree);
510         tree.setRedraw(true);
511     }
512
513     /**
514      * Sets the grayed state for the given element and its parents
515      * in this viewer.
516      *
517      * @param element the element
518      * @param state <code>true</code> if the item should be grayed,
519      * and <code>false</code> if it should be ungrayed
520      * @return <code>true</code> if the element is visible and the gray
521      * state could be set, and <code>false</code> otherwise
522      * @see #setGrayed
523      */

524     public boolean setParentsGrayed(Object JavaDoc element, boolean state) {
525         Assert.isNotNull(element);
526         Widget widget = internalExpand(element, false);
527         if (widget instanceof TreeItem) {
528             TreeItem item = (TreeItem) widget;
529             item.setGrayed(state);
530             item = item.getParentItem();
531             while (item != null) {
532                 item.setGrayed(state);
533                 item = item.getParentItem();
534             }
535             return true;
536         }
537         return false;
538     }
539
540     /**
541      * Sets the checked state for the given element and its visible
542      * children in this viewer.
543      * Assumes that the element has been expanded before. To enforce
544      * that the item is expanded, call <code>expandToLevel</code>
545      * for the element.
546      * Does not fire events to check state listeners.
547      *
548      * @param element the element
549      * @param state <code>true</code> if the item should be checked,
550      * and <code>false</code> if it should be unchecked
551      * @return <code>true</code> if the checked state could be set,
552      * and <code>false</code> otherwise
553      */

554     public boolean setSubtreeChecked(Object JavaDoc element, boolean state) {
555         Widget widget = internalExpand(element, false);
556         if (widget instanceof TreeItem) {
557             TreeItem item = (TreeItem) widget;
558             item.setChecked(state);
559             setCheckedChildren(item, state);
560             return true;
561         }
562         return false;
563     }
564
565     /**
566      * Sets to the given value the checked state for all elements in this viewer.
567      * Does not fire events to check state listeners.
568      *
569      * @param state <code>true</code> if the element should be checked,
570      * and <code>false</code> if it should be unchecked
571      *
572      * @since 3.2
573      */

574     public void setAllChecked(boolean state) {
575         setAllChecked(state, getTree().getItems());
576         
577     }
578
579     /**
580      * Set the checked state of items and their children to state.
581      * @param state
582      * @param items
583      */

584     private void setAllChecked(boolean state, TreeItem[] items) {
585         for (int i = 0; i < items.length; i++) {
586             items[i].setChecked(state);
587             TreeItem[] children = items[i].getItems();
588             setAllChecked(state, children);
589         }
590     }
591 }
592
Popular Tags