KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > ObjectContributorManager


1 /*******************************************************************************
2  * Copyright (c) 2000, 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;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.Collections JavaDoc;
17 import java.util.HashMap JavaDoc;
18 import java.util.HashSet JavaDoc;
19 import java.util.Hashtable JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.Set JavaDoc;
24
25 import org.eclipse.core.runtime.IAdaptable;
26 import org.eclipse.core.runtime.IAdapterManager;
27 import org.eclipse.core.runtime.IConfigurationElement;
28 import org.eclipse.core.runtime.IExtension;
29 import org.eclipse.core.runtime.Platform;
30 import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
31 import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
32 import org.eclipse.jface.viewers.IStructuredSelection;
33 import org.eclipse.ui.PlatformUI;
34 import org.eclipse.ui.internal.util.Util;
35
36 /**
37  * This class is a default implementation of <code>IObjectContributorManager</code>.
38  * It provides fast merging of contributions with the following semantics:
39  * <ul>
40  * <li> All of the matching contributors will be invoked per property lookup
41  * <li> The search order from a class with the definition<br>
42  * <code>class X extends Y implements A, B</code><br>
43  * is as follows:
44  * <il>
45  * <li>the target's class: X
46  * <li>X's superclasses in order to <code>Object</code>
47  * <li>a depth-first traversal of the target class's interaces in the order
48  * returned by <code>getInterfaces()</code> (in the example, A and
49  * its superinterfaces then B and its superinterfaces)
50  * </il>
51  * </ul>
52  *
53  * @see IObjectContributor
54  */

