KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > ide > dialogs > ResourceTreeAndListGroup


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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.ui.internal.ide.dialogs;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Collection JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Map JavaDoc;
20 import java.util.Set JavaDoc;
21
22 import org.eclipse.core.commands.common.EventManager;
23 import org.eclipse.core.runtime.IPath;
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.core.runtime.Path;
26 import org.eclipse.core.runtime.SafeRunner;
27 import org.eclipse.jface.util.SafeRunnable;
28 import org.eclipse.jface.viewers.CheckStateChangedEvent;
29 import org.eclipse.jface.viewers.CheckboxTableViewer;
30 import org.eclipse.jface.viewers.CheckboxTreeViewer;
31 import org.eclipse.jface.viewers.ICheckStateListener;
32 import org.eclipse.jface.viewers.ILabelProvider;
33 import org.eclipse.jface.viewers.ISelectionChangedListener;
34 import org.eclipse.jface.viewers.IStructuredContentProvider;
35 import org.eclipse.jface.viewers.IStructuredSelection;
36 import org.eclipse.jface.viewers.ITreeContentProvider;
37 import org.eclipse.jface.viewers.ITreeViewerListener;
38 import org.eclipse.jface.viewers.SelectionChangedEvent;
39 import org.eclipse.jface.viewers.StructuredSelection;
40 import org.eclipse.jface.viewers.TreeExpansionEvent;
41 import org.eclipse.jface.viewers.ViewerComparator;
42 import org.eclipse.swt.SWT;
43 import org.eclipse.swt.custom.BusyIndicator;
44 import org.eclipse.swt.layout.GridData;
45 import org.eclipse.swt.layout.GridLayout;
46 import org.eclipse.swt.widgets.Composite;
47 import org.eclipse.swt.widgets.Table;
48 import org.eclipse.swt.widgets.Tree;
49
50 /**
51  * Workbench-level composite that combines a CheckboxTreeViewer and CheckboxListViewer.
52  * All viewer selection-driven interactions are handled within this object
53  */

