KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > navigator > NavigatorContentServiceContentProvider


1 /*******************************************************************************
2  * Copyright (c) 2003, 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.ui.internal.navigator;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Collections JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.LinkedHashSet JavaDoc;
17 import java.util.LinkedList JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Set JavaDoc;
20
21 import org.eclipse.jface.viewers.ITreeContentProvider;
22 import org.eclipse.jface.viewers.ITreePathContentProvider;
23 import org.eclipse.jface.viewers.TreePath;
24 import org.eclipse.jface.viewers.Viewer;
25 import org.eclipse.osgi.util.NLS;
26 import org.eclipse.ui.internal.navigator.extensions.NavigatorContentDescriptor;
27 import org.eclipse.ui.internal.navigator.extensions.NavigatorContentExtension;
28 import org.eclipse.ui.internal.navigator.extensions.NavigatorViewerDescriptor;
29 import org.eclipse.ui.internal.navigator.extensions.OverridePolicy;
30 import org.eclipse.ui.navigator.CommonViewer;
31 import org.eclipse.ui.navigator.INavigatorContentDescriptor;
32 import org.eclipse.ui.navigator.INavigatorViewerDescriptor;
33 import org.eclipse.ui.navigator.IPipelinedTreeContentProvider;
34
35 /**
36  * <p>
37  * Provides relevant content based on the associated
38  * {@link org.eclipse.ui.internal.navigator.NavigatorContentService}&nbsp; for
39  * a TreeViewer .
40  * </p>
41  * <p>
42  * Except for the dependency on
43  * {@link org.eclipse.ui.internal.navigator.NavigatorContentService}, this
44  * class has no dependencies on the rest of the Common Navigator framework. Tree
45  * viewers that would like to use the extensions defined by the Common
46  * Navigator, without using the actual view part or other pieces of
47  * functionality (filters, sorting, etc) may choose to use this class, in effect
48  * using an extensible, aggregating, delegate content provider.
49  * </p>
50  *
51  * @see org.eclipse.ui.internal.navigator.NavigatorContentService
52  * @see org.eclipse.ui.internal.navigator.NavigatorContentServiceLabelProvider
53  *
54  * <p>
55  * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
56  * part of a work in progress. There is a guarantee neither that this API will
57  * work nor that it will remain the same. Please do not use this API without
58  * consulting with the Platform/UI team.
59  * </p>
60  *
61  * @since 3.2
62  *
63  */