55 public abstract class ObjectContributorManager implements IExtensionChangeHandler {
56     
57     /**
58      * @since 3.1
59      */

60     private class ContributorRecord {
61         /**
62          * @param contributor
63          * @param targetType
64          */

65         public ContributorRecord(IObjectContributor contributor, String JavaDoc targetType) {
66             this.contributor = contributor;
67             this.objectClassName = targetType;
68         }
69         
70         String JavaDoc objectClassName;
71         IObjectContributor contributor;
72     }
73
74     /** Table of contributors. */
75     protected Map JavaDoc contributors;
76
77     /** Cache of object class contributor search paths; <code>null</code> if none. */
78     protected Map JavaDoc objectLookup;
79
80     /** Cache of resource adapter class contributor search paths; <code>null</code> if none. */
81     protected Map JavaDoc resourceAdapterLookup;
82     
83     /** Cache of adaptable class contributor search paths; <code>null</code> if none. */
84     protected Map JavaDoc adaptableLookup;
85     
86     protected Set JavaDoc contributorRecordSet;
87
88     /**
89      * Constructs a new contributor manager.
90      */

91     public ObjectContributorManager() {
92         contributors = new Hashtable JavaDoc(5);
93         contributorRecordSet = new HashSet JavaDoc(5);
94         objectLookup = null;
95         resourceAdapterLookup = null;
96         adaptableLookup = null;
97         if(canHandleExtensionTracking()){
98             IExtensionTracker tracker = PlatformUI.getWorkbench().getExtensionTracker();
99             tracker.registerHandler(this, null);
100         }
101     }
102
103     /**
104      * Return whether or not the receiver handles extension
105      * tracking. Default is <code>true</code>. Subclasses may override.
106      * @return boolean <code>true</code> if it should be registered
107      * as an extension handler.
108      */

109     protected boolean canHandleExtensionTracking() {
110         return true;
111     }
112
113     /**
114      * Adds contributors for the given types to the result list.
115      */

116     private void addContributorsFor(List JavaDoc types, List JavaDoc result) {
117         for (Iterator JavaDoc classes = types.iterator(); classes.hasNext();) {
118             Class JavaDoc clazz = (Class JavaDoc) classes.next();
119             List JavaDoc contributorList = (List JavaDoc) contributors.get(clazz.getName());
120             if (contributorList != null) {
121                 result.addAll(contributorList);
122             }
123         }
124     }
125
126     /**
127      * Returns the class search order starting with <code>extensibleClass</code>.
128      * The search order is defined in this class' comment.
129      */

130     protected final List JavaDoc computeClassOrder(Class JavaDoc extensibleClass) {
131         ArrayList JavaDoc result = new ArrayList JavaDoc(4);
132         Class JavaDoc clazz = extensibleClass;
133         while (clazz != null) {
134             result.add(clazz);
135             clazz = clazz.getSuperclass();
136         }
137         return result;
138     }
139
140     /**
141      * Returns the interface search order for the class hierarchy described
142      * by <code>classList</code>.
143      * The search order is defined in this class' comment.
144      */

145     protected final List JavaDoc computeInterfaceOrder(List JavaDoc classList) {
146         ArrayList JavaDoc result = new ArrayList JavaDoc(4);
147         Map JavaDoc seen = new HashMap JavaDoc(4);
148         for (Iterator JavaDoc list = classList.iterator(); list.hasNext();) {
149             Class JavaDoc[] interfaces = ((Class JavaDoc) list.next()).getInterfaces();
150             internalComputeInterfaceOrder(interfaces, result, seen);
151         }
152         return result;
153     }
154
155     /**
156      * Flushes the cache of contributor search paths. This is generally required
157      * whenever a contributor is added or removed.
158      * <p>
159      * It is likely easier to just toss the whole cache rather than trying to be
160      * smart and remove only those entries affected.
161      */

162     public void flushLookup() {
163         objectLookup = null;
164         resourceAdapterLookup = null;
165         adaptableLookup = null;
166     }
167
168     /**
169      * Cache the real adapter class contributor search path.
170      */

171     private void cacheResourceAdapterLookup(Class JavaDoc adapterClass, List JavaDoc results) {
172         if (resourceAdapterLookup == null) {
173             resourceAdapterLookup = new HashMap JavaDoc();
174         }
175         resourceAdapterLookup.put(adapterClass, results);
176     }
177     
178     /**
179      * Cache the real adapter class contributor search path.
180      */

181     private void cacheAdaptableLookup(String JavaDoc adapterClass, List JavaDoc results) {
182         if (adaptableLookup == null) {
183             adaptableLookup = new HashMap JavaDoc();
184         }
185         adaptableLookup.put(adapterClass, results);
186     }
187
188     /**
189      * Cache the object class contributor search path.
190      */

191     private void cacheObjectLookup(Class JavaDoc objectClass, List JavaDoc results) {
192         if (objectLookup == null) {
193             objectLookup = new HashMap JavaDoc();
194         }
195         objectLookup.put(objectClass, results);
196     }
197
198     /**
199      * Get the contributions registered to this manager.
200      *
201      * @return an unmodifiable <code>Collection</code> containing all registered
202      * contributions. The objects in this <code>Collection</code> will be
203      * <code>List</code>s containing the actual contributions.
204      * @since 3.0
205      */

206     public Collection JavaDoc getContributors() {
207         return Collections.unmodifiableCollection(contributors.values());
208     }
209
210     /**
211      * Return the list of contributors for the supplied class.
212      */

213     protected List JavaDoc addContributorsFor(Class JavaDoc objectClass) {
214
215         List JavaDoc classList = computeClassOrder(objectClass);
216         List JavaDoc result = new ArrayList JavaDoc();
217         addContributorsFor(classList, result);
218         classList = computeInterfaceOrder(classList); // interfaces
219
addContributorsFor(classList, result);
220         return result;
221     }
222
223     /**
224      * Returns true if contributors exist in the manager for
225      * this object and any of it's super classes, interfaces, or
226      * adapters.
227      *
228      * @param object the object to test
229      * @return whether the object has contributors
230      */

231     public boolean hasContributorsFor(Object JavaDoc object) {
232
233         List JavaDoc contributors = getContributors(object);
234         return contributors.size() > 0;
235     }
236
237     /**
238      * Add interface Class objects to the result list based
239      * on the class hierarchy. Interfaces will be searched
240      * based on their position in the result list.
241      */

242     private void internalComputeInterfaceOrder(Class JavaDoc[] interfaces, List JavaDoc result,
243             Map JavaDoc seen) {
244         List JavaDoc newInterfaces = new ArrayList JavaDoc(seen.size());
245         for (int i = 0; i < interfaces.length; i++) {
246             Class JavaDoc interfac = interfaces[i];
247             if (seen.get(interfac) == null) {
248                 result.add(interfac);
249                 seen.put(interfac, interfac);
250                 newInterfaces.add(interfac);
251             }
252         }
253         for (Iterator JavaDoc newList = newInterfaces.iterator(); newList.hasNext();) {
254             internalComputeInterfaceOrder(((Class JavaDoc) newList.next())
255                     .getInterfaces(), result, seen);
256         }
257     }
258
259     /**
260      * Return whether the given contributor is applicable to all elements in the
261      * selection.
262      *
263      * @param selection
264      * the selection
265      * @param contributor
266      * the contributor
267      * @return whether it is applicable
268      */

269     public boolean isApplicableTo(IStructuredSelection selection,
270             IObjectContributor contributor) {
271         Iterator JavaDoc elements = selection.iterator();
272         while (elements.hasNext()) {
273             if (contributor.isApplicableTo(elements.next()) == false) {
274                 return false;
275             }
276         }
277         return true;
278     }
279
280     /**
281      * Return whether the given contributor is applicable to all elements in the
282      * list.
283      *
284      * @param list
285      * the selection
286      * @param contributor
287      * the contributor
288      * @return whether it is applicable
289      */

290
291     public boolean isApplicableTo(List JavaDoc list, IObjectContributor contributor) {
292         Iterator JavaDoc elements = list.iterator();
293         while (elements.hasNext()) {
294             if (contributor.isApplicableTo(elements.next()) == false) {
295                 return false;
296             }
297         }
298         return true;
299     }
300
301     /**
302      * Register a contributor.
303      *
304      * @param contributor the contributor
305      * @param targetType the target type
306      */

307     public void registerContributor(IObjectContributor contributor,
308             String JavaDoc targetType) {
309         List JavaDoc contributorList = (List JavaDoc) contributors.get(targetType);
310         if (contributorList == null) {
311             contributorList = new ArrayList JavaDoc(5);
312             contributors.put(targetType, contributorList);
313         }
314         contributorList.add(contributor);
315         flushLookup();
316
317         IConfigurationElement element = (IConfigurationElement) Util.getAdapter(contributor,
318             IConfigurationElement.class);
319         
320         //hook the object listener
321
if (element != null) {
322             ContributorRecord contributorRecord = new ContributorRecord(
323                     contributor, targetType);
324             contributorRecordSet.add(contributorRecord);
325             PlatformUI.getWorkbench().getExtensionTracker().registerObject(
326                     element.getDeclaringExtension(), contributorRecord,
327                     IExtensionTracker.REF_WEAK);
328         }
329     }
330
331     /**
332      * Unregister all contributors.
333      */

334     public void unregisterAllContributors() {
335         contributors = new Hashtable JavaDoc(5);
336         flushLookup();
337     }
338
339     /**
340      * Unregister a contributor from the target type.
341      *
342      * @param contributor the contributor
343      * @param targetType the target type
344      */

345     public void unregisterContributor(IObjectContributor contributor,
346             String JavaDoc targetType) {
347         List JavaDoc contributorList = (List JavaDoc) contributors.get(targetType);
348         if (contributorList == null) {
349             return;
350         }
351         contributorList.remove(contributor);
352         if (contributorList.isEmpty()) {
353             contributors.remove(targetType);
354         }
355         flushLookup();
356     }
357
358
359     /**
360      * Unregister all contributors for the target type.
361      *
362      * @param targetType the target type
363      */

364     public void unregisterContributors(String JavaDoc targetType) {
365         contributors.remove(targetType);
366         flushLookup();
367     }
368     
369     protected List JavaDoc getContributors(Object JavaDoc object) {
370         // Determine is the object is a resource
371
Object JavaDoc resource = LegacyResourceSupport.getAdaptedContributorResource(object);
372         
373         // Fetch the unique adapters
374
List JavaDoc adapters = new ArrayList JavaDoc(Arrays.asList(Platform.getAdapterManager().computeAdapterTypes(object.getClass())));
375         removeCommonAdapters(adapters, Arrays.asList(new Class JavaDoc[] {object.getClass()}));
376
377         List JavaDoc contributors = new ArrayList JavaDoc();
378         
379         // Calculate the contributors for this object class
380
addAll(contributors, getObjectContributors(object.getClass()));
381         // Calculate the contributors for resource classes
382
if(resource != null) {
383             addAll(contributors, getResourceContributors(resource.getClass()));
384         }
385         // Calculate the contributors for each adapter type
386
if(adapters != null) {
387             for (Iterator JavaDoc it = adapters.iterator(); it.hasNext();) {
388                 String JavaDoc adapter = (String JavaDoc) it.next();
389                 addAll(contributors, getAdaptableContributors(adapter));
390             }
391         }
392         
393         // Remove duplicates. Note: this -must- maintain the element order to preserve menu order.
394
contributors = removeDups(contributors);
395
396         return contributors.isEmpty() ? Collections.EMPTY_LIST : new ArrayList JavaDoc(contributors);
397     }
398     
399     /**
400      * Returns the contributions for the given class. This considers
401      * contributors on any super classes and interfaces.
402      *
403      * @param objectClass the class to search for contributions.
404      * @return the contributions for the given class. This considers
405      * contributors on any super classes and interfaces.
406      *
407      * @since 3.1
408      */

409     protected List JavaDoc getObjectContributors(Class JavaDoc objectClass) {
410         List JavaDoc objectList = null;
411         // Lookup the results in the cache first.
412
if (objectLookup != null) {
413             objectList = (List JavaDoc) objectLookup.get(objectClass);
414         }
415         if (objectList == null) {
416             objectList = addContributorsFor(objectClass);
417             if (objectList.size() == 0) {
418                 objectList = Collections.EMPTY_LIST;
419             }
420             else {
421                 objectList = Collections.unmodifiableList(objectList);
422             }
423             cacheObjectLookup(objectClass, objectList);
424         }
425         return objectList;
426     }
427
428     /**
429      * Returns the contributions for the given <code>IResource</code>class.
430      * This considers contributors on any super classes and interfaces. This
431      * will only return contributions that are adaptable.
432      *
433      * @param resourceClass the class to search for contributions.
434      * @return the contributions for the given class. This considers
435      * adaptable contributors on any super classes and interfaces.
436      *
437      * @since 3.1
438      */

439     protected List JavaDoc getResourceContributors(Class JavaDoc resourceClass) {
440         List JavaDoc resourceList = null;
441         if (resourceAdapterLookup != null) {
442             resourceList = (List JavaDoc) resourceAdapterLookup.get(resourceClass);
443         }
444         if (resourceList == null) {
445             resourceList = addContributorsFor(resourceClass);
446             if (resourceList.size() == 0) {
447                 resourceList = Collections.EMPTY_LIST;
448             } else {
449                 resourceList = Collections.unmodifiableList(filterOnlyAdaptableContributors(resourceList));
450             }
451             cacheResourceAdapterLookup(resourceClass, resourceList);
452         }
453         return resourceList;
454     }
455
456     /**
457      * Returns the contributions for the given type name.
458      *
459      * @param adapterType the class to search for contributions.
460      * @return the contributions for the given class. This considers
461      * contributors to this specific type.
462      *
463      * @since 3.1
464      */

465     protected List JavaDoc getAdaptableContributors(String JavaDoc adapterType) {
466         List JavaDoc adaptableList = null;
467         // Lookup the results in the cache first, there are two caches
468
// one that stores non-adapter contributions and the other
469
// contains adapter contributions.
470
if (adaptableLookup != null) {
471             adaptableList = (List JavaDoc) adaptableLookup.get(adapterType);
472         }
473         if (adaptableList == null) {
474             // ignore resource adapters because these must be adapted via the
475
// IContributorResourceAdapter.
476
if (LegacyResourceSupport.isResourceType(adapterType) || LegacyResourceSupport.isResourceMappingType(adapterType)) {
477                 adaptableList = Collections.EMPTY_LIST;
478             }
479             else {
480                 adaptableList = (List JavaDoc) contributors.get(adapterType);
481                 if (adaptableList == null || adaptableList.size() == 0) {
482                     adaptableList = Collections.EMPTY_LIST;
483                 } else {
484                     adaptableList = Collections.unmodifiableList(filterOnlyAdaptableContributors(adaptableList));
485                 }
486             }
487             cacheAdaptableLookup(adapterType, adaptableList);
488         }
489         return adaptableList;
490     }
491     
492     /**
493      * Prunes from the list of adapters type names that are in the class
494      * search order of every class in <code>results</code>.
495      * @param adapters
496      * @param results
497      * @since 3.1
498      */

499     protected void removeCommonAdapters(List JavaDoc adapters, List JavaDoc results) {
500         for (Iterator JavaDoc it = results.iterator(); it.hasNext();) {
501             Class JavaDoc clazz = ((Class JavaDoc) it.next());
502             List JavaDoc commonTypes = computeCombinedOrder(clazz);
503             for (Iterator JavaDoc it2 = commonTypes.iterator(); it2.hasNext();) {
504                 Class JavaDoc type = (Class JavaDoc) it2.next();
505                 adapters.remove(type.getName());
506             }
507         }
508     }
509     
510     /**
511      * Returns the class search order starting with <code>extensibleClass</code>.
512      * The search order is defined in this class' comment.
513      */

514     protected List JavaDoc computeCombinedOrder(Class JavaDoc inputClass) {
515         List JavaDoc result = new ArrayList JavaDoc(4);
516         Class JavaDoc clazz = inputClass;
517         while (clazz != null) {
518             // add the class
519
result.add(clazz);
520             // add all the interfaces it implements
521
Class JavaDoc[] interfaces = clazz.getInterfaces();
522             for (int i = 0; i < interfaces.length; i++) {
523                 result.add(interfaces[i]);
524             }
525             // get the superclass
526
clazz = clazz.getSuperclass();
527         }
528         return result;
529     }
530
531     private List JavaDoc filterOnlyAdaptableContributors(List JavaDoc contributors) {
532         List JavaDoc adaptableContributors = null;
533         for (Iterator JavaDoc it = contributors.iterator(); it.hasNext();) {
534             IObjectContributor c = (IObjectContributor) it.next();
535             if(c.canAdapt()) {
536                 if(adaptableContributors == null) {
537                     adaptableContributors = new ArrayList JavaDoc();
538                 }
539                 adaptableContributors.add(c);
540             }
541         }
542         return adaptableContributors == null ? Collections.EMPTY_LIST : adaptableContributors;
543     }
544     
545     /* (non-Javadoc)
546      * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#removeExtension(org.eclipse.core.runtime.IExtension, java.lang.Object[])
547      */

548     public void removeExtension(IExtension source, Object JavaDoc[] objects) {
549         for (int i = 0; i < objects.length; i++) {
550             if (objects[i] instanceof ContributorRecord) {
551                 ContributorRecord contributorRecord = (ContributorRecord) objects[i];
552                 unregisterContributor((contributorRecord).contributor, (contributorRecord).objectClassName);
553                 contributorRecordSet.remove(contributorRecord);
554             }
555         }
556     }
557
558     /**
559      * Remove listeners and dispose of this manager.
560      *
561      * @since 3.1
562      */

563     public void dispose() {
564         if(canHandleExtensionTracking()) {
565             PlatformUI.getWorkbench().getExtensionTracker().unregisterHandler(this);
566         }
567     }
568     
569     /**
570      * Returns the list of contributors that are interested in the
571      * given list of model elements.
572      * @param elements a list of model elements (<code>Object</code>)
573      * @return the list of interested contributors (<code>IObjectContributor</code>)
574      */

575     protected List JavaDoc getContributors(List JavaDoc elements) {
576         // Calculate the common class, interfaces, and adapters registered
577
// via the IAdapterManager.
578
List JavaDoc commonAdapters = new ArrayList JavaDoc();
579         List JavaDoc commonClasses = getCommonClasses(elements, commonAdapters);
580         
581         // Get the resource class. It will be null if any of the
582
// elements are resources themselves or do not adapt to
583
// IResource.
584
Class JavaDoc resourceClass = getCommonResourceClass(elements);
585         Class JavaDoc resourceMappingClass = getResourceMappingClass(elements);
586
587         // Get the contributors.
588

589         List JavaDoc contributors = new ArrayList JavaDoc();
590         
591         // Add the resource contributions to avoid duplication
592
if (resourceClass != null) {
593             addAll(contributors, getResourceContributors(resourceClass));
594         }
595         if (commonClasses != null && !commonClasses.isEmpty()) {
596             for (int i = 0; i < commonClasses.size(); i++) {
597                 List JavaDoc results = getObjectContributors((Class JavaDoc) commonClasses
598                         .get(i));
599                 addAll(contributors, results);
600             }
601         }
602         // Add the resource mappings explicitly to avoid possible duplication
603
if (resourceMappingClass == null) {
604             // Still show the menus if the object is not adaptable but the adapter manager
605
// has an entry for it
606
resourceMappingClass = LegacyResourceSupport
607                     .getResourceMappingClass();
608             if (resourceMappingClass != null
609                     && commonAdapters.contains(resourceMappingClass.getName())) {
610                 addAll(contributors, getResourceContributors(resourceMappingClass));
611             }
612         } else {
613             contributors.addAll(getResourceContributors(resourceMappingClass));
614         }
615         if (!commonAdapters.isEmpty()) {
616             for (Iterator JavaDoc it = commonAdapters.iterator(); it.hasNext();) {
617                 String JavaDoc adapter = (String JavaDoc) it.next();
618                 addAll(contributors, getAdaptableContributors(adapter));
619             }
620         }
621         
622         // Remove duplicates. Note: this -must- maintain the element order to preserve menu order.
623
contributors = removeDups(contributors);
624         
625         return contributors.isEmpty() ? Collections.EMPTY_LIST : new ArrayList JavaDoc(contributors);
626     }
627
628     /**
629      * Adds all items in toAdd to the given collection. Optimized to avoid creating an iterator.
630      * This assumes that toAdd is efficient to index (i.e. it's an ArrayList or some other RandomAccessList),
631      * which is the case for all uses in this class.
632      */

633     private static void addAll(Collection JavaDoc collection, List JavaDoc toAdd) {
634         for (int i = 0, size = toAdd.size(); i < size; ++i) {
635             collection.add(toAdd.get(i));
636         }
637     }
638
639     /**
640      * Removes duplicates from the given list, preserving order.
641      */

642     private static List JavaDoc removeDups(List JavaDoc list) {
643         if (list.size() <= 1) {
644             return list;
645         }
646         HashSet JavaDoc set = new HashSet JavaDoc(list);
647         if (set.size() == list.size()) {
648             return list;
649         }
650         ArrayList JavaDoc result = new ArrayList JavaDoc(set.size());
651         for (Iterator JavaDoc i = list.iterator(); i.hasNext();) {
652             Object JavaDoc o = i.next();
653             if (set.remove(o)) {
654                 result.add(o);
655             }
656         }
657         return result;
658     }
659     
660     /**
661      * Returns the common denominator class, interfaces, and adapters
662      * for the given collection of objects.
663      */

664     private List JavaDoc getCommonClasses(List JavaDoc objects, List JavaDoc commonAdapters) {
665         if (objects == null || objects.size() == 0) {
666             return null;
667         }
668
669         // Optimization: if n==1 (or if all objects are of the same class), then the common class is the object's class,
670
// and the common adapters are the adapters cached for that class in the adapter manager
671
// See bug 177592 for more details.
672
if (allSameClass(objects)) {
673             
674             Class JavaDoc clazz = objects.get(0).getClass();
675             commonAdapters.addAll(Arrays.asList(Platform.getAdapterManager().computeAdapterTypes(clazz)));
676             List JavaDoc result = new ArrayList JavaDoc(1);
677             result.add(clazz);
678             return result;
679         }
680         
681         // Compute all the super classes, interfaces, and adapters
682
// for the first element.
683
List JavaDoc classes = computeClassOrder(objects.get(0).getClass());
684         List JavaDoc adapters = computeAdapterOrder(classes);
685         List JavaDoc interfaces = computeInterfaceOrder(classes);
686
687         // Cache of all types found in the selection - this is needed
688
// to compute common adapters.
689
List JavaDoc lastCommonTypes = new ArrayList JavaDoc();
690
691         boolean classesEmpty = classes.isEmpty();
692         boolean interfacesEmpty = interfaces.isEmpty();
693
694         // Traverse the selection if there is more than one element selected.
695
for (int i = 1; i < objects.size(); i++) {
696             // Compute all the super classes for the current element
697
List JavaDoc otherClasses = computeClassOrder(objects.get(i).getClass());
698             if (!classesEmpty) {
699                 classesEmpty = extractCommonClasses(classes, otherClasses);
700             }
701
702             // Compute all the interfaces for the current element
703
// and all of its super classes.
704
List JavaDoc otherInterfaces = computeInterfaceOrder(otherClasses);
705             if (!interfacesEmpty) {
706                 interfacesEmpty = extractCommonClasses(interfaces,
707                         otherInterfaces);
708             }
709
710             // Compute all the adapters provided for the calculated
711
// classes and interfaces for this element.
712
List JavaDoc classesAndInterfaces = new ArrayList JavaDoc(otherClasses);
713             if (otherInterfaces != null) {
714                 classesAndInterfaces.addAll(otherInterfaces);
715             }
716             List JavaDoc otherAdapters = computeAdapterOrder(classesAndInterfaces);
717
718             // Compute common adapters
719
// Note here that an adapter can match a class or interface, that is
720
// that an element in the selection may not adapt to a type but instead
721
// be of that type.
722
// If the selected classes doesn't have adapters, keep
723
// adapters that match the given classes types (classes and interfaces).
724
if (otherAdapters.isEmpty() && !adapters.isEmpty()) {
725                 removeNonCommonAdapters(adapters, classesAndInterfaces);
726             } else {
727                 if (adapters.isEmpty()) {
728                     removeNonCommonAdapters(otherAdapters, lastCommonTypes);
729                     if (!otherAdapters.isEmpty()) {
730                         adapters.addAll(otherAdapters);
731                     }
732                 } else {
733                     // Remove any adapters of the first element that
734
// are not in the current element's adapter list.
735
for (Iterator JavaDoc it = adapters.iterator(); it.hasNext();) {
736                         String JavaDoc adapter = (String JavaDoc) it.next();
737                         if (!otherAdapters.contains(adapter)) {
738                             it.remove();
739                         }
740                     }
741                 }
742             }
743
744             // Remember the common search order up to now, this is
745
// used to match adapters against common classes or interfaces.
746
lastCommonTypes.clear();
747             lastCommonTypes.addAll(classes);
748             lastCommonTypes.addAll(interfaces);
749
750             if (interfacesEmpty && classesEmpty && adapters.isEmpty()) {
751                 // As soon as we detect nothing in common, just exit.
752
return null;
753             }
754         }
755
756         // Once the common classes, interfaces, and adapters are
757
// calculated, let's prune the lists to remove duplicates.
758
ArrayList JavaDoc results = new ArrayList JavaDoc(4);
759         ArrayList JavaDoc superClasses = new ArrayList JavaDoc(4);
760         if (!classesEmpty) {
761             for (int j = 0; j < classes.size(); j++) {
762                 if (classes.get(j) != null) {
763                     superClasses.add(classes.get(j));
764                 }
765             }
766             // Just keep the first super class
767
if (!superClasses.isEmpty()) {
768                 results.add(superClasses.get(0));
769             }
770         }
771
772         if (!interfacesEmpty) {
773             removeCommonInterfaces(superClasses, interfaces, results);
774         }
775
776         // Remove adapters already included as common classes
777
if (!adapters.isEmpty()) {
778             removeCommonAdapters(adapters, results);
779             commonAdapters.addAll(adapters);
780         }
781         return results;
782     }
783
784     /**
785      * Returns <code>true</code> if all objects in the given list are of the same class,
786      * <code>false</code> otherwise.
787      */

788     private boolean allSameClass(List JavaDoc objects) {
789         int size = objects.size();
790         if (size <= 1) return true;
791         Class JavaDoc clazz = objects.get(0).getClass();
792         for (int i = 1; i < size; ++i) {
793             if (!objects.get(i).getClass().equals(clazz)) {
794                 return false;
795             }
796         }
797         return true;
798     }
799
800     private boolean extractCommonClasses(List JavaDoc classes, List JavaDoc otherClasses) {
801         boolean classesEmpty = true;
802         if (otherClasses.isEmpty()) {
803             // When no super classes, then it is obvious there
804
// are no common super classes with the first element
805
// so clear its list.
806
classes.clear();
807         } else {
808             // Remove any super classes of the first element that
809
// are not in the current element's super classes list.
810
for (int j = 0; j < classes.size(); j++) {
811                 if (classes.get(j) != null) {
812                     classesEmpty = false; // TODO: should this only be set if item not nulled out?
813
if (!otherClasses.contains(classes.get(j))) {
814                         classes.set(j, null);
815                     }
816                 }
817             }
818         }
819         return classesEmpty;
820     }
821
822     private void removeNonCommonAdapters(List JavaDoc adapters, List JavaDoc classes) {
823         for (int i = 0; i < classes.size(); i++) {
824             Object JavaDoc o = classes.get(i);
825             if (o != null) {
826                 Class JavaDoc clazz = (Class JavaDoc) o;
827                 String JavaDoc name = clazz.getName();
828                 if (adapters.contains(name)) {
829                     return;
830                 }
831             }
832         }
833         adapters.clear();
834     }
835
836     private void removeCommonInterfaces(List JavaDoc superClasses, List JavaDoc types,
837             List JavaDoc results) {
838         List JavaDoc dropInterfaces = null;
839         if (!superClasses.isEmpty()) {
840             dropInterfaces = computeInterfaceOrder(superClasses);
841         }
842         for (int j = 0; j < types.size(); j++) {
843             if (types.get(j) != null) {
844                 if (dropInterfaces != null
845                         && !dropInterfaces.contains(types.get(j))) {
846                     results.add(types.get(j));
847                 }
848             }
849         }
850     }
851
852     private List JavaDoc computeAdapterOrder(List JavaDoc classList) {
853         Set JavaDoc result = new HashSet JavaDoc(4);
854         IAdapterManager adapterMgr = Platform.getAdapterManager();
855         for (Iterator JavaDoc list = classList.iterator(); list.hasNext();) {
856             Class JavaDoc clazz = ((Class JavaDoc) list.next());
857             String JavaDoc[] adapters = adapterMgr.computeAdapterTypes(clazz);
858             for (int i = 0; i < adapters.length; i++) {
859                 String JavaDoc adapter = adapters[i];
860                 if (!result.contains(adapter)) {
861                     result.add(adapter);
862                 }
863             }
864         }
865         return new ArrayList JavaDoc(result);
866     }
867
868     /**
869      * Returns the common denominator resource class for the given
870      * collection of objects.
871      * Do not return a resource class if the objects are resources
872      * themselves so as to prevent double registration of actions.
873      */

874     private Class JavaDoc getCommonResourceClass(List JavaDoc objects) {
875         if (objects == null || objects.size() == 0) {
876             return null;
877         }
878         Class JavaDoc resourceClass = LegacyResourceSupport.getResourceClass();
879         if (resourceClass == null) {
880             // resources plug-in not loaded - no resources. period.
881
return null;
882         }
883
884         List JavaDoc testList = new ArrayList JavaDoc(objects.size());
885
886         for (int i = 0; i < objects.size(); i++) {
887             Object JavaDoc object = objects.get(i);
888
889             if (object instanceof IAdaptable) {
890                 if (resourceClass.isInstance(object)) {
891                     continue;
892                 }
893
894                 Object JavaDoc resource = LegacyResourceSupport
895                         .getAdaptedContributorResource(object);
896
897                 if (resource == null) {
898                     //Not a resource and does not adapt. No common resource class
899
return null;
900                 }
901                 testList.add(resource);
902             } else {
903                 return null;
904             }
905         }
906
907         return getCommonClass(testList);
908     }
909
910     /**
911      * Return the ResourceMapping class if the elements all adapt to it.
912      */

913     private Class JavaDoc getResourceMappingClass(List JavaDoc objects) {
914         if (objects == null || objects.size() == 0) {
915             return null;
916         }
917         Class JavaDoc resourceMappingClass = LegacyResourceSupport
918                 .getResourceMappingClass();
919         if (resourceMappingClass == null) {
920             // resources plug-in not loaded - no resources. period.
921
return null;
922         }
923
924         for (int i = 0; i < objects.size(); i++) {
925             Object JavaDoc object = objects.get(i);
926
927             if (object instanceof IAdaptable) {
928                 if (resourceMappingClass.isInstance(object)) {
929                     continue;
930                 }
931
932                 Object JavaDoc resourceMapping = LegacyResourceSupport
933                         .getAdaptedContributorResourceMapping(object);
934
935                 if (resourceMapping == null) {
936                     //Not a resource and does not adapt. No common resource class
937
return null;
938                 }
939             } else {
940                 return null;
941             }
942         }
943         // If we get here then all objects adapt to ResourceMapping
944
return resourceMappingClass;
945     }
946
947     /**
948      * Returns the common denominator class for the given
949      * collection of objects.
950      */

951     private Class JavaDoc getCommonClass(List JavaDoc objects) {
952         if (objects == null || objects.size() == 0) {
953             return null;
954         }
955         Class JavaDoc commonClass = objects.get(0).getClass();
956         // try easy
957
if (objects.size() == 1) {
958             return commonClass;
959         // try harder
960
}
961
962         for (int i = 1; i < objects.size(); i++) {
963             Object JavaDoc object = objects.get(i);
964             Class JavaDoc newClass = object.getClass();
965             // try the short cut
966
if (newClass.equals(commonClass)) {
967                 continue;
968             }
969             // compute common class
970
commonClass = getCommonClass(commonClass, newClass);
971             // give up
972
if (commonClass == null) {
973                 return null;
974             }
975         }
976         return commonClass;
977     }
978
979     /**
980      * Returns the common denominator class for
981      * two input classes.
982      */

983     private Class JavaDoc getCommonClass(Class JavaDoc class1, Class JavaDoc class2) {
984         List JavaDoc list1 = computeCombinedOrder(class1);
985         List JavaDoc list2 = computeCombinedOrder(class2);
986         for (int i = 0; i < list1.size(); i++) {
987             for (int j = 0; j < list2.size(); j++) {
988                 Class JavaDoc candidate1 = (Class JavaDoc) list1.get(i);
989                 Class JavaDoc candidate2 = (Class JavaDoc) list2.get(j);
990                 if (candidate1.equals(candidate2)) {
991                     return candidate1;
992                 }
993             }
994         }
995         // no common class
996
return null;
997     }
998 }
999
Popular Tags