KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > debug > internal > ui > views > RemoteTreeViewer


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 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.views;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.List JavaDoc;
16
17 import org.eclipse.core.runtime.IAdaptable;
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.core.runtime.IStatus;
20 import org.eclipse.core.runtime.Status;
21 import org.eclipse.core.runtime.jobs.Job;
22 import org.eclipse.debug.core.ILaunch;
23 import org.eclipse.jface.util.Assert;
24 import org.eclipse.jface.viewers.IStructuredSelection;
25 import org.eclipse.jface.viewers.TreeViewer;
26 import org.eclipse.jface.viewers.ViewerSorter;
27 import org.eclipse.swt.SWT;
28 import org.eclipse.swt.events.DisposeEvent;
29 import org.eclipse.swt.events.DisposeListener;
30 import org.eclipse.swt.widgets.Composite;
31 import org.eclipse.swt.widgets.Item;
32 import org.eclipse.swt.widgets.Tree;
33 import org.eclipse.swt.widgets.TreeItem;
34 import org.eclipse.swt.widgets.Widget;
35 import org.eclipse.ui.model.IWorkbenchAdapter;
36 import org.eclipse.ui.progress.UIJob;
37
38 /**
39  * A tree viewer that displays remote content. Content is retrieved in a background
40  * job, and the viewer is updated incrementally on a refresh.
41  *
42  * @since 3.1
43  */

