KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

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
19 import org.eclipse.core.runtime.CoreException;
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.Platform;
24 import org.eclipse.core.runtime.Status;
25 import org.eclipse.core.runtime.jobs.Job;
26 import org.eclipse.debug.internal.ui.DebugUIPlugin;
27 import org.eclipse.debug.internal.ui.elements.adapters.AsynchronousDebugLabelAdapter;
28 import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
29 import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
30 import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
31 import org.eclipse.debug.internal.ui.viewers.model.provisional.IStatusMonitor;
32 import org.eclipse.debug.internal.ui.viewers.provisional.AsynchronousContentAdapter;
33 import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousContentAdapter;
34 import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter;
35 import org.eclipse.debug.internal.ui.viewers.provisional.IChildrenRequestMonitor;
36 import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
37 import org.eclipse.jface.viewers.ViewerFilter;
38 import org.eclipse.jface.viewers.ViewerSorter;
39
40 /**
41  * Model for an asynchronous viewer
42  *
43  * @since 3.2
44  */

45 public abstract class AsynchronousModel {
46     
47     private ModelNode fRoot; // root node
48
private Map JavaDoc fElementToNodes = new HashMap JavaDoc(); // map of element to corresponding tree nodes (list)
49
private Map JavaDoc fModelProxies = new HashMap JavaDoc(); // map of installed model proxies, by element
50
private AsynchronousViewer fViewer; // viewer this model works for
51
private boolean fDisposed = false; // whether disposed
52

53     // debug flags
54
public static boolean DEBUG_MODEL = false;
55     
56     static {
57         DEBUG_MODEL = DebugUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
58
Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/model")); //$NON-NLS-1$
59
}
60     
61     class EmptyContentAdapter extends AsynchronousContentAdapter {
62         
63         /* (non-Javadoc)
64          * @see org.eclipse.debug.internal.ui.viewers.provisional.AsynchronousContentAdapter#getChildren(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
65          */

66         protected Object JavaDoc[] getChildren(Object JavaDoc parent, IPresentationContext context) throws CoreException {
67             return EMPTY;
68         }
69
70         /* (non-Javadoc)
71          * @see org.eclipse.debug.internal.ui.viewers.provisional.AsynchronousContentAdapter#hasChildren(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
72          */

73         protected boolean hasChildren(Object JavaDoc element, IPresentationContext context) throws CoreException {
74             return false;
75         }
76
77         /* (non-Javadoc)
78          * @see org.eclipse.debug.internal.ui.viewers.provisional.AsynchronousContentAdapter#supportsPartId(java.lang.String)
79          */

80         protected boolean supportsPartId(String JavaDoc id) {
81             return true;
82         }
83     }
84     
85     protected IAsynchronousContentAdapter fEmptyContentAdapter = new EmptyContentAdapter();
86     
87     /**
88      * List of requests currently being performed.
89      */

90     private List JavaDoc fPendingUpdates = new ArrayList JavaDoc();
91     
92     /**
93      * List of pending viewer udpates
94      */

95     private List JavaDoc fViewerUpdates = new ArrayList JavaDoc();
96
97     /**
98      * Constructs a new empty tree model
99      *
100      * @param viewer associated viewer
101      */

102     public AsynchronousModel(AsynchronousViewer viewer) {
103         fViewer = viewer;
104         if (DEBUG_MODEL) {
105             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
106             buffer.append("MODEL CREATED for: "); //$NON-NLS-1$
107
buffer.append(fViewer);
108             buffer.append(" ("); //$NON-NLS-1$
109
buffer.append(this);
110             buffer.append(")"); //$NON-NLS-1$
111
DebugUIPlugin.debug(buffer.toString());
112         }
113     }
114     
115     /**
116      * Initializes this model. Called once after creation.
117      *
118      * @param root root element or <code>null</code>
119      * @param widget root widget/control
120      */

121     public void init(Object JavaDoc root) {
122         if (root != null) {
123             fRoot = new ModelNode(null, root);
124             mapElement(root, fRoot);
125         }
126     }
127     
128     protected AsynchronousViewer getViewer() {
129         return fViewer;
130     }
131     
132     /**
133      * Disposes this model
134      */

135     public synchronized void dispose() {
136         if (DEBUG_MODEL) {
137             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
138             buffer.append("MODEL DISPOSED for: "); //$NON-NLS-1$
139
buffer.append(fViewer);
140             buffer.append(" ("); //$NON-NLS-1$
141
buffer.append(this);
142             buffer.append(")"); //$NON-NLS-1$
143
DebugUIPlugin.debug(buffer.toString());
144         }
145         fDisposed = true;
146         cancelPendingUpdates();
147         disposeAllModelProxies();
148         ModelNode rootNode = getRootNode();
149         if (rootNode != null) {
150             rootNode.dispose();
151         }
152         fElementToNodes.clear();
153     }
154     
155     /**
156      * Returns whether this model has been disposed
157      */

158     public synchronized boolean isDisposed() {
159         return fDisposed;
160     }
161     
162     /**
163      * Cancels all pending update requests.
164      */

165     protected synchronized void cancelPendingUpdates() {
166         Iterator JavaDoc updates = fPendingUpdates.iterator();
167         while (updates.hasNext()) {
168             IStatusMonitor update = (IStatusMonitor) updates.next();
169             updates.remove();
170             update.setCanceled(true);
171         }
172         fPendingUpdates.clear();
173     }
174     
175     /**
176      * Installs the model proxy for the given element into this viewer
177      * if not already installed.
178      *
179      * @param element element to install an update policy for
180      */

181     public synchronized void installModelProxy(Object JavaDoc element) {
182         if (!fModelProxies.containsKey(element)) {
183             IModelProxyFactory modelProxyFactory = getModelProxyFactoryAdapter(element);
184             if (modelProxyFactory != null) {
185                 final IModelProxy proxy = modelProxyFactory.createModelProxy(element, getPresentationContext());
186                 if (proxy != null) {
187                     fModelProxies.put(element, proxy);
188                     Job job = new Job("Model Proxy installed notification job") {//$NON-NLS-1$
189
protected IStatus run(IProgressMonitor monitor) {
190                             if (!monitor.isCanceled()) {
191                                 proxy.init(getPresentationContext());
192                                 getViewer().modelProxyAdded(proxy);
193                                 proxy.installed(getViewer());
194                             }
195                             return Status.OK_STATUS;
196                         }
197                     };
198                     job.setSystem(true);
199                     job.schedule();
200                 }
201             }
202         }
203     }
204     
205     /**
206      * Uninstalls the model proxy installed for the given element, if any.
207      *
208      * @param element
209      */

210     protected synchronized void disposeModelProxy(Object JavaDoc element) {
211         IModelProxy proxy = (IModelProxy) fModelProxies.remove(element);
212         if (proxy != null) {
213             getViewer().modelProxyRemoved(proxy);
214             proxy.dispose();
215         }
216     }
217     
218     /**
219      * Unintalls all model proxies installed for this model
220      */

221     private void disposeAllModelProxies() {
222         synchronized(fModelProxies) {
223             Iterator JavaDoc updatePolicies = fModelProxies.values().iterator();
224             while (updatePolicies.hasNext()) {
225                 IModelProxy proxy = (IModelProxy)updatePolicies.next();
226                 getViewer().modelProxyRemoved(proxy);
227                 proxy.dispose();
228             }
229             
230             fModelProxies.clear();
231         }
232     }
233     
234     /**
235      * Returns the presentation this model is installed in
236      *
237      * @return
238      */

239     protected IPresentationContext getPresentationContext() {
240         return fViewer.getPresentationContext();
241     }
242     
243     /**
244      * Returns the model proxy factory for the given element of <code>null</code> if none.
245      *
246      * @param element element to retrieve adapters for
247      * @return model proxy factory adapter or <code>null</code>
248      */

249     protected IModelProxyFactory getModelProxyFactoryAdapter(Object JavaDoc element) {
250         IModelProxyFactory adapter = null;
251         if (element instanceof IModelProxyFactory) {
252             adapter = (IModelProxyFactory) element;
253         } else if (element instanceof IAdaptable) {
254             IAdaptable adaptable = (IAdaptable) element;
255             adapter = (IModelProxyFactory) adaptable.getAdapter(IModelProxyFactory.class);
256         }
257         return adapter;
258     }
259     
260     /**
261      * Maps the given element to the given node.
262      *
263      * @param element
264      * @param node
265      */

266     protected synchronized void mapElement(Object JavaDoc element, ModelNode node) {
267         ModelNode[] nodes = getNodes(element);
268         node.remap(element);
269         if (nodes == null) {
270             fElementToNodes.put(element, new ModelNode[] { node});
271         } else {
272             for (int i = 0; i < nodes.length; i++) {
273                 if (nodes[i] == node) {
274                     return;
275                 }
276             }
277             ModelNode[] old = nodes;
278             ModelNode[] newNodes = new ModelNode[old.length + 1];
279             System.arraycopy(old, 0, newNodes, 0, old.length);
280             newNodes[old.length] = node;
281             fElementToNodes.put(element, newNodes);
282         }
283         installModelProxy(element);
284     }
285     
286     /**
287      * Unmaps the given node from its element and widget.
288      *
289      * @param node
290      */

291     protected synchronized void unmapNode(ModelNode node) {
292         Object JavaDoc element = node.getElement();
293         ModelNode[] nodes = (ModelNode[]) fElementToNodes.get(element);
294         if (nodes == null) {
295             return;
296         }
297         if (nodes.length == 1) {
298             fElementToNodes.remove(element);
299             disposeModelProxy(element);
300         } else {
301             for (int i = 0; i < nodes.length; i++) {
302                 ModelNode node2 = nodes[i];
303                 if (node2 == node) {
304                     ModelNode[] newNodes= new ModelNode[nodes.length - 1];
305                     System.arraycopy(nodes, 0, newNodes, 0, i);
306                     if (i < newNodes.length) {
307                         System.arraycopy(nodes, i + 1, newNodes, i, newNodes.length - i);
308                     }
309                     fElementToNodes.put(element, newNodes);
310                 }
311             }
312         }
313     }
314     
315     /**
316      * Returns the nodes in this model for the given element or
317      * <code>null</code> if none.
318      *
319      * @param element model element
320      * @return associated nodes or <code>null</code>
321      */

322     public synchronized ModelNode[] getNodes(Object JavaDoc element) {
323         return (ModelNode[]) fElementToNodes.get(element);
324     }
325     
326     /**
327      * Returns the root node or <code>null</code>
328      *
329      * @return the root node or <code>null</code>
330      */

331     public ModelNode getRootNode() {
332         return fRoot;
333     }
334     
335     /**
336      * Cancels any conflicting updates for children of the given item, and
337      * schedules the new update.
338      *
339      * @param update the update to schedule
340      */

341     protected void requestScheduled(IStatusMonitor update) {
342         AsynchronousRequestMonitor absUpdate = (AsynchronousRequestMonitor) update;
343         synchronized (fPendingUpdates) {
344             Iterator JavaDoc updates = fPendingUpdates.listIterator();
345             while (updates.hasNext()) {
346                 AsynchronousRequestMonitor pendingUpdate = (AsynchronousRequestMonitor) updates.next();
347                 if (absUpdate.contains(pendingUpdate)) {
348                     updates.remove();
349                     pendingUpdate.setCanceled(true);
350                 }
351             }
352             fPendingUpdates.add(update);
353         }
354     }
355     
356     /**
357      * Removes the update from the pending updates list.
358      *
359      * @param update
360      */

361     protected void requestComplete(IStatusMonitor update) {
362         synchronized (fPendingUpdates) {
363             fPendingUpdates.remove(update);
364         }
365     }
366     
367     /**
368      * An viewer update has been scheduled due to the following update request.
369      *
370      * @param update
371      */

372     protected void viewerUpdateScheduled(IStatusMonitor update) {
373         // synch viewer updates and pending updates on same lock - fPendingUpdates
374
synchronized (fPendingUpdates) {
375             fViewerUpdates.add(update);
376         }
377     }
378     
379     /**
380      * Returns the result of running the given elements through the
381      * viewers filters.
382      *
383      * @param parent parent element
384      * @param elements the elements to filter
385      * @return only the elements which all filters accept
386      */

387     protected Object JavaDoc[] filter(Object JavaDoc parent, Object JavaDoc[] elements) {
388         ViewerFilter[] filters = getViewer().getFilters();
389         if (filters != null) {
390             ArrayList JavaDoc filtered = new ArrayList JavaDoc(elements.length);
391             for (int i = 0; i < elements.length; i++) {
392                 boolean add = true;
393                 for (int j = 0; j < filters.length; j++) {
394                     add = filters[j].select(getViewer(), parent, elements[i]);
395                     if (!add)
396                         break;
397                 }
398                 if (add)
399                     filtered.add(elements[i]);
400             }
401             return filtered.toArray();
402         }
403         return elements;
404     }
405     
406     /**
407      * Refreshes the given node.
408      *
409      * @param node
410      */

411     protected void updateLabel(ModelNode node) {
412         Object JavaDoc element = node.getElement();
413         IAsynchronousLabelAdapter adapter = getLabelAdapter(element);
414         if (adapter != null) {
415             ILabelRequestMonitor labelUpdate = new LabelRequestMonitor(node, this);
416             requestScheduled(labelUpdate);
417             adapter.retrieveLabel(element, getPresentationContext(), labelUpdate);
418         }
419     }
420     
421     /**
422      * Returns the label adapter for the given element or <code>null</code> if none.
423      *
424      * @param element element to retrieve adapter for
425      * @return presentation adapter or <code>null</code>
426      */

427     protected IAsynchronousLabelAdapter getLabelAdapter(Object JavaDoc element) {
428         IAsynchronousLabelAdapter adapter = null;
429         if (element instanceof IAsynchronousLabelAdapter) {
430             adapter = (IAsynchronousLabelAdapter) element;
431         } else if (element instanceof IAdaptable) {
432             IAdaptable adaptable = (IAdaptable) element;
433             adapter = (IAsynchronousLabelAdapter) adaptable.getAdapter(IAsynchronousLabelAdapter.class);
434         }
435         // if no adapter, use default (i.e. model presentation)
436
if (adapter == null) {
437             return new AsynchronousDebugLabelAdapter();
438         }
439         return adapter;
440     }
441     
442     /**
443      * Returns the tree element adapter for the given element or
444      * <code>null</code> if none.
445      *
446      * @param element
447      * element to retrieve adapter for
448      * @return presentation adapter or <code>null</code>
449      */

450     protected IAsynchronousContentAdapter getContentAdapter(Object JavaDoc element) {
451         IAsynchronousContentAdapter adapter = null;
452         if (element instanceof IAsynchronousContentAdapter) {
453             adapter = (IAsynchronousContentAdapter) element;
454         } else if (element instanceof IAdaptable) {
455             IAdaptable adaptable = (IAdaptable) element;
456             adapter = (IAsynchronousContentAdapter) adaptable.getAdapter(IAsynchronousContentAdapter.class);
457         }
458         return adapter;
459     }
460     
461     /**
462      * Updates the children of the given node.
463      *
464      * @param parent
465      * node of which to update children
466      */

467     public void updateChildren(ModelNode parent) {
468         Object JavaDoc element = parent.getElement();
469         IAsynchronousContentAdapter adapter = getContentAdapter(element);
470         if (adapter == null) {
471             adapter = fEmptyContentAdapter;
472         }
473         if (adapter != null) {
474             IChildrenRequestMonitor update = new ChildrenRequestMonitor(parent, this);
475             requestScheduled(update);
476             adapter.retrieveChildren(element, getPresentationContext(), update);
477         }
478     }
479     
480     /**
481      * Update this model's viewer preserving its selection.
482      *
483      * @param update
484      */

485     protected void preservingSelection(Runnable JavaDoc update) {
486         getViewer().preservingSelection(update);
487     }
488
489     /**
490      * The viewer updated associated with a request is compelte.
491      *
492      * @param monitor
493      */

494     protected void viewerUpdateComplete(IStatusMonitor monitor) {
495         // synch viewer updates and pending updates on same lock - fPendingUpdates
496
synchronized (fPendingUpdates) {
497             fViewerUpdates.remove(monitor);
498         }
499         getViewer().updateComplete(monitor);
500     }
501     
502     /**
503      * An update request was cancelled
504      *
505      * @param monitor
506      */

507     protected void requestCanceled(AsynchronousRequestMonitor monitor) {
508         synchronized (fPendingUpdates) {
509             fPendingUpdates.remove(monitor);
510         }
511     }
512     
513     /**
514      * Whether any updates are still in progress in the model or against the viewer.
515      *
516      * @return
517      */

518     protected boolean hasPendingUpdates() {
519         synchronized (fViewerUpdates) {
520             return !fPendingUpdates.isEmpty() || !fViewerUpdates.isEmpty();
521         }
522     }
523     
524     /**
525      * Asynchronous update for add/set children request.
526      *
527      * @param parent
528      * @param element
529      */

530     protected abstract void add(ModelNode parent, Object JavaDoc element);
531     
532     /**
533      * Notification from children request monitor
534      *
535      * @param parentNode parent node
536      * @param kids list of model elements
537      */

538     protected void setChildren(final ModelNode parentNode, List JavaDoc kids) {
539         
540         final Object JavaDoc[] children = filter(parentNode.getElement(), kids.toArray());
541         final AsynchronousViewer viewer = getViewer();
542         ViewerSorter sorter = viewer.getSorter();
543         if (sorter != null) {
544             sorter.sort(viewer, children);
545         }
546         
547         ModelNode[] prevKids = null;
548         ModelNode[] newChildren = null;
549         ModelNode[] unmap = null;
550         
551         synchronized (this) {
552             if (isDisposed()) {
553                 return;
554             }
555             prevKids = parentNode.getChildrenNodes();
556             if (prevKids == null) {
557                 newChildren = new ModelNode[children.length];
558                 for (int i = 0; i < children.length; i++) {
559                     ModelNode node = new ModelNode(parentNode, children[i]);
560                     mapElement(children[i], node);
561                     newChildren[i] = node;
562                 }
563                 parentNode.setChildren(newChildren);
564             } else {
565                 newChildren = new ModelNode[children.length];
566                 unmap = new ModelNode[prevKids.length];
567                 for (int i = 0; i < prevKids.length; i++) {
568                     unmap[i] = prevKids[i];
569                 }
570                 for (int i = 0; i < children.length; i++) {
571                     Object JavaDoc child = children[i];
572                     boolean found = false;
573                     for (int j = 0; j < prevKids.length; j++) {
574                         ModelNode prevKid = prevKids[j];
575                         if (prevKid != null && child.equals(prevKid.getElement())) {
576                             newChildren[i] = prevKid;
577                             prevKids[j] = null;
578                             found = true;
579                             break;
580                         }
581                     }
582                     if (!found) {
583                         newChildren[i] = new ModelNode(parentNode, child);
584                         mapElement(child, newChildren[i]);
585                     }
586                 }
587                 for (int i = 0; i < prevKids.length; i++) {
588                     ModelNode kid = prevKids[i];
589                     if (kid != null) {
590                         kid.dispose();
591                         unmapNode(kid);
592                     }
593                 }
594                 parentNode.setChildren(newChildren);
595             }
596             if (DEBUG_MODEL) {
597                 DebugUIPlugin.debug("CHILDREN CHANGED: " + parentNode); //$NON-NLS-1$
598
DebugUIPlugin.debug(toString());
599             }
600         }
601         
602         //update viewer outside the lock
603
final ModelNode[] finalUnmap = unmap;
604         preservingSelection(new Runnable JavaDoc() {
605             public void run() {
606                 if (finalUnmap != null) {
607                     for (int i = 0; i < finalUnmap.length; i++) {
608                         viewer.unmapNode(finalUnmap[i]);
609                     }
610                 }
611                 viewer.nodeChildrenChanged(parentNode);
612             }
613         });
614
615     }
616     
617     public String JavaDoc toString() {
618         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
619         if (fRoot != null) {
620             buf.append("ROOT: "); //$NON-NLS-1$
621
append(buf, fRoot, 0);
622         } else {
623             buf.append("ROOT: null"); //$NON-NLS-1$
624
}
625         return buf.toString();
626     }
627     
628     private void append(StringBuffer JavaDoc buf, ModelNode node, int level) {
629         for (int i = 0; i < level; i++) {
630             buf.append('\t');
631         }
632         buf.append(node);
633         buf.append('\n');
634         ModelNode[] childrenNodes = node.getChildrenNodes();
635         if (childrenNodes != null) {
636             for (int i = 0; i < childrenNodes.length; i++) {
637                 append(buf, childrenNodes[i], level + 1);
638             }
639         }
640     }
641 }
642
Popular Tags