64 public class NavigatorContentServiceContentProvider implements
65         ITreeContentProvider, ITreePathContentProvider {
66
67     private static final Object JavaDoc[] NO_CHILDREN = new Object JavaDoc[0];
68
69     private final NavigatorContentService contentService;
70
71     private final boolean isContentServiceSelfManaged;
72     
73     private final boolean enforceHasChildren;
74
75     private Viewer viewer;
76
77     /**
78      * <p>
79      * Creates a cached {@link NavigatorContentService}&nbsp;from the given
80      * viewer Id.
81      * </p>
82      *
83      * @param aViewerId
84      * The associated viewer id that this
85      * NavigatorContentServiceContentProvider will provide content
86      * for
87      */

88     public NavigatorContentServiceContentProvider(String JavaDoc aViewerId) {
89         super();
90         contentService = new NavigatorContentService(aViewerId);
91         INavigatorViewerDescriptor vDesc = contentService.getViewerDescriptor();
92         enforceHasChildren = vDesc.getBooleanConfigProperty(NavigatorViewerDescriptor.PROP_ENFORCE_HAS_CHILDREN);
93         isContentServiceSelfManaged = true;
94     }
95
96     /**
97      * <p>
98      * Uses the supplied content service to acquire the available extensions.
99      * </p>
100      *
101      * @param aContentService
102      * The associated NavigatorContentService that should be used to
103      * acquire information.
104      */

105     public NavigatorContentServiceContentProvider(
106             NavigatorContentService aContentService) {
107         super();
108         contentService = aContentService;
109         isContentServiceSelfManaged = false;
110         INavigatorViewerDescriptor vDesc = contentService.getViewerDescriptor();
111         enforceHasChildren = vDesc.getBooleanConfigProperty(NavigatorViewerDescriptor.PROP_ENFORCE_HAS_CHILDREN);
112     }
113
114     /**
115      *
116      * <p>
117      * Return the root objects for the supplied anInputElement. anInputElement
118      * is the root thing that the viewer visualizes.
119      * </p>
120      * <p>
121      * This method will call out to its {@link NavigatorContentService}&nbsp;for
122      * extensions that are enabled on the supplied anInputElement or enabled on
123      * the viewerId supplied when the {@link NavigatorContentService}&nbsp; was
124      * created (either by this class or its client). The extensions will then be
125      * queried for relevant content. The children returned from each extension
126      * will be aggregated and returned as is -- there is no additional sorting
127      * or filtering at this level.
128      * </p>
129      * <p>
130      * The results of this method will be displayed in the root of the
131      * TreeViewer.
132      * </p>
133      * {@inheritDoc}
134      *
135      * @param anInputElement
136      * The relevant element that a client would like children for -
137      * the input element of the TreeViewer
138      * @return A non-null array of objects that are logical children of
139      * anInputElement
140      * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
141      */

142     public synchronized Object JavaDoc[] getElements(Object JavaDoc anInputElement) {
143         Set JavaDoc rootContentExtensions = contentService
144                 .findRootContentExtensions(anInputElement);
145         if (rootContentExtensions.size() == 0) {
146             return NO_CHILDREN;
147         }
148         ContributorTrackingSet finalElementsSet = new ContributorTrackingSet(contentService);
149         ContributorTrackingSet localSet = new ContributorTrackingSet(contentService);
150
151         Object JavaDoc[] contributedChildren = null;
152         NavigatorContentExtension foundExtension;
153         NavigatorContentExtension[] overridingExtensions;
154         for (Iterator JavaDoc itr = rootContentExtensions.iterator(); itr.hasNext();) {
155             foundExtension = (NavigatorContentExtension) itr.next();
156             try {
157
158                 if (!isOverridingExtensionInSet(foundExtension.getDescriptor(),
159                         rootContentExtensions)) {
160
161                     contributedChildren = foundExtension.internalGetContentProvider()
162                             .getElements(anInputElement);
163                     
164                     localSet.setContents(contributedChildren);
165
166                     overridingExtensions = foundExtension
167                             .getOverridingExtensionsForTriggerPoint(anInputElement);
168
169                     if (overridingExtensions.length > 0) {
170                         localSet = pipelineElements(anInputElement,
171                                 overridingExtensions, localSet);
172                     }
173                     finalElementsSet.addAll(localSet);
174                 }
175             } catch (RuntimeException JavaDoc re) {
176                 NavigatorPlugin
177                         .logError(
178                                 0,
179                                 NLS
180                                         .bind(
181                                                 CommonNavigatorMessages.Could_not_provide_children_for_element,
182                                                 new Object JavaDoc[] { foundExtension
183                                                         .getDescriptor()
184                                                         .getId() }), re);
185             } catch (Error JavaDoc e) {
186                 NavigatorPlugin
187                         .logError(
188                                 0,
189                                 NLS
190                                         .bind(
191                                                 CommonNavigatorMessages.Could_not_provide_children_for_element,
192                                                 new Object JavaDoc[] { foundExtension
193                                                         .getDescriptor()
194                                                         .getId() }), e);
195
196             }
197         }
198         return finalElementsSet.toArray();
199     }
200
201     /**
202      * <p>
203      * Return the children of the supplied aParentElement
204      * </p>
205      *
206      * <p>
207      * This method will call out to its {@link NavigatorContentService}&nbsp;for
208      * extensions that are enabled on the supplied aParentElement. The
209      * extensions will then be queried for children for aParentElement. The
210      * children returned from each extension will be aggregated and returned as
211      * is -- there is no additional sorting or filtering at this level.
212      * </p>
213      * <p>
214      * The results of this method will be displayed as children of the supplied
215      * element in the TreeViewer.
216      * </p>
217      * {@inheritDoc}
218      *
219      * @param aParentElement
220      * An element that requires children content in the viewer (e.g.
221      * an end-user expanded a node)
222      * @return A non-null array of objects that are logical children of
223      * aParentElement
224      * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
225      */

226     public synchronized Object JavaDoc[] getChildren(Object JavaDoc aParentElement) {
227         return internalGetChildren(aParentElement);
228     }
229
230     private Object JavaDoc[] internalGetChildren(Object JavaDoc aParentElementOrPath) {
231         Object JavaDoc aParentElement = internalAsElement(aParentElementOrPath);
232         Set JavaDoc enabledExtensions = contentService
233                 .findContentExtensionsByTriggerPoint(aParentElement);
234         if (enabledExtensions.size() == 0) {
235             return NO_CHILDREN;
236         }
237         ContributorTrackingSet finalChildrenSet = new ContributorTrackingSet(contentService);
238         ContributorTrackingSet localSet = new ContributorTrackingSet(contentService);
239
240         Object JavaDoc[] contributedChildren = null;
241         NavigatorContentExtension foundExtension;
242         NavigatorContentExtension[] overridingExtensions;
243         for (Iterator JavaDoc itr = enabledExtensions.iterator(); itr.hasNext();) {
244             foundExtension = (NavigatorContentExtension) itr.next();
245             try {
246
247                 if (!isOverridingExtensionInSet(foundExtension.getDescriptor(),
248                         enabledExtensions)) {
249
250                     contributedChildren = foundExtension.internalGetContentProvider()
251                             .getChildren(aParentElementOrPath);
252
253                     overridingExtensions = foundExtension
254                             .getOverridingExtensionsForTriggerPoint(aParentElement);
255                     
256                     localSet.setContents(contributedChildren);
257
258                     if (overridingExtensions.length > 0) {
259                         // TODO: could pass tree path through pipeline
260
localSet = pipelineChildren(aParentElement,
261                                 overridingExtensions, localSet);
262                     }
263                     finalChildrenSet.addAll(localSet);
264                 }
265             } catch (RuntimeException JavaDoc re) {
266                 NavigatorPlugin
267                         .logError(
268                                 0,
269                                 NLS
270                                         .bind(
271                                                 CommonNavigatorMessages.Could_not_provide_children_for_element,
272                                                 new Object JavaDoc[] { foundExtension
273                                                         .getDescriptor()
274                                                         .getId() }), re);
275             } catch (Error JavaDoc e) {
276                 NavigatorPlugin
277                         .logError(
278                                 0,
279                                 NLS
280                                         .bind(
281                                                 CommonNavigatorMessages.Could_not_provide_children_for_element,
282                                                 new Object JavaDoc[] { foundExtension
283                                                         .getDescriptor()
284                                                         .getId() }), e);
285
286             }
287         }
288         return finalChildrenSet.toArray();
289     }
290
291     /**
292      * Query each of <code>theOverridingExtensions</code> for children, and
293      * then pipe them through the Pipeline content provider.
294      *
295      * @param aParentOrPath
296      * The parent element in the tree
297      * @param theOverridingExtensions
298      * The set of overriding extensions that should participate in
299      * the pipeline chain
300      * @param theCurrentChildren
301      * The current children to return to the viewer (should be
302      * modifiable)
303      * @return The set of children to return to the viewer
304      */

305     private ContributorTrackingSet pipelineChildren(Object JavaDoc aParentOrPath,
306             NavigatorContentExtension[] theOverridingExtensions,
307             ContributorTrackingSet theCurrentChildren) {
308         IPipelinedTreeContentProvider pipelinedContentProvider;
309         NavigatorContentExtension[] overridingExtensions;
310         ContributorTrackingSet pipelinedChildren = theCurrentChildren;
311         for (int i = 0; i < theOverridingExtensions.length; i++) {
312
313             if (theOverridingExtensions[i].getContentProvider() instanceof IPipelinedTreeContentProvider) {
314                 pipelinedContentProvider = (IPipelinedTreeContentProvider) theOverridingExtensions[i]
315                         .getContentProvider();
316                 
317                 pipelinedChildren.setContributor((NavigatorContentDescriptor) theOverridingExtensions[i].getDescriptor());
318                 pipelinedContentProvider.getPipelinedChildren(aParentOrPath,
319                         pipelinedChildren);
320                 
321                 pipelinedChildren.setContributor(null);
322                 
323                 overridingExtensions = theOverridingExtensions[i]
324                         .getOverridingExtensionsForTriggerPoint(aParentOrPath);
325                 if (overridingExtensions.length > 0) {
326                     pipelinedChildren = pipelineChildren(aParentOrPath,
327                             overridingExtensions, pipelinedChildren);
328                 }
329             }
330         }
331
332         return pipelinedChildren;
333
334     }
335
336     /**
337      * Query each of <code>theOverridingExtensions</code> for elements, and
338      * then pipe them through the Pipeline content provider.
339      *
340      * @param anInputElement
341      * The input element in the tree
342      * @param theOverridingExtensions
343      * The set of overriding extensions that should participate in
344      * the pipeline chain
345      * @param theCurrentElements
346      * The current elements to return to the viewer (should be
347      * modifiable)
348      * @return The set of elements to return to the viewer
349      */

350     private ContributorTrackingSet pipelineElements(Object JavaDoc anInputElement,
351             NavigatorContentExtension[] theOverridingExtensions,
352             ContributorTrackingSet theCurrentElements) {
353         IPipelinedTreeContentProvider pipelinedContentProvider;
354         NavigatorContentExtension[] overridingExtensions;
355         ContributorTrackingSet pipelinedElements = theCurrentElements;
356         for (int i = 0; i < theOverridingExtensions.length; i++) {
357
358             if (theOverridingExtensions[i].getContentProvider() instanceof IPipelinedTreeContentProvider) {
359                 pipelinedContentProvider = (IPipelinedTreeContentProvider) theOverridingExtensions[i]
360                         .getContentProvider();
361
362                 pipelinedElements.setContributor((NavigatorContentDescriptor) theOverridingExtensions[i].getDescriptor());
363                 pipelinedContentProvider.getPipelinedElements(anInputElement,
364                         pipelinedElements);
365                 pipelinedElements.setContributor(null);
366
367                 overridingExtensions = theOverridingExtensions[i]
368                         .getOverridingExtensionsForTriggerPoint(anInputElement);
369                 if (overridingExtensions.length > 0) {
370                     pipelinedElements = pipelineElements(anInputElement,
371                             overridingExtensions, pipelinedElements);
372                 }
373             }
374         }
375         return pipelinedElements;
376     }
377
378     /**
379      * Currently this method only checks one level deep. If the suppressed
380      * extension of the given descriptor is contained lower in the tree, then
381      * the extension could still be invoked twice.
382      *
383      * @param aDescriptor
384      * The descriptor which may be overriding other extensions.
385      * @param theEnabledExtensions
386      * The other available extensions.
387      * @return True if the results should be pipelined through the downstream
388      * extensions.
389      */

390     private boolean isOverridingExtensionInSet(
391             INavigatorContentDescriptor aDescriptor, Set JavaDoc theEnabledExtensions) {
392
393         if (aDescriptor.getSuppressedExtensionId() != null /*
394                                                              * The descriptor is
395                                                              * an override
396                                                              * descriptor
397                                                              */

398                 && aDescriptor.getOverridePolicy() == OverridePolicy.InvokeAlwaysRegardlessOfSuppressedExt) {
399             /*
400              * if the policy is set as such, it can lead to this extension being
401              * invoked twice; once as a first class extension, and once an
402              * overriding extension.
403              */

404             if (theEnabledExtensions.contains(contentService
405                     .getExtension(aDescriptor.getOverriddenDescriptor()))) {
406                 return true;
407             }
408         }
409         return false;
410     }
411     
412     /**
413      * Currently this method only checks one level deep. If the suppressed
414      * extension of the given descriptor is contained lower in the tree, then
415      * the extension could still be invoked twice.
416      *
417      * @param aDescriptor
418      * The descriptor which may be overriding other extensions.
419      * @param theEnabledDescriptors
420      * The other available descriptors.
421      * @return True if the results should be pipelined through the downstream
422      * extensions.
423      */

424     private boolean isOverridingDescriptorInSet(
425             INavigatorContentDescriptor aDescriptor, Set JavaDoc theEnabledDescriptors) {
426
427         if (aDescriptor.getSuppressedExtensionId() != null /*
428                                                              * The descriptor is
429                                                              * an override
430                                                              * descriptor
431                                                              */

432                 && aDescriptor.getOverridePolicy() == OverridePolicy.InvokeAlwaysRegardlessOfSuppressedExt) {
433             /*
434              * if the policy is set as such, it can lead to this extension being
435              * invoked twice; once as a first class extension, and once an
436              * overriding extension.
437              */

438             if (theEnabledDescriptors.contains(aDescriptor.getOverriddenDescriptor())) {
439                 return true;
440             }
441         }
442         return false;
443     }
444     
445     
446
447     /**
448      * <p>
449      * Returns the logical parent of anElement.
450      * </p>
451      * <p>
452      * This method requires that any extension that would like an opportunity to
453      * supply a parent for anElement expressly indicate that in the action
454      * expression &lt;enables&gt; statement of the
455      * <b>org.eclipse.ui.navigator.navigatorContent </b> extension point.
456      * </p>
457      * {@inheritDoc}
458      *
459      * @param anElement
460      * An element that requires its logical parent - generally as a
461      * result of setSelection(expand=true) on the viewer
462      * @return The logical parent if available or null if the parent cannot be
463      * determined
464      * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
465      */

466     public synchronized Object JavaDoc getParent(Object JavaDoc anElement) {
467         Set JavaDoc extensions = contentService
468                 .findContentExtensionsWithPossibleChild(anElement);
469
470         Object JavaDoc parent;
471         NavigatorContentExtension foundExtension;
472         NavigatorContentExtension[] overridingExtensions;
473         for (Iterator JavaDoc itr = extensions.iterator(); itr.hasNext();) {
474             foundExtension = (NavigatorContentExtension) itr.next();
475             try {
476
477                 if (!isOverridingExtensionInSet(foundExtension.getDescriptor(),
478                         extensions)) {
479
480                     parent = foundExtension.internalGetContentProvider().getParent(
481                             anElement);
482
483                     overridingExtensions = foundExtension
484                             .getOverridingExtensionsForPossibleChild(anElement);
485
486                     if (overridingExtensions.length > 0) {
487                         parent = pipelineParent(anElement,
488                                 overridingExtensions, parent);
489                     }
490
491                     if (parent != null) {
492                         return parent;
493                     }
494                 }
495             } catch (RuntimeException JavaDoc re) {
496                 NavigatorPlugin
497                         .logError(
498                                 0,
499                                 NLS
500                                         .bind(
501                                                 CommonNavigatorMessages.Could_not_provide_children_for_element,
502                                                 new Object JavaDoc[] { foundExtension
503                                                         .getDescriptor()
504                                                         .getId() }), re);
505             } catch (Error JavaDoc e) {
506                 NavigatorPlugin
507                         .logError(
508                                 0,
509                                 NLS
510                                         .bind(
511                                                 CommonNavigatorMessages.Could_not_provide_children_for_element,
512                                                 new Object JavaDoc[] { foundExtension
513                                                         .getDescriptor()
514                                                         .getId() }), e);
515
516             }
517         }
518
519         return null;
520     }
521
522     /**
523      * Query each of <code>theOverridingExtensions</code> for elements, and
524      * then pipe them through the Pipeline content provider.
525      *
526      * @param anInputElement
527      * The input element in the tree
528      * @param theOverridingExtensions
529      * The set of overriding extensions that should participate in
530      * the pipeline chain
531      * @param theCurrentParent
532      * The current elements to return to the viewer (should be
533      * modifiable)
534      * @return The set of elements to return to the viewer
535      */

536     private Object JavaDoc pipelineParent(Object JavaDoc anInputElement,
537             NavigatorContentExtension[] theOverridingExtensions,
538             Object JavaDoc theCurrentParent) {
539         IPipelinedTreeContentProvider pipelinedContentProvider;
540         NavigatorContentExtension[] overridingExtensions;
541         Object JavaDoc aSuggestedParent = null;
542         for (int i = 0; i < theOverridingExtensions.length; i++) {
543
544             if (theOverridingExtensions[i].getContentProvider() instanceof IPipelinedTreeContentProvider) {
545                 pipelinedContentProvider = (IPipelinedTreeContentProvider) theOverridingExtensions[i]
546                         .getContentProvider();
547
548                 aSuggestedParent = pipelinedContentProvider.getPipelinedParent(
549                         anInputElement, aSuggestedParent);
550
551                 overridingExtensions = theOverridingExtensions[i]
552                         .getOverridingExtensionsForTriggerPoint(anInputElement);
553                 if (overridingExtensions.length > 0) {
554                     aSuggestedParent = pipelineParent(anInputElement,
555                             overridingExtensions, aSuggestedParent);
556                 }
557             }
558         }
559         return aSuggestedParent != null ? aSuggestedParent : theCurrentParent;
560     }
561
562     /**
563      * <p>
564      * Used to determine of anElement should be displayed with a '+' or not.
565      * </p>
566      * {@inheritDoc}
567      *
568      * @param anElement
569      * The element in question
570      * @return True if anElement has logical children as returned by this
571      * content provider.
572      * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
573      */

574     public synchronized boolean hasChildren(Object JavaDoc anElement) {
575         Set JavaDoc resultInstances = contentService
576                 .findContentExtensionsByTriggerPoint(anElement);
577
578         NavigatorContentExtension ext;
579         for (Iterator JavaDoc itr = resultInstances.iterator(); itr.hasNext();) {
580             ext = (NavigatorContentExtension) itr.next();
581             if (!ext.isLoaded() && !enforceHasChildren) {
582                 return true;
583             } else if (ext.internalGetContentProvider().hasChildren(anElement)) {
584                 return true;
585             }
586         }
587
588         return false;
589     }
590
591     /**
592      * <p>
593      * Handles any necessary clean up of the {@link NavigatorContentService}
594      * </p>
595      *
596      * <p>
597      * <b>If a client uses this class outside of the framework of
598      * {@link CommonViewer}, the client must ensure that this method is called
599      * when finished. </b>
600      * </p>
601      *
602      * @see org.eclipse.jface.viewers.IContentProvider#dispose()
603      */

604     public synchronized void dispose() {
605         if (isContentServiceSelfManaged) {
606             contentService.dispose();
607         }
608     }
609
610     /**
611      * <p>
612      * Indicates that the current content provider is now representing a
613      * different input element. The input element is the root thing that the
614      * viewer displays.
615      * </p>
616      * <p>
617      * This method should handle any cleanup associated with the old input
618      * element and any initiailization associated with the new input element.
619      * </p>
620      * {@inheritDoc}
621      *
622      * @param aViewer
623      * The viewer that the current content provider is associated
624      * with
625      * @param anOldInput
626      * The original input element that the viewer was visualizing
627      * @param aNewInput
628      * The new input element that the viewer will visualize.
629      * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
630      * java.lang.Object, java.lang.Object)
631      *
632      */

633     public synchronized void inputChanged(Viewer aViewer, Object JavaDoc anOldInput,
634             Object JavaDoc aNewInput) {
635         viewer = aViewer;
636         contentService.updateService(aViewer, anOldInput, aNewInput);
637     }
638
639     /* (non-Javadoc)
640      * @see org.eclipse.jface.viewers.ITreePathContentProvider#getChildren(org.eclipse.jface.viewers.TreePath)
641      */

642     public Object JavaDoc[] getChildren(TreePath parentPath) {
643         return internalGetChildren(parentPath);
644     }
645
646     /* (non-Javadoc)
647      * @see org.eclipse.jface.viewers.ITreePathContentProvider#hasChildren(org.eclipse.jface.viewers.TreePath)
648      */

649     public boolean hasChildren(TreePath path) {
650         Object JavaDoc anElement = internalAsElement(path);
651         Set JavaDoc resultInstances = contentService
652                 .findContentExtensionsByTriggerPoint(anElement);
653
654         NavigatorContentExtension ext;
655         for (Iterator JavaDoc itr = resultInstances.iterator(); itr.hasNext();) {
656             ext = (NavigatorContentExtension) itr.next();
657             if (!ext.isLoaded() && !enforceHasChildren)
658                 return true;
659             ITreeContentProvider cp = ext.internalGetContentProvider();
660             if (cp instanceof ITreePathContentProvider) {
661                 ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
662                 if (tpcp.hasChildren(path)) {
663                     return true;
664                 }
665             } else if (cp.hasChildren(anElement))
666                 return true;
667         }
668
669         return false;
670     }
671
672     /* (non-Javadoc)
673      * @see org.eclipse.jface.viewers.ITreePathContentProvider#getParents(java.lang.Object)
674      */

675     public TreePath[] getParents(Object JavaDoc anElement) {
676         
677         List JavaDoc paths = new ArrayList JavaDoc();
678         TreePathCompiler compiler = new TreePathCompiler(anElement);
679         Set JavaDoc compilers = findPaths(compiler);
680         for (Iterator JavaDoc iter = compilers.iterator(); iter.hasNext();) {
681             TreePathCompiler c = (TreePathCompiler) iter.next();
682             paths.add(c.createParentPath());
683             
684         }
685         return (TreePath[]) paths.toArray(new TreePath[paths.size()]);
686          
687     }
688   
689
690     /**
691      * Get the element from an element or tree path argument.
692      * @param parentElementOrPath the element or tree path
693      * @return the element
694      */

695     private Object JavaDoc internalAsElement(Object JavaDoc parentElementOrPath) {
696         if (parentElementOrPath instanceof TreePath) {
697             TreePath tp = (TreePath) parentElementOrPath;
698             if (tp.getSegmentCount() > 0) {
699                 return tp.getLastSegment();
700             }
701             // If the path is empty, the parent element is the root
702
return viewer.getInput();
703         }
704         return parentElementOrPath;
705     }
706     
707
708     class CyclicPathException extends Exception JavaDoc {
709
710         private static final long serialVersionUID = 2111962579612444989L;
711
712         protected CyclicPathException(TreePathCompiler compiler, Object JavaDoc invalidSegment, boolean asChild) {
713             super("Cannot add " + invalidSegment + //$NON-NLS-1$
714
" to the list of segments in " + compiler + //$NON-NLS-1$
715
(asChild ? " as a child." : " as a parent.") ); //$NON-NLS-1$ //$NON-NLS-2$
716
}
717     }
718
719     class TreePathCompiler {
720
721
722         private final LinkedList JavaDoc segments = new LinkedList JavaDoc();
723
724         protected TreePathCompiler(Object JavaDoc segment) {
725             segments.add(segment);
726         }
727
728         protected TreePathCompiler(TreePathCompiler aCompiler) {
729             segments.addAll(aCompiler.segments);
730         }
731
732         protected TreePathCompiler(TreePath aPath) {
733             for (int i = 0; i < aPath.getSegmentCount(); i++) {
734                 segments.addLast(aPath.getSegment(i));
735             }
736         }
737
738         protected void addParent(Object JavaDoc segment) throws CyclicPathException {
739             if(segments.contains(segment)) {
740                 throw new CyclicPathException(this, segment, false);
741             }
742             segments.addFirst(segment);
743         }
744
745         protected void addChild(Object JavaDoc segment) throws CyclicPathException {
746             if(segments.contains(segment)) {
747                 throw new CyclicPathException(this, segment, false);
748             }
749             segments.addLast(segment);
750         }
751
752         /**
753          * Create the full tree path.
754          *
755          * @return A TreePath with all segments from the compiler.
756          */

757         public TreePath createPath() {
758             return new TreePath(segments.toArray());
759         }
760
761         /**
762          * Create parent tree path.
763          *
764          * @return A TreePath with all segments but the last from the compiler
765          */

766         public TreePath createParentPath() {
767             LinkedList JavaDoc parentSegments = new LinkedList JavaDoc(segments);
768             parentSegments.removeLast();
769             return new TreePath(parentSegments.toArray());
770         }
771         
772         public Object JavaDoc getLastSegment() {
773             return segments.getLast();
774         }
775         
776         public Object JavaDoc getFirstSegment() {
777             return segments.getFirst();
778         }
779         
780         /* (non-Javadoc)
781          * @see java.lang.Object#toString()
782          */

783         public String JavaDoc toString() {
784         
785             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
786             for (Iterator JavaDoc iter = segments.iterator(); iter.hasNext();) {
787                 Object JavaDoc segment = iter.next();
788                 buffer.append(segment).append("::"); //$NON-NLS-1$
789
}
790             return buffer.toString();
791         }
792
793     }
794
795     private Set JavaDoc findPaths(TreePathCompiler aPathCompiler) {
796
797         Set JavaDoc/* <Object> */ parents = findParents(aPathCompiler.getFirstSegment());
798         Set JavaDoc/* <TreePathCompiler> */ parentPaths = new LinkedHashSet JavaDoc();
799         Set JavaDoc/* <TreePathCompiler> */ foundPaths = Collections.EMPTY_SET;
800         if (parents.size() > 0) {
801             for (Iterator JavaDoc parentIter = parents.iterator(); parentIter.hasNext();) {
802                 Object JavaDoc parent = (Object JavaDoc) parentIter.next();
803                 TreePathCompiler c = new TreePathCompiler(aPathCompiler);
804                 try {
805                     c.addParent(parent);
806                     foundPaths = findPaths(c);
807                 } catch(CyclicPathException cpe) {
808                     String JavaDoc msg = cpe.getMessage() != null ? cpe.getMessage() : cpe.toString();
809                     NavigatorPlugin.logError(0, msg, cpe);
810                 }
811                 if (foundPaths.isEmpty())
812                     parentPaths.add(c);
813                 else
814                     parentPaths.addAll(foundPaths);
815             }
816         }
817         return parentPaths;
818
819     }
820
821     private Set JavaDoc findParents(Object JavaDoc anElement) {
822
823         Set JavaDoc descriptors = contentService.findDescriptorsWithPossibleChild(
824                 anElement, false);
825         Set JavaDoc parents = new LinkedHashSet JavaDoc();
826         NavigatorContentDescriptor foundDescriptor;
827         NavigatorContentExtension foundExtension;
828         Object JavaDoc parent = null;
829         for (Iterator JavaDoc itr = descriptors.iterator(); itr.hasNext();) {
830             foundDescriptor = (NavigatorContentDescriptor) itr.next();
831             foundExtension = contentService.getExtension(foundDescriptor);
832             try {
833
834                 if (!isOverridingDescriptorInSet(
835                         foundExtension.getDescriptor(), descriptors)) {
836
837                     /* internalGetContentProvider returns the real delegate */
838                     if (foundExtension.getContentProvider() instanceof ITreePathContentProvider) {
839                         /*
840                          * but we use the safe version to automatically handle
841                          * errors
842                          */

843                         TreePath[] parentTreePaths = ((ITreePathContentProvider) foundExtension
844                                 .internalGetContentProvider())
845                                 .getParents(anElement);
846
847                         for (int i = 0; i < parentTreePaths.length; i++) {
848
849                             parent = parentTreePaths[i].getLastSegment();
850                             if ((parent = findParent(foundExtension, anElement,
851                                     parent)) != null)
852                                 parents.add(parent);
853                         }
854
855                     } else {
856
857                         parent = foundExtension.internalGetContentProvider()
858                                 .getParent(anElement);
859                         if ((parent = findParent(foundExtension, anElement,
860                                 parent)) != null)
861                             parents.add(parent);
862                     }
863                 }
864
865             } catch (RuntimeException JavaDoc re) {
866                 NavigatorPlugin
867                         .logError(
868                                 0,
869                                 NLS
870                                         .bind(
871                                                 CommonNavigatorMessages.Could_not_provide_children_for_element,
872                                                 new Object JavaDoc[] { foundExtension
873                                                         .getDescriptor()
874                                                         .getId() }), re);
875             } catch (Error JavaDoc e) {
876                 NavigatorPlugin
877                         .logError(
878                                 0,
879                                 NLS
880                                         .bind(
881                                                 CommonNavigatorMessages.Could_not_provide_children_for_element,
882                                                 new Object JavaDoc[] { foundExtension
883                                                         .getDescriptor()
884                                                         .getId() }), e);
885         
886             }
887         }
888         
889         return parents;
890         
891     }
892      
893     
894     private Object JavaDoc findParent(NavigatorContentExtension anExtension, Object JavaDoc anElement, Object JavaDoc aSuggestedParent) {
895         
896         /* the last valid (non-null) parent for the anElement */
897         Object JavaDoc lastValidParent = aSuggestedParent;
898         /* used to keep track of new suggestions */
899         Object JavaDoc suggestedOverriddenParent = null;
900         IPipelinedTreeContentProvider piplineContentProvider;
901         NavigatorContentExtension[] overridingExtensions = anExtension.getOverridingExtensionsForPossibleChild(anElement);
902         for (int i = 0; i < overridingExtensions.length; i++) {
903             if(overridingExtensions[i].getContentProvider() instanceof IPipelinedTreeContentProvider) {
904                 piplineContentProvider = (IPipelinedTreeContentProvider) overridingExtensions[i].getContentProvider();
905                 suggestedOverriddenParent = piplineContentProvider.getPipelinedParent(anElement, lastValidParent);
906                 
907                 if(suggestedOverriddenParent != null)
908                     lastValidParent = suggestedOverriddenParent;
909                 
910                 // should never return null
911
lastValidParent = findParent(overridingExtensions[i], anElement, lastValidParent);
912             }
913                 
914         }
915         return lastValidParent;
916     }
917
918 }
919
Popular Tags