44 public class RemoteTreeViewer extends TreeViewer {
45
46     private ExpansionJob fExpansionJob = null;
47     private SelectionJob fSelectionJob = null;
48     
49
50     class ExpansionJob extends UIJob {
51         
52         private Object JavaDoc element;
53         private List JavaDoc parents = new ArrayList JavaDoc(); // top down
54

55         /**
56          * Constucts a job to expand the given element.
57          *
58          * @param target the element to expand
59          */

60         public ExpansionJob() {
61             super(DebugUIViewsMessages.LaunchViewer_1); //$NON-NLS-1$
62
setPriority(Job.INTERACTIVE);
63             setSystem(true);
64         }
65
66         /* (non-Javadoc)
67          * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
68          */

69         public IStatus runInUIThread(IProgressMonitor monitor) {
70             if (getControl().isDisposed() || element == null) {
71                 return Status.OK_STATUS;
72             }
73             synchronized (RemoteTreeViewer.this) {
74                 boolean allParentsExpanded = true;
75                 Iterator JavaDoc iterator = parents.iterator();
76                 while (iterator.hasNext() && !monitor.isCanceled()) {
77                     Object JavaDoc parent = iterator.next();
78                     Widget item = findItem(parent);
79                     if (item != null) {
80                         expandToLevel(parent, 1);
81                     } else {
82                         allParentsExpanded = false;
83                         break;
84                     }
85                 }
86                 if (allParentsExpanded) {
87                     Widget item = findItem(element);
88                     if (item != null) {
89                         if (isExpandable(element)) {
90                             expandToLevel(element, 1);
91                         }
92                         element = null;
93                         parents.clear();
94                         return Status.OK_STATUS;
95                     }
96                 }
97                 return Status.OK_STATUS;
98             }
99         }
100         
101         public void validate(Object JavaDoc object) {
102             if (element != null) {
103                 if (element.equals(object) || parents.contains(object)) {
104                     cancel();
105                     element = null;
106                 }
107             }
108         }
109
110         public void setDeferredExpansion(Object JavaDoc toExpand) {
111             element = toExpand;
112             parents.clear();
113             addAllParents(parents, element);
114         }
115         
116     }
117
118     class SelectionJob extends UIJob {
119         
120         private IStructuredSelection selection;
121         private Object JavaDoc first;
122         private List JavaDoc parents = new ArrayList JavaDoc(); // top down
123

124         /**
125          * Constucts a job to select the given element.
126          *
127          * @param target the element to select
128          */

129         public SelectionJob() {
130             super(DebugUIViewsMessages.LaunchViewer_0); //$NON-NLS-1$
131
setPriority(Job.INTERACTIVE);
132             setSystem(true);
133         }
134
135         /* (non-Javadoc)
136          * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
137          */

138         public IStatus runInUIThread(IProgressMonitor monitor) {
139             if (getControl().isDisposed() || selection == null) {
140                 return Status.OK_STATUS;
141             }
142             synchronized (RemoteTreeViewer.this) {
143                 boolean allParentsExpanded = true;
144                 Iterator JavaDoc iterator = parents.iterator();
145                 while (iterator.hasNext() && !monitor.isCanceled()) {
146                     Object JavaDoc parent = iterator.next();
147                     Widget item = findItem(parent);
148                     if (item != null) {
149                         expandToLevel(parent, 1);
150                     } else {
151                         allParentsExpanded = false;
152                         break;
153                     }
154                 }
155                 if (allParentsExpanded) {
156                     if (findItem(first) != null) {
157                         setSelection(selection, true);
158                         selection = null;
159                         first = null;
160                         parents.clear();
161                         return Status.OK_STATUS;
162                     }
163                 }
164
165                 return Status.OK_STATUS;
166             }
167         }
168         
169         public void setDeferredSelection(IStructuredSelection sel) {
170             selection = sel;
171             first = selection.getFirstElement();
172             parents.clear();
173             addAllParents(parents, first);
174         }
175         
176         public void validate(Object JavaDoc object) {
177             if (first != null) {
178                 if (first.equals(object) || parents.contains(object)) {
179                     cancel();
180                     selection = null;
181                 }
182             }
183         }
184     }
185     
186
187     /**
188      * Constructs a remote tree viewer parented by the given composite.
189      *
190      * @param parent parent composite
191      */

192     public RemoteTreeViewer(Composite parent) {
193         super(parent);
194         addDisposeListener();
195         fExpansionJob = new ExpansionJob();
196         fSelectionJob = new SelectionJob();
197     }
198
199     /**
200      * Constructs a remote tree viewer parented by the given composite
201      * with the given style.
202      *
203      * @param parent parent composite
204      * @param style style bits
205      */

206     public RemoteTreeViewer(Composite parent, int style) {
207         super(parent, style);
208         addDisposeListener();
209         fExpansionJob = new ExpansionJob();
210         fSelectionJob = new SelectionJob();
211     }
212
213     /**
214      * Constructs a remote tree viewer with the given tree.
215      *
216      * @param tree tree widget
217      */

218     public RemoteTreeViewer(Tree tree) {
219         super(tree);
220         addDisposeListener();
221         fExpansionJob = new ExpansionJob();
222         fSelectionJob = new SelectionJob();
223     }
224     
225     private void addDisposeListener() {
226         getControl().addDisposeListener(new DisposeListener() {
227             public void widgetDisposed(DisposeEvent e) {
228                 cancelJobs();
229             }
230         });
231     }
232     
233     protected void runDeferredUpdates() {
234         if (fExpansionJob != null) {
235             fExpansionJob.schedule();
236         }
237         if (fSelectionJob != null) {
238             fSelectionJob.schedule();
239         }
240     }
241     
242     /**
243      * The given element is being removed from the tree. Cancel
244      * any deferred updates for the element.
245      *
246      * @param element
247      */

248     protected void validateDeferredUpdates(Object JavaDoc element) {
249         if (element != null) {
250             if (fExpansionJob != null) {
251                 fExpansionJob.validate(element);
252             }
253             if (fSelectionJob != null) {
254                 fSelectionJob.validate(element);
255             }
256         }
257     }
258     
259     /* (non-Javadoc)
260      * @see org.eclipse.jface.viewers.AbstractTreeViewer#add(java.lang.Object, java.lang.Object)
261      */

262     public synchronized void add(Object JavaDoc parentElement, Object JavaDoc childElement) {
263         super.add(parentElement, childElement);
264         runDeferredUpdates();
265     }
266     
267     /* (non-Javadoc)
268      * @see org.eclipse.jface.viewers.AbstractTreeViewer#add(java.lang.Object, java.lang.Object[])
269      */

270     public synchronized void add(Object JavaDoc parentElement, Object JavaDoc[] childElements) {
271         super.add(parentElement, childElements);
272         runDeferredUpdates();
273     }
274     
275     /* (non-Javadoc)
276      * @see org.eclipse.jface.viewers.AbstractTreeViewer#remove(java.lang.Object)
277      */

278     public synchronized void remove(Object JavaDoc element) {
279         validateDeferredUpdates(element);
280         super.remove(element);
281     }
282     
283     /* (non-Javadoc)
284      * @see org.eclipse.jface.viewers.AbstractTreeViewer#remove(java.lang.Object[])
285      */

286     public synchronized void remove(Object JavaDoc[] elements) {
287         for (int i = 0; i < elements.length; i++) {
288             validateDeferredUpdates(elements[i]);
289         }
290         super.remove(elements);
291     }
292
293     /**
294      * Cancels any deferred updates currently scheduled/running.
295      */

296     public void cancelJobs() {
297         cancel(fSelectionJob);
298         cancel(fExpansionJob);
299     }
300
301     public synchronized void deferExpansion(Object JavaDoc element) {
302         TreeItem treeItem = (TreeItem) findItem(element);
303         if (treeItem == null) {
304             fExpansionJob.setDeferredExpansion(element);
305             fExpansionJob.schedule();
306         } else {
307             if (!getExpanded(treeItem)) {
308                 fExpansionJob.setDeferredExpansion(element);
309                 fExpansionJob.schedule();
310             }
311         }
312     }
313     
314     public synchronized void deferSelection(IStructuredSelection selection) {
315         if (fSelectionJob == null) {
316             fSelectionJob = new SelectionJob();
317         }
318         
319         fSelectionJob.setDeferredSelection(selection);
320         fSelectionJob.schedule();
321     }
322     
323     public IStructuredSelection getDeferredSelection() {
324         if (fSelectionJob != null) {
325             return fSelectionJob.selection;
326         }
327         return null;
328     }
329
330     private void cancel(Job job) {
331         if (job != null) {
332             job.cancel();
333         }
334     }
335
336     private void addAllParents(List JavaDoc list, Object JavaDoc element) {
337         if (element instanceof IAdaptable) {
338             IAdaptable adaptable = (IAdaptable) element;
339             IWorkbenchAdapter adapter = (IWorkbenchAdapter) adaptable.getAdapter(IWorkbenchAdapter.class);
340             if (adapter != null) {
341                 Object JavaDoc parent = adapter.getParent(element);
342                 if (parent != null) {
343                     list.add(0, parent);
344                     if (!(parent instanceof ILaunch))
345                     addAllParents(list, parent);
346                 }
347             }
348         }
349     }
350
351     public Object JavaDoc[] filter(Object JavaDoc[] elements) {
352         return super.filter(elements);
353     }
354     
355     public Object JavaDoc[] getCurrentChildren(Object JavaDoc parent) {
356         Widget widget = findItem(parent);
357         if (widget != null) {
358             Item[] items = getChildren(widget);
359             Object JavaDoc[] children = new Object JavaDoc[items.length];
360             for (int i = 0; i < children.length; i++) {
361                 Object JavaDoc data = items[i].getData();
362                 if (data == null) {
363                     return null;
364                 }
365                 children[i] = data;
366             }
367             return children;
368         }
369         return null;
370     }
371
372     public synchronized void prune(final Object JavaDoc parent, final int offset) {
373         Widget widget = findItem(parent);
374         if (widget != null) {
375             final Item[] currentChildren = getChildren(widget);
376             if (offset < currentChildren.length) {
377                 preservingSelection(new Runnable JavaDoc() {
378                     public void run() {
379                         for (int i = offset; i < currentChildren.length; i++) {
380                             if (currentChildren[i].getData() != null) {
381                                 disassociate(currentChildren[i]);
382                             }
383                             currentChildren[i].dispose();
384                         }
385                     }
386                 });
387             }
388         }
389     }
390
391     public synchronized void replace(final Object JavaDoc parent, final Object JavaDoc[] children, final int offset) {
392         preservingSelection(new Runnable JavaDoc() {
393             public void run() {
394                 Widget[] widgets = findItems(parent);
395                 for (int n = 0; n < widgets.length; n++) {
396                     Widget widget = widgets[n];
397                     if (widget == null) {
398                         add(parent, children);
399                     } else {
400                         Item[] currentChildren = getChildren(widget);
401                         int pos = offset;
402                         if (pos >= currentChildren.length) {
403                             // append
404
add(parent, children);
405                         } else {
406                             // replace
407
for (int i = 0; i < children.length; i++) {
408                                 Object JavaDoc child = children[i];
409                                 if (pos < currentChildren.length) {
410                                     // replace
411
Item item = currentChildren[pos];
412                                     Object JavaDoc data = item.getData();
413                                     if (!child.equals(data)) {
414                                         // no need to cancel pending updates here, the child may have shifted up/down
415
internalRefresh(item, child, true, true);
416                                     } else {
417                                         // If it's the same child, the label/content may still have changed
418
doUpdateItem(item, child);
419                                         updatePlus(item, child);
420                                     }
421                                 } else {
422                                     // add
423
int numLeft = children.length - i;
424                                     if (numLeft > 1) {
425                                         Object JavaDoc[] others = new Object JavaDoc[numLeft];
426                                         System.arraycopy(children, i, others, 0, numLeft);
427                                         add(parent, others);
428                                     } else {
429                                         add(parent, child);
430                                     }
431                                     break;
432                                 }
433                                 pos++;
434                             }
435                         }
436                     }
437                 }
438
439                 runDeferredUpdates();
440             }
441         });
442     }
443
444     protected void internalAdd(Widget widget, Object JavaDoc parentElement, Object JavaDoc[] childElements) {
445         
446         // optimization!
447
// if the widget is not expanded we just invalidate the subtree
448
if (widget instanceof Item) {
449             Item ti = (Item) widget;
450             if (!getExpanded(ti)) {
451                 boolean needDummy = isExpandable(parentElement);
452                 boolean haveDummy = false;
453                 // remove all children
454
Item[] items = getItems(ti);
455                 for (int i = 0; i < items.length; i++) {
456                     if (items[i].getData() != null) {
457                         disassociate(items[i]);
458                         items[i].dispose();
459                     } else {
460                         if (needDummy && !haveDummy) {
461                             haveDummy = true;
462                         } else {
463                             items[i].dispose();
464                         }
465                     }
466                 }
467                 // append a dummy if necessary
468
if (needDummy && !haveDummy)
469                     newItem(ti, SWT.NULL, -1);
470                 return;
471             }
472         }
473
474         if (childElements.length > 0) {
475             Object JavaDoc[] filtered = filter(childElements);
476             if(getSorter() != null)
477                 getSorter().sort(this,filtered);
478             createAddedElements(widget, filtered);
479         }
480     }
481     
482
483     // tree viewer hacks start here. These hacks allow us to display the same Object in a tree viewer more
484
// than once. Workbench does on support this (July 6, 2005)
485

486     private void createAddedElements(Widget widget, Object JavaDoc[] elements) {
487
488         if(elements.length == 1){
489             if (equals(elements[0], widget.getData()))
490                 return;
491         }
492         
493         ViewerSorter sorter = getSorter ();
494         Item[] items = getChildren(widget);
495         
496         //As the items are sorted already we optimize for a
497
//start position
498
int lastInsertion = 0;
499         
500         //Optimize for the empty case
501
if(items.length == 0){
502             for (int i = 0; i < elements.length; i++) {
503                 createTreeItem(widget, elements[i], -1);
504             }
505             return;
506         }
507     
508         for (int i = 0; i < elements.length; i++) {
509             boolean newItem = true;
510             Object JavaDoc element = elements[i];
511             int index;
512             if(sorter == null){
513                 index = -1;
514             }
515             else{
516                 lastInsertion = insertionPosition(items,sorter,lastInsertion, element);
517                 //As we are only searching the original array we keep track of those positions only
518
if(lastInsertion == items.length)
519                     index = -1;
520                 else{//See if we should just refresh
521
while(lastInsertion < items.length && sorter.compare(this,element,items[lastInsertion].getData()) == 0){
522                         //As we cannot assume the sorter is consistent with equals() - therefore we can
523
// just check against the item prior to this index (if any)
524
if (items[lastInsertion].getData().equals(element)) {
525                             //refresh the element in case it has new children
526
refresh(element);
527                             newItem = false;
528                         }
529                         lastInsertion ++;//We had an insertion so increment
530
}
531                     //Did we get to the end?
532
if(lastInsertion == items.length)
533                         index = -1;
534                     else
535                         index = lastInsertion + i; //Add the index as the array is growing
536
}
537             }
538             if(newItem)
539                 createTreeItem(widget, element, index);
540         }
541     }
542     
543     private int insertionPosition(Item[] items, ViewerSorter sorter, int lastInsertion, Object JavaDoc element) {
544         int size = items.length;
545         if (sorter == null)
546             return size;
547         int min = lastInsertion, max = size - 1;
548
549         while (min <= max) {
550             int mid = (min + max) / 2;
551             Object JavaDoc data = items[mid].getData();
552             int compare = sorter.compare(this, data, element);
553             if (compare == 0) {
554                 return mid;//Return if we already match
555
}
556             if (compare < 0)
557                 min = mid + 1;
558             else
559                 max = mid - 1;
560             }
561        return min;
562     }
563     
564     public void update(Object JavaDoc element, String JavaDoc[] properties) {
565         Assert.isNotNull(element);
566         Widget[] widgets = findItems(element);
567         for (int i = 0; i < widgets.length; i++) {
568             Widget widget = widgets[i];
569             if (widget != null) {
570                 internalUpdate(widget, element, properties);
571             }
572         }
573     }
574
575     protected Widget[] findItems(Object JavaDoc target) {
576         List JavaDoc widgets = new ArrayList JavaDoc();
577         Object JavaDoc root = getRoot();
578         if (root != null) {
579             if (equals(root, target)) {
580                 Widget widget = findItem(root);
581                 widgets.add(widget);
582             }
583         }
584         Item[] children = getChildren(getControl());
585         
586         if (children != null) {
587             for (int i = 0; i < children.length; i++) {
588                 Item child = children[i];
589                 internalFindItems(target, child, widgets);
590             }
591         }
592         return (Widget[]) widgets.toArray(new Widget[widgets.size()]);
593     }
594
595     private void internalFindItems(Object JavaDoc target, Item item, List JavaDoc widgets) {
596         if (equals(target, item.getData())) {
597             widgets.add(item);
598         }
599         
600         Item[] children = getChildren(item);
601         for (int i = 0; i < children.length; i++) {
602             Item child = children[i];
603             internalFindItems(target, child, widgets);
604         }
605     }
606 }
607
608
609
Popular Tags