001: /*******************************************************************************
002: * Copyright (c) 2003, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.navigator.extensions;
011:
012: import java.lang.ref.SoftReference;
013: import java.util.Arrays;
014: import java.util.HashMap;
015: import java.util.HashSet;
016: import java.util.Iterator;
017: import java.util.Map;
018: import java.util.Set;
019: import java.util.TreeSet;
020: import java.util.WeakHashMap;
021:
022: import org.eclipse.core.runtime.IConfigurationElement;
023: import org.eclipse.jface.resource.ImageDescriptor;
024: import org.eclipse.jface.resource.ImageRegistry;
025: import org.eclipse.swt.graphics.Image;
026: import org.eclipse.ui.WorkbenchException;
027: import org.eclipse.ui.internal.navigator.NavigatorPlugin;
028: import org.eclipse.ui.internal.navigator.VisibilityAssistant;
029: import org.eclipse.ui.internal.navigator.VisibilityAssistant.VisibilityListener;
030: import org.eclipse.ui.navigator.INavigatorContentDescriptor;
031: import org.eclipse.ui.plugin.AbstractUIPlugin;
032:
033: /**
034: * <p>
035: * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
036: * part of a work in progress. There is a guarantee neither that this API will
037: * work nor that it will remain the same. Please do not use this API without
038: * consulting with the Platform/UI team.
039: * </p>
040: *
041: * @since 3.2
042: */
043: public class NavigatorContentDescriptorManager {
044:
045: private static final NavigatorContentDescriptorManager INSTANCE = new NavigatorContentDescriptorManager();
046:
047: private final Map firstClassDescriptorsMap = new HashMap();
048:
049: private final Map allDescriptors = new HashMap();
050:
051: private class EvaluationCache implements VisibilityListener {
052:
053: private final Map evaluations/*<Object, NavigatorContentDescriptor[]>*/= new HashMap();
054: private final Map evaluationsWithOverrides/*<Object, NavigatorContentDescriptor[]>*/= new HashMap();
055:
056: EvaluationCache(VisibilityAssistant anAssistant) {
057: anAssistant.addListener(this );
058: }
059:
060: protected final NavigatorContentDescriptor[] getDescriptors(
061: Object anElement) {
062: return getDescriptors(anElement, true);
063: }
064:
065: protected final void setDescriptors(Object anElement,
066: NavigatorContentDescriptor[] theDescriptors) {
067: setDescriptors(anElement, theDescriptors, true);
068: }
069:
070: protected final NavigatorContentDescriptor[] getDescriptors(
071: Object anElement, boolean toComputeOverrides) {
072:
073: if (anElement == null)
074: return null;
075:
076: NavigatorContentDescriptor[] cachedDescriptors = null;
077: if (toComputeOverrides) {
078: SoftReference cache = (SoftReference) evaluations
079: .get(anElement);
080: if (cache != null
081: && (cachedDescriptors = (NavigatorContentDescriptor[]) cache
082: .get()) == null)
083: evaluations.remove(anElement);
084: return cachedDescriptors;
085: }
086: SoftReference cache = (SoftReference) evaluationsWithOverrides
087: .get(anElement);
088: if (cache != null
089: && (cachedDescriptors = (NavigatorContentDescriptor[]) cache
090: .get()) == null)
091: evaluationsWithOverrides.remove(anElement);
092: return cachedDescriptors;
093:
094: }
095:
096: protected final void setDescriptors(Object anElement,
097: NavigatorContentDescriptor[] theDescriptors,
098: boolean toComputeOverrides) {
099: if (anElement != null) {
100: if (toComputeOverrides)
101: evaluations.put(
102: new EvalutationReference(anElement),
103: new SoftReference(theDescriptors));
104: else
105: evaluationsWithOverrides.put(
106: new EvalutationReference(anElement),
107: new SoftReference(theDescriptors));
108: }
109: }
110:
111: /*
112: * (non-Javadoc)
113: *
114: * @see org.eclipse.ui.internal.navigator.VisibilityAssistant.VisibilityListener#onVisibilityOrActivationChange()
115: */
116: public void onVisibilityOrActivationChange() {
117: evaluations.clear();
118: evaluationsWithOverrides.clear();
119: }
120: }
121:
122: /* Map of (VisibilityAssistant, EvaluationCache)-pairs */
123: private final Map cachedTriggerPointEvaluations = new WeakHashMap();
124:
125: /* Map of (VisibilityAssistant, EvaluationCache)-pairs */
126: private final Map cachedPossibleChildrenEvaluations = new WeakHashMap();
127:
128: private ImageRegistry imageRegistry;
129:
130: private final Set overridingDescriptors = new HashSet();
131:
132: private final Set saveablesProviderDescriptors = new HashSet();
133:
134: private final Set firstClassDescriptorsSet = new HashSet();
135:
136: /**
137: * @return the singleton instance of the manager
138: */
139: public static NavigatorContentDescriptorManager getInstance() {
140: return INSTANCE;
141: }
142:
143: private NavigatorContentDescriptorManager() {
144: new NavigatorContentDescriptorRegistry().readRegistry();
145: }
146:
147: /**
148: *
149: * @return Returns all content descriptor(s).
150: */
151: public NavigatorContentDescriptor[] getAllContentDescriptors() {
152: NavigatorContentDescriptor[] finalDescriptors = new NavigatorContentDescriptor[allDescriptors
153: .size()];
154: finalDescriptors = (NavigatorContentDescriptor[]) allDescriptors
155: .values().toArray(finalDescriptors);
156: Arrays.sort(finalDescriptors,
157: ExtensionPriorityComparator.INSTANCE);
158: return finalDescriptors;
159: }
160:
161: /**
162: *
163: * @return Returns all content descriptors that provide saveables.
164: */
165: public NavigatorContentDescriptor[] getContentDescriptorsWithSaveables() {
166: NavigatorContentDescriptor[] finalDescriptors = new NavigatorContentDescriptor[saveablesProviderDescriptors
167: .size()];
168: saveablesProviderDescriptors.toArray(finalDescriptors);
169: Arrays.sort(finalDescriptors,
170: ExtensionPriorityComparator.INSTANCE);
171: return finalDescriptors;
172: }
173:
174: /**
175: *
176: * Returns all content descriptor(s) which enable for the given element.
177: *
178: * @param anElement
179: * the element to return the best content descriptor for
180: *
181: * @param aVisibilityAssistant
182: * The relevant viewer assistant; used to filter out unbound
183: * content descriptors.
184: * @return the best content descriptor for the given element.
185: */
186: public Set findDescriptorsForTriggerPoint(Object anElement,
187: VisibilityAssistant aVisibilityAssistant) {
188: EvaluationCache cache = getEvaluationCache(
189: cachedTriggerPointEvaluations, aVisibilityAssistant);
190:
191: Set descriptors = new TreeSet(
192: ExtensionPriorityComparator.INSTANCE);
193: NavigatorContentDescriptor[] cachedDescriptors = null;
194: if ((cachedDescriptors = cache.getDescriptors(anElement)) != null) {
195: descriptors.addAll(Arrays.asList(cachedDescriptors));
196: }
197:
198: /* Find other ContentProviders which enable for this object */
199: for (Iterator contentDescriptorsItr = firstClassDescriptorsMap
200: .values().iterator(); contentDescriptorsItr.hasNext();) {
201: NavigatorContentDescriptor descriptor = (NavigatorContentDescriptor) contentDescriptorsItr
202: .next();
203:
204: if (aVisibilityAssistant.isActive(descriptor)
205: && aVisibilityAssistant.isVisible(descriptor)
206: && descriptor.isTriggerPoint(anElement)) {
207: descriptors.add(descriptor);
208: }
209: }
210:
211: cache
212: .setDescriptors(
213: anElement,
214: (NavigatorContentDescriptor[]) descriptors
215: .toArray(new NavigatorContentDescriptor[descriptors
216: .size()]));
217:
218: return descriptors;
219: }
220:
221: private EvaluationCache getEvaluationCache(Map anEvaluationMap,
222: VisibilityAssistant aVisibilityAssistant) {
223: EvaluationCache c = (EvaluationCache) anEvaluationMap
224: .get(aVisibilityAssistant);
225: if (c == null) {
226: anEvaluationMap.put(aVisibilityAssistant,
227: c = new EvaluationCache(aVisibilityAssistant));
228: }
229: return c;
230:
231: }
232:
233: /**
234: *
235: * Returns all content descriptor(s) which enable for the given element.
236: *
237: * @param anElement
238: * the element to return the best content descriptor for
239: *
240: * @param aVisibilityAssistant
241: * The relevant viewer assistant; used to filter out unbound
242: * content descriptors.
243: * @return the best content descriptor for the given element.
244: */
245: public Set findDescriptorsForPossibleChild(Object anElement,
246: VisibilityAssistant aVisibilityAssistant) {
247: return findDescriptorsForPossibleChild(anElement,
248: aVisibilityAssistant, true);
249: }
250:
251: /**
252: *
253: * Returns all content descriptor(s) which enable for the given element.
254: *
255: * @param anElement
256: * the element to return the best content descriptor for
257: *
258: * @param aVisibilityAssistant
259: * The relevant viewer assistant; used to filter out unbound
260: * content descriptors.
261: * @return the best content descriptor for the given element.
262: */
263: public Set findDescriptorsForPossibleChild(Object anElement,
264: VisibilityAssistant aVisibilityAssistant,
265: boolean toComputeOverrides) {
266:
267: EvaluationCache cache = getEvaluationCache(
268: cachedPossibleChildrenEvaluations, aVisibilityAssistant);
269:
270: Set descriptors = new TreeSet(
271: ExtensionPriorityComparator.INSTANCE);
272: NavigatorContentDescriptor[] cachedDescriptors = null;
273: if ((cachedDescriptors = cache.getDescriptors(anElement,
274: toComputeOverrides)) != null) {
275: descriptors.addAll(Arrays.asList(cachedDescriptors));
276: }
277:
278: if (toComputeOverrides) {
279: addDescriptorsForPossibleChild(anElement,
280: firstClassDescriptorsSet, aVisibilityAssistant,
281: descriptors);
282: } else {
283:
284: NavigatorContentDescriptor descriptor;
285: /* Find other ContentProviders which enable for this object */
286: for (Iterator contentDescriptorsItr = allDescriptors
287: .values().iterator(); contentDescriptorsItr
288: .hasNext();) {
289: descriptor = (NavigatorContentDescriptor) contentDescriptorsItr
290: .next();
291:
292: boolean isApplicable = aVisibilityAssistant
293: .isActive(descriptor)
294: && aVisibilityAssistant.isVisible(descriptor)
295: && descriptor.isPossibleChild(anElement);
296:
297: if (isApplicable) {
298: descriptors.add(descriptor);
299: }
300:
301: }
302: }
303: cache
304: .setDescriptors(
305: anElement,
306: (NavigatorContentDescriptor[]) descriptors
307: .toArray(new NavigatorContentDescriptor[descriptors
308: .size()]), toComputeOverrides);
309:
310: return descriptors;
311: }
312:
313: private boolean addDescriptorsForPossibleChild(Object anElement,
314: Set theChildDescriptors,
315: VisibilityAssistant aVisibilityAssistant,
316: Set theFoundDescriptors) {
317: int initialSize = theFoundDescriptors.size();
318:
319: NavigatorContentDescriptor descriptor;
320: /* Find other ContentProviders which enable for this object */
321: for (Iterator contentDescriptorsItr = theChildDescriptors
322: .iterator(); contentDescriptorsItr.hasNext();) {
323: descriptor = (NavigatorContentDescriptor) contentDescriptorsItr
324: .next();
325:
326: boolean isApplicable = aVisibilityAssistant
327: .isActive(descriptor)
328: && aVisibilityAssistant.isVisible(descriptor)
329: && descriptor.isPossibleChild(anElement);
330:
331: if (descriptor.hasOverridingExtensions()) {
332:
333: boolean isOverridden = addDescriptorsForPossibleChild(
334: anElement, descriptor
335: .getOverriddingExtensions(),
336: aVisibilityAssistant, theFoundDescriptors);
337:
338: if (!isOverridden && isApplicable) {
339: theFoundDescriptors.add(descriptor);
340: }
341:
342: } else if (isApplicable) {
343: theFoundDescriptors.add(descriptor);
344: }
345:
346: }
347: return initialSize < theFoundDescriptors.size();
348:
349: }
350:
351: /**
352: * Returns the navigator content descriptor with the given id.
353: *
354: * @param id
355: * The id of the content descriptor that should be returned
356: * @return The content descriptor of the given id
357: */
358: public NavigatorContentDescriptor getContentDescriptor(String id) {
359: return (NavigatorContentDescriptor) allDescriptors.get(id);
360: }
361:
362: /**
363: *
364: * @param descriptorId
365: * The unique id of a particular descriptor
366: * @return The name (value of the 'name' attribute) of the given descriptor
367: */
368: public String getText(String descriptorId) {
369: INavigatorContentDescriptor descriptor = getContentDescriptor(descriptorId);
370: if (descriptor != null) {
371: return descriptor.getName();
372: }
373: return descriptorId;
374: }
375:
376: /**
377: *
378: * @param descriptorId
379: * The unique id of a particular descriptor
380: * @return The image (corresponding to the value of the 'icon' attribute) of
381: * the given descriptor
382: */
383: public Image getImage(String descriptorId) {
384: return retrieveAndStoreImage(descriptorId);
385: }
386:
387: protected Image retrieveAndStoreImage(String descriptorId) {
388: NavigatorContentDescriptor contentDescriptor = getContentDescriptor(descriptorId);
389:
390: Image image = null;
391: if (contentDescriptor != null) {
392: String icon = contentDescriptor.getIcon();
393: if (icon != null) {
394: image = getImageRegistry().get(icon);
395: if (image == null || image.isDisposed()) {
396: ImageDescriptor imageDescriptor = AbstractUIPlugin
397: .imageDescriptorFromPlugin(
398: contentDescriptor.getContribution()
399: .getPluginId(), icon);
400: if (imageDescriptor != null) {
401: image = imageDescriptor.createImage();
402: if (image != null) {
403: getImageRegistry().put(icon, image);
404: }
405: }
406: }
407: }
408: }
409: return image;
410: }
411:
412: /**
413: * @param desc
414: */
415: private void addNavigatorContentDescriptor(
416: NavigatorContentDescriptor desc) {
417: if (desc == null) {
418: return;
419: }
420: synchronized (firstClassDescriptorsMap) {
421: if (firstClassDescriptorsMap.containsKey(desc.getId())) {
422: NavigatorPlugin
423: .logError(
424: 0,
425: "An extension already exists with id \"" + desc.getId() + "\".", null); //$NON-NLS-1$ //$NON-NLS-2$
426: } else {
427: if (desc.getSuppressedExtensionId() == null) {
428: firstClassDescriptorsMap.put(desc.getId(), desc);
429: firstClassDescriptorsSet.add(desc);
430: } else {
431: overridingDescriptors.add(desc);
432: }
433: allDescriptors.put(desc.getId(), desc);
434: if (desc.hasSaveablesProvider()) {
435: saveablesProviderDescriptors.add(desc);
436: }
437: }
438: }
439: }
440:
441: /**
442: *
443: */
444: private void computeOverrides() {
445: if (overridingDescriptors.size() > 0) {
446: NavigatorContentDescriptor descriptor;
447: NavigatorContentDescriptor overriddenDescriptor;
448: for (Iterator overridingIterator = overridingDescriptors
449: .iterator(); overridingIterator.hasNext();) {
450: descriptor = (NavigatorContentDescriptor) overridingIterator
451: .next();
452: overriddenDescriptor = (NavigatorContentDescriptor) allDescriptors
453: .get(descriptor.getSuppressedExtensionId());
454: if (overriddenDescriptor != null) {
455:
456: /*
457: * add the descriptor as an overriding extension for its
458: * suppressed extension
459: */
460: overriddenDescriptor.getOverriddingExtensions()
461: .add(descriptor);
462: descriptor
463: .setOverriddenDescriptor(overriddenDescriptor);
464: /*
465: * the always policy implies this is also a top-level
466: * extension
467: */
468: if (descriptor.getOverridePolicy() == OverridePolicy.InvokeAlwaysRegardlessOfSuppressedExt) {
469: firstClassDescriptorsMap.put(
470: descriptor.getId(), descriptor);
471: firstClassDescriptorsSet.add(descriptor);
472: }
473:
474: } else {
475: NavigatorPlugin
476: .logError(
477: 0,
478: "Invalid suppressedExtensionId (\"" //$NON-NLS-1$
479: + descriptor
480: .getSuppressedExtensionId()
481: + "\" specified from " //$NON-NLS-1$
482: + descriptor
483: .getContribution()
484: .getPluginId()
485: + ". No extension with matching id found.", //$NON-NLS-1$
486: null);
487: }
488: }
489: }
490: }
491:
492: private ImageRegistry getImageRegistry() {
493: if (imageRegistry == null) {
494: imageRegistry = new ImageRegistry();
495: }
496: return imageRegistry;
497: }
498:
499: private class NavigatorContentDescriptorRegistry extends
500: NavigatorContentRegistryReader {
501:
502: /*
503: * (non-Javadoc)
504: *
505: * @see org.eclipse.ui.internal.navigator.extensions.RegistryReader#readRegistry()
506: */
507: public void readRegistry() {
508: super .readRegistry();
509: computeOverrides();
510: }
511:
512: protected boolean readElement(IConfigurationElement anElement) {
513: if (TAG_NAVIGATOR_CONTENT.equals(anElement.getName())) {
514: try {
515: addNavigatorContentDescriptor(new NavigatorContentDescriptor(
516: anElement));
517:
518: } catch (WorkbenchException e) {
519: // log an error since its not safe to open a dialog here
520: NavigatorPlugin.log(e.getStatus());
521: }
522: }
523: return super.readElement(anElement);
524: }
525: }
526:
527: }
|