KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > debug > internal > ui > viewers > AsynchronousTreeViewer


1 /*******************************************************************************
2  * Copyright (c) 2005, 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.debug.internal.ui.viewers;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Map JavaDoc;
18 import java.util.Map.Entry;
19
20 import org.eclipse.core.runtime.IAdaptable;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.core.runtime.IStatus;
23 import org.eclipse.core.runtime.Status;
24 import org.eclipse.debug.internal.ui.DebugUIPlugin;
25 import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter;
26 import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor;
27 import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter;
28 import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation;
29 import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentationFactoryAdapter;
30 import org.eclipse.jface.resource.ImageDescriptor;
31 import org.eclipse.jface.util.Assert;
32 import org.eclipse.jface.viewers.CellEditor;
33 import org.eclipse.jface.viewers.DoubleClickEvent;
34 import org.eclipse.jface.viewers.ICellModifier;
35 import org.eclipse.jface.viewers.ISelection;
36 import org.eclipse.jface.viewers.IStructuredSelection;
37 import org.eclipse.jface.viewers.OpenEvent;
38 import org.eclipse.jface.viewers.StructuredSelection;
39 import org.eclipse.jface.viewers.TreePath;
40 import org.eclipse.jface.viewers.TreeSelection;
41 import org.eclipse.jface.viewers.Viewer;
42 import org.eclipse.swt.SWT;
43 import org.eclipse.swt.custom.TreeEditor;
44 import org.eclipse.swt.events.ControlEvent;
45 import org.eclipse.swt.events.ControlListener;
46 import org.eclipse.swt.events.MouseAdapter;
47 import org.eclipse.swt.events.MouseEvent;
48 import org.eclipse.swt.events.MouseListener;
49 import org.eclipse.swt.events.PaintEvent;
50 import org.eclipse.swt.events.PaintListener;
51 import org.eclipse.swt.events.TreeEvent;
52 import org.eclipse.swt.events.TreeListener;
53 import org.eclipse.swt.graphics.Color;
54 import org.eclipse.swt.graphics.Font;
55 import org.eclipse.swt.graphics.FontData;
56 import org.eclipse.swt.graphics.Image;
57 import org.eclipse.swt.graphics.Point;
58 import org.eclipse.swt.graphics.RGB;
59 import org.eclipse.swt.graphics.Rectangle;
60 import org.eclipse.swt.widgets.Composite;
61 import org.eclipse.swt.widgets.Control;
62 import org.eclipse.swt.widgets.Item;
63 import org.eclipse.swt.widgets.Tree;
64 import org.eclipse.swt.widgets.TreeColumn;
65 import org.eclipse.swt.widgets.TreeItem;
66 import org.eclipse.swt.widgets.Widget;
67 import org.eclipse.ui.IMemento;
68 import org.eclipse.ui.progress.WorkbenchJob;
69
70 /**
71  * A tree viewer that retrieves children and labels asynchronously via adapters
72  * and supports duplicate elements in the tree with different parents.
73  * Retrieving children and labels asynchrnously allows for arbitrary latency
74  * without blocking the UI thread.
75  * <p>
76  * Clients may instantiate and subclass this class.
77  * </p>
78  *
79  * @since 3.2
80  */

