/******************************************************************************* * Copyright (c) 2003, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Fair Issac Corp - bug 287103 - NCSLabelProvider does not properly handle overrides *******************************************************************************/ package org.eclipse.ui.internal.navigator; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IMemento; import org.eclipse.ui.internal.navigator.dnd.NavigatorDnDService; import org.eclipse.ui.internal.navigator.extensions.ExtensionSequenceNumberComparator; import org.eclipse.ui.internal.navigator.extensions.NavigatorContentDescriptor; import org.eclipse.ui.internal.navigator.extensions.NavigatorContentDescriptorManager; import org.eclipse.ui.internal.navigator.extensions.NavigatorContentExtension; import org.eclipse.ui.internal.navigator.extensions.NavigatorViewerDescriptor; import org.eclipse.ui.internal.navigator.extensions.NavigatorViewerDescriptorManager; import org.eclipse.ui.internal.navigator.extensions.SafeDelegateTreeContentProvider; import org.eclipse.ui.internal.navigator.extensions.StructuredViewerManager; import org.eclipse.ui.internal.navigator.sorters.NavigatorSorterService; import org.eclipse.ui.navigator.ICommonLabelProvider; import org.eclipse.ui.navigator.IDescriptionProvider; import org.eclipse.ui.navigator.IExtensionActivationListener; import org.eclipse.ui.navigator.IExtensionStateModel; import org.eclipse.ui.navigator.IMementoAware; import org.eclipse.ui.navigator.INavigatorActivationService; import org.eclipse.ui.navigator.INavigatorContentDescriptor; import org.eclipse.ui.navigator.INavigatorContentExtension; import org.eclipse.ui.navigator.INavigatorContentService; import org.eclipse.ui.navigator.INavigatorContentServiceListener; import org.eclipse.ui.navigator.INavigatorDnDService; import org.eclipse.ui.navigator.INavigatorFilterService; import org.eclipse.ui.navigator.INavigatorPipelineService; import org.eclipse.ui.navigator.INavigatorSaveablesService; import org.eclipse.ui.navigator.INavigatorSorterService; import org.eclipse.ui.navigator.INavigatorViewerDescriptor; import org.osgi.service.prefs.BackingStoreException; /** * <p> * Provides centralized access to the information provided by * NavigatorContentExtensions. Can be instantiated as needed, but should be * cached for active viewers. Information specific to a given viewer will be * cached by the NavigatorContentService, not including ContentProviders and * Label Providers created by {@link #createCommonContentProvider()}and * {@link #createCommonLabelProvider()}respectively. * </p> * * <p> * The following class is experimental until fully documented. * </p> */ public class NavigatorContentService implements IExtensionActivationListener, IMementoAware, INavigatorContentService { /** * */ public static final String WIDGET_KEY = "org.eclipse.ui.navigator"; //$NON-NLS-1$ private static final NavigatorContentDescriptorManager CONTENT_DESCRIPTOR_REGISTRY = NavigatorContentDescriptorManager .getInstance(); private static final NavigatorViewerDescriptorManager VIEWER_DESCRIPTOR_REGISTRY = NavigatorViewerDescriptorManager .getInstance(); private static final ITreeContentProvider[] NO_CONTENT_PROVIDERS = new ITreeContentProvider[0]; private static final ILabelProvider[] NO_LABEL_PROVIDERS = new ILabelProvider[0]; private static final INavigatorContentDescriptor[] NO_DESCRIPTORS = new INavigatorContentDescriptor[0]; private static final String[] NO_EXTENSION_IDS = new String[0]; private final NavigatorViewerDescriptor viewerDescriptor; private final List<INavigatorContentServiceListener> listeners = new ArrayList<INavigatorContentServiceListener>(); /* * A map of (String-based-Navigator-Content-Extension-IDs, * NavigatorContentExtension-objects)-pairs */ private final Map<INavigatorContentDescriptor, NavigatorContentExtension> contentExtensions = new HashMap<INavigatorContentDescriptor, NavigatorContentExtension>(); private StructuredViewerManager structuredViewerManager; private ITreeContentProvider[] rootContentProviders; private ITreeContentProvider contentProvider; /* * Used when providing objects to the CommonViewer by the contentProvider * to record the object/description associations which are when stored * in the Tree associated with the viewer. */ private Map<Object, INavigatorContentDescriptor> contributionMemory; private Map<Object, INavigatorContentDescriptor> contributionMemoryFirstClass; private ILabelProvider labelProvider; private final VisibilityAssistant assistant; private NavigatorFilterService navigatorFilterService; private NavigatorSorterService navigatorSorterService; private INavigatorPipelineService navigatorPipelineService; private INavigatorDnDService navigatorDnDService; private INavigatorActivationService navigatorActivationService; private NavigatorSaveablesService navigatorSaveablesService; private NavigatorExtensionStateService navigatorExtensionStateService; private IDescriptionProvider descriptionProvider; private boolean contentProviderInitialized; private boolean labelProviderInitialized; private boolean isDisposed; /** * @param aViewerId * The viewer id for this content service; normally from the * <b>org.eclipse.ui.views</b> extension. */ public NavigatorContentService(String aViewerId) { super(); aViewerId = aViewerId != null ? aViewerId : ""; //$NON-NLS-1$ viewerDescriptor = VIEWER_DESCRIPTOR_REGISTRY .getNavigatorViewerDescriptor(aViewerId); assistant = new VisibilityAssistant(viewerDescriptor, getActivationService()); getActivationService().addExtensionActivationListener(this); contributionMemory = new HashMap<Object, INavigatorContentDescriptor>(); contributionMemoryFirstClass = new HashMap<Object, INavigatorContentDescriptor>(); } /** * @param aViewerId * The viewer id for this content service; normally from the * <b>org.eclipse.ui.views</b> extension. * @param aViewer * The viewer that this content service will be associated with. */ public NavigatorContentService(String aViewerId, StructuredViewer aViewer) { this(aViewerId); structuredViewerManager = new StructuredViewerManager(aViewer, this); } @Override public String[] getVisibleExtensionIds() { List<String> visibleExtensionIds = new ArrayList<String>(); NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY .getAllContentDescriptors(); for (NavigatorContentDescriptor descriptor : descriptors) { if (assistant.isVisible(descriptor.getId())) { visibleExtensionIds.add(descriptor.getId()); } } if (visibleExtensionIds.isEmpty()) { return NO_EXTENSION_IDS; } return visibleExtensionIds .toArray(new String[visibleExtensionIds.size()]); } @Override public INavigatorContentDescriptor[] getVisibleExtensions() { List<NavigatorContentDescriptor> visibleDescriptors = new ArrayList<NavigatorContentDescriptor>(); NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY .getAllContentDescriptors(); for (NavigatorContentDescriptor descriptor : descriptors) { if (assistant.isVisible(descriptor.getId())) { visibleDescriptors.add(descriptor); } } if (visibleDescriptors.isEmpty()) { return NO_DESCRIPTORS; } return visibleDescriptors .toArray(new INavigatorContentDescriptor[visibleDescriptors .size()]); } /* package */INavigatorContentDescriptor[] getActiveDescriptorsWithSaveables() { List<NavigatorContentDescriptor> result = new ArrayList<NavigatorContentDescriptor>(); NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY .getContentDescriptorsWithSaveables(); for (NavigatorContentDescriptor descriptor : descriptors) { if (assistant.isVisible(descriptor.getId()) && assistant.isActive(descriptor)) { result.add(descriptor); } } if (result.isEmpty()) { return NO_DESCRIPTORS; } return result .toArray(new INavigatorContentDescriptor[result.size()]); } @Override public INavigatorContentDescriptor[] bindExtensions(String[] extensionIds, boolean isRoot) { if (extensionIds == null || extensionIds.length == 0) { return NO_DESCRIPTORS; } assistant.bindExtensions(extensionIds, isRoot); Set<INavigatorContentDescriptor> boundDescriptors = new HashSet<INavigatorContentDescriptor>(); INavigatorContentDescriptor descriptor; for (String extensionId : extensionIds) { descriptor = CONTENT_DESCRIPTOR_REGISTRY .getContentDescriptor(extensionId); if (descriptor != null) { boundDescriptors.add(descriptor); } } if (boundDescriptors.size() == 0) { return NO_DESCRIPTORS; } if (Policy.DEBUG_EXTENSION_SETUP) { System.out.println("bindExtensions: " + //$NON-NLS-1$ boundDescriptors); } return boundDescriptors .toArray(new INavigatorContentDescriptor[boundDescriptors .size()]); } @Override public ITreeContentProvider createCommonContentProvider() { if (contentProviderInitialized) { return contentProvider; } synchronized (this) { if (contentProvider == null) { contentProvider = new NavigatorContentServiceContentProvider( this); } contentProviderInitialized = true; } return contentProvider; } @Override public ILabelProvider createCommonLabelProvider() { if (labelProviderInitialized) { return labelProvider; } synchronized (this) { if (labelProvider == null) { labelProvider = new NavigatorContentServiceLabelProvider(this); } labelProviderInitialized = true; } return labelProvider; } @Override public IDescriptionProvider createCommonDescriptionProvider() { if (descriptionProvider != null) { return descriptionProvider; } synchronized (this) { if (descriptionProvider == null) { descriptionProvider = new NavigatorContentServiceDescriptionProvider( this); } } return descriptionProvider; } @Override public void dispose() { if (navigatorSaveablesService != null) { assistant.removeListener(navigatorSaveablesService); } if (navigatorSorterService != null) { assistant.removeListener(navigatorSorterService); } synchronized (this) { for (NavigatorContentExtension navigatorContentExtension : contentExtensions.values()) { navigatorContentExtension.dispose(); } } getActivationService().removeExtensionActivationListener(this); assistant.dispose(); isDisposed = true; } protected void updateService(Viewer aViewer, Object anOldInput, Object aNewInput) { // Prevents the world from being started again once we have been disposed. In // the dispose process, the ContentViewer will call setInput() on the // NavigatorContentServiceContentProvider, which gets us here if (isDisposed) return; NavigatorContentDescriptorManager.getInstance().clearCache(); synchronized (this) { if (structuredViewerManager == null) { structuredViewerManager = new StructuredViewerManager((StructuredViewer) aViewer, this); structuredViewerManager.inputChanged(anOldInput, aNewInput); } else { structuredViewerManager.inputChanged(aViewer, anOldInput, aNewInput); } for (NavigatorContentExtension ext : contentExtensions.values()) { if (ext.isLoaded()) { structuredViewerManager.initialize(ext.internalGetContentProvider()); } } rootContentProviders = extractContentProviders(findRootContentExtensions(aNewInput)); } } @Override public IExtensionStateModel findStateModel(String anExtensionId) { if (anExtensionId == null) { return null; } INavigatorContentDescriptor desc = CONTENT_DESCRIPTOR_REGISTRY .getContentDescriptor(anExtensionId); if (desc == null) { return null; } INavigatorContentExtension ext = getExtension(desc); if (ext == null) { return null; } return ext.getStateModel(); } /** * <p> * Return all of the content providers that are relevant for the viewer. The * viewer is determined by the ID used to create the * INavigatorContentService ({@link #getViewerId() }). See * {@link #createCommonContentProvider() } for more information about how * content providers are located for the root of the viewer. The root * content providers are calculated once. If a new element is supplied, a * client must call {@link #update() } prior in order to reset the calculated * root providers. * </p> * * @param anElement * An element from the tree (generally the input of the viewer) * @return The set of content providers that can provide root elements for a * viewer. */ public ITreeContentProvider[] findRootContentProviders(Object anElement) { if (rootContentProviders != null) { return rootContentProviders; } synchronized (this) { if (rootContentProviders == null) { rootContentProviders = extractContentProviders(findRootContentExtensions(anElement)); } } return rootContentProviders; } /** * Returns the list of extensions that should be considered as possible * contributors of CNF artifacts (labels, sorters, ...). The algorithm * first considers the source of contribution and its overrides, and then * any possibleChildren and their overrides in order. * * @param anElement * An element from the tree (any element contributed to the * tree). * @return A Collection of NCEs sorted in the correct order for label provider application */ public Collection<NavigatorContentExtension> findPossibleLabelExtensions(Object anElement) { LinkedHashSet<NavigatorContentExtension> contributors = new LinkedHashSet<NavigatorContentExtension>(); INavigatorContentDescriptor sourceDescriptor = getSourceOfContribution(anElement); // This is a TreeSet sorted ascending Set<INavigatorContentDescriptor> possibleChildDescriptors = findDescriptorsWithPossibleChild(anElement, false); // Add the source so that it gets sorted into the right place if (sourceDescriptor != null) { possibleChildDescriptors.add(sourceDescriptor); } for (INavigatorContentDescriptor iNavigatorContentDescriptor : possibleChildDescriptors) { NavigatorContentDescriptor ncd = (NavigatorContentDescriptor) iNavigatorContentDescriptor; findOverridingLabelExtensions(anElement, ncd, contributors); } return contributors; } private void findOverridingLabelExtensions(Object anElement, INavigatorContentDescriptor descriptor, LinkedHashSet<NavigatorContentExtension> contributors) { ListIterator iter = ((NavigatorContentDescriptor) descriptor).getOverridingExtensionsListIterator(false); while (iter.hasPrevious()) { INavigatorContentDescriptor child = (INavigatorContentDescriptor) iter.previous(); if (assistant.isVisibleAndActive(child) && child.isPossibleChild(anElement)) { findOverridingLabelExtensions(anElement, child, contributors); } } contributors.add(getExtension(descriptor)); } /** * * The label provider that is are enabled for the given element. * A label provider is 'enabled' if its corresponding content provider * returned the element. * * @param anElement * An element from the tree (any element contributed to the * tree). * @return The label provider */ public ILabelProvider[] findRelevantLabelProviders(Object anElement) { Collection<NavigatorContentExtension> extensions = findPossibleLabelExtensions(anElement); if (extensions.size() == 0) { return NO_LABEL_PROVIDERS; } List<ICommonLabelProvider> resultProvidersList = new ArrayList<ICommonLabelProvider>(); for (NavigatorContentExtension navigatorContentExtension : extensions) { resultProvidersList.add(navigatorContentExtension.getLabelProvider()); } return resultProvidersList.toArray(new ILabelProvider[resultProvidersList.size()]); } /** * Search for extensions that declare the given element in their * <b>triggerPoints</b> expression. * * @param anElement * The element to use in the query * @return The set of {@link INavigatorContentExtension}s that are * <i>visible</i> and <i>active</i> for this content service and * either declared through a * <b>org.eclipse.ui.navigator.viewer/viewerContentBinding</b> to be * a root element or have a <b>triggerPoints</b> expression that is * <i>enabled</i> for the given element. */ @Override public Set<NavigatorContentExtension> findRootContentExtensions(Object anElement) { return findRootContentExtensions(anElement, true); } /** * Search for extensions that declare the given element in their * <b>triggerPoints</b> expression. * * @param anElement * The element to use in the query * @param toRespectViewerRoots * True respect the <b>viewerContentBinding</b>s, False will look * only for matching <b>triggerPoints</b> expressions. * @return The set of {@link INavigatorContentExtension}s that are * <i>visible</i> and <i>active</i> for this content service and * either declared through a * <b>org.eclipse.ui.navigator.viewer/viewerContentBinding</b> to be * a root element or have a <b>triggerPoints</b> expression that is * <i>enabled</i> for the given element. */ public Set<NavigatorContentExtension> findRootContentExtensions(Object anElement, boolean toRespectViewerRoots) { SortedSet<NavigatorContentExtension> rootExtensions = new TreeSet<NavigatorContentExtension>( ExtensionSequenceNumberComparator.INSTANCE); if (toRespectViewerRoots /*&& viewerDescriptor.hasOverriddenRootExtensions()*/) { NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY .getAllContentDescriptors(); NavigatorContentExtension extension = null; for (NavigatorContentDescriptor descriptor : descriptors) { if (isActive(descriptor.getId()) && isRootExtension(descriptor.getId())) { extension = getExtension(descriptor); if (!extension.hasLoadingFailed()) { rootExtensions.add(extension); } } } } if (rootExtensions.isEmpty()) { return findContentExtensionsByTriggerPoint(anElement); } return rootExtensions; } /** * Search for extensions that declare the given element in their * <b>possibleChildren</b> expression. * * @param anElement * The element to use in the query * @return The set of {@link INavigatorContentExtension}s that are * <i>visible</i> and <i>active</i> for this content service and * have a <b>possibleChildren</b> expression that is <i>enabled</i> * for the given element. */ public Set<NavigatorContentExtension> findOverrideableContentExtensionsForPossibleChild( Object anElement) { Set<NavigatorContentExtension> overrideableExtensions = new TreeSet<NavigatorContentExtension>( ExtensionSequenceNumberComparator.INSTANCE); Set<INavigatorContentDescriptor> descriptors = findDescriptorsWithPossibleChild(anElement, false); for (INavigatorContentDescriptor descriptor : descriptors) { if (descriptor.hasOverridingExtensions()) { overrideableExtensions.add(getExtension(descriptor)); } } return overrideableExtensions; } @Override public INavigatorContentDescriptor getContentDescriptorById( String anExtensionId) { return CONTENT_DESCRIPTOR_REGISTRY.getContentDescriptor(anExtensionId); } /** * * @param anExtensionId * The id used to define the * <b>org.eclipse.ui.navigator.navigatorContent * /navigatorContent</b> extension. * @return An instance of the content extension for the given extension id. * May return <b>null</b> if the id is invalid. */ @Override public INavigatorContentExtension getContentExtensionById( String anExtensionId) { NavigatorContentDescriptor descriptor = CONTENT_DESCRIPTOR_REGISTRY .getContentDescriptor(anExtensionId); if (descriptor != null) return getExtension(descriptor); return null; } /** * Search for extensions that declare the given element in their * <b>triggerPoints</b> expression. * * @param anElement * The element to use in the query * @return The set of {@link INavigatorContentExtension}s that are * <i>visible</i> and <i>active</i> for this content service and * have a <b>triggerPoints</b> expression that is <i>enabled</i> for * the given element. */ @Override public Set<NavigatorContentExtension> findContentExtensionsByTriggerPoint(Object anElement) { return findContentExtensionsByTriggerPoint(anElement, true, !CONSIDER_OVERRIDES); } /** * Search for extensions that declare the given element in their * <b>triggerPoints</b> expression. * * @param anElement * The element to use in the query * @param toLoadIfNecessary * True will force the load of the extension, False will not * @param computeOverrides * @return The set of {@link INavigatorContentExtension}s that are * <i>visible</i> and <i>active</i> for this content service and * have a <b>triggerPoints</b> expression that is <i>enabled</i> for * the given element. */ public Set<NavigatorContentExtension> findContentExtensionsByTriggerPoint(Object anElement, boolean toLoadIfNecessary, boolean computeOverrides) { Set<INavigatorContentDescriptor> enabledDescriptors = findDescriptorsByTriggerPoint(anElement, computeOverrides); return extractDescriptorInstances(enabledDescriptors, toLoadIfNecessary); } /** * Search for extensions that declare the given element in their * <b>possibleChildren</b> expression. * * @param anElement * The element to use in the query * @return The set of {@link INavigatorContentExtension}s that are * <i>visible</i> and <i>active</i> for this content service and * have a <b>possibleChildren</b> expression that is <i>enabled</i> * for the given element. */ @Override public Set<NavigatorContentExtension> findContentExtensionsWithPossibleChild(Object anElement) { return findContentExtensionsWithPossibleChild(anElement, true); } /** * Search for extensions that declare the given element in their * <b>possibleChildren</b> expression. * * @param anElement * The element to use in the query * @param toLoadIfNecessary * True will force the load of the extension, False will not * @return The set of {@link INavigatorContentExtension}s that are * <i>visible</i> and <i>active</i> for this content service and * have a <b>possibleChildren</b> expression that is <i>enabled</i> * for the given element. */ public Set<NavigatorContentExtension> findContentExtensionsWithPossibleChild(Object anElement, boolean toLoadIfNecessary) { Set<INavigatorContentDescriptor> enabledDescriptors = findDescriptorsWithPossibleChild(anElement); return extractDescriptorInstances(enabledDescriptors, toLoadIfNecessary); } /** * * * @param firstClassSource * @param source * @param element */ public void rememberContribution(INavigatorContentDescriptor source, INavigatorContentDescriptor firstClassSource, Object element) { /* * We want to write to (overwrite) the contributionMemory only if we * have never heard of the element before, or if the element is coming * from the same first class NCE, which means that the subsequent NCE is * an override. The override will take precedence over the originally * contributing NCE. However in the case of different first class NCEs, * the first one wins, so we don't update the contribution memory. */ synchronized (this) { if (contributionMemory.get(element) == null || contributionMemoryFirstClass.get(element) == firstClassSource) { if (Policy.DEBUG_RESOLUTION) System.out .println("rememberContribution: " + Policy.getObjectString(element) + " source: " + source); //$NON-NLS-1$//$NON-NLS-2$ contributionMemory.put(element, source); contributionMemoryFirstClass.put(element, firstClassSource); } } } /** * Forget about the specified element * * @param element * The element to forget. */ public void forgetContribution(Object element) { synchronized (this) { contributionMemory.remove(element); contributionMemoryFirstClass.remove(element); } } /** * @param element * @return the remembered NavigatorContentDescriptor */ public NavigatorContentDescriptor getContribution(Object element) { NavigatorContentDescriptor desc; synchronized (this) { desc = (NavigatorContentDescriptor) contributionMemory.get(element); } return desc; } /** * Used only for the tests * @return the size of the contribution memory */ public int getContributionMemorySize() { synchronized (this) { return contributionMemory.size(); } } /** * * @param element * The element contributed by the descriptor to be returned * @return The descriptor that contributed the element or null. * @see #findContentExtensionsByTriggerPoint(Object) */ public synchronized NavigatorContentDescriptor getSourceOfContribution(Object element) { if (element == null) return null; if (structuredViewerManager == null) return null; // Try here first because it might not yet be in the tree NavigatorContentDescriptor src; synchronized (this) { src = (NavigatorContentDescriptor) contributionMemory.get(element); } if (src != null) return src; return (NavigatorContentDescriptor) structuredViewerManager.getData(element); } /** * */ public static final boolean CONSIDER_OVERRIDES = true; /** * Search for extensions that declare the given element in their * <b>triggerPoints</b> expression. * * @param anElement * The element to use in the query * @param considerOverrides * * @return The set of {@link INavigatorContentDescriptor}s that are * <i>visible</i> and <i>active</i> for this content service and * have a <b>triggerPoints</b> expression that is <i>enabled</i> for * the given element. */ public Set<INavigatorContentDescriptor> findDescriptorsByTriggerPoint(Object anElement, boolean considerOverrides) { // Here we use the cache, since objects are inserted into the // cache in response to the trigger point NavigatorContentDescriptor descriptor = getSourceOfContribution(anElement); Set<INavigatorContentDescriptor> result = new TreeSet<INavigatorContentDescriptor>(ExtensionSequenceNumberComparator.INSTANCE); if (descriptor != null) { result.add(descriptor); } result.addAll(CONTENT_DESCRIPTOR_REGISTRY .findDescriptorsForTriggerPoint(anElement, assistant, considerOverrides)); return result; } /** * Search for extensions that declare the given element in their * <b>possibleChildren</b> expression. * * @param anElement * The element to use in the query * @return The set of {@link INavigatorContentDescriptor}s that are * <i>visible</i> and <i>active</i> for this content service and * have a <b>possibleChildren</b> expression that is <i>enabled</i> * for the given element. */ public Set<INavigatorContentDescriptor> findDescriptorsWithPossibleChild(Object anElement) { return findDescriptorsWithPossibleChild(anElement, true); } /** * Search for extensions that declare the given element in their * <b>possibleChildren</b> expression. * * @param anElement * The element to use in the query * @param toComputeOverrides * True indicates the overridden tree should be traversed. * @return The set of {@link INavigatorContentDescriptor}s that are * <i>visible</i> and <i>active</i> for this content service and * have a <b>possibleChildren</b> expression that is <i>enabled</i> * for the given element. */ public Set<INavigatorContentDescriptor> findDescriptorsWithPossibleChild(Object anElement, boolean toComputeOverrides) { // Don't use the cache which is only used for triggerPoints Set<INavigatorContentDescriptor> result = new TreeSet<INavigatorContentDescriptor>(ExtensionSequenceNumberComparator.INSTANCE); result.addAll(CONTENT_DESCRIPTOR_REGISTRY .findDescriptorsForPossibleChild(anElement, assistant, toComputeOverrides)); return result; } @Override public void onExtensionActivation(String aViewerId, String[] aNavigatorExtensionId, boolean toEnable) { synchronized (this) { SafeRunner.run(new NavigatorSafeRunnable() { @Override public void run() throws Exception { NavigatorContentDescriptor key; NavigatorContentExtension extension; for (Iterator<INavigatorContentDescriptor> iter = contentExtensions.keySet().iterator(); iter .hasNext();) { key = (NavigatorContentDescriptor) iter.next(); INavigatorActivationService activation = getActivationService(); if (!activation.isNavigatorExtensionActive(key.getId())) { extension = contentExtensions .get(key); iter.remove(); extension.dispose(); } } } }); } if (structuredViewerManager != null) { structuredViewerManager.resetViewerData(); } update(); } @Override public void update() { rootContentProviders = null; NavigatorContentDescriptorManager.getInstance().clearCache(); if (structuredViewerManager != null) { structuredViewerManager.safeRefresh(); } } @Override public final String getViewerId() { return viewerDescriptor.getViewerId(); } /** * Returns the remembered data (the NavigatorContentDescriptor) associated with * an object in the viewer. This can be used to test an object's presence in the viewer. * @param element * @return the object stored as data in the viewer */ public Object getViewerElementData(Object element) { if (structuredViewerManager != null) { return structuredViewerManager.getData(element); } return null; } /** * * @param aDescriptorKey * A descriptor * @return The cached NavigatorContentExtension from the descriptor */ public final NavigatorContentExtension getExtension( INavigatorContentDescriptor aDescriptorKey) { return getExtension(aDescriptorKey, true); } /** * * @param aDescriptorKey * @param toLoadIfNecessary * True if the extension should be loaded if it is not already. * @return The instance of the extension for the given descriptor key. */ public final NavigatorContentExtension getExtension( INavigatorContentDescriptor aDescriptorKey, boolean toLoadIfNecessary) { /* Query and return the relevant descriptor instance */ NavigatorContentExtension extension = contentExtensions .get(aDescriptorKey); if (extension != null || !toLoadIfNecessary) { return extension; } /* * If the descriptor instance hasn't been created yet, then we need to * (1) verify that it wasn't added by another thread, (2) create and add * the result into the map */ synchronized (this) { extension = contentExtensions .get(aDescriptorKey); if (extension == null) { contentExtensions.put(aDescriptorKey, (extension = new NavigatorContentExtension( (NavigatorContentDescriptor) aDescriptorKey, this, structuredViewerManager))); notifyListeners(extension); } } return extension; } @Override public INavigatorViewerDescriptor getViewerDescriptor() { return viewerDescriptor; } @Override public void restoreState(final IMemento aMemento) { synchronized (this) { for (Iterator extensionItr = getExtensions().iterator(); extensionItr.hasNext();) { final NavigatorContentExtension element = (NavigatorContentExtension) extensionItr .next(); SafeRunner.run(new NavigatorSafeRunnable(((NavigatorContentDescriptor) element .getDescriptor()).getConfigElement()) { @Override public void run() throws Exception { element.restoreState(aMemento); } }); } } } @Override public void saveState(final IMemento aMemento) { synchronized (this) { for (Iterator extensionItr = getExtensions().iterator(); extensionItr.hasNext();) { final NavigatorContentExtension element = (NavigatorContentExtension) extensionItr .next(); SafeRunner.run(new NavigatorSafeRunnable(((NavigatorContentDescriptor) element .getDescriptor()).getConfigElement()) { @Override public void run() throws Exception { element.saveState(aMemento); } }); } } } @Override public boolean isActive(String anExtensionId) { return assistant.isActive(anExtensionId); } @Override public boolean isVisible(String anExtensionId) { return assistant.isVisible(anExtensionId); } protected final Collection getExtensions() { return (contentExtensions.size() > 0) ? Collections .unmodifiableCollection(contentExtensions.values()) : Collections.EMPTY_LIST; } @Override public void addListener(INavigatorContentServiceListener aListener) { listeners.add(aListener); } @Override public INavigatorFilterService getFilterService() { if (navigatorFilterService == null) { navigatorFilterService = new NavigatorFilterService(this); } return navigatorFilterService; } @Override public INavigatorSorterService getSorterService() { if (navigatorSorterService == null) { navigatorSorterService = new NavigatorSorterService(this); assistant.addListener(navigatorSorterService); } return navigatorSorterService; } @Override public INavigatorPipelineService getPipelineService() { if (navigatorPipelineService == null) { navigatorPipelineService = new NavigatorPipelineService(this); } return navigatorPipelineService; } @Override public INavigatorDnDService getDnDService() { if (navigatorDnDService == null) { navigatorDnDService = new NavigatorDnDService(this); } return navigatorDnDService; } @Override public INavigatorActivationService getActivationService() { if (navigatorActivationService == null) { navigatorActivationService = new NavigatorActivationService(this); } return navigatorActivationService; } @Override public INavigatorSaveablesService getSaveablesService() { synchronized (this) { if (navigatorSaveablesService == null) { navigatorSaveablesService = new NavigatorSaveablesService(this); assistant.addListener(navigatorSaveablesService); } return navigatorSaveablesService; } } /** * Not API as of 3.3. * * @return The extension state service for this content service. * */ public NavigatorExtensionStateService getExtensionStateService() { if (navigatorExtensionStateService == null) { navigatorExtensionStateService = new NavigatorExtensionStateService( this); } return navigatorExtensionStateService; } /** * Non-API method to return a shell. * * @return A shell associated with the current viewer (if any) or * <b>null</b>. */ public Shell getShell() { if (structuredViewerManager != null && structuredViewerManager.getViewer() != null) { return structuredViewerManager.getViewer().getControl().getShell(); } return null; } protected boolean isRootExtension(String anExtensionId) { return assistant.isRootExtension(anExtensionId); } @Override public void removeListener(INavigatorContentServiceListener aListener) { listeners.remove(aListener); } @Override public String toString() { return "ContentService[" + viewerDescriptor.getViewerId() + "]"; //$NON-NLS-1$//$NON-NLS-2$ } private void notifyListeners(final NavigatorContentExtension aDescriptorInstance) { if (listeners.size() == 0) { return; } final List<INavigatorContentServiceListener> failedListeners = new ArrayList<INavigatorContentServiceListener>(); for (INavigatorContentServiceListener listener : listeners) { SafeRunner.run(new NavigatorSafeRunnable() { @Override public void run() throws Exception { listener.onLoad(aDescriptorInstance); } @Override public void handleException(Throwable e) { super.handleException(e); failedListeners.add(listener); } }); } if (failedListeners.size() > 0) { listeners.removeAll(failedListeners); } } private ITreeContentProvider[] extractContentProviders( Set<NavigatorContentExtension> theDescriptorInstances) { if (theDescriptorInstances.size() == 0) { return NO_CONTENT_PROVIDERS; } List<SafeDelegateTreeContentProvider> resultProvidersList = new ArrayList<SafeDelegateTreeContentProvider>(); for (NavigatorContentExtension navigatorContentExtension : theDescriptorInstances) { resultProvidersList.add(navigatorContentExtension.internalGetContentProvider()); } return resultProvidersList .toArray(new ITreeContentProvider[resultProvidersList.size()]); } private Set<NavigatorContentExtension> extractDescriptorInstances(Set<INavigatorContentDescriptor> theDescriptors, boolean toLoadAllIfNecessary) { if (theDescriptors.size() == 0) { return Collections.EMPTY_SET; } Set<NavigatorContentExtension> resultInstances = new TreeSet<NavigatorContentExtension>(ExtensionSequenceNumberComparator.INSTANCE); for (INavigatorContentDescriptor iNavigatorContentDescriptor : theDescriptors) { NavigatorContentExtension extension = getExtension(iNavigatorContentDescriptor, toLoadAllIfNecessary); if (extension != null) { resultInstances.add(extension); } } return resultInstances; } /** * @return the viewer */ public Viewer getViewer() { return structuredViewerManager.getViewer(); } /** * Get our preferences */ static IEclipsePreferences getPreferencesRoot() { IEclipsePreferences root = (IEclipsePreferences) Platform.getPreferencesService().getRootNode().node( InstanceScope.SCOPE); return (IEclipsePreferences) root.node(NavigatorPlugin.PLUGIN_ID); } static void flushPreferences(IEclipsePreferences prefs) { try { prefs.flush(); } catch (BackingStoreException e) { IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, IStatus.ERROR, CommonNavigatorMessages.NavigatorContentService_problemSavingPreferences, e); Platform.getLog(Platform.getBundle(NavigatorPlugin.PLUGIN_ID)).log(status); } } }