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