81 public class AsynchronousTreeViewer extends AsynchronousViewer {
82
83     /**
84      * The tree
85      */

86     private Tree fTree;
87     
88     /**
89      * Cell editing
90      */

91     private TreeEditorImpl fTreeEditorImpl;
92     private TreeEditor fTreeEditor;
93
94     /**
95      * Collection of tree paths to be expanded. A path is removed from the
96      * collection when it is expanded. The entire list is cleared when the input
97      * to the viewer changes.
98      */

99     private List JavaDoc fPendingExpansion = new ArrayList JavaDoc();
100     
101     /**
102      * Current column presentation or <code>null</code>
103      */

104     private IColumnPresentation fColumnPresentation = null;
105     
106     /**
107      * Current column editor or <code>null</code>
108      */

109     private IColumnEditor fColumnEditor = null;
110     
111     /**
112      * Map of columns presentation id to its visible colums ids (String[])
113      * When a columns presentation is not in the map, default settings are used.
114      */

115     private Map JavaDoc fVisibleColumns = new HashMap JavaDoc();
116     
117     /**
118      * Map of column ids to persisted sizes
119      */

120     private Map JavaDoc fColumnSizes = new HashMap JavaDoc();
121     
122     /**
123      * Map of column presentation id to whether columns should be displayed
124      * for that presentation (the user can toggle columns on/off when a
125      * presentation is optional.
126      */

127     private Map JavaDoc fShowColumns = new HashMap JavaDoc();
128         
129     /**
130      * Memento type for column sizes. Sizes are keyed by colunm presentation id
131      */

132     private static final String JavaDoc COLUMN_SIZES = "COLUMN_SIZES"; //$NON-NLS-1$
133
/**
134      * Memento type for the visible columns for a presentation context.
135      * A memento is created for each colunm presentation keyed by column number
136      */

137     private static final String JavaDoc VISIBLE_COLUMNS = "VISIBLE_COLUMNS"; //$NON-NLS-1$
138
/**
139      * Memento type for whether columns are visible for a presentation context.
140      * Booleans are keyed by column presentation id
141      */

142     private static final String JavaDoc SHOW_COLUMNS = "SHOW_COLUMNS"; //$NON-NLS-1$
143
/**
144      * Memento key for the number of visible columns in a VISIBLE_COLUMNS memento
145      * or for the width of a column
146      */

147     private static final String JavaDoc SIZE = "SIZE"; //$NON-NLS-1$
148
/**
149      * Memento key prefix a visible column
150      */

151     private static final String JavaDoc COLUMN = "COLUMN"; //$NON-NLS-1$
152

153     /**
154      * Persist column sizes when they change.
155      *
156      * @since 3.2
157      */

158     class ColumnListener implements ControlListener {
159         /* (non-Javadoc)
160          * @see org.eclipse.swt.events.ControlListener#controlMoved(org.eclipse.swt.events.ControlEvent)
161          */

162         public void controlMoved(ControlEvent e) {
163         }
164
165         /* (non-Javadoc)
166          * @see org.eclipse.swt.events.ControlListener#controlResized(org.eclipse.swt.events.ControlEvent)
167          */

168         public void controlResized(ControlEvent e) {
169             persistColumnSizes();
170         }
171     }
172     
173     private ColumnListener fListener = new ColumnListener();
174     
175     /**
176      * Creates an asynchronous tree viewer on a newly-created tree control under
177      * the given parent. The tree control is created using the SWT style bits
178      * <code>MULTI, H_SCROLL, V_SCROLL,</code> and <code>BORDER</code>. The
179      * viewer has no input, no content provider, a default label provider, no
180      * sorter, and no filters.
181      *
182      * @param parent
183      * the parent control
184      */

185     public AsynchronousTreeViewer(Composite parent) {
186         this(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL);
187     }
188
189     /**
190      * Creates an asynchronous tree viewer on a newly-created tree control under
191      * the given parent. The tree control is created using the given SWT style
192      * bits. The viewer has no input.
193      *
194      * @param parent
195      * the parent control
196      * @param style
197      * the SWT style bits used to create the tree.
198      */

199     public AsynchronousTreeViewer(Composite parent, int style) {
200         this(new Tree(parent, style));
201     }
202
203     /**
204      * Creates an asynchronous tree viewer on the given tree control. The viewer
205      * has no input, no content provider, a default label provider, no sorter,
206      * and no filters.
207      *
208      * @param tree
209      * the tree control
210      */

211     public AsynchronousTreeViewer(Tree tree) {
212         super();
213         Assert.isTrue((tree.getStyle() & SWT.VIRTUAL) != 0);
214         fTree = tree;
215         hookControl(fTree);
216         fTreeEditor = new TreeEditor(tree);
217         initTreeViewerImpl();
218     }
219
220     /* (non-Javadoc)
221      * @see org.eclipse.jface.viewers.StructuredViewer#hookControl(org.eclipse.swt.widgets.Control)
222      */

223     protected void hookControl(Control control) {
224         super.hookControl(control);
225         Tree tree = (Tree)control;
226         tree.addMouseListener(new MouseAdapter() {
227             public void mouseDown(MouseEvent e) {
228                 if (isShowColumns()) {
229                     Item[] items = fTreeEditorImpl.getSelection();
230                     if (items.length > 0) {
231                         TreeItem treeItem = (TreeItem) items[0];
232                         if (treeItem != null) {
233                             Object JavaDoc element = treeItem.getData();
234                             updateColumnEditor(element);
235                             if (fColumnEditor != null) {
236                                 int columnToEdit = -1;
237                                 int columns = fTree.getColumnCount();
238                                 if (columns == 0) {
239                                     // If no TreeColumn, Tree acts as if it has a single column
240
// which takes the whole width.
241
columnToEdit = 0;
242                                 } else {
243                                     columnToEdit = -1;
244                                     for (int i = 0; i < columns; i++) {
245                                         Rectangle bounds = fTreeEditorImpl.getBounds(treeItem, i);
246                                         if (bounds.contains(e.x, e.y)) {
247                                             columnToEdit = i;
248                                             break;
249                                         }
250                                     }
251                                     if (columnToEdit == -1) {
252                                         return;
253                                     }
254                                 }
255                                 CellEditor cellEditor = fColumnEditor.getCellEditor(getVisibleColumns()[columnToEdit], element, fTree);
256                                 if (cellEditor == null) {
257                                     return;
258                                 }
259                                 disposeCellEditors();
260                                 CellEditor[] newEditors = new CellEditor[columns];
261                                 newEditors[columnToEdit] = cellEditor;
262                                 setCellEditors(newEditors);
263                                 setCellModifier(fColumnEditor.getCellModifier());
264                                 setColumnProperties(getVisibleColumns());
265                             }
266                         }
267                     }
268                 }
269                 
270                 fTreeEditorImpl.handleMouseDown(e);
271             }
272         });
273         tree.addTreeListener(new TreeListener() {
274             public void treeExpanded(TreeEvent e) {
275                 ((TreeItem) e.item).setExpanded(true);
276                 ModelNode node = findNode(e.item);
277                 if (node != null) {
278                     internalRefresh(node);
279                 }
280             }
281
282             public void treeCollapsed(TreeEvent e) {
283             }
284         });
285
286         tree.addMouseListener(new MouseListener() {
287             public void mouseUp(MouseEvent e) {
288             }
289
290             public void mouseDown(MouseEvent e) {
291             }
292
293             public void mouseDoubleClick(MouseEvent e) {
294                 TreeItem item = ((Tree) e.widget).getItem(new Point(e.x, e.y));
295                 if (item != null) {
296                     if (item.getExpanded()) {
297                         item.setExpanded(false);
298                     } else {
299                         item.setExpanded(true);
300                         ModelNode node = findNode(item);
301                         if (node != null) {
302                             internalRefresh(node);
303                         }
304                     }
305                 }
306             }
307         });
308     }
309
310     /**
311      * Sets the column editor for the given element
312      *
313      * @param element
314      */

315     protected void updateColumnEditor(Object JavaDoc element) {
316         IColumnEditorFactoryAdapter factoryAdapter = getColumnEditorFactoryAdapter(element);
317         if (factoryAdapter != null) {
318             if (fColumnEditor != null) {
319                 if (fColumnEditor.getId().equals(factoryAdapter.getColumnEditorId(getPresentationContext(), element))) {
320                     // no change
321
return;
322                 } else {
323                     // dipose current
324
fColumnEditor.dispose();
325                 }
326             }
327             // create new one
328
fColumnEditor = factoryAdapter.createColumnEditor(getPresentationContext(), element);
329             if (fColumnEditor != null) {
330                 fColumnEditor.init(getPresentationContext());
331             }
332         } else {
333             // no editor - dispose current
334
if (fColumnEditor != null) {
335                 fColumnEditor.dispose();
336                 fColumnEditor = null;
337             }
338         }
339     }
340     
341     /**
342      * Returns the tree control for this viewer.
343      *
344      * @return the tree control for this viewer
345      */

346     public Tree getTree() {
347         return fTree;
348     }
349
350     /**
351      * Updates whether the given node has children.
352      *
353      * @param node node to update
354      */

355     protected void updateHasChildren(ModelNode node) {
356         ((AsynchronousTreeModel)getModel()).updateHasChildren(node);
357     }
358
359     /**
360      * Expands all elements in the given tree selection.
361      *
362      * @param selection
363      */

364     public synchronized void expand(ISelection selection) {
365         if (selection instanceof TreeSelection) {
366             TreePath[] paths = ((TreeSelection) selection).getPaths();
367             for (int i = 0; i < paths.length; i++) {
368                 fPendingExpansion.add(paths[i]);
369             }
370             if (getControl().getDisplay().getThread() == Thread.currentThread()) {
371                 attemptExpansion();
372             } else {
373                 WorkbenchJob job = new WorkbenchJob("attemptExpansion") { //$NON-NLS-1$
374
public IStatus runInUIThread(IProgressMonitor monitor) {
375                         attemptExpansion();
376                         return Status.OK_STATUS;
377                     }
378
379                 };
380                 job.setSystem(true);
381                 job.schedule();
382             }
383         }
384     }
385
386     /**
387      * Attempts to expand all pending expansions.
388      */

389     synchronized void attemptExpansion() {
390         if (fPendingExpansion != null) {
391             for (Iterator JavaDoc i = fPendingExpansion.iterator(); i.hasNext();) {
392                 TreePath path = (TreePath) i.next();
393                 if (attemptExpansion(path)) {
394                     i.remove();
395                 }
396             }
397         }
398     }
399
400     /**
401      * Attempts to expand the given tree path and returns whether the expansion
402      * was completed.
403      *
404      * @param path path to expand
405      * @return whether the expansion was completed
406      */

407     synchronized boolean attemptExpansion(TreePath path) {
408         int segmentCount = path.getSegmentCount();
409         for (int j = segmentCount - 1; j >= 0; j--) {
410             Object JavaDoc element = path.getSegment(j);
411             ModelNode[] nodes = getModel().getNodes(element);
412             if (nodes != null) {
413                 for (int k = 0; k < nodes.length; k++) {
414                     ModelNode node = nodes[k];
415                     TreePath treePath = node.getTreePath();
416                     if (path.startsWith(treePath, null)) {
417                         if (!node.isDisposed()) {
418                             Widget widget = findItem(node);
419                             if (widget == null) {
420                                 // force the widgets to be mapped
421
ModelNode parent = node.getParentNode();
422                                 ModelNode child = node;
423                                 widget = findItem(parent);
424                                 while (widget == null && parent != null) {
425                                     child = parent;
426                                     parent = parent.getParentNode();
427                                     if (parent != null) {
428                                         widget = findItem(parent);
429                                         treePath = parent.getTreePath();
430                                     }
431                                 }
432                                 int childIndex = parent.getChildIndex(child);
433                                 if (childIndex < 0) {
434                                     return false;
435                                 }
436                                 TreeItem[] items = getItems(widget);
437                                 if (childIndex < items.length) {
438                                     widget = items[childIndex];
439                                     mapElement(child, widget);
440                                     widget.setData(child.getElement());
441                                     treePath = child.getTreePath();
442                                     node = child;
443                                 } else {
444                                     return false;
445                                 }
446                             }
447                             if (widget instanceof TreeItem && !widget.isDisposed()) {
448                                 TreeItem treeItem = (TreeItem) widget;
449                                 if (treeItem.getExpanded()) {
450                                     return path.getSegmentCount() == treePath.getSegmentCount();
451                                 }
452                                 if (treeItem.getItemCount() > 0) {
453                                     updateChildren(node);
454                                     expand(treeItem);
455                                     if (path.getSegmentCount() == treePath.getSegmentCount()) {
456                                         return true;
457                                     }
458                                     return false;
459                                 }
460                             }
461                         }
462                     }
463                 }
464             }
465         }
466         return false;
467     }
468
469     /*
470      * (non-Javadoc)
471      *
472      * @see org.eclipse.jface.viewers.Viewer#getControl()
473      */

474     public Control getControl() {
475         return fTree;
476     }
477
478     
479     /* (non-Javadoc)
480      * @see org.eclipse.debug.internal.ui.viewers.AsynchronousViewer#dispose()
481      */

482     public synchronized void dispose() {
483         if (fColumnPresentation != null) {
484             fColumnPresentation.dispose();
485         }
486         disposeCellEditors();
487         if (fColumnEditor != null) {
488             fColumnEditor.dispose();
489         }
490         super.dispose();
491     }
492
493     /**
494      * Disposes cell editors
495      */

496     protected void disposeCellEditors() {
497         CellEditor[] cellEditors = getCellEditors();
498         if (cellEditors != null) {
499             for (int i = 0; i < cellEditors.length; i++) {
500                 CellEditor editor = cellEditors[i];
501                 if (editor != null) {
502                     editor.dispose();
503                 }
504             }
505         }
506         setCellEditors(null);
507     }
508
509     /*
510      * (non-Javadoc)
511      *
512      * @see org.eclipse.jface.viewers.Viewer#inputChanged(java.lang.Object,
513      * java.lang.Object)
514      */

515     synchronized protected void inputChanged(Object JavaDoc input, Object JavaDoc oldInput) {
516         fPendingExpansion.clear();
517         super.inputChanged(input, oldInput);
518         resetColumns(input);
519     }
520     
521     /**
522      * Refreshes the columns in the view, based on the viewer input.
523      */

524     public void refreshColumns() {
525         configureColumns();
526         refresh();
527     }
528     
529     /**
530      * Configures the columns for the given viewer input.
531      *
532      * @param input
533      */

534     protected void resetColumns(Object JavaDoc input) {
535         if (input != null) {
536             // only change columns if the input is non-null (persist when empty)
537
IColumnPresentationFactoryAdapter factory = getColumnPresenetationFactoryAdapter(input);
538             PresentationContext context = (PresentationContext) getPresentationContext();
539             String JavaDoc type = null;
540             if (factory != null) {
541                 type = factory.getColumnPresentationId(context, input);
542             }
543             if (type != null) {
544                 if (fColumnPresentation != null) {
545                     if (!fColumnPresentation.getId().equals(type)) {
546                         // dispose old, create new
547
fColumnPresentation.dispose();
548                         fColumnPresentation = null;
549                     }
550                 }
551                 if (fColumnPresentation == null) {
552                     fColumnPresentation = factory.createColumnPresentation(context, input);
553                     if (fColumnPresentation != null) {
554                         fColumnPresentation.init(context);
555                         configureColumns();
556                     }
557                 }
558             } else {
559                 if (fColumnPresentation != null) {
560                     fColumnPresentation.dispose();
561                     fColumnPresentation = null;
562                     configureColumns();
563                 }
564             }
565         }
566     }
567     
568     /**
569      * Configures the columns based on the current settings.
570      *
571      * @param input
572      */

573     protected void configureColumns() {
574         if (fColumnPresentation != null) {
575             IColumnPresentation build = null;
576             if (isShowColumns(fColumnPresentation.getId())) {
577                 build = fColumnPresentation;
578             }
579             buildColumns(build);
580         } else {
581             // get rid of columns
582
buildColumns(null);
583         }
584     }
585     
586     /**
587      * Creates new columns for the given presentation.
588      *
589      * TODO: does this need to be async?
590      *
591      * @param presentation
592      */

593     protected void buildColumns(IColumnPresentation presentation) {
594         // dispose current columns, persisting their weigts
595
Tree tree = getTree();
596         final TreeColumn[] columns = tree.getColumns();
597         String JavaDoc[] visibleColumnIds = getVisibleColumns();
598         for (int i = 0; i < columns.length; i++) {
599             TreeColumn treeColumn = columns[i];
600             treeColumn.removeControlListener(fListener);
601             treeColumn.dispose();
602         }
603         PresentationContext presentationContext = (PresentationContext) getPresentationContext();
604         if (presentation != null) {
605             for (int i = 0; i < visibleColumnIds.length; i++) {
606                 String JavaDoc id = visibleColumnIds[i];
607                 String JavaDoc header = presentation.getHeader(id);
608                 // TODO: allow client to specify style
609
TreeColumn column = new TreeColumn(tree, SWT.LEFT, i);
610                 column.setMoveable(true);
611                 column.setText(header);
612                 column.setWidth(1);
613                 ImageDescriptor image = presentation.getImageDescriptor(id);
614                 if (image != null) {
615                     column.setImage(getImage(image));
616                 }
617                 column.setData(id);
618             }
619             tree.setHeaderVisible(true);
620             tree.setLinesVisible(true);
621             presentationContext.setColumns(getVisibleColumns());
622         } else {
623             tree.setHeaderVisible(false);
624             tree.setLinesVisible(false);
625             presentationContext.setColumns(null);
626         }
627
628         int avg = tree.getSize().x;
629         if (visibleColumnIds != null)
630             avg /= visibleColumnIds.length;
631         
632         if (avg == 0) {
633             tree.addPaintListener(new PaintListener() {
634                 public void paintControl(PaintEvent e) {
635                     Tree tree2 = getTree();
636                     String JavaDoc[] visibleColumns = getVisibleColumns();
637                     if (visibleColumns != null) {
638                         int avg1 = tree2.getSize().x / visibleColumns.length;
639                         initColumns(avg1);
640                     }
641                     tree2.removePaintListener(this);
642                 }
643             });
644         } else {
645             initColumns(avg);
646         }
647     }
648
649     private void initColumns(int widthHint) {
650         TreeColumn[] columns = getTree().getColumns();
651         for (int i = 0; i < columns.length; i++) {
652             TreeColumn treeColumn = columns[i];
653             Integer JavaDoc width = (Integer JavaDoc) fColumnSizes.get(treeColumn.getData());
654             if (width == null) {
655                 treeColumn.setWidth(widthHint);
656             } else {
657                 treeColumn.setWidth(width.intValue());
658             }
659             treeColumn.addControlListener(fListener);
660         }
661     }
662     /**
663      * Persists column sizes in cache
664      */

665     protected void persistColumnSizes() {
666         Tree tree = getTree();
667         TreeColumn[] columns = tree.getColumns();
668         for (int i = 0; i < columns.length; i++) {
669             TreeColumn treeColumn = columns[i];
670             Object JavaDoc id = treeColumn.getData();
671             fColumnSizes.put(id, new Integer JavaDoc(treeColumn.getWidth()));
672         }
673     }
674     
675     /**
676      * Returns the column presentation factory for the given element or <code>null</code>.
677      *
678      * @param input
679      * @return column presentation factory of <code>null</code>
680      */

681     protected IColumnPresentationFactoryAdapter getColumnPresenetationFactoryAdapter(Object JavaDoc input) {
682         if (input instanceof IColumnPresentationFactoryAdapter) {
683             return (IColumnPresentationFactoryAdapter) input;
684         }
685         if (input instanceof IAdaptable) {
686             IAdaptable adaptable = (IAdaptable) input;
687             return (IColumnPresentationFactoryAdapter) adaptable.getAdapter(IColumnPresentationFactoryAdapter.class);
688         }
689         return null;
690     }
691     
692     /**
693      * Returns the column editor factory for the given element or <code>null</code>.
694      *
695      * @param input
696      * @return column editor factory of <code>null</code>
697      */

698     protected IColumnEditorFactoryAdapter getColumnEditorFactoryAdapter(Object JavaDoc input) {
699         if (input instanceof IColumnEditorFactoryAdapter) {
700             return (IColumnEditorFactoryAdapter) input;
701         }
702         if (input instanceof IAdaptable) {
703             IAdaptable adaptable = (IAdaptable) input;
704             return (IColumnEditorFactoryAdapter) adaptable.getAdapter(IColumnEditorFactoryAdapter.class);
705         }
706         return null;
707     }
708
709     /**
710      * Constructs and returns a tree path for the given item
711      * or <code>null</code>. Must be called
712      * from the UI thread.
713      *
714      * @param item
715      * item to constuct a path for
716      * @return tree path for the item or <code>null</code> if none
717      */

718     protected synchronized TreePath getTreePath(TreeItem item) {
719         TreeItem parent = item;
720         List JavaDoc path = new ArrayList JavaDoc();
721         while (parent != null && !parent.isDisposed()) {
722             Object JavaDoc parentElement = parent.getData();
723             if (parentElement == null) {
724                 // this is a fix for bug 139859:
725
// on Mac, an item gets a 'selection' event before 'set data' when
726
// scrolling with arrow keys. so this forces the item to get a
727
// 'set data' callback
728
parent.getItemCount();
729                 parentElement = parent.getData();
730                 if (parentElement == null)
731                     return null;
732             }
733             path.add(0, parentElement);
734             parent = parent.getParentItem();
735         }
736         Object JavaDoc data = fTree.getData();
737         if (data == null) {
738             return null;
739         }
740         path.add(0, data);
741         return new TreePath(path.toArray());
742     }
743     
744     /**
745      * Returns the tree paths to the given element in this viewer, possibly
746      * empty.
747      *
748      * @param element model element
749      * @return the paths to the element in this viewer
750      */

751     public TreePath[] getTreePaths(Object JavaDoc element) {
752         ModelNode[] nodes = getModel().getNodes(element);
753         if (nodes == null) {
754             return new TreePath[]{};
755         }
756         TreePath[] paths = new TreePath[nodes.length];
757         for (int i = 0; i < nodes.length; i++) {
758             paths[i] = nodes[i].getTreePath();
759         }
760         return paths;
761     }
762     
763     protected int getItemCount(Widget widget) {
764         if (widget instanceof TreeItem) {
765             return ((TreeItem) widget).getItemCount();
766         }
767         return ((Tree) widget).getItemCount();
768     }
769
770     /* (non-Javadoc)
771      * @see org.eclipse.debug.internal.ui.model.viewers.AsynchronousViewer#setItemCount(org.eclipse.swt.widgets.Widget, int)
772      */

773     protected void setItemCount(Widget widget, int itemCount) {
774         if (widget == fTree) {
775             fTree.setItemCount(itemCount);
776         } else {
777             ((TreeItem) widget).setItemCount(itemCount);
778         }
779     }
780
781     /* (non-Javadoc)
782      * @see org.eclipse.debug.internal.ui.model.viewers.AsynchronousViewer#getChildWidget(org.eclipse.swt.widgets.Widget, int)
783      */

784     protected Widget getChildWidget(Widget parent, int index) {
785         if (parent instanceof Tree) {
786             Tree tree = (Tree) parent;
787             if (index < tree.getItemCount()) {
788                 return tree.getItem(index);
789             }
790         } else if (parent instanceof TreeItem){
791             TreeItem item = (TreeItem) parent;
792             if (index < item.getItemCount()) {
793                 return item.getItem(index);
794             }
795         }
796         return null;
797     }
798
799     private TreeItem[] getItems(Widget widget) {
800         if (widget instanceof TreeItem) {
801             return ((TreeItem) widget).getItems();
802         } else {
803             return fTree.getItems();
804         }
805     }
806
807     /**
808      * Returns the parent widget for the given widget or <code>null</code>
809      *
810      * @param widget
811      * @return parent widget or <code>null</code>
812      */

813     protected Widget getParentWidget(Widget widget) {
814         if (widget instanceof TreeItem) {
815             TreeItem parentItem = ((TreeItem)widget).getParentItem();
816             if (parentItem == null) {
817                 return getControl();
818             }
819             return parentItem;
820         }
821         return null;
822     }
823     
824     
825     /**
826      * Expands the given tree item and all of its parents. Does *not* update
827      * elements or retrieve children.
828      *
829      * @param child
830      * item to expand
831      */

832     private void expand(TreeItem child) {
833         if (!child.getExpanded()) {
834             child.setExpanded(true);
835
836             TreeItem parent = child.getParentItem();
837             if (parent != null) {
838                 expand(parent);
839             }
840         }
841     }
842
843     /* (non-Javadoc)
844      * @see org.eclipse.debug.internal.ui.model.viewers.AsynchronousViewer#clear(org.eclipse.swt.widgets.Widget)
845      */

846     protected void clear(Widget widget) {
847         if (DEBUG_VIEWER) {
848             DebugUIPlugin.debug("CLEAR [" + widget + "]"); //$NON-NLS-1$//$NON-NLS-2$
849
}
850
851         if (widget instanceof TreeItem && !widget.isDisposed()) {
852             TreeItem item = (TreeItem) widget;
853             TreeItem parentItem = item.getParentItem();
854             if (parentItem == null) {
855                 int index = fTree.indexOf(item);
856                 if (index >= 0)
857                     fTree.clear(index, true);
858             } else {
859                 int index = parentItem.indexOf(item);
860                 if (index >= 0)
861                     parentItem.clear(index, true);
862             }
863             item.clearAll(true);
864         } else {
865             fTree.clearAll(true);
866         }
867     }
868     
869     /* (non-Javadoc)
870      * @see org.eclipse.debug.internal.ui.viewers.AsynchronousViewer#clearChildren(org.eclipse.swt.widgets.Widget)
871      */

872     protected void clearChildren(Widget widget) {
873         if (DEBUG_VIEWER) {
874             DebugUIPlugin.debug("CLEAR_CHILDREN [" + widget + "]"); //$NON-NLS-1$//$NON-NLS-2$
875
}
876
877         if (widget instanceof TreeItem && !widget.isDisposed()) {
878             TreeItem item = (TreeItem) widget;
879             item.clearAll(true);
880         } else {
881             fTree.clearAll(true);
882         }
883     }
884     
885     /* (non-Javadoc)
886      * @see org.eclipse.debug.internal.ui.viewers.AsynchronousViewer#clearChild(org.eclipse.swt.widgets.Widget, int)
887      */

888     protected void clearChild(Widget parent, int childIndex) {
889         if (DEBUG_VIEWER) {
890             DebugUIPlugin.debug("CLEAR_CHILD [" + parent + "]: " + childIndex); //$NON-NLS-1$//$NON-NLS-2$
891
}
892   
893         if (parent instanceof TreeItem && !parent.isDisposed()) {
894             TreeItem item = (TreeItem) parent;
895             item.clear(childIndex, true);
896         } else {
897             fTree.clear(childIndex, true);
898         }
899     }
900
901     /*
902      * (non-Javadoc)
903      *
904      * @see org.eclipse.debug.internal.ui.viewers.AsynchronousModelViewer#newSelectionFromWidget()
905      */

906     protected ISelection newSelectionFromWidget() {
907         Control control = getControl();
908         if (control == null || control.isDisposed()) {
909             return StructuredSelection.EMPTY;
910         }
911         List JavaDoc list = getSelectionFromWidget();
912         return new TreeSelection((TreePath[]) list.toArray(new TreePath[list.size()]));
913     }
914
915     /*
916      * (non-Javadoc)
917      *
918      * @see org.eclipse.jface.viewers.StructuredViewer#getSelectionFromWidget()
919      */

920     protected synchronized List JavaDoc getSelectionFromWidget() {
921         TreeItem[] selection = fTree.getSelection();
922         List JavaDoc paths = new ArrayList JavaDoc(selection.length);
923         for (int i = 0; i < selection.length; i++) {
924             TreePath treePath = getTreePath(selection[i]);
925             if (treePath != null) {
926                 paths.add(treePath);
927             }
928         }
929         return paths;
930     }
931
932     /* (non-Javadoc)
933      * @see org.eclipse.debug.internal.ui.model.viewers.AsynchronousViewer#internalRefresh(org.eclipse.debug.internal.ui.model.viewers.ModelNode)
934      */

935     protected void internalRefresh(ModelNode node) {
936         super.internalRefresh(node);
937         updateHasChildren(node);
938     }
939
940     /*
941      * (non-Javadoc)
942      *
943      * @see org.eclipse.jface.viewers.StructuredViewer#reveal(java.lang.Object)
944      */

945     public void reveal(Object JavaDoc element) {
946         // TODO: in virtual case, we should attempt expansion
947
ModelNode[] nodes = getModel().getNodes(element);
948         if (nodes != null) {
949             for (int i = 0; i < nodes.length; i++) {
950                 ModelNode node = nodes[i];
951                 Widget widget = findItem(node);
952                 if (widget instanceof TreeItem) {
953                     // TODO: only reveals the first occurrence - should we reveal all?
954
TreeItem item = (TreeItem) widget;
955                     Tree tree = (Tree) getControl();
956                     tree.showItem(item);
957                     return;
958                 }
959             }
960         }
961     }
962
963     /*
964      * (non-Javadoc)
965      *
966      * @see org.eclipse.debug.ui.viewers.AsynchronousViewer#doAttemptSelectionToWidget(org.eclipse.jface.viewers.ISelection,
967      * boolean)
968      */

969     protected synchronized ISelection doAttemptSelectionToWidget(ISelection selection, boolean reveal) {
970         List JavaDoc remaining = new ArrayList JavaDoc();
971         if (!selection.isEmpty()) {
972             List JavaDoc toSelect = new ArrayList JavaDoc();
973             List JavaDoc theNodes = new ArrayList JavaDoc();
974             List JavaDoc theElements = new ArrayList JavaDoc();
975             TreeSelection treeSelection = (TreeSelection) selection;
976             TreePath[] paths = treeSelection.getPaths();
977             for (int i = 0; i < paths.length; i++) {
978                 TreePath path = paths[i];
979                 if (path == null) {
980                     continue;
981                 }
982                 ModelNode[] nodes = getModel().getNodes(path.getLastSegment());
983                 boolean selected = false;
984                 if (nodes != null) {
985                     for (int j = 0; j < nodes.length; j++) {
986                         ModelNode node = nodes[j];
987                         if (node.correspondsTo(path)) {
988                             Widget widget = findItem(node);
989                             if (widget != null && !widget.isDisposed()) {
990                                 toSelect.add(widget);
991                                 theNodes.add(node);
992                                 theElements.add(path.getLastSegment());
993                                 selected = true;
994                                 break;
995                             }
996                         }
997                         // attempt to map widget
998
ModelNode parent = node.getParentNode();
999                         ModelNode child = node;
1000                        if (parent != null) {
1001                            Widget widget = findItem(parent);
1002                            if (widget != null && !widget.isDisposed()) {
1003                                int childIndex = parent.getChildIndex(child);
1004                                if (childIndex < 0) {
1005                                    break;
1006                                }
1007                                TreeItem[] items = getItems(widget);
1008                                if (childIndex < items.length) {
1009                                    widget = items[childIndex];
1010                                    mapElement(child, widget);
1011                                    widget.setData(child.getElement());
1012                                    toSelect.add(widget);
1013                                    theNodes.add(child);
1014                                    theElements.add(child.getElement());
1015                                    selected = true;
1016                                } else {
1017                                    break;
1018                                }
1019                            }
1020                        }
1021                    }
1022                }
1023                if (!selected) {
1024                    remaining.add(path);
1025                }
1026            }
1027            if (!toSelect.isEmpty()) {
1028                final TreeItem[] items = (TreeItem[]) toSelect.toArray(new TreeItem[toSelect.size()]);
1029                // TODO: hack to ensure selection contains 'selected' element
1030
// instead of 'equivalent' element. Handles synch problems
1031
// between set selection & refresh
1032
for (int i = 0; i < items.length; i++) {
1033                    TreeItem item = items[i];
1034                    Object JavaDoc element = theElements.get(i);
1035                    if (!item.isDisposed() && item.getData() != element) {
1036                        ModelNode theNode = (ModelNode) theNodes.get(i);
1037                        Widget mapped = findItem(theNode);
1038                        if (mapped == null) {
1039                            // the node has been unmapped from the widget (pushed down perhaps)
1040
return selection;
1041                        }
1042                        theNode.remap(element);
1043                        item.setData(element);
1044                    }
1045                }
1046                fTree.setSelection(items);
1047                if (reveal) {
1048                    fTree.showItem(items[0]);
1049                }
1050            }
1051        } else {
1052            fTree.setSelection(new TreeItem[0]);
1053        }
1054        return new TreeSelection((TreePath[]) remaining.toArray(new TreePath[remaining.size()]));
1055    }
1056
1057    /**
1058     * Collapses all items in the tree.
1059     */

1060    public void collapseAll() {
1061        TreeItem[] items = fTree.getItems();
1062        for (int i = 0; i < items.length; i++) {
1063            TreeItem item = items[i];
1064            if (item.getExpanded())
1065                collapse(item);
1066        }
1067    }
1068
1069    /**
1070     * Collaspes the given item and all of its children items.
1071     *
1072     * @param item
1073     * item to collapose recursively
1074     */

1075    protected void collapse(TreeItem item) {
1076        TreeItem[] items = item.getItems();
1077        for (int i = 0; i < items.length; i++) {
1078            TreeItem child = items[i];
1079            if (child.getExpanded()) {
1080                collapse(child);
1081            }
1082        }
1083        item.setExpanded(false);
1084    }
1085
1086    /*
1087     * (non-Javadoc)
1088     *
1089     * @see org.eclipse.debug.ui.viewers.AsynchronousViewer#setColor(org.eclipse.swt.widgets.Widget,
1090     * org.eclipse.swt.graphics.RGB, org.eclipse.swt.graphics.RGB)
1091     */

1092    protected void setColors(Widget widget, RGB[] foregrounds, RGB[] backgrounds) {
1093        if (widget instanceof TreeItem) {
1094            TreeItem item = (TreeItem) widget;
1095            Color[] fgs = getColors(foregrounds);
1096            for (int i = 0; i < fgs.length; i++) {
1097                item.setForeground(i, fgs[i]);
1098            }
1099            Color[] bgs = getColors(backgrounds);
1100            for (int i = 0; i < bgs.length; i++) {
1101                item.setBackground(i, bgs[i]);
1102            }
1103        }
1104    }
1105
1106    /*
1107     * (non-Javadoc)
1108     *
1109     * @see org.eclipse.debug.ui.viewers.AsynchronousViewer#setFont(org.eclipse.swt.widgets.Widget,
1110     * org.eclipse.swt.graphics.FontData)
1111     */

1112    protected void setFonts(Widget widget, FontData[] fontData) {
1113        if (widget instanceof TreeItem) {
1114            TreeItem item = (TreeItem) widget;
1115            Font[] fonts = getFonts(fontData);
1116            for (int i = 0; i < fonts.length; i++) {
1117                item.setFont(i, fonts[i]);
1118            }
1119        }
1120    }
1121
1122    /*
1123     * (non-Javadoc)
1124     *
1125     * @see org.eclipse.debug.ui.viewers.AsynchronousViewer#acceptsSelection(org.eclipse.jface.viewers.ISelection)
1126     */

1127    protected boolean acceptsSelection(ISelection selection) {
1128        return selection instanceof TreeSelection;
1129    }
1130
1131    /*
1132     * (non-Javadoc)
1133     *
1134     * @see org.eclipse.debug.ui.viewers.AsynchronousViewer#getEmptySelection()
1135     */

1136    protected ISelection getEmptySelection() {
1137        return new TreeSelection(new TreePath[0]);
1138    }
1139
1140    /**
1141     * Adds the item specified by the given tree path to this tree. Can be
1142     * called in a non-UI thread.
1143     *
1144     * @param treePath
1145     */

1146    public void add(TreePath treePath) {
1147        ((AsynchronousTreeModel)getModel()).add(treePath);
1148    }
1149
1150    /**
1151     * Removes the item specified in the given tree path from this tree. Can be
1152     * called in a non-UI thread.
1153     *
1154     * @param treePath
1155     */

1156    public void remove(TreePath treePath) {
1157        synchronized (this) {
1158            for (Iterator JavaDoc i = fPendingExpansion.iterator(); i.hasNext();) {
1159                TreePath expansionPath = (TreePath) i.next();
1160                if (expansionPath.startsWith(treePath, null)) {
1161                    i.remove();
1162                }
1163            }
1164        }
1165        ((AsynchronousTreeModel)getModel()).remove(treePath);
1166    }
1167
1168    
1169    protected void restoreLabels(Item item) {
1170        TreeItem treeItem = (TreeItem) item;
1171        String JavaDoc[] values = (String JavaDoc[]) treeItem.getData(OLD_LABEL);
1172        Image[] images = (Image[])treeItem.getData(OLD_IMAGE);
1173        if (values != null) {
1174            treeItem.setText(values);
1175            treeItem.setImage(images);
1176        }
1177    }
1178
1179    protected void setLabels(Widget widget, String JavaDoc[] text, ImageDescriptor[] image) {
1180        if (widget instanceof TreeItem) {
1181            TreeItem item = (TreeItem) widget;
1182            if (!item.isDisposed()) {
1183                item.setText(text);
1184                item.setData(OLD_LABEL, text);
1185                Image[] images = getImages(image);
1186                item.setImage(images);
1187                item.setData(OLD_IMAGE, images);
1188            }
1189        }
1190    }
1191
1192    /* (non-Javadoc)
1193     * @see org.eclipse.debug.internal.ui.viewers.AsynchronousModelViewer#createModel()
1194     */

1195    protected AsynchronousModel createModel() {
1196        return new AsynchronousTreeModel(this);
1197    }
1198    
1199    /**
1200     * Attempt pending udpates. Subclasses may override but should call super.
1201     */

1202    protected void attemptPendingUpdates() {
1203        attemptExpansion();
1204        super.attemptPendingUpdates();
1205    }
1206
1207    /* (non-Javadoc)
1208     * @see org.eclipse.debug.internal.ui.model.viewers.AsynchronousViewer#createUpdatePolicy()
1209     */

1210    public AbstractUpdatePolicy createUpdatePolicy() {
1211        return new TreeUpdatePolicy();
1212    }
1213
1214    protected synchronized void unmapAllElements() {
1215        super.unmapAllElements();
1216        Tree tree = getTree();
1217        if (!tree.isDisposed()) {
1218            TreeItem[] items = tree.getItems();
1219            for (int i = 0; i < items.length; i++) {
1220                items[i].dispose();
1221            }
1222            clear(tree);
1223        }
1224    }
1225    
1226    /**
1227     * Returns the current column presentation for this viewer, or <code>null</code>
1228     * if none.
1229     *
1230     * @return column presentation or <code>null</code>
1231     */

1232    public IColumnPresentation getColumnPresentation() {
1233        return fColumnPresentation;
1234    }
1235    
1236    /**
1237     * Returns identifiers of the visible columns in this viewer, or <code>null</code>
1238     * if there is currently no column presentation.
1239     *
1240     * @return visible columns or <code>null</code>
1241     */

1242    public String JavaDoc[] getVisibleColumns() {
1243        IColumnPresentation presentation = getColumnPresentation();
1244        if (presentation != null) {
1245            String JavaDoc[] columns = (String JavaDoc[]) fVisibleColumns.get(presentation.getId());
1246            if (columns == null) {
1247                return presentation.getInitialColumns();
1248            }
1249            return columns;
1250        }
1251        return null;
1252    }
1253    
1254    /**
1255     * Sets the ids of visible columns, or <code>null</code> to set default columns.
1256     * Only effects the current column presentation.
1257     *
1258     * @param ids visible columns
1259     */

1260    public void setVisibleColumns(String JavaDoc[] ids) {
1261        IColumnPresentation presentation = getColumnPresentation();
1262        if (presentation != null) {
1263            fVisibleColumns.remove(presentation.getId());
1264            if (ids != null) {
1265                // put back in table if not default
1266
String JavaDoc[] columns = presentation.getInitialColumns();
1267                if (columns.length == ids.length) {
1268                    for (int i = 0; i < columns.length; i++) {
1269                        if (!ids[i].equals(columns[i])) {
1270                            fVisibleColumns.put(presentation.getId(), ids);
1271                            break;
1272                        }
1273                    }
1274                } else {
1275                    fVisibleColumns.put(presentation.getId(), ids);
1276                }
1277            }
1278            PresentationContext presentationContext = (PresentationContext) getPresentationContext();
1279            presentationContext.setColumns(getVisibleColumns());
1280            refreshColumns();
1281        }
1282    }
1283    
1284    /**
1285     * Save viewer state into the given memento.
1286     *
1287     * @param memento
1288     */

1289    public void saveState(IMemento memento) {
1290        if (!fColumnSizes.isEmpty()) {
1291            Iterator JavaDoc iterator = fColumnSizes.entrySet().iterator();
1292            while (iterator.hasNext()) {
1293                Map.Entry JavaDoc entry = (Entry) iterator.next();
1294                IMemento sizes = memento.createChild(COLUMN_SIZES, (String JavaDoc)entry.getKey());
1295                sizes.putInteger(SIZE, ((Integer JavaDoc)entry.getValue()).intValue());
1296            }
1297        }
1298        if (!fShowColumns.isEmpty()) {
1299            Iterator JavaDoc iterator = fShowColumns.entrySet().iterator();
1300            while (iterator.hasNext()) {
1301                Map.Entry JavaDoc entry = (Entry) iterator.next();
1302                IMemento sizes = memento.createChild(SHOW_COLUMNS, (String JavaDoc)entry.getKey());
1303                sizes.putString(SHOW_COLUMNS, ((Boolean JavaDoc)entry.getValue()).toString());
1304            }
1305        }
1306        if (!fVisibleColumns.isEmpty()) {
1307            Iterator JavaDoc iterator = fVisibleColumns.entrySet().iterator();
1308            while (iterator.hasNext()) {
1309                Map.Entry JavaDoc entry = (Entry) iterator.next();
1310                String JavaDoc id = (String JavaDoc) entry.getKey();
1311                IMemento visible = memento.createChild(VISIBLE_COLUMNS, id);
1312                String JavaDoc[] columns = (String JavaDoc[]) entry.getValue();
1313                visible.putInteger(SIZE, columns.length);
1314                for (int i = 0; i < columns.length; i++) {
1315                    visible.putString(COLUMN+Integer.toString(i), columns[i]);
1316                }
1317            }
1318        }
1319    }
1320    
1321    /**
1322     * Resets any persisted column size for the given columns
1323     */

1324    public void resetColumnSizes(String JavaDoc[] columnIds) {
1325        for (int i = 0; i < columnIds.length; i++) {
1326            fColumnSizes.remove(columnIds[i]);
1327        }
1328    }
1329    
1330    /**
1331     * Initializes veiwer state from the memento
1332     *
1333     * @param memento
1334     */

1335    public void initState(IMemento memento) {
1336        IMemento[] mementos = memento.getChildren(COLUMN_SIZES);
1337        for (int i = 0; i < mementos.length; i++) {
1338            IMemento child = mementos[i];
1339            String JavaDoc id = child.getID();
1340            Integer JavaDoc size = child.getInteger(SIZE);
1341            if (size != null) {
1342                fColumnSizes.put(id, size);
1343            }
1344        }
1345        mementos = memento.getChildren(SHOW_COLUMNS);
1346        for (int i = 0; i < mementos.length; i++) {
1347            IMemento child = mementos[i];
1348            String JavaDoc id = child.getID();
1349            Boolean JavaDoc bool = Boolean.valueOf(child.getString(SHOW_COLUMNS));
1350            if (!bool.booleanValue()) {
1351                fShowColumns.put(id, bool);
1352            }
1353        }
1354        mementos = memento.getChildren(VISIBLE_COLUMNS);
1355        for (int i = 0; i < mementos.length; i++) {
1356            IMemento child = mementos[i];
1357            String JavaDoc id = child.getID();
1358            Integer JavaDoc integer = child.getInteger(SIZE);
1359            if (integer != null) {
1360                int length = integer.intValue();
1361                String JavaDoc[] columns = new String JavaDoc[length];
1362                for (int j = 0; j < length; j++) {
1363                    columns[j] = child.getString(COLUMN+Integer.toString(j));
1364                }
1365                fVisibleColumns.put(id, columns);
1366            }
1367        }
1368        
1369    }
1370
1371    /**
1372     * Initializes the tree viewer implementation.
1373     */

1374    private void initTreeViewerImpl() {
1375        fTreeEditorImpl = new TreeEditorImpl(this) {
1376            Rectangle getBounds(Item item, int columnNumber) {
1377                return ((TreeItem) item).getBounds(columnNumber);
1378            }
1379
1380            int getColumnCount() {
1381                return getTree().getColumnCount();
1382            }
1383
1384            Item[] getSelection() {
1385                return getTree().getSelection();
1386            }
1387
1388            void setEditor(Control w, Item item, int columnNumber) {
1389                fTreeEditor.setEditor(w, (TreeItem) item, columnNumber);
1390            }
1391
1392            void setSelection(IStructuredSelection selection, boolean b) {
1393                AsynchronousTreeViewer.this.setSelection(selection, b);
1394            }
1395
1396            void showSelection() {
1397                getTree().showSelection();
1398            }
1399
1400            void setLayoutData(CellEditor.LayoutData layoutData) {
1401                fTreeEditor.grabHorizontal = layoutData.grabHorizontal;
1402                fTreeEditor.horizontalAlignment = layoutData.horizontalAlignment;
1403                fTreeEditor.minimumWidth = layoutData.minimumWidth;
1404            }
1405
1406            void handleDoubleClickEvent() {
1407                Viewer viewer = getViewer();
1408                fireDoubleClick(new DoubleClickEvent(viewer, viewer
1409                        .getSelection()));
1410                fireOpen(new OpenEvent(viewer, viewer.getSelection()));
1411            }
1412        };
1413    }
1414    
1415    /**
1416     * Starts editing the given element.
1417     *
1418     * @param element
1419     * the element
1420     * @param column
1421     * the column number
1422     */

1423    public void editElement(Object JavaDoc element, int column) {
1424        fTreeEditorImpl.editElement(element, column);
1425    }
1426
1427    /**
1428     * Returns the cell editors of this tree viewer.
1429     *
1430     * @return the list of cell editors
1431     */

1432    public CellEditor[] getCellEditors() {
1433        return fTreeEditorImpl.getCellEditors();
1434    }
1435
1436    /**
1437     * Returns the cell modifier of this tree viewer.
1438     *
1439     * @return the cell modifier
1440     */

1441    public ICellModifier getCellModifier() {
1442        return fTreeEditorImpl.getCellModifier();
1443    }
1444    
1445    /**
1446     * Cancels a currently active cell editor. All changes already done in the
1447     * cell editor are lost.
1448     *
1449     */

1450    public void cancelEditing() {
1451        fTreeEditorImpl.cancelEditing();
1452    }
1453    
1454    /**
1455     * Returns whether there is an active cell editor.
1456     *
1457     * @return <code>true</code> if there is an active cell editor, and
1458     * <code>false</code> otherwise
1459     */

1460    public boolean isCellEditorActive() {
1461        return fTreeEditorImpl.isCellEditorActive();
1462    }
1463    
1464    /**
1465     * Sets the cell editors of this tree viewer.
1466     *
1467     * @param editors
1468     * the list of cell editors
1469     */

1470    protected void setCellEditors(CellEditor[] editors) {
1471        fTreeEditorImpl.setCellEditors(editors);
1472    }
1473
1474    /**
1475     * Sets the cell modifier of this tree viewer.
1476     *
1477     * @param modifier
1478     * the cell modifier
1479     */

1480    protected void setCellModifier(ICellModifier modifier) {
1481        fTreeEditorImpl.setCellModifier(modifier);
1482    }
1483    
1484    /**
1485     * Sets the column properties of this tree viewer. The properties must
1486     * correspond with the columns of the tree control. They are used to
1487     * identify the column in a cell modifier.
1488     *
1489     * @param columnProperties
1490     * the list of column properties
1491     */

1492    protected void setColumnProperties(String JavaDoc[] columnProperties) {
1493        fTreeEditorImpl.setColumnProperties(columnProperties);
1494    }
1495    
1496    /**
1497     * Toggles columns on/off for the current column presentation, if any.
1498     *
1499     * @param show whether to show columns if the current input suppports
1500     * columns
1501     */

1502    public void setShowColumns(boolean show) {
1503        if (show) {
1504            if (!isShowColumns()) {
1505                fShowColumns.remove(fColumnPresentation.getId());
1506            }
1507        } else {
1508            if (isShowColumns()){
1509                fShowColumns.put(fColumnPresentation.getId(), Boolean.FALSE);
1510            }
1511        }
1512        refreshColumns();
1513    }
1514    
1515    /**
1516     * Returns whether columns are being displayed currently.
1517     *
1518     * @return
1519     */

1520    public boolean isShowColumns() {
1521        if (fColumnPresentation != null) {
1522            return isShowColumns(fColumnPresentation.getId());
1523        }
1524        return false;
1525    }
1526    
1527    /**
1528     * Returns whether columns can be toggled on/off for the current input.
1529     *
1530     * @return whether columns can be toggled on/off for the current input
1531     */

1532    public boolean canToggleColumns() {
1533        return fColumnPresentation != null && fColumnPresentation.isOptional();
1534    }
1535    
1536    protected boolean isShowColumns(String JavaDoc columnPresentationId) {
1537        Boolean JavaDoc bool = (Boolean JavaDoc) fShowColumns.get(columnPresentationId);
1538        if (bool == null) {
1539            return true;
1540        }
1541        return bool.booleanValue();
1542    }
1543    
1544    /**
1545     * Notification the container status of a node has changed/been computed.
1546     *
1547     * @param node
1548     */

1549    protected void nodeContainerChanged(ModelNode node) {
1550        Widget widget = findItem(node);
1551        if (widget != null && !widget.isDisposed()) {
1552            if (node.isContainer()) {
1553                if (widget instanceof TreeItem) {
1554                    if (((TreeItem)widget).getExpanded()) {
1555                        updateChildren(node);
1556                    }
1557                } else {
1558                    updateChildren(node);
1559                }
1560                attemptPendingUpdates();
1561            }
1562        }
1563    }
1564    
1565    /**
1566     * Collects label results.
1567     *
1568     * @param monitor progress monitor
1569     * @param element element to start collecting at, including all children
1570     * @param taskName label for prorgress monitor main task
1571     *
1572     * @return results or <code>null</code> if cancelled
1573     */

1574    public List JavaDoc buildLabels(IProgressMonitor monitor, Object JavaDoc element, String JavaDoc taskName) {
1575        ModelNode[] theNodes = getModel().getNodes(element);
1576        List JavaDoc results = new ArrayList JavaDoc();
1577        if (theNodes != null && theNodes.length > 0) {
1578            ModelNode root = theNodes[0];
1579            List JavaDoc nodes = new ArrayList JavaDoc();
1580            collectNodes(nodes, root);
1581            monitor.beginTask(taskName, nodes.size());
1582            Iterator JavaDoc iterator = nodes.iterator();
1583            while (!monitor.isCanceled() && iterator.hasNext()) {
1584                ModelNode node = (ModelNode) iterator.next();
1585                IAsynchronousLabelAdapter labelAdapter = getModel().getLabelAdapter(node.getElement());
1586                if (labelAdapter != null) {
1587                    LabelResult result = new LabelResult(node, getModel());
1588                    labelAdapter.retrieveLabel(node.getElement(), getPresentationContext(), result);
1589                    synchronized (result) {
1590                        if (!result.isDone()) {
1591                            try {
1592                                result.wait();
1593                            } catch (InterruptedException JavaDoc e) {
1594                                monitor.setCanceled(true);
1595                                return null;
1596                            }
1597                        }
1598                    }
1599                    IStatus status = result.getStatus();
1600                    if (status == null || status.isOK()) {
1601                        results.add(result);
1602                    }
1603                }
1604                monitor.worked(1);
1605            }
1606        }
1607        monitor.done();
1608        return results;
1609    }
1610    
1611    private void collectNodes(List JavaDoc nodes, ModelNode node) {
1612        if (node.getParentNode() != null) {
1613            nodes.add(node);
1614        }
1615        ModelNode[] childrenNodes = node.getChildrenNodes();
1616        if (childrenNodes != null) {
1617            for (int i = 0; i < childrenNodes.length; i++) {
1618                collectNodes(nodes, childrenNodes[i]);
1619            }
1620        }
1621    }
1622
1623    /* (non-Javadoc)
1624     * @see org.eclipse.debug.internal.ui.viewers.AsynchronousViewer#indexOf(org.eclipse.swt.widgets.Widget, org.eclipse.swt.widgets.Widget)
1625     */

1626    protected int indexOf(Widget parent, Widget child) {
1627        if (parent instanceof Tree) {
1628            return ((Tree)parent).indexOf((TreeItem)child);
1629        } else {
1630            return ((TreeItem)parent).indexOf((TreeItem)child);
1631        }
1632    }
1633
1634    /* (non-Javadoc)
1635     * @see org.eclipse.debug.internal.ui.viewers.AsynchronousViewer#selectionExists(org.eclipse.jface.viewers.ISelection)
1636     */

1637    protected boolean selectionExists(ISelection selection) {
1638        if (!selection.isEmpty() && selection instanceof TreeSelection) {
1639            TreeSelection ts = (TreeSelection) selection;
1640            TreePath[] paths = ts.getPaths();
1641            int matchingPaths = 0;
1642            for (int i = 0; i < paths.length; i++) {
1643                TreePath path = paths[i];
1644                Object JavaDoc element = path.getLastSegment();
1645                ModelNode[] nodes = getModel().getNodes(element);
1646                if (nodes != null) {
1647                    for (int j = 0; j < nodes.length; j++) {
1648                        ModelNode node = nodes[j];
1649                        if (node.getTreePath().equals(path)) {
1650                            matchingPaths++;
1651                            break;
1652                        }
1653                    }
1654                }
1655            }
1656            return matchingPaths == paths.length;
1657        }
1658        return super.selectionExists(selection);
1659    }
1660    
1661    
1662    
1663
1664}
1665
Popular Tags