KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2004, 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  * Tom Schindl <tom.schindl@bestsolution.at> - concept of ViewerRow,
11  * refactoring (bug 153993), bug 167323, 191468
12  *******************************************************************************/

13
14 package org.eclipse.jface.viewers;
15
16 import java.util.Arrays JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.LinkedList JavaDoc;
19 import java.util.List JavaDoc;
20
21 import org.eclipse.jface.util.Policy;
22 import org.eclipse.swt.SWT;
23 import org.eclipse.swt.events.DisposeEvent;
24 import org.eclipse.swt.events.DisposeListener;
25 import org.eclipse.swt.events.TreeEvent;
26 import org.eclipse.swt.events.TreeListener;
27 import org.eclipse.swt.graphics.Point;
28 import org.eclipse.swt.widgets.Composite;
29 import org.eclipse.swt.widgets.Control;
30 import org.eclipse.swt.widgets.Event;
31 import org.eclipse.swt.widgets.Item;
32 import org.eclipse.swt.widgets.Listener;
33 import org.eclipse.swt.widgets.Tree;
34 import org.eclipse.swt.widgets.TreeItem;
35 import org.eclipse.swt.widgets.Widget;
36
37 /**
38  * A concrete viewer based on an SWT <code>Tree</code> control.
39  * <p>
40  * This class is not intended to be subclassed outside the viewer framework. It
41  * is designed to be instantiated with a pre-existing SWT tree control and
42  * configured with a domain-specific content provider, label provider, element
43  * filter (optional), and element sorter (optional).
44  * </p>
45  * <p>
46  * Content providers for tree viewers must implement either the
47  * {@link ITreeContentProvider} interface, (as of 3.2) the
48  * {@link ILazyTreeContentProvider} interface, or (as of 3.3) the
49  * {@link ILazyTreePathContentProvider}. If the content provider is an
50  * <code>ILazyTreeContentProvider</code> or an
51  * <code>ILazyTreePathContentProvider</code>, the underlying Tree must be
52  * created using the {@link SWT#VIRTUAL} style bit, and the tree viewer will not
53  * support sorting or filtering.
54  * </p>
55  */

56 public class TreeViewer extends AbstractTreeViewer {
57
58     private static final String JavaDoc VIRTUAL_DISPOSE_KEY = Policy.JFACE
59             + ".DISPOSE_LISTENER"; //$NON-NLS-1$
60

61     /**
62      * This viewer's control.
63      */

64     private Tree tree;
65
66     /**
67      * Flag for whether the tree has been disposed of.
68      */

69     private boolean treeIsDisposed = false;
70
71     private boolean contentProviderIsLazy;
72
73     private boolean contentProviderIsTreeBased;
74
75     /**
76      * The row object reused
77      */

78     private TreeViewerRow cachedRow;
79
80     /**
81      * true if we are inside a preservingSelection() call
82      */

83     private boolean preservingSelection;
84
85     /**
86      * Creates a tree viewer on a newly-created tree control under the given
87      * parent. The tree control is created using the SWT style bits
88      * <code>MULTI, H_SCROLL, V_SCROLL,</code> and <code>BORDER</code>. The
89      * viewer has no input, no content provider, a default label provider, no
90      * sorter, and no filters.
91      *
92      * @param parent
93      * the parent control
94      */

95     public TreeViewer(Composite parent) {
96         this(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
97     }
98
99     /**
100      * Creates a tree viewer on a newly-created tree control under the given
101      * parent. The tree control is created using the given SWT style bits. The
102      * viewer has no input, no content provider, a default label provider, no
103      * sorter, and no filters.
104      *
105      * @param parent
106      * the parent control
107      * @param style
108      * the SWT style bits used to create the tree.
109      */

110     public TreeViewer(Composite parent, int style) {
111         this(new Tree(parent, style));
112     }
113
114     /**
115      * Creates a tree viewer on the given tree control. The viewer has no input,
116      * no content provider, a default label provider, no sorter, and no filters.
117      *
118      * @param tree
119      * the tree control
120      */

121     public TreeViewer(Tree tree) {
122         super();
123         this.tree = tree;
124         hookControl(tree);
125     }
126
127     /*
128      * (non-Javadoc) Method declared in AbstractTreeViewer.
129      */

130     protected void addTreeListener(Control c, TreeListener listener) {
131         ((Tree) c).addTreeListener(listener);
132     }
133
134     /*
135      * (non-Javadoc)
136      *
137      * @see org.eclipse.jface.viewers.ColumnViewer#getColumnViewerOwner(int)
138      */

139     protected Widget getColumnViewerOwner(int columnIndex) {
140         if (columnIndex < 0 || ( columnIndex > 0 && columnIndex >= getTree().getColumnCount() ) ) {
141             return null;
142         }
143
144         if (getTree().getColumnCount() == 0)// Hang it off the table if it
145
return getTree();
146
147         return getTree().getColumn(columnIndex);
148     }
149
150     /*
151      * (non-Javadoc) Method declared in AbstractTreeViewer.
152      */

153     protected Item[] getChildren(Widget o) {
154         if (o instanceof TreeItem) {
155             return ((TreeItem) o).getItems();
156         }
157         if (o instanceof Tree) {
158             return ((Tree) o).getItems();
159         }
160         return null;
161     }
162
163     /*
164      * (non-Javadoc) Method declared in Viewer.
165      */

166     public Control getControl() {
167         return tree;
168     }
169
170     /*
171      * (non-Javadoc) Method declared in AbstractTreeViewer.
172      */

173     protected boolean getExpanded(Item item) {
174         return ((TreeItem) item).getExpanded();
175     }
176
177     /*
178      * (non-Javadoc)
179      *
180      * @see org.eclipse.jface.viewers.ColumnViewer#getItemAt(org.eclipse.swt.graphics.Point)
181      */

182     protected Item getItemAt(Point p) {
183         TreeItem[] selection = tree.getSelection();
184
185         if( selection.length == 1 ) {
186             int columnCount = tree.getColumnCount();
187             
188             for( int i = 0; i < columnCount; i++ ) {
189                 if( selection[0].getBounds(i).contains(p) ) {
190                     return selection[0];
191                 }
192             }
193         }
194
195         return getTree().getItem(p);
196     }
197
198     /*
199      * (non-Javadoc) Method declared in AbstractTreeViewer.
200      */

201     protected int getItemCount(Control widget) {
202         return ((Tree) widget).getItemCount();
203     }
204
205     /*
206      * (non-Javadoc) Method declared in AbstractTreeViewer.
207      */

208     protected int getItemCount(Item item) {
209         return ((TreeItem) item).getItemCount();
210     }
211
212     /*
213      * (non-Javadoc) Method declared in AbstractTreeViewer.
214      */

215     protected Item[] getItems(Item item) {
216         return ((TreeItem) item).getItems();
217     }
218
219     /**
220      * The tree viewer implementation of this <code>Viewer</code> framework
221      * method ensures that the given label provider is an instance of either
222      * <code>ITableLabelProvider</code> or <code>ILabelProvider</code>. If
223      * it is an <code>ITableLabelProvider</code>, then it provides a separate
224      * label text and image for each column. If it is an
225      * <code>ILabelProvider</code>, then it provides only the label text and
226      * image for the first column, and any remaining columns are blank.
227      */

228     public IBaseLabelProvider getLabelProvider() {
229         return super.getLabelProvider();
230     }
231
232     /*
233      * (non-Javadoc) Method declared in AbstractTreeViewer.
234      */

235     protected Item getParentItem(Item item) {
236         return ((TreeItem) item).getParentItem();
237     }
238
239     /*
240      * (non-Javadoc) Method declared in AbstractTreeViewer.
241      */

242     protected Item[] getSelection(Control widget) {
243         return ((Tree) widget).getSelection();
244     }
245
246     /**
247      * Returns this tree viewer's tree control.
248      *
249      * @return the tree control
250      */

251     public Tree getTree() {
252         return tree;
253     }
254
255     /*
256      * (non-Javadoc)
257      *
258      * @see org.eclipse.jface.viewers.AbstractTreeViewer#hookControl(org.eclipse.swt.widgets.Control)
259      */

260     protected void hookControl(Control control) {
261         super.hookControl(control);
262         Tree treeControl = (Tree) control;
263
264         if ((treeControl.getStyle() & SWT.VIRTUAL) != 0) {
265             treeControl.addDisposeListener(new DisposeListener() {
266                 public void widgetDisposed(DisposeEvent e) {
267                     treeIsDisposed = true;
268                     unmapAllElements();
269                 }
270             });
271             treeControl.addListener(SWT.SetData, new Listener() {
272
273                 public void handleEvent(Event event) {
274                     if (contentProviderIsLazy) {
275                         TreeItem item = (TreeItem) event.item;
276                         TreeItem parentItem = item.getParentItem();
277                         int index = event.index;
278                         virtualLazyUpdateWidget(
279                                 parentItem == null ? (Widget) getTree()
280                                         : parentItem, index);
281                     }
282                 }
283
284             });
285         }
286     }
287
288     protected ColumnViewerEditor createViewerEditor() {
289         return new TreeViewerEditor(this,null,new ColumnViewerEditorActivationStrategy(this),ColumnViewerEditor.DEFAULT);
290     }
291
292     /*
293      * (non-Javadoc) Method declared in AbstractTreeViewer.
294      */

295     protected Item newItem(Widget parent, int flags, int ix) {
296         TreeItem item;
297
298         if (parent instanceof TreeItem) {
299             item = (TreeItem) createNewRowPart(getViewerRowFromItem(parent),
300                     flags, ix).getItem();
301         } else {
302             item = (TreeItem) createNewRowPart(null, flags, ix).getItem();
303         }
304
305         return item;
306     }
307
308     /*
309      * (non-Javadoc) Method declared in AbstractTreeViewer.
310      */

311     protected void removeAll(Control widget) {
312         ((Tree) widget).removeAll();
313     }
314
315     /*
316      * (non-Javadoc) Method declared in AbstractTreeViewer.
317      */

318     protected void setExpanded(Item node, boolean expand) {
319         ((TreeItem) node).setExpanded(expand);
320         if (contentProviderIsLazy) {
321             // force repaints to happen
322
getControl().update();
323         }
324     }
325
326     /*
327      * (non-Javadoc) Method declared in AbstractTreeViewer.
328      */

329     protected void setSelection(List JavaDoc items) {
330
331         Item[] current = getSelection(getTree());
332
333         // Don't bother resetting the same selection
334
if (isSameSelection(items, current)) {
335             return;
336         }
337
338         TreeItem[] newItems = new TreeItem[items.size()];
339         items.toArray(newItems);
340         getTree().setSelection(newItems);
341     }
342
343     /*
344      * (non-Javadoc) Method declared in AbstractTreeViewer.
345      */

346     protected void showItem(Item item) {
347         getTree().showItem((TreeItem) item);
348     }
349
350     /*
351      * (non-Javadoc)
352      *
353      * @see org.eclipse.jface.viewers.AbstractTreeViewer#getChild(org.eclipse.swt.widgets.Widget,
354      * int)
355      */

356     protected Item getChild(Widget widget, int index) {
357         if (widget instanceof TreeItem) {
358             return ((TreeItem) widget).getItem(index);
359         }
360         if (widget instanceof Tree) {
361             return ((Tree) widget).getItem(index);
362         }
363         return null;
364     }
365
366     protected void assertContentProviderType(IContentProvider provider) {
367         if (provider instanceof ILazyTreeContentProvider
368                 || provider instanceof ILazyTreePathContentProvider) {
369             return;
370         }
371         super.assertContentProviderType(provider);
372     }
373
374     protected Object JavaDoc[] getRawChildren(Object JavaDoc parent) {
375         if (contentProviderIsLazy) {
376             return new Object JavaDoc[0];
377         }
378         return super.getRawChildren(parent);
379     }
380
381     void preservingSelection(Runnable JavaDoc updateCode, boolean reveal) {
382         if (preservingSelection){
383             // avoid preserving the selection if called reentrantly,
384
// see bug 172640
385
updateCode.run();
386             return;
387         }
388         preservingSelection = true;
389         try {
390             super.preservingSelection(updateCode, reveal);
391         } finally {
392             preservingSelection = false;
393         }
394     }
395
396     /**
397      * For a TreeViewer with a tree with the VIRTUAL style bit set, set the
398      * number of children of the given element or tree path. To set the number
399      * of children of the invisible root of the tree, you can pass the input
400      * object or an empty tree path.
401      *
402      * @param elementOrTreePath
403      * the element, or tree path
404      * @param count
405      *
406      * @since 3.2
407      */

408     public void setChildCount(final Object JavaDoc elementOrTreePath, final int count) {
409         if (isBusy())
410             return;
411         preservingSelection(new Runnable JavaDoc() {
412             public void run() {
413                 if (internalIsInputOrEmptyPath(elementOrTreePath)) {
414                     getTree().setItemCount(count);
415                     return;
416                 }
417                 Widget[] items = internalFindItems(elementOrTreePath);
418                 for (int i = 0; i < items.length; i++) {
419                     TreeItem treeItem = (TreeItem) items[i];
420                     treeItem.setItemCount(count);
421                 }
422             }
423         });
424     }
425
426     /**
427      * For a TreeViewer with a tree with the VIRTUAL style bit set, replace the
428      * given parent's child at index with the given element. If the given parent
429      * is this viewer's input or an empty tree path, this will replace the root
430      * element at the given index.
431      * <p>
432      * This method should be called by implementers of ILazyTreeContentProvider
433      * to populate this viewer.
434      * </p>
435      *
436      * @param parentElementOrTreePath
437      * the parent of the element that should be updated, or the tree
438      * path to that parent
439      * @param index
440      * the index in the parent's children
441      * @param element
442      * the new element
443      *
444      * @see #setChildCount(Object, int)
445      * @see ILazyTreeContentProvider
446      * @see ILazyTreePathContentProvider
447      *
448      * @since 3.2
449      */

450     public void replace(final Object JavaDoc parentElementOrTreePath, final int index,
451             final Object JavaDoc element) {
452         if (isBusy())
453             return;
454         Item[] selectedItems = getSelection(getControl());
455         TreeSelection selection = (TreeSelection) getSelection();
456         Widget[] itemsToDisassociate;
457         if (parentElementOrTreePath instanceof TreePath) {
458             TreePath elementPath = ((TreePath) parentElementOrTreePath)
459                     .createChildPath(element);
460             itemsToDisassociate = internalFindItems(elementPath);
461         } else {
462             itemsToDisassociate = internalFindItems(element);
463         }
464         if (internalIsInputOrEmptyPath(parentElementOrTreePath)) {
465             if (index < tree.getItemCount()) {
466                 TreeItem item = tree.getItem(index);
467                 selection = adjustSelectionForReplace(selectedItems, selection, item, element, getRoot());
468                 // disassociate any different item that represents the
469
// same element under the same parent (the tree)
470
for (int i = 0; i < itemsToDisassociate.length; i++) {
471                     if (itemsToDisassociate[i] instanceof TreeItem) {
472                         TreeItem itemToDisassociate = (TreeItem) itemsToDisassociate[i];
473                         if (itemToDisassociate != item
474                                 && itemToDisassociate.getParentItem() == null) {
475                             int indexToDisassociate = getTree().indexOf(
476                                     itemToDisassociate);
477                             disassociate(itemToDisassociate);
478                             getTree().clear(indexToDisassociate, true);
479                         }
480                     }
481                 }
482                 Object JavaDoc oldData = item.getData();
483                 updateItem(item, element);
484                 if (!TreeViewer.this.equals(oldData, element)) {
485                     item.clearAll(true);
486                 }
487             }
488         } else {
489             Widget[] parentItems = internalFindItems(parentElementOrTreePath);
490             for (int i = 0; i < parentItems.length; i++) {
491                 TreeItem parentItem = (TreeItem) parentItems[i];
492                 if (index < parentItem.getItemCount()) {
493                     TreeItem item = parentItem.getItem(index);
494                     selection = adjustSelectionForReplace(selectedItems, selection, item, element, parentItem.getData());
495                     // disassociate any different item that represents the
496
// same element under the same parent (the tree)
497
for (int j = 0; j < itemsToDisassociate.length; j++) {
498                         if (itemsToDisassociate[j] instanceof TreeItem) {
499                             TreeItem itemToDisassociate = (TreeItem) itemsToDisassociate[j];
500                             if (itemToDisassociate != item
501                                     && itemToDisassociate.getParentItem() == parentItem) {
502                                 int indexToDisaccociate = parentItem
503                                         .indexOf(itemToDisassociate);
504                                 disassociate(itemToDisassociate);
505                                 parentItem.clear(indexToDisaccociate, true);
506                             }
507                         }
508                     }
509                     Object JavaDoc oldData = item.getData();
510                     updateItem(item, element);
511                     if (!TreeViewer.this.equals(oldData, element)) {
512                         item.clearAll(true);
513                     }
514                 }
515             }
516         }
517         // Restore the selection if we are not already in a nested preservingSelection:
518
if (!preservingSelection) {
519             setSelectionToWidget(selection, false);
520             // send out notification if old and new differ
521
ISelection newSelection = getSelection();
522             if (!newSelection.equals(selection)) {
523                 handleInvalidSelection(selection, newSelection);
524             }
525         }
526     }
527
528     /**
529      * Fix for bug 185673: If the currently replaced item was selected, add it
530      * to the selection that is being restored. Only do this if its getData() is
531      * currently null
532      *
533      * @param selectedItems
534      * @param selection
535      * @param item
536      * @param element
537      * @return
538      */

539     private TreeSelection adjustSelectionForReplace(Item[] selectedItems,
540             TreeSelection selection, TreeItem item, Object JavaDoc element, Object JavaDoc parentElement) {
541         if (item.getData() != null || selectedItems.length == selection.size()
542                 || parentElement == null) {
543             // Don't do anything - we are not seeing an instance of bug 185673
544
return selection;
545         }
546         for (int i = 0; i < selectedItems.length; i++) {
547             if (item == selectedItems[i]) {
548                 // The current item was selected, but its data is null.
549
// The data will be replaced by the given element, so to keep
550
// it selected, we have to add it to the selection.
551
TreePath[] originalPaths = selection.getPaths();
552                 int length = originalPaths.length;
553                 TreePath[] paths = new TreePath[length + 1];
554                 System.arraycopy(originalPaths, 0, paths, 0, length);
555                 // set the element temporarily so that we can call getTreePathFromItem
556
item.setData(element);
557                 paths[length] = getTreePathFromItem(item);
558                 item.setData(null);
559                 return new TreeSelection(paths, selection.getElementComparer());
560             }
561         }
562         // The item was not selected, return the given selection
563
return selection;
564     }
565
566     public boolean isExpandable(Object JavaDoc element) {
567         if (contentProviderIsLazy) {
568             TreeItem treeItem = (TreeItem) internalExpand(element, false);
569             if (treeItem == null) {
570                 return false;
571             }
572             virtualMaterializeItem(treeItem);
573             return treeItem.getItemCount() > 0;
574         }
575         return super.isExpandable(element);
576     }
577
578     protected Object JavaDoc getParentElement(Object JavaDoc element) {
579         boolean oldBusy = busy;
580         busy = true;
581         try {
582             if (contentProviderIsLazy && !contentProviderIsTreeBased && !(element instanceof TreePath)) {
583                 ILazyTreeContentProvider lazyTreeContentProvider = (ILazyTreeContentProvider) getContentProvider();
584                 return lazyTreeContentProvider.getParent(element);
585             }
586             if (contentProviderIsLazy && contentProviderIsTreeBased && !(element instanceof TreePath)) {
587                 ILazyTreePathContentProvider lazyTreePathContentProvider = (ILazyTreePathContentProvider) getContentProvider();
588                 TreePath[] parents = lazyTreePathContentProvider
589                 .getParents(element);
590                 if (parents != null && parents.length > 0) {
591                     return parents[0];
592                 }
593             }
594             return super.getParentElement(element);
595         } finally {
596             busy = oldBusy;
597         }
598     }
599
600     protected void createChildren(Widget widget) {
601         if (contentProviderIsLazy) {
602             Object JavaDoc element = widget.getData();
603             if (element == null && widget instanceof TreeItem) {
604                 // parent has not been materialized
605
virtualMaterializeItem((TreeItem) widget);
606                 // try getting the element now that updateElement was called
607
element = widget.getData();
608             }
609             if (element == null) {
610                 // give up because the parent is still not materialized
611
return;
612             }
613             Item[] children = getChildren(widget);
614             if (children.length == 1 && children[0].getData() == null) {
615                 // found a dummy node
616
virtualLazyUpdateChildCount(widget, children.length);
617                 children = getChildren(widget);
618             }
619             // touch all children to make sure they are materialized
620
for (int i = 0; i < children.length; i++) {
621                 if (children[i].getData() == null) {
622                     virtualLazyUpdateWidget(widget, i);
623                 }
624             }
625             return;
626         }
627         super.createChildren(widget);
628     }
629
630     protected void internalAdd(Widget widget, Object JavaDoc parentElement,
631             Object JavaDoc[] childElements) {
632         if (contentProviderIsLazy) {
633             if (widget instanceof TreeItem) {
634                 TreeItem ti = (TreeItem) widget;
635                 int count = ti.getItemCount() + childElements.length;
636                 ti.setItemCount(count);
637                 ti.clearAll(false);
638             } else {
639                 Tree t = (Tree) widget;
640                 t.setItemCount(t.getItemCount() + childElements.length);
641                 t.clearAll(false);
642             }
643             return;
644         }
645         super.internalAdd(widget, parentElement, childElements);
646     }
647
648     private void virtualMaterializeItem(TreeItem treeItem) {
649         if (treeItem.getData() != null) {
650             // already materialized
651
return;
652         }
653         if (!contentProviderIsLazy) {
654             return;
655         }
656         int index;
657         Widget parent = treeItem.getParentItem();
658         if (parent == null) {
659             parent = treeItem.getParent();
660         }
661         Object JavaDoc parentElement = parent.getData();
662         if (parentElement != null) {
663             if (parent instanceof Tree) {
664                 index = ((Tree) parent).indexOf(treeItem);
665             } else {
666                 index = ((TreeItem) parent).indexOf(treeItem);
667             }
668             virtualLazyUpdateWidget(parent, index);
669         }
670     }
671
672     /*
673      * (non-Javadoc)
674      *
675      * @see org.eclipse.jface.viewers.AbstractTreeViewer#internalRefreshStruct(org.eclipse.swt.widgets.Widget,
676      * java.lang.Object, boolean)
677      */

678     protected void internalRefreshStruct(Widget widget, Object JavaDoc element,
679             boolean updateLabels) {
680         if (contentProviderIsLazy) {
681             // clear all starting with the given widget
682
if (widget instanceof Tree) {
683                 ((Tree) widget).clearAll(true);
684             } else if (widget instanceof TreeItem) {
685                 ((TreeItem) widget).clearAll(true);
686             }
687             int index = 0;
688             Widget parent = null;
689             if (widget instanceof TreeItem) {
690                 TreeItem treeItem = (TreeItem) widget;
691                 parent = treeItem.getParentItem();
692                 if (parent == null) {
693                     parent = treeItem.getParent();
694                 }
695                 if (parent instanceof Tree) {
696                     index = ((Tree) parent).indexOf(treeItem);
697                 } else {
698                     index = ((TreeItem) parent).indexOf(treeItem);
699                 }
700             }
701             virtualRefreshExpandedItems(parent, widget, element, index);
702             return;
703         }
704         super.internalRefreshStruct(widget, element, updateLabels);
705     }
706
707     /**
708      * Traverses the visible (expanded) part of the tree and updates child
709      * counts.
710      *
711      * @param parent the parent of the widget, or <code>null</code> if the widget is the tree
712      * @param widget
713      * @param element
714      * @param index the index of the widget in the children array of its parent, or 0 if the widget is the tree
715      */

716     private void virtualRefreshExpandedItems(Widget parent, Widget widget, Object JavaDoc element, int index) {
717         if (widget instanceof Tree) {
718             if (element == null) {
719                 ((Tree) widget).setItemCount(0);
720                 return;
721             }
722             virtualLazyUpdateChildCount(widget, getChildren(widget).length);
723         } else if (((TreeItem) widget).getExpanded()) {
724             // prevent SetData callback
725
((TreeItem)widget).setText(" "); //$NON-NLS-1$
726
virtualLazyUpdateWidget(parent, index);
727         } else {
728             return;
729         }
730         Item[] items = getChildren(widget);
731         for (int i = 0; i < items.length; i++) {
732             Item item = items[i];
733             Object JavaDoc data = item.getData();
734             virtualRefreshExpandedItems(widget, item, data, i);
735         }
736     }
737
738     /*
739      * To unmap elements correctly, we need to register a dispose listener with
740      * the item if the tree is virtual.
741      */

742     protected void mapElement(Object JavaDoc element, final Widget item) {
743         super.mapElement(element, item);
744         // make sure to unmap elements if the tree is virtual
745
if ((getTree().getStyle() & SWT.VIRTUAL) != 0) {
746             // only add a dispose listener if item hasn't already on assigned
747
// because it is reused
748
if (item.getData(VIRTUAL_DISPOSE_KEY) == null) {
749                 item.setData(VIRTUAL_DISPOSE_KEY, Boolean.TRUE);
750                 item.addDisposeListener(new DisposeListener() {
751                     public void widgetDisposed(DisposeEvent e) {
752                         if (!treeIsDisposed) {
753                             Object JavaDoc data = item.getData();
754                             if (usingElementMap() && data != null) {
755                                 unmapElement(data, item);
756                             }
757                         }
758                     }
759                 });
760             }
761         }
762     }
763
764     /*
765      * (non-Javadoc)
766      *
767      * @see org.eclipse.jface.viewers.ColumnViewer#getRowPartFromItem(org.eclipse.swt.widgets.Widget)
768      */

769     protected ViewerRow getViewerRowFromItem(Widget item) {
770         if( cachedRow == null ) {
771             cachedRow = new TreeViewerRow((TreeItem) item);
772         } else {
773             cachedRow.setItem((TreeItem) item);
774         }
775
776         return cachedRow;
777     }
778
779     /**
780      * Create a new ViewerRow at rowIndex
781      *
782      * @param parent
783      * @param style
784      * @param rowIndex
785      * @return ViewerRow
786      */

787     private ViewerRow createNewRowPart(ViewerRow parent, int style, int rowIndex) {
788         if (parent == null) {
789             if (rowIndex >= 0) {
790                 return getViewerRowFromItem(new TreeItem(tree, style, rowIndex));
791             }
792             return getViewerRowFromItem(new TreeItem(tree, style));
793         }
794
795         if (rowIndex >= 0) {
796             return getViewerRowFromItem(new TreeItem((TreeItem) parent.getItem(),
797                     SWT.NONE, rowIndex));
798         }
799
800         return getViewerRowFromItem(new TreeItem((TreeItem) parent.getItem(),
801                 SWT.NONE));
802     }
803
804     /*
805      * (non-Javadoc)
806      *
807      * @see org.eclipse.jface.viewers.AbstractTreeViewer#internalInitializeTree(org.eclipse.swt.widgets.Control)
808      */

809     protected void internalInitializeTree(Control widget) {
810         if (contentProviderIsLazy) {
811             if (widget instanceof Tree && widget.getData() != null) {
812                 virtualLazyUpdateChildCount(widget, 0);
813                 return;
814             }
815         }
816         super.internalInitializeTree(tree);
817     }
818
819     /*
820      * (non-Javadoc)
821      *
822      * @see org.eclipse.jface.viewers.AbstractTreeViewer#updatePlus(org.eclipse.swt.widgets.Item,
823      * java.lang.Object)
824      */

825     protected void updatePlus(Item item, Object JavaDoc element) {
826         if (contentProviderIsLazy) {
827             Object JavaDoc data = item.getData();
828             int itemCount = 0;
829             if (data != null) {
830                 // item is already materialized
831
itemCount = ((TreeItem) item).getItemCount();
832             }
833             virtualLazyUpdateHasChildren(item, itemCount);
834         } else {
835             super.updatePlus(item, element);
836         }
837     }
838
839     /**
840      * Removes the element at the specified index of the parent. The selection is updated if required.
841      *
842      * @param parentOrTreePath the parent element, the input element, or a tree path to the parent element
843      * @param index child index
844      * @since 3.3
845      */

846     public void remove(final Object JavaDoc parentOrTreePath, final int index) {
847         if (isBusy())
848             return;
849         final List JavaDoc oldSelection = new LinkedList JavaDoc(Arrays
850                 .asList(((TreeSelection) getSelection()).getPaths()));
851         preservingSelection(new Runnable JavaDoc() {
852             public void run() {
853                 TreePath removedPath = null;
854                 if (internalIsInputOrEmptyPath(parentOrTreePath)) {
855                     Tree tree = (Tree) getControl();
856                     if (index < tree.getItemCount()) {
857                         TreeItem item = tree.getItem(index);
858                         if (item.getData() != null) {
859                             removedPath = getTreePathFromItem(item);
860                             disassociate(item);
861                         }
862                         item.dispose();
863                     }
864                 } else {
865                     Widget[] parentItems = internalFindItems(parentOrTreePath);
866                     for (int i = 0; i < parentItems.length; i++) {
867                         TreeItem parentItem = (TreeItem) parentItems[i];
868                         if (index < parentItem.getItemCount()) {
869                             TreeItem item = parentItem.getItem(index);
870                             if (item.getData() != null) {
871                                 removedPath = getTreePathFromItem(item);
872                                 disassociate(item);
873                             }
874                             item.dispose();
875                         }
876                     }
877                 }
878                 if (removedPath != null) {
879                     boolean removed = false;
880                     for (Iterator JavaDoc it = oldSelection.iterator(); it
881                             .hasNext();) {
882                         TreePath path = (TreePath) it.next();
883                         if (path.startsWith(removedPath, getComparer())) {
884                             it.remove();
885                             removed = true;
886                         }
887                     }
888                     if (removed) {
889                         setSelection(new TreeSelection(
890                                 (TreePath[]) oldSelection
891                                         .toArray(new TreePath[oldSelection
892                                                 .size()]), getComparer()),
893                                 false);
894                     }
895
896                 }
897             }
898         });
899     }
900
901     /* (non-Javadoc)
902      * @see org.eclipse.jface.viewers.AbstractTreeViewer#handleTreeExpand(org.eclipse.swt.events.TreeEvent)
903      */

904     protected void handleTreeExpand(TreeEvent event) {
905         if (contentProviderIsLazy) {
906             if (event.item.getData() != null) {
907                 Item[] children = getChildren(event.item);
908                 if (children.length == 1 && children[0].getData()==null) {
909                     // we have a dummy child node, ask for an updated child
910
// count
911
virtualLazyUpdateChildCount(event.item, children.length);
912                 }
913                 fireTreeExpanded(new TreeExpansionEvent(this, event.item
914                         .getData()));
915             }
916             return;
917         }
918         super.handleTreeExpand(event);
919     }
920
921     /* (non-Javadoc)
922      * @see org.eclipse.jface.viewers.AbstractTreeViewer#setContentProvider(org.eclipse.jface.viewers.IContentProvider)
923      */

924     public void setContentProvider(IContentProvider provider) {
925         contentProviderIsLazy = (provider instanceof ILazyTreeContentProvider)
926                 || (provider instanceof ILazyTreePathContentProvider);
927         contentProviderIsTreeBased = provider instanceof ILazyTreePathContentProvider;
928         super.setContentProvider(provider);
929     }
930
931     /**
932      * For a TreeViewer with a tree with the VIRTUAL style bit set, inform the
933      * viewer about whether the given element or tree path has children. Avoid
934      * calling this method if the number of children has already been set.
935      *
936      * @param elementOrTreePath
937      * the element, or tree path
938      * @param hasChildren
939      *
940      * @since 3.3
941      */

942     public void setHasChildren(final Object JavaDoc elementOrTreePath, final boolean hasChildren) {
943         if (isBusy())
944             return;
945         preservingSelection(new Runnable JavaDoc() {
946             public void run() {
947                 if (internalIsInputOrEmptyPath(elementOrTreePath)) {
948                     if (hasChildren) {
949                         virtualLazyUpdateChildCount(getTree(),
950                                 getChildren(getTree()).length);
951                     } else {
952                         setChildCount(elementOrTreePath, 0);
953                     }
954                     return;
955                 }
956                 Widget[] items = internalFindItems(elementOrTreePath);
957                 for (int i = 0; i < items.length; i++) {
958                     TreeItem item = (TreeItem) items[i];
959                     if (!hasChildren) {
960                         item.setItemCount(0);
961                     } else {
962                         if (!item.getExpanded()) {
963                             item.setItemCount(1);
964                             TreeItem child = item.getItem(0);
965                             if (child.getData() != null) {
966                                 disassociate(child);
967                             }
968                             item.clear(0, true);
969                         } else {
970                             virtualLazyUpdateChildCount(item, item.getItemCount());
971                         }
972                     }
973                 }
974             }
975         });
976     }
977
978     /**
979      * Update the widget at index.
980      * @param widget
981      * @param index
982      */

983     private void virtualLazyUpdateWidget(Widget widget, int index) {
984         boolean oldBusy = busy;
985         busy = false;
986         try {
987             if (contentProviderIsTreeBased) {
988                 TreePath treePath;
989                 if (widget instanceof Item) {
990                     if (widget.getData() == null) {
991                         // we need to materialize the parent first
992
// see bug 167668
993
// however, that would be too risky
994
// see bug 182782 and bug 182598
995
// so we just ignore this call altogether
996
// and don't do this: virtualMaterializeItem((TreeItem) widget);
997
return;
998                     }
999                     treePath = getTreePathFromItem((Item) widget);
1000                } else {
1001                    treePath = TreePath.EMPTY;
1002                }
1003                ((ILazyTreePathContentProvider) getContentProvider())
1004                        .updateElement(treePath, index);
1005            } else {
1006                ((ILazyTreeContentProvider) getContentProvider()).updateElement(
1007                        widget.getData(), index);
1008            }
1009        } finally {
1010            busy = oldBusy;
1011        }
1012    }
1013
1014    /**
1015     * Update the child count
1016     * @param widget
1017     * @param currentChildCount
1018     */

1019    private void virtualLazyUpdateChildCount(Widget widget, int currentChildCount) {
1020        boolean oldBusy = busy;
1021        busy = false;
1022        try {
1023            if (contentProviderIsTreeBased) {
1024                TreePath treePath;
1025                if (widget instanceof Item) {
1026                    treePath = getTreePathFromItem((Item) widget);
1027                } else {
1028                    treePath = TreePath.EMPTY;
1029                }
1030                ((ILazyTreePathContentProvider) getContentProvider())
1031                .updateChildCount(treePath, currentChildCount);
1032            } else {
1033                ((ILazyTreeContentProvider) getContentProvider()).updateChildCount(widget.getData(), currentChildCount);
1034            }
1035        } finally {
1036            busy = oldBusy;
1037        }
1038    }
1039
1040    /**
1041     * Update the item with the current child count.
1042     * @param item
1043     * @param currentChildCount
1044     */

1045    private void virtualLazyUpdateHasChildren(Item item, int currentChildCount) {
1046        boolean oldBusy = busy;
1047        busy = false;
1048        try {
1049            if (contentProviderIsTreeBased) {
1050                TreePath treePath;
1051                treePath = getTreePathFromItem(item);
1052                if (currentChildCount == 0) {
1053                    // item is not expanded (but may have a plus currently)
1054
((ILazyTreePathContentProvider) getContentProvider())
1055                    .updateHasChildren(treePath);
1056                } else {
1057                    ((ILazyTreePathContentProvider) getContentProvider())
1058                    .updateChildCount(treePath, currentChildCount);
1059                }
1060            } else {
1061                ((ILazyTreeContentProvider) getContentProvider()).updateChildCount(item.getData(), currentChildCount);
1062            }
1063        } finally {
1064            busy = oldBusy;
1065        }
1066    }
1067
1068    protected void disassociate(Item item) {
1069        if (contentProviderIsLazy) {
1070            // avoid causing a callback:
1071
item.setText(" "); //$NON-NLS-1$
1072
}
1073        super.disassociate(item);
1074    }
1075
1076    protected int doGetColumnCount() {
1077        return tree.getColumnCount();
1078    }
1079
1080    /**
1081     * Sets a new selection for this viewer and optionally makes it visible.
1082     * <p>
1083     * <b>Currently the <code>reveal</code> parameter is not honored because
1084     * {@link Tree} does not provide an API to only select an item without
1085     * scrolling it into view</b>
1086     * </p>
1087     *
1088     * @param selection
1089     * the new selection
1090     * @param reveal
1091     * <code>true</code> if the selection is to be made visible,
1092     * and <code>false</code> otherwise
1093     */

1094    public void setSelection(ISelection selection, boolean reveal) {
1095        super.setSelection(selection, reveal);
1096    }
1097
1098    public void editElement(Object JavaDoc element, int column) {
1099        if( element instanceof TreePath ) {
1100            setSelection(new TreeSelection((TreePath) element));
1101            TreeItem[] items = tree.getSelection();
1102
1103            if( items.length == 1 ) {
1104                ViewerRow row = getViewerRowFromItem(items[0]);
1105
1106                if (row != null) {
1107                    ViewerCell cell = row.getCell(column);
1108                    if (cell != null) {
1109                        getControl().setRedraw(false);
1110                        triggerEditorActivationEvent(new ColumnViewerEditorActivationEvent(cell));
1111                        getControl().setRedraw(true);
1112                    }
1113                }
1114            }
1115        } else {
1116            super.editElement(element, column);
1117        }
1118    }
1119}
1120
Popular Tags