54 public class ResourceTreeAndListGroup extends EventManager implements
55         ICheckStateListener, ISelectionChangedListener, ITreeViewerListener {
56     private Object JavaDoc root;
57
58     private Object JavaDoc currentTreeSelection;
59
60     private Collection JavaDoc expandedTreeNodes = new HashSet JavaDoc();
61
62     private Map JavaDoc checkedStateStore = new HashMap JavaDoc(9);
63
64     private Collection JavaDoc whiteCheckedTreeItems = new HashSet JavaDoc();
65
66     private ITreeContentProvider treeContentProvider;
67
68     private IStructuredContentProvider listContentProvider;
69
70     private ILabelProvider treeLabelProvider;
71
72     private ILabelProvider listLabelProvider;
73
74     // widgets
75
private CheckboxTreeViewer treeViewer;
76
77     private CheckboxTableViewer listViewer;
78
79     //height hint for viewers
80
private static int PREFERRED_HEIGHT = 150;
81
82     /**
83      * Create an instance of this class. Use this constructor if you wish to specify
84      * the width and/or height of the combined widget (to only hardcode one of the
85      * sizing dimensions, specify the other dimension's value as -1)
86      *
87      * @param parent
88      * @param rootObject
89      * @param treeContentProvider
90      * @param treeLabelProvider
91      * @param listContentProvider
92      * @param listLabelProvider
93      * @param style
94      * @param useHeightHint If true then use the height hint
95      * to make this group big enough
96      *
97      */

98     public ResourceTreeAndListGroup(Composite parent, Object JavaDoc rootObject,
99             ITreeContentProvider treeContentProvider,
100             ILabelProvider treeLabelProvider,
101             IStructuredContentProvider listContentProvider,
102             ILabelProvider listLabelProvider, int style, boolean useHeightHint) {
103
104         root = rootObject;
105         this.treeContentProvider = treeContentProvider;
106         this.listContentProvider = listContentProvider;
107         this.treeLabelProvider = treeLabelProvider;
108         this.listLabelProvider = listLabelProvider;
109         createContents(parent, style, useHeightHint);
110     }
111
112     /**
113      * This method must be called just before this window becomes visible.
114      */

115     public void aboutToOpen() {
116         determineWhiteCheckedDescendents(root);
117         checkNewTreeElements(treeContentProvider.getElements(root));
118         currentTreeSelection = null;
119
120         //select the first element in the list
121
Object JavaDoc[] elements = treeContentProvider.getElements(root);
122         Object JavaDoc primary = elements.length > 0 ? elements[0] : null;
123         if (primary != null) {
124             treeViewer.setSelection(new StructuredSelection(primary));
125         }
126         treeViewer.getControl().setFocus();
127     }
128
129     /**
130      * Add the passed listener to self's collection of clients
131      * that listen for changes to element checked states
132      *
133      * @param listener ICheckStateListener
134      */

135     public void addCheckStateListener(ICheckStateListener listener) {
136         addListenerObject(listener);
137     }
138
139     /**
140      * Return a boolean indicating whether all children of the passed tree element
141      * are currently white-checked
142      *
143      * @return boolean
144      * @param treeElement java.lang.Object
145      */

146     protected boolean areAllChildrenWhiteChecked(Object JavaDoc treeElement) {
147         Object JavaDoc[] children = treeContentProvider.getChildren(treeElement);
148         for (int i = 0; i < children.length; ++i) {
149             if (!whiteCheckedTreeItems.contains(children[i])) {
150                 return false;
151             }
152         }
153
154         return true;
155     }
156
157     /**
158      * Return a boolean indicating whether all list elements associated with
159      * the passed tree element are currently checked
160      *
161      * @return boolean
162      * @param treeElement java.lang.Object
163      */

164     protected boolean areAllElementsChecked(Object JavaDoc treeElement) {
165         List JavaDoc checkedElements = (List JavaDoc) checkedStateStore.get(treeElement);
166         if (checkedElements == null) {
167             return false;
168         }
169
170         return getListItemsSize(treeElement) == checkedElements.size();
171     }
172
173     /**
174      * Iterate through the passed elements which are being realized for the first
175      * time and check each one in the tree viewer as appropriate
176      */

177     protected void checkNewTreeElements(Object JavaDoc[] elements) {
178         for (int i = 0; i < elements.length; ++i) {
179             Object JavaDoc currentElement = elements[i];
180             boolean checked = checkedStateStore.containsKey(currentElement);
181             treeViewer.setChecked(currentElement, checked);
182             treeViewer.setGrayed(currentElement, checked
183                     && !whiteCheckedTreeItems.contains(currentElement));
184         }
185     }
186
187     /**
188      * An item was checked in one of self's two views. Determine which
189      * view this occurred in and delegate appropriately
190      *
191      * @param event CheckStateChangedEvent
192      */

193     public void checkStateChanged(final CheckStateChangedEvent event) {
194
195         //Potentially long operation - show a busy cursor
196
BusyIndicator.showWhile(treeViewer.getControl().getDisplay(),
197                 new Runnable JavaDoc() {
198                     public void run() {
199                         if (event.getCheckable().equals(treeViewer)) {
200                             treeItemChecked(event.getElement(), event
201                                     .getChecked());
202                         } else {
203                             listItemChecked(event.getElement(), event
204                                     .getChecked(), true);
205                         }
206
207                         notifyCheckStateChangeListeners(event);
208                     }
209                 });
210     }
211
212     /**
213      * Lay out and initialize self's visual components.
214      *
215      * @param parent org.eclipse.swt.widgets.Composite
216      * @param style the style flags for the new Composite
217      * @param useHeightHint If true yse the preferredHeight.
218      */

219     protected void createContents(Composite parent, int style,
220             boolean useHeightHint) {
221         // group pane
222
Composite composite = new Composite(parent, style);
223         composite.setFont(parent.getFont());
224         GridLayout layout = new GridLayout();
225         layout.numColumns = 2;
226         layout.makeColumnsEqualWidth = true;
227         layout.marginHeight = 0;
228         layout.marginWidth = 0;
229         composite.setLayout(layout);
230         composite.setLayoutData(new GridData(GridData.FILL_BOTH));
231
232         createTreeViewer(composite, useHeightHint);
233         createListViewer(composite, useHeightHint);
234
235         initialize();
236     }
237
238     /**
239      * Create this group's list viewer.
240      */

241     protected void createListViewer(Composite parent, boolean useHeightHint) {
242         listViewer = CheckboxTableViewer.newCheckList(parent, SWT.BORDER);
243         GridData data = new GridData(GridData.FILL_BOTH);
244         if (useHeightHint) {
245             data.heightHint = PREFERRED_HEIGHT;
246         }
247         listViewer.getTable().setLayoutData(data);
248         listViewer.getTable().setFont(parent.getFont());
249         listViewer.setContentProvider(listContentProvider);
250         listViewer.setLabelProvider(listLabelProvider);
251         listViewer.addCheckStateListener(this);
252     }
253
254     /**
255      * Create this group's tree viewer.
256      */

257     protected void createTreeViewer(Composite parent, boolean useHeightHint) {
258         Tree tree = new Tree(parent, SWT.CHECK | SWT.BORDER);
259         GridData data = new GridData(GridData.FILL_BOTH);
260         if (useHeightHint) {
261             data.heightHint = PREFERRED_HEIGHT;
262         }
263         tree.setLayoutData(data);
264         tree.setFont(parent.getFont());
265
266         treeViewer = new CheckboxTreeViewer(tree);
267         treeViewer.setContentProvider(treeContentProvider);
268         treeViewer.setLabelProvider(treeLabelProvider);
269         treeViewer.addTreeListener(this);
270         treeViewer.addCheckStateListener(this);
271         treeViewer.addSelectionChangedListener(this);
272     }
273
274     /**
275      * Returns a boolean indicating whether the passed tree element should be
276      * at LEAST gray-checked. Note that this method does not consider whether
277      * it should be white-checked, so a specified tree item which should be
278      * white-checked will result in a <code>true</code> answer from this method.
279      * To determine whether a tree item should be white-checked use method
280      * #determineShouldBeWhiteChecked(Object).
281      *
282      * @param treeElement java.lang.Object
283      * @return boolean
284      * @see #determineShouldBeWhiteChecked(Object)
285      */

286     protected boolean determineShouldBeAtLeastGrayChecked(Object JavaDoc treeElement) {
287         // if any list items associated with treeElement are checked then it
288
// retains its gray-checked status regardless of its children
289
List JavaDoc checked = (List JavaDoc) checkedStateStore.get(treeElement);
290         if (checked != null && (!checked.isEmpty())) {
291             return true;
292         }
293
294         // if any children of treeElement are still gray-checked then treeElement
295
// must remain gray-checked as well. Only ask expanded nodes
296
if (expandedTreeNodes.contains(treeElement)) {
297             Object JavaDoc[] children = treeContentProvider.getChildren(treeElement);
298             for (int i = 0; i < children.length; ++i) {
299                 if (checkedStateStore.containsKey(children[i])) {
300                     return true;
301                 }
302             }
303         }
304
305         return false;
306     }
307
308     /**
309      * Returns a boolean indicating whether the passed tree item should be
310      * white-checked.
311      *
312      * @return boolean
313      * @param treeElement java.lang.Object
314      */

315     protected boolean determineShouldBeWhiteChecked(Object JavaDoc treeElement) {
316         return areAllChildrenWhiteChecked(treeElement)
317                 && areAllElementsChecked(treeElement);
318     }
319
320     /**
321      * Recursively add appropriate tree elements to the collection of
322      * known white-checked tree elements.
323      *
324      * @param treeElement java.lang.Object
325      */

326     protected void determineWhiteCheckedDescendents(Object JavaDoc treeElement) {
327         // always go through all children first since their white-checked
328
// statuses will be needed to determine the white-checked status for
329
// this tree element
330
Object JavaDoc[] children = treeContentProvider.getElements(treeElement);
331         for (int i = 0; i < children.length; ++i) {
332             determineWhiteCheckedDescendents(children[i]);
333         }
334
335         // now determine the white-checked status for this tree element
336
if (determineShouldBeWhiteChecked(treeElement)) {
337             setWhiteChecked(treeElement, true);
338         }
339     }
340
341     /**
342      * Cause the tree viewer to expand all its items
343      */

344     public void expandAll() {
345         treeViewer.expandAll();
346     }
347
348     /**
349      * Expand an element in a tree viewer
350      */

351     private void expandTreeElement(final Object JavaDoc item) {
352         BusyIndicator.showWhile(treeViewer.getControl().getDisplay(),
353                 new Runnable JavaDoc() {
354                     public void run() {
355
356                         // First see if the children need to be given their checked state at all. If they've
357
// already been realized then this won't be necessary
358
if (expandedTreeNodes.contains(item)) {
359                             checkNewTreeElements(treeContentProvider
360                                     .getChildren(item));
361                         } else {
362
363                             expandedTreeNodes.add(item);
364                             if (whiteCheckedTreeItems.contains(item)) {
365                                 //If this is the first expansion and this is a white checked node then check the children
366
Object JavaDoc[] children = treeContentProvider
367                                         .getChildren(item);
368                                 for (int i = 0; i < children.length; ++i) {
369                                     if (!whiteCheckedTreeItems
370                                             .contains(children[i])) {
371                                         Object JavaDoc child = children[i];
372                                         setWhiteChecked(child, true);
373                                         treeViewer.setChecked(child, true);
374                                         checkedStateStore.put(child,
375                                                 new ArrayList JavaDoc());
376                                     }
377                                 }
378
379                                 //Now be sure to select the list of items too
380
setListForWhiteSelection(item);
381                             }
382                         }
383
384                     }
385                 });
386     }
387
388     /**
389      * Add all of the selected children of nextEntry to result recursively.
390      * This does not set any values in the checked state.
391      * @param The treeElement being queried
392      * @param addAll a boolean to indicate if the checked state store needs to be queried
393      * @param filter IElementFilter - the filter being used on the data
394      * @param monitor IProgressMonitor or null that the cancel is polled for
395      */

396     private void findAllSelectedListElements(Object JavaDoc treeElement,
397             String JavaDoc parentLabel, boolean addAll, IElementFilter filter,
398             IProgressMonitor monitor) throws InterruptedException JavaDoc {
399
400         String JavaDoc fullLabel = null;
401         if (monitor != null && monitor.isCanceled()) {
402             return;
403         }
404         if (monitor != null) {
405             fullLabel = getFullLabel(treeElement, parentLabel);
406             monitor.subTask(fullLabel);
407         }
408
409         if (addAll) {
410             filter.filterElements(listContentProvider.getElements(treeElement),
411                     monitor);
412         } else { //Add what we have stored
413
if (checkedStateStore.containsKey(treeElement)) {
414                 filter.filterElements((Collection JavaDoc) checkedStateStore
415                         .get(treeElement), monitor);
416             }
417         }
418
419         Object JavaDoc[] treeChildren = treeContentProvider.getChildren(treeElement);
420         for (int i = 0; i < treeChildren.length; i++) {
421             Object JavaDoc child = treeChildren[i];
422             if (addAll) {
423                 findAllSelectedListElements(child, fullLabel, true, filter,
424                         monitor);
425             } else { //Only continue for those with checked state
426
if (checkedStateStore.containsKey(child)) {
427                     findAllSelectedListElements(child, fullLabel,
428                             whiteCheckedTreeItems.contains(child), filter,
429                             monitor);
430                 }
431             }
432
433         }
434     }
435
436     /**
437      * Find all of the white checked children of the treeElement and add them to the collection.
438      * If the element itself is white select add it. If not then add any selected list elements
439      * and recurse down to the children.
440      * @param treeElement java.lang.Object
441      * @param result java.util.Collection
442      */

443     private void findAllWhiteCheckedItems(Object JavaDoc treeElement, Collection JavaDoc result) {
444
445         if (whiteCheckedTreeItems.contains(treeElement)) {
446             result.add(treeElement);
447         } else {
448             Collection JavaDoc listChildren = (Collection JavaDoc) checkedStateStore
449                     .get(treeElement);
450             //if it is not in the store then it and it's children are not interesting
451
if (listChildren == null) {
452                 return;
453             }
454             result.addAll(listChildren);
455             Object JavaDoc[] children = treeContentProvider.getChildren(treeElement);
456             for (int i = 0; i < children.length; ++i) {
457                 findAllWhiteCheckedItems(children[i], result);
458             }
459         }
460     }
461
462     /**
463      * Returns a flat list of all of the leaf elements which are checked. Filter
464      * then based on the supplied ElementFilter. If monitor is cancelled then
465      * return null
466      *
467      * @param filter -
468      * the filter for the data
469      * @param monitor
470      * IProgressMonitor or null
471      * @throws InterruptedException
472      * If the find is interrupted.
473      */

474     public void getAllCheckedListItems(IElementFilter filter,
475             IProgressMonitor monitor) throws InterruptedException JavaDoc {
476
477         //Iterate through the children of the root as the root is not in the store
478
Object JavaDoc[] children = treeContentProvider.getChildren(root);
479         for (int i = 0; i < children.length; ++i) {
480             findAllSelectedListElements(children[i], null,
481                     whiteCheckedTreeItems.contains(children[i]), filter,
482                     monitor);
483         }
484     }
485
486     /**
487      * Returns a flat list of all of the leaf elements which are checked.
488      *
489      * @return all of the leaf elements which are checked. This API does not
490      * return null in order to keep backwards compatibility.
491      */

492     public List JavaDoc getAllCheckedListItems() {
493
494         final ArrayList JavaDoc returnValue = new ArrayList JavaDoc();
495
496         IElementFilter passThroughFilter = new IElementFilter() {
497
498             public void filterElements(Collection JavaDoc elements,
499                     IProgressMonitor monitor) {
500                 returnValue.addAll(elements);
501             }
502
503             public void filterElements(Object JavaDoc[] elements,
504                     IProgressMonitor monitor) {
505                 for (int i = 0; i < elements.length; i++) {
506                     returnValue.add(elements[i]);
507                 }
508             }
509         };
510
511         try {
512             getAllCheckedListItems(passThroughFilter, null);
513         } catch (InterruptedException JavaDoc exception) {
514             return new ArrayList JavaDoc();
515         }
516         return returnValue;
517
518     }
519
520     /**
521      * Returns a list of all of the items that are white checked.
522      * Any folders that are white checked are added and then any files
523      * from white checked folders are added.
524      *
525      * @return the list of all of the items that are white checked
526      */

527     public List JavaDoc getAllWhiteCheckedItems() {
528
529         List JavaDoc result = new ArrayList JavaDoc();
530
531         //Iterate through the children of the root as the root is not in the store
532
Object JavaDoc[] children = treeContentProvider.getChildren(root);
533         for (int i = 0; i < children.length; ++i) {
534             findAllWhiteCheckedItems(children[i], result);
535         }
536
537         return result;
538     }
539
540     /**
541      * Answer the number of elements that have been checked by the
542      * user.
543      *
544      * @return int
545      */

546     public int getCheckedElementCount() {
547         return checkedStateStore.size();
548     }
549
550     /**
551      * Get the full label of the treeElement (its name and its parent's name).
552      * @param treeElement - the element being exported
553      * @param parentLabel - the label of the parent, can be null
554      * @return String
555      */

556     protected String JavaDoc getFullLabel(Object JavaDoc treeElement, String JavaDoc parentLabel) {
557         String JavaDoc label = parentLabel;
558         if (parentLabel == null){
559             label = ""; //$NON-NLS-1$
560
}
561         IPath parentName = new Path(label);
562
563         String JavaDoc elementText = treeLabelProvider.getText(treeElement);
564         if(elementText == null) {
565             return parentName.toString();
566         }
567         return parentName.append(elementText).toString();
568     }
569
570     /**
571      * Return a count of the number of list items associated with a
572      * given tree item.
573      *
574      * @return int
575      * @param treeElement java.lang.Object
576      */

577     protected int getListItemsSize(Object JavaDoc treeElement) {
578         Object JavaDoc[] elements = listContentProvider.getElements(treeElement);
579         return elements.length;
580     }
581
582     /**
583      * Get the table the list viewer uses.
584      * @return org.eclipse.swt.widgets.Table
585      */

586     public Table getListTable() {
587         return this.listViewer.getTable();
588     }
589
590     /**
591      * Logically gray-check all ancestors of treeItem by ensuring that they
592      * appear in the checked table
593      */

594     protected void grayCheckHierarchy(Object JavaDoc treeElement) {
595
596         //expand the element first to make sure we have populated for it
597
expandTreeElement(treeElement);
598
599         // if this tree element is already gray then its ancestors all are as well
600
if (checkedStateStore.containsKey(treeElement)) {
601             return; // no need to proceed upwards from here
602
}
603
604         checkedStateStore.put(treeElement, new ArrayList JavaDoc());
605         Object JavaDoc parent = treeContentProvider.getParent(treeElement);
606         if (parent != null) {
607             grayCheckHierarchy(parent);
608         }
609     }
610
611     /**
612      * Set the checked state of self and all ancestors appropriately. Do not white check anyone - this is
613      * only done down a hierarchy.
614      */

615     private void grayUpdateHierarchy(Object JavaDoc treeElement) {
616
617         boolean shouldBeAtLeastGray = determineShouldBeAtLeastGrayChecked(treeElement);
618
619         treeViewer.setGrayChecked(treeElement, shouldBeAtLeastGray);
620
621         if (whiteCheckedTreeItems.contains(treeElement)) {
622             whiteCheckedTreeItems.remove(treeElement);
623         }
624
625         // proceed up the tree element hierarchy
626
Object JavaDoc parent = treeContentProvider.getParent(treeElement);
627         if (parent != null) {
628             grayUpdateHierarchy(parent);
629         }
630     }
631
632     /**
633      * Set the initial checked state of the passed list element to true.
634      * @param element
635      */

636     public void initialCheckListItem(Object JavaDoc element) {
637         Object JavaDoc parent = treeContentProvider.getParent(element);
638         selectAndReveal(parent);
639         //Check the element in the viewer as if it had been manually checked
640
listViewer.setChecked(element, true);
641         //As this is not done from the UI then set the box for updating from the selection to false
642
listItemChecked(element, true, false);
643         grayUpdateHierarchy(parent);
644     }
645
646     /**
647      * Set the initial checked state of the passed element to true,
648      * as well as to all of its children and associated list elements
649      * @param element
650      */

651     public void initialCheckTreeItem(Object JavaDoc element) {
652         treeItemChecked(element, true);
653         selectAndReveal(element);
654     }
655
656     private void selectAndReveal(Object JavaDoc treeElement) {
657         treeViewer.reveal(treeElement);
658         IStructuredSelection selection = new StructuredSelection(treeElement);
659         treeViewer.setSelection(selection);
660     }
661
662     /**
663      * Initialize this group's viewers after they have been laid out.
664      */

665     protected void initialize() {
666         treeViewer.setInput(root);
667         this.expandedTreeNodes = new ArrayList JavaDoc();
668         this.expandedTreeNodes.add(root);
669
670     }
671
672     /**
673      * Callback that's invoked when the checked status of an item in the list
674      * is changed by the user. Do not try and update the hierarchy if we are building the
675      * initial list.
676      */

677     protected void listItemChecked(Object JavaDoc listElement, boolean state,
678             boolean updatingFromSelection) {
679         List JavaDoc checkedListItems = (List JavaDoc) checkedStateStore
680                 .get(currentTreeSelection);
681         //If it has not been expanded do so as the selection of list items will affect gray state
682
if (!expandedTreeNodes.contains(currentTreeSelection)) {
683             expandTreeElement(currentTreeSelection);
684         }
685
686         if (state) {
687             if (checkedListItems == null) {
688                 // since the associated tree item has gone from 0 -> 1 checked
689
// list items, tree checking may need to be updated
690
grayCheckHierarchy(currentTreeSelection);
691                 checkedListItems = (List JavaDoc) checkedStateStore
692                         .get(currentTreeSelection);
693             }
694             checkedListItems.add(listElement);
695         } else {
696             checkedListItems.remove(listElement);
697             if (checkedListItems.isEmpty()) {
698                 // since the associated tree item has gone from 1 -> 0 checked
699
// list items, tree checking may need to be updated
700
ungrayCheckHierarchy(currentTreeSelection);
701             }
702         }
703
704         //Update the list with the selections if there are any
705
if (checkedListItems.size() > 0) {
706             checkedStateStore.put(currentTreeSelection, checkedListItems);
707         }
708         if (updatingFromSelection) {
709             grayUpdateHierarchy(currentTreeSelection);
710         }
711     }
712
713     /**
714      * Notify all checked state listeners that the passed element has had
715      * its checked state changed to the passed state
716      */

717     protected void notifyCheckStateChangeListeners(
718             final CheckStateChangedEvent event) {
719         Object JavaDoc[] array = getListeners();
720         for (int i = 0; i < array.length; i++) {
721             final ICheckStateListener l = (ICheckStateListener) array[i];
722             SafeRunner.run(new SafeRunnable() {
723                 public void run() {
724                     l.checkStateChanged(event);
725                 }
726             });
727         }
728     }
729
730     /**
731      *Set the contents of the list viewer based upon the specified selected
732      *tree element. This also includes checking the appropriate list items.
733      *
734      *@param treeElement java.lang.Object
735      */

736     protected void populateListViewer(final Object JavaDoc treeElement) {
737         listViewer.setInput(treeElement);
738
739         //If the element is white checked but not expanded we have not set up all of the children yet
740
if (!(expandedTreeNodes.contains(treeElement))
741                 && whiteCheckedTreeItems.contains(treeElement)) {
742
743             //Potentially long operation - show a busy cursor
744
BusyIndicator.showWhile(treeViewer.getControl().getDisplay(),
745                     new Runnable JavaDoc() {
746                         public void run() {
747                             setListForWhiteSelection(treeElement);
748                             listViewer.setAllChecked(true);
749                         }
750                     });
751
752         } else {
753             List JavaDoc listItemsToCheck = (List JavaDoc) checkedStateStore.get(treeElement);
754
755             if (listItemsToCheck != null) {
756                 Iterator JavaDoc listItemsEnum = listItemsToCheck.iterator();
757                 while (listItemsEnum.hasNext()) {
758                     listViewer.setChecked(listItemsEnum.next(), true);
759                 }
760             }
761         }
762     }
763
764     /**
765      * Logically gray-check all ancestors of treeItem by ensuring that they
766      * appear in the checked table. Add any elements to the selectedNodes
767      * so we can track that has been done.
768      */

769     private void primeHierarchyForSelection(Object JavaDoc item, Set JavaDoc selectedNodes) {
770
771         //Only prime it if we haven't visited yet
772
if (selectedNodes.contains(item)) {
773             return;
774         }
775
776         checkedStateStore.put(item, new ArrayList JavaDoc());
777
778         //mark as expanded as we are going to populate it after this
779
expandedTreeNodes.add(item);
780         selectedNodes.add(item);
781
782         Object JavaDoc parent = treeContentProvider.getParent(item);
783         if (parent != null) {
784             primeHierarchyForSelection(parent, selectedNodes);
785         }
786     }
787
788     /**
789      * Remove the passed listener from self's collection of clients
790      * that listen for changes to element checked states
791      *
792      * @param listener ICheckStateListener
793      */

794     public void removeCheckStateListener(ICheckStateListener listener) {
795         removeListenerObject(listener);
796     }
797
798     /**
799      * Handle the selection of an item in the tree viewer
800      *
801      * @param event SelectionChangedEvent
802      */

803     public void selectionChanged(SelectionChangedEvent event) {
804         IStructuredSelection selection = (IStructuredSelection) event
805                 .getSelection();
806         Object JavaDoc selectedElement = selection.getFirstElement();
807         if (selectedElement == null) {
808             currentTreeSelection = null;
809             listViewer.setInput(currentTreeSelection);
810             return;
811         }
812
813         // ie.- if not an item deselection
814
if (selectedElement != currentTreeSelection) {
815             populateListViewer(selectedElement);
816         }
817
818         currentTreeSelection = selectedElement;
819     }
820
821     /**
822      * Select or deselect all of the elements in the tree depending on the value of the selection
823      * boolean. Be sure to update the displayed files as well.
824      * @param selection
825      */

826     public void setAllSelections(final boolean selection) {
827
828         //If there is no root there is nothing to select
829
if (root == null) {
830             return;
831         }
832
833         //Potentially long operation - show a busy cursor
834
BusyIndicator.showWhile(treeViewer.getControl().getDisplay(),
835                 new Runnable JavaDoc() {
836                     public void run() {
837                         setTreeChecked(root, selection);
838                         listViewer.setAllChecked(selection);
839                     }
840                 });
841     }
842
843     /**
844      * The treeElement has been white selected. Get the list for the element and
845      * set it in the checked state store.
846      * @param treeElement the element being updated
847      */

848     private void setListForWhiteSelection(Object JavaDoc treeElement) {
849
850         Object JavaDoc[] listItems = listContentProvider.getElements(treeElement);
851         List JavaDoc listItemsChecked = new ArrayList JavaDoc();
852         for (int i = 0; i < listItems.length; ++i) {
853             listItemsChecked.add(listItems[i]);
854         }
855
856         checkedStateStore.put(treeElement, listItemsChecked);
857     }
858
859     /**
860      * Set the list viewer's providers to those passed
861      *
862      * @param contentProvider ITreeContentProvider
863      * @param labelProvider ILabelProvider
864      */

865     public void setListProviders(IStructuredContentProvider contentProvider,
866             ILabelProvider labelProvider) {
867         listViewer.setContentProvider(contentProvider);
868         listViewer.setLabelProvider(labelProvider);
869     }
870
871     /**
872      * Set the comparator that is to be applied to self's list viewer
873      *
874      * @param comparator the sorter for the list
875      */

876     public void setListComparator(ViewerComparator comparator) {
877         listViewer.setComparator(comparator);
878     }
879
880     /**
881      * Set the root of the widget to be new Root. Regenerate all of the tables and lists from this
882      * value.
883      * @param newRoot
884      */

885     public void setRoot(Object JavaDoc newRoot) {
886         this.root = newRoot;
887         initialize();
888     }
889
890     /**
891      * Set the checked state of the passed tree element appropriately, and
892      * do so recursively to all of its child tree elements as well
893      */

894     protected void setTreeChecked(Object JavaDoc treeElement, boolean state) {
895
896         if (treeElement.equals(currentTreeSelection)) {
897             listViewer.setAllChecked(state);
898         }
899
900         if (state) {
901             setListForWhiteSelection(treeElement);
902         } else {
903             checkedStateStore.remove(treeElement);
904         }
905
906         setWhiteChecked(treeElement, state);
907         treeViewer.setChecked(treeElement, state);
908         treeViewer.setGrayed(treeElement, false);
909
910         // now logically check/uncheck all children as well if it has been expanded
911
if (expandedTreeNodes.contains(treeElement)) {
912             Object JavaDoc[] children = treeContentProvider.getChildren(treeElement);
913             for (int i = 0; i < children.length; ++i) {
914                 setTreeChecked(children[i], state);
915             }
916         }
917     }
918
919     /**
920      * Set the tree viewer's providers to those passed
921      *
922      * @param contentProvider ITreeContentProvider
923      * @param labelProvider ILabelProvider
924      */

925     public void setTreeProviders(ITreeContentProvider contentProvider,
926             ILabelProvider labelProvider) {
927         treeViewer.setContentProvider(contentProvider);
928         treeViewer.setLabelProvider(labelProvider);
929     }
930
931     /**
932      * Set the comparator that is to be applied to self's tree viewer
933      *
934      * @param comparator the comparator for the tree
935      */

936     public void setTreeComparator(ViewerComparator comparator) {
937         treeViewer.setComparator(comparator);
938     }
939
940     /**
941      * Adjust the collection of references to white-checked tree elements appropriately.
942      *
943      * @param treeElement java.lang.Object
944      * @param isWhiteChecked boolean
945      */

946     protected void setWhiteChecked(Object JavaDoc treeElement, boolean isWhiteChecked) {
947         if (isWhiteChecked) {
948             if (!whiteCheckedTreeItems.contains(treeElement)) {
949                 whiteCheckedTreeItems.add(treeElement);
950             }
951         } else {
952             whiteCheckedTreeItems.remove(treeElement);
953         }
954     }
955
956     /**
957      * Handle the collapsing of an element in a tree viewer
958      */

959     public void treeCollapsed(TreeExpansionEvent event) {
960         // We don't need to do anything with this
961
}
962
963     /**
964      * Handle the expansionsion of an element in a tree viewer
965      */

966     public void treeExpanded(TreeExpansionEvent event) {
967         expandTreeElement(event.getElement());
968     }
969
970     /**
971      * Callback that's invoked when the checked status of an item in the tree
972      * is changed by the user.
973      */

974     protected void treeItemChecked(Object JavaDoc treeElement, boolean state) {
975
976         // recursively adjust all child tree elements appropriately
977
setTreeChecked(treeElement, state);
978
979         Object JavaDoc parent = treeContentProvider.getParent(treeElement);
980         if (parent == null) {
981             return;
982         }
983
984         // now update upwards in the tree hierarchy
985
if (state) {
986             grayCheckHierarchy(parent);
987         } else {
988             ungrayCheckHierarchy(parent);
989         }
990
991         //Update the hierarchy but do not white select the parent
992
grayUpdateHierarchy(parent);
993     }
994
995     /**
996      * Logically un-gray-check all ancestors of treeItem iff appropriate.
997      */

998     protected void ungrayCheckHierarchy(Object JavaDoc treeElement) {
999         if (!determineShouldBeAtLeastGrayChecked(treeElement)) {
1000            checkedStateStore.remove(treeElement);
1001        }
1002
1003        Object JavaDoc parent = treeContentProvider.getParent(treeElement);
1004        if (parent != null) {
1005            ungrayCheckHierarchy(parent);
1006        }
1007    }
1008
1009    /**
1010     * Set the checked state of self and all ancestors appropriately
1011     */

1012    protected void updateHierarchy(Object JavaDoc treeElement) {
1013
1014        boolean whiteChecked = determineShouldBeWhiteChecked(treeElement);
1015        boolean shouldBeAtLeastGray = determineShouldBeAtLeastGrayChecked(treeElement);
1016
1017        treeViewer.setChecked(treeElement, shouldBeAtLeastGray);
1018        setWhiteChecked(treeElement, whiteChecked);
1019        if (whiteChecked) {
1020            treeViewer.setGrayed(treeElement, false);
1021        } else {
1022            treeViewer.setGrayed(treeElement, shouldBeAtLeastGray);
1023        }
1024
1025        // proceed up the tree element hierarchy but gray select all of them
1026
Object JavaDoc parent = treeContentProvider.getParent(treeElement);
1027        if (parent != null) {
1028            grayUpdateHierarchy(parent);
1029        }
1030    }
1031
1032    /**
1033     * Update the selections of the tree elements in items to reflect the new
1034     * selections provided.
1035     * @param items Map with keys of Object (the tree element) and values of List (the selected
1036     * list elements).
1037     * NOTE: This method does not special case keys with no values (i.e.,
1038     * a tree element with an empty list). If a tree element does not have any selected
1039     * items, do not include the element in the Map.
1040     */

1041    public void updateSelections(Map JavaDoc items) {
1042        // We are replacing all selected items with the given selected items,
1043
// so reinitialize everything.
1044
this.listViewer.setAllChecked(false);
1045        this.treeViewer.setCheckedElements(new Object JavaDoc[0]);
1046        this.whiteCheckedTreeItems = new HashSet JavaDoc();
1047        Set JavaDoc selectedNodes = new HashSet JavaDoc();
1048        checkedStateStore = new HashMap JavaDoc();
1049
1050        //Update the store before the hierarchy to prevent updating parents before all of the children are done
1051
Iterator JavaDoc keyIterator = items.keySet().iterator();
1052        while (keyIterator.hasNext()) {
1053            Object JavaDoc key = keyIterator.next();
1054            List JavaDoc selections = (List JavaDoc) items.get(key);
1055            //Replace the items in the checked state store with those from the supplied items
1056
checkedStateStore.put(key, selections);
1057            selectedNodes.add(key);
1058            // proceed up the tree element hierarchy
1059
Object JavaDoc parent = treeContentProvider.getParent(key);
1060            if (parent != null) {
1061                // proceed up the tree element hierarchy and make sure everything is in the table
1062
primeHierarchyForSelection(parent, selectedNodes);
1063            }
1064        }
1065
1066        // Update the checked tree items. Since each tree item has a selected
1067
// item, all the tree items will be gray checked.
1068
treeViewer.setCheckedElements(checkedStateStore.keySet().toArray());
1069        treeViewer.setGrayedElements(checkedStateStore.keySet().toArray());
1070
1071        // Update the listView of the currently selected tree item.
1072
if (currentTreeSelection != null) {
1073            Object JavaDoc displayItems = items.get(currentTreeSelection);
1074            if (displayItems != null) {
1075                listViewer.setCheckedElements(((List JavaDoc) displayItems).toArray());
1076            }
1077        }
1078    }
1079
1080    /**
1081     * Set the focus on to the list widget.
1082     */

1083    public void setFocus() {
1084
1085        this.treeViewer.getTree().setFocus();
1086    }
1087
1088}
1089
1090
Popular Tags