0001: /*******************************************************************************
0002: * Copyright (c) 2003, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.ui.internal.navigator;
0011:
0012: import java.util.ArrayList;
0013: import java.util.Collection;
0014: import java.util.Collections;
0015: import java.util.HashMap;
0016: import java.util.HashSet;
0017: import java.util.Iterator;
0018: import java.util.List;
0019: import java.util.Map;
0020: import java.util.Set;
0021: import java.util.SortedSet;
0022: import java.util.TreeSet;
0023: import java.util.WeakHashMap;
0024:
0025: import org.eclipse.core.runtime.ISafeRunnable;
0026: import org.eclipse.core.runtime.SafeRunner;
0027: import org.eclipse.jface.viewers.ILabelProvider;
0028: import org.eclipse.jface.viewers.ITreeContentProvider;
0029: import org.eclipse.jface.viewers.StructuredViewer;
0030: import org.eclipse.jface.viewers.Viewer;
0031: import org.eclipse.swt.widgets.Shell;
0032: import org.eclipse.ui.IMemento;
0033: import org.eclipse.ui.internal.navigator.dnd.NavigatorDnDService;
0034: import org.eclipse.ui.internal.navigator.extensions.ExtensionPriorityComparator;
0035: import org.eclipse.ui.internal.navigator.extensions.NavigatorContentDescriptor;
0036: import org.eclipse.ui.internal.navigator.extensions.NavigatorContentDescriptorManager;
0037: import org.eclipse.ui.internal.navigator.extensions.NavigatorContentExtension;
0038: import org.eclipse.ui.internal.navigator.extensions.NavigatorViewerDescriptor;
0039: import org.eclipse.ui.internal.navigator.extensions.NavigatorViewerDescriptorManager;
0040: import org.eclipse.ui.internal.navigator.extensions.StructuredViewerManager;
0041: import org.eclipse.ui.internal.navigator.sorters.NavigatorSorterService;
0042: import org.eclipse.ui.navigator.IDescriptionProvider;
0043: import org.eclipse.ui.navigator.IExtensionActivationListener;
0044: import org.eclipse.ui.navigator.IExtensionStateModel;
0045: import org.eclipse.ui.navigator.IMementoAware;
0046: import org.eclipse.ui.navigator.INavigatorActivationService;
0047: import org.eclipse.ui.navigator.INavigatorContentDescriptor;
0048: import org.eclipse.ui.navigator.INavigatorContentExtension;
0049: import org.eclipse.ui.navigator.INavigatorContentService;
0050: import org.eclipse.ui.navigator.INavigatorContentServiceListener;
0051: import org.eclipse.ui.navigator.INavigatorDnDService;
0052: import org.eclipse.ui.navigator.INavigatorFilterService;
0053: import org.eclipse.ui.navigator.INavigatorPipelineService;
0054: import org.eclipse.ui.navigator.INavigatorSaveablesService;
0055: import org.eclipse.ui.navigator.INavigatorSorterService;
0056: import org.eclipse.ui.navigator.INavigatorViewerDescriptor;
0057:
0058: /**
0059: * <p>
0060: * Provides centralized access to the information provided by
0061: * NavigatorContentExtensions. Can be instantiated as needed, but should be
0062: * cached for active viewers. Information specific to a given viewer will be
0063: * cached by the NavigatorContentService, not including ContentProviders and
0064: * Label Providers created by {@link #createCommonContentProvider()}and
0065: * {@link #createCommonLabelProvider()}respectively.
0066: * </p>
0067: *
0068: * <p>
0069: * The following class is experimental until fully documented.
0070: * </p>
0071: */
0072: public class NavigatorContentService implements
0073: IExtensionActivationListener, IMementoAware,
0074: INavigatorContentService {
0075:
0076: private static final NavigatorContentDescriptorManager CONTENT_DESCRIPTOR_REGISTRY = NavigatorContentDescriptorManager
0077: .getInstance();
0078:
0079: private static final NavigatorViewerDescriptorManager VIEWER_DESCRIPTOR_REGISTRY = NavigatorViewerDescriptorManager
0080: .getInstance();
0081:
0082: private static final ITreeContentProvider[] NO_CONTENT_PROVIDERS = new ITreeContentProvider[0];
0083:
0084: private static final ILabelProvider[] NO_LABEL_PROVIDERS = new ILabelProvider[0];
0085:
0086: private static final INavigatorContentDescriptor[] NO_DESCRIPTORS = new INavigatorContentDescriptor[0];
0087:
0088: private static final String[] NO_EXTENSION_IDS = new String[0];
0089:
0090: private final NavigatorViewerDescriptor viewerDescriptor;
0091:
0092: private final List listeners = new ArrayList();
0093:
0094: /*
0095: * A map of (String-based-Navigator-Content-Extension-IDs,
0096: * NavigatorContentExtension-objects)-pairs
0097: */
0098: private final Map contentExtensions = new HashMap();
0099:
0100: private StructuredViewerManager structuredViewerManager;
0101:
0102: private ITreeContentProvider[] rootContentProviders;
0103:
0104: private WeakHashMap contributionMemory;
0105:
0106: private ITreeContentProvider contentProvider;
0107:
0108: private ILabelProvider labelProvider;
0109:
0110: private final VisibilityAssistant assistant;
0111:
0112: private NavigatorFilterService navigatorFilterService;
0113:
0114: private INavigatorSorterService navigatorSorterService;
0115:
0116: private INavigatorPipelineService navigatorPipelineService;
0117:
0118: private INavigatorDnDService navigatorDnDService;
0119:
0120: private INavigatorActivationService navigatorActivationService;
0121:
0122: private NavigatorSaveablesService navigatorSaveablesService;
0123:
0124: private NavigatorExtensionStateService navigatorExtensionStateService;
0125:
0126: private IDescriptionProvider descriptionProvider;
0127:
0128: private boolean contentProviderInitialized;
0129:
0130: private boolean labelProviderInitialized;
0131:
0132: /**
0133: * @param aViewerId
0134: * The viewer id for this content service; normally from the
0135: * <b>org.eclipse.ui.views</b> extension.
0136: */
0137: public NavigatorContentService(String aViewerId) {
0138: super ();
0139: aViewerId = aViewerId != null ? aViewerId : ""; //$NON-NLS-1$
0140: viewerDescriptor = VIEWER_DESCRIPTOR_REGISTRY
0141: .getNavigatorViewerDescriptor(aViewerId);
0142: assistant = new VisibilityAssistant(viewerDescriptor,
0143: getActivationService());
0144: getActivationService().addExtensionActivationListener(this );
0145: }
0146:
0147: /**
0148: * @param aViewerId
0149: * The viewer id for this content service; normally from the
0150: * <b>org.eclipse.ui.views</b> extension.
0151: * @param aViewer
0152: * The viewer that this content service will be associated with.
0153: */
0154: public NavigatorContentService(String aViewerId,
0155: StructuredViewer aViewer) {
0156: this (aViewerId);
0157: structuredViewerManager = new StructuredViewerManager(aViewer);
0158: }
0159:
0160: public String[] getVisibleExtensionIds() {
0161:
0162: List visibleExtensionIds = new ArrayList();
0163:
0164: NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY
0165: .getAllContentDescriptors();
0166: for (int i = 0; i < descriptors.length; i++) {
0167: if (assistant.isVisible(descriptors[i].getId())) {
0168: visibleExtensionIds.add(descriptors[i].getId());
0169: }
0170: }
0171: if (visibleExtensionIds.isEmpty()) {
0172: return NO_EXTENSION_IDS;
0173: }
0174: return (String[]) visibleExtensionIds
0175: .toArray(new String[visibleExtensionIds.size()]);
0176:
0177: }
0178:
0179: public INavigatorContentDescriptor[] getVisibleExtensions() {
0180: List visibleDescriptors = new ArrayList();
0181:
0182: NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY
0183: .getAllContentDescriptors();
0184: for (int i = 0; i < descriptors.length; i++) {
0185: if (assistant.isVisible(descriptors[i].getId())) {
0186: visibleDescriptors.add(descriptors[i]);
0187: }
0188: }
0189: if (visibleDescriptors.isEmpty()) {
0190: return NO_DESCRIPTORS;
0191: }
0192: return (INavigatorContentDescriptor[]) visibleDescriptors
0193: .toArray(new INavigatorContentDescriptor[visibleDescriptors
0194: .size()]);
0195:
0196: }
0197:
0198: /* package */INavigatorContentDescriptor[] getActiveDescriptorsWithSaveables() {
0199: List result = new ArrayList();
0200:
0201: NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY
0202: .getContentDescriptorsWithSaveables();
0203: for (int i = 0; i < descriptors.length; i++) {
0204: if (assistant.isVisible(descriptors[i].getId())
0205: && assistant.isActive(descriptors[i])) {
0206: result.add(descriptors[i]);
0207: }
0208: }
0209: if (result.isEmpty()) {
0210: return NO_DESCRIPTORS;
0211: }
0212: return (INavigatorContentDescriptor[]) result
0213: .toArray(new INavigatorContentDescriptor[result.size()]);
0214:
0215: }
0216:
0217: /*
0218: * (non-Javadoc)
0219: *
0220: * @see org.eclipse.ui.navigator.INavigatorContentService#bindExtensions(java.lang.String[],
0221: * boolean)
0222: */
0223: public INavigatorContentDescriptor[] bindExtensions(
0224: String[] extensionIds, boolean isRoot) {
0225: if (extensionIds == null || extensionIds.length == 0) {
0226: return NO_DESCRIPTORS;
0227: }
0228:
0229: for (int i = 0; i < extensionIds.length; i++) {
0230: assistant.bindExtensions(extensionIds, isRoot);
0231: }
0232: Set boundDescriptors = new HashSet();
0233: INavigatorContentDescriptor descriptor;
0234: for (int i = 0; i < extensionIds.length; i++) {
0235: descriptor = CONTENT_DESCRIPTOR_REGISTRY
0236: .getContentDescriptor(extensionIds[i]);
0237: if (descriptor != null) {
0238: boundDescriptors.add(descriptor);
0239: }
0240: }
0241:
0242: if (boundDescriptors.size() == 0) {
0243: return NO_DESCRIPTORS;
0244: }
0245: return (INavigatorContentDescriptor[]) boundDescriptors
0246: .toArray(new INavigatorContentDescriptor[boundDescriptors
0247: .size()]);
0248:
0249: }
0250:
0251: /*
0252: * (non-Javadoc)
0253: *
0254: * @see org.eclipse.ui.internal.navigator.INavigatorContentService#createCommonContentProvider()
0255: */
0256: public ITreeContentProvider createCommonContentProvider() {
0257: if (contentProviderInitialized) {
0258: return contentProvider;
0259: }
0260: synchronized (this ) {
0261: if (contentProvider == null) {
0262: contentProvider = new NavigatorContentServiceContentProvider(
0263: this );
0264: }
0265: contentProviderInitialized = true;
0266: }
0267: return contentProvider;
0268: }
0269:
0270: /*
0271: * (non-Javadoc)
0272: *
0273: * @see org.eclipse.ui.internal.navigator.INavigatorContentService#createCommonLabelProvider()
0274: */
0275: public ILabelProvider createCommonLabelProvider() {
0276: if (labelProviderInitialized) {
0277: return labelProvider;
0278: }
0279: synchronized (this ) {
0280: if (labelProvider == null) {
0281: labelProvider = new NavigatorContentServiceLabelProvider(
0282: this );
0283: }
0284: labelProviderInitialized = true;
0285: }
0286: return labelProvider;
0287: }
0288:
0289: /*
0290: * (non-Javadoc)
0291: *
0292: * @see org.eclipse.ui.navigator.INavigatorContentService#createCommonDescriptionProvider()
0293: */
0294: public IDescriptionProvider createCommonDescriptionProvider() {
0295: if (descriptionProvider != null) {
0296: return descriptionProvider;
0297: }
0298: synchronized (this ) {
0299: if (descriptionProvider == null) {
0300: descriptionProvider = new NavigatorContentServiceDescriptionProvider(
0301: this );
0302: }
0303: }
0304: return descriptionProvider;
0305: }
0306:
0307: /*
0308: * (non-Javadoc)
0309: *
0310: * @see org.eclipse.ui.internal.navigator.INavigatorContentService#dispose()
0311: */
0312: public void dispose() {
0313: if (navigatorSaveablesService != null) {
0314: assistant.removeListener(navigatorSaveablesService);
0315: }
0316: for (Iterator contentItr = contentExtensions.values()
0317: .iterator(); contentItr.hasNext();) {
0318: ((NavigatorContentExtension) contentItr.next()).dispose();
0319: }
0320: getActivationService().removeExtensionActivationListener(this );
0321: assistant.dispose();
0322: }
0323:
0324: protected void updateService(Viewer aViewer, Object anOldInput,
0325: Object aNewInput) {
0326:
0327: synchronized (this ) {
0328:
0329: if (structuredViewerManager == null) {
0330: structuredViewerManager = new StructuredViewerManager(
0331: aViewer);
0332: structuredViewerManager.inputChanged(anOldInput,
0333: aNewInput);
0334: } else {
0335: structuredViewerManager.inputChanged(aViewer,
0336: anOldInput, aNewInput);
0337: }
0338:
0339: for (Iterator contentItr = contentExtensions.values()
0340: .iterator(); contentItr.hasNext();) {
0341: NavigatorContentExtension ext = (NavigatorContentExtension) contentItr
0342: .next();
0343: if (ext.isLoaded()) {
0344: structuredViewerManager.initialize(ext
0345: .getContentProvider());
0346: }
0347: }
0348:
0349: rootContentProviders = extractContentProviders(findRootContentExtensions(aNewInput));
0350: }
0351: }
0352:
0353: public IExtensionStateModel findStateModel(String anExtensionId) {
0354: if (anExtensionId == null) {
0355: return null;
0356: }
0357: INavigatorContentDescriptor desc = CONTENT_DESCRIPTOR_REGISTRY
0358: .getContentDescriptor(anExtensionId);
0359: if (desc == null) {
0360: return null;
0361: }
0362: INavigatorContentExtension ext = getExtension(desc);
0363: if (ext == null) {
0364: return null;
0365: }
0366: return ext.getStateModel();
0367: }
0368:
0369: /**
0370: * Return a set of content providers that could provide a parent for the
0371: * given element. These content extensions are determined by consulting the
0372: * <b>possibleChildren</b> expression in the <b>navigatorContent</b>
0373: * extension.
0374: *
0375: * <p>
0376: * Clients that wish to tap into the link with editor support must describe
0377: * all of their possible children in their <b>possibleChildren</b>
0378: * expressions.
0379: * </p>
0380: *
0381: * @param anElement
0382: * An element from the tree (generally from a setSelection()
0383: * method).
0384: * @return The set of content providers that may be able to provide a
0385: * parent.
0386: */
0387: public ITreeContentProvider[] findParentContentProviders(
0388: Object anElement) {
0389: return extractContentProviders(findContentExtensionsWithPossibleChild(anElement));
0390: }
0391:
0392: /**
0393: * <p>
0394: * Return all of the content providers that are relevant for the viewer. The
0395: * viewer is determined by the ID used to create the
0396: * INavigatorContentService ({@link #getViewerId() }). See
0397: * {@link #createCommonContentProvider() } for more information about how
0398: * content providers are located for the root of the viewer. The root
0399: * content providers are calculated once. If a new element is supplied, a
0400: * client must call {@link #update() } prior in order to reset the
0401: * calculated root providers.
0402: * </p>
0403: *
0404: * @param anElement
0405: * An element from the tree (generally the input of the viewer)
0406: * @return The set of content providers that can provide root elements for a
0407: * viewer.
0408: */
0409: public ITreeContentProvider[] findRootContentProviders(
0410: Object anElement) {
0411: if (rootContentProviders != null) {
0412: return rootContentProviders;
0413: }
0414: synchronized (this ) {
0415: if (rootContentProviders == null) {
0416: rootContentProviders = extractContentProviders(findRootContentExtensions(anElement));
0417:
0418: }
0419: }
0420: return rootContentProviders;
0421: }
0422:
0423: /**
0424: *
0425: * Return all of the label providers that are enabled for the given element.
0426: * A label provider is 'enabled' if its corresponding content provider
0427: * returned the element, or the element is described in the content
0428: * extension's <b>triggerPoints</b> expression.
0429: *
0430: * @param anElement
0431: * An element from the tree (any element contributed to the
0432: * tree).
0433: * @return The set of label providers that may be able to provide a valid
0434: * (non-null) label.
0435: */
0436: public ILabelProvider[] findRelevantLabelProviders(Object anElement) {
0437: return extractLabelProviders(findContentExtensionsWithPossibleChild(
0438: anElement, false));
0439: }
0440:
0441: /**
0442: * Search for extensions that declare the given element in their
0443: * <b>triggerPoints</b> expression.
0444: *
0445: * @param anElement
0446: * The element to use in the query
0447: * @return The set of {@link INavigatorContentExtension}s that are
0448: * <i>visible</i> and <i>active</i> for this content service and
0449: * either declared through a
0450: * <b>org.eclipse.ui.navigator.viewer/viewerContentBinding</b> to
0451: * be a root element or have a <b>triggerPoints</b> expression that
0452: * is <i>enabled</i> for the given element.
0453: */
0454: public Set findRootContentExtensions(Object anElement) {
0455: return findRootContentExtensions(anElement, true);
0456: }
0457:
0458: /**
0459: * Search for extensions that declare the given element in their
0460: * <b>triggerPoints</b> expression.
0461: *
0462: * @param anElement
0463: * The element to use in the query
0464: * @param toRespectViewerRoots
0465: * True respect the <b>viewerContentBinding</b>s, False will
0466: * look only for matching <b>triggerPoints</b> expressions.
0467: * @return The set of {@link INavigatorContentExtension}s that are
0468: * <i>visible</i> and <i>active</i> for this content service and
0469: * either declared through a
0470: * <b>org.eclipse.ui.navigator.viewer/viewerContentBinding</b> to
0471: * be a root element or have a <b>triggerPoints</b> expression that
0472: * is <i>enabled</i> for the given element.
0473: */
0474: public Set findRootContentExtensions(Object anElement,
0475: boolean toRespectViewerRoots) {
0476:
0477: SortedSet rootExtensions = new TreeSet(
0478: ExtensionPriorityComparator.INSTANCE);
0479: if (toRespectViewerRoots
0480: && viewerDescriptor.hasOverriddenRootExtensions()) {
0481:
0482: NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY
0483: .getAllContentDescriptors();
0484:
0485: NavigatorContentExtension extension = null;
0486: for (int i = 0; i < descriptors.length; i++) {
0487: if (isActive(descriptors[i].getId())
0488: && isRootExtension(descriptors[i].getId())) {
0489: extension = getExtension(descriptors[i]);
0490: if (!extension.hasLoadingFailed()) {
0491: rootExtensions.add(extension);
0492: }
0493: }
0494: }
0495: }
0496: if (rootExtensions.isEmpty()) {
0497: return findContentExtensionsByTriggerPoint(anElement);
0498: }
0499: return rootExtensions;
0500: }
0501:
0502: /**
0503: * Search for extensions that declare the given element in their
0504: * <b>possibleChildren</b> expression.
0505: *
0506: * @param anElement
0507: * The element to use in the query
0508: * @return The set of {@link INavigatorContentExtension}s that are
0509: * <i>visible</i> and <i>active</i> for this content service and
0510: * have a <b>possibleChildren</b> expression that is <i>enabled</i>
0511: * for the given element.
0512: */
0513: public Set findOverrideableContentExtensionsByTriggerPoint(
0514: Object anElement) {
0515: Set overrideableExtensions = new TreeSet(
0516: ExtensionPriorityComparator.INSTANCE);
0517: Set descriptors = findDescriptorsByTriggerPoint(anElement);
0518: for (Iterator iter = descriptors.iterator(); iter.hasNext();) {
0519: INavigatorContentDescriptor descriptor = (INavigatorContentDescriptor) iter
0520: .next();
0521: if (descriptor.hasOverridingExtensions()) {
0522: overrideableExtensions.add(getExtension(descriptor));
0523: }
0524: }
0525: return overrideableExtensions;
0526: }
0527:
0528: /**
0529: * Search for extensions that declare the given element in their
0530: * <b>possibleChildren</b> expression.
0531: *
0532: * @param anElement
0533: * The element to use in the query
0534: * @return The set of {@link INavigatorContentExtension}s that are
0535: * <i>visible</i> and <i>active</i> for this content service and
0536: * have a <b>possibleChildren</b> expression that is <i>enabled</i>
0537: * for the given element.
0538: */
0539: public Set findOverrideableContentExtensionsForPossibleChild(
0540: Object anElement) {
0541: Set overrideableExtensions = new TreeSet(
0542: ExtensionPriorityComparator.INSTANCE);
0543: Set descriptors = findDescriptorsWithPossibleChild(anElement,
0544: false);
0545: for (Iterator iter = descriptors.iterator(); iter.hasNext();) {
0546: INavigatorContentDescriptor descriptor = (INavigatorContentDescriptor) iter
0547: .next();
0548: if (descriptor.hasOverridingExtensions()) {
0549: overrideableExtensions.add(getExtension(descriptor));
0550: }
0551: }
0552: return overrideableExtensions;
0553: }
0554:
0555: /*
0556: * (Non-Javadoc)
0557: *
0558: * @see INavigatorContentService#getContentDescriptorById(String)
0559: */
0560: public INavigatorContentDescriptor getContentDescriptorById(
0561: String anExtensionId) {
0562: return CONTENT_DESCRIPTOR_REGISTRY
0563: .getContentDescriptor(anExtensionId);
0564: }
0565:
0566: /**
0567: *
0568: * @param anExtensionId The id used to define the <b>org.eclipse.ui.navigator.navigatorContent/navigatorContent</b> extension.
0569: * @return An instance of the content extension for the given extension id. May return <b>null</b> if the id is invalid.
0570: */
0571: public INavigatorContentExtension getContentExtensionById(
0572: String anExtensionId) {
0573: NavigatorContentDescriptor descriptor = CONTENT_DESCRIPTOR_REGISTRY
0574: .getContentDescriptor(anExtensionId);
0575: if (descriptor != null)
0576: return getExtension(descriptor);
0577: return null;
0578: }
0579:
0580: /**
0581: * Search for extensions that declare the given element in their
0582: * <b>triggerPoints</b> expression.
0583: *
0584: * @param anElement
0585: * The element to use in the query
0586: * @return The set of {@link INavigatorContentExtension}s that are
0587: * <i>visible</i> and <i>active</i> for this content service and
0588: * have a <b>triggerPoints</b> expression that is <i>enabled</i>
0589: * for the given element.
0590: */
0591: public Set findContentExtensionsByTriggerPoint(Object anElement) {
0592: return findContentExtensionsByTriggerPoint(anElement, true);
0593: }
0594:
0595: /**
0596: * Search for extensions that declare the given element in their
0597: * <b>triggerPoints</b> expression.
0598: *
0599: * @param anElement
0600: * The element to use in the query
0601: * @param toLoadIfNecessary
0602: * True will force the load of the extension, False will not
0603: * @return The set of {@link INavigatorContentExtension}s that are
0604: * <i>visible</i> and <i>active</i> for this content service and
0605: * have a <b>triggerPoints</b> expression that is <i>enabled</i>
0606: * for the given element.
0607: */
0608: public Set findContentExtensionsByTriggerPoint(Object anElement,
0609: boolean toLoadIfNecessary) {
0610: Set enabledDescriptors = findDescriptorsByTriggerPoint(anElement);
0611: return extractDescriptorInstances(enabledDescriptors,
0612: toLoadIfNecessary);
0613: }
0614:
0615: /**
0616: * Search for extensions that declare the given element in their
0617: * <b>possibleChildren</b> expression.
0618: *
0619: * @param anElement
0620: * The element to use in the query
0621: * @return The set of {@link INavigatorContentExtension}s that are
0622: * <i>visible</i> and <i>active</i> for this content service and
0623: * have a <b>possibleChildren</b> expression that is <i>enabled</i>
0624: * for the given element.
0625: */
0626: public Set findContentExtensionsWithPossibleChild(Object anElement) {
0627: return findContentExtensionsWithPossibleChild(anElement, true);
0628: }
0629:
0630: /**
0631: * Search for extensions that declare the given element in their
0632: * <b>possibleChildren</b> expression.
0633: *
0634: * @param anElement
0635: * The element to use in the query
0636: * @param toLoadIfNecessary
0637: * True will force the load of the extension, False will not
0638: * @return The set of {@link INavigatorContentExtension}s that are
0639: * <i>visible</i> and <i>active</i> for this content service and
0640: * have a <b>possibleChildren</b> expression that is <i>enabled</i>
0641: * for the given element.
0642: */
0643: public Set findContentExtensionsWithPossibleChild(Object anElement,
0644: boolean toLoadIfNecessary) {
0645: Set enabledDescriptors = findDescriptorsWithPossibleChild(anElement);
0646: return extractDescriptorInstances(enabledDescriptors,
0647: toLoadIfNecessary);
0648: }
0649:
0650: /**
0651: * Remember that the elements in the given array came from the given source
0652: *
0653: * @param source
0654: * The descriptor of the extension that contributed the set of
0655: * elements.
0656: * @param elements
0657: * An array of elements from the given source.
0658: */
0659: public synchronized void rememberContribution(
0660: NavigatorContentDescriptor source, Object[] elements) {
0661:
0662: if (source != null && elements != null) {
0663: for (int i = 0; i < elements.length; i++) {
0664: getContributionMemory().put(elements[i], source);
0665: }
0666: }
0667: }
0668:
0669: /**
0670: * Remember that the elements in the given array came from the given source
0671: *
0672: * @param source
0673: * The descriptor of the extension that contributed the set of
0674: * elements.
0675: * @param element
0676: * An element from the given source.
0677: */
0678: public synchronized void rememberContribution(
0679: NavigatorContentDescriptor source, Object element) {
0680: if (source != null && element != null) {
0681: getContributionMemory().put(element, source);
0682: }
0683: }
0684:
0685: /**
0686: *
0687: * @param element
0688: * The element contributed by the descriptor to be returned
0689: * @return The descriptor that contributed the element or null.
0690: * @see #findContentExtensionsWithPossibleChild(Object)
0691: */
0692: public NavigatorContentDescriptor getSourceOfContribution(
0693: Object element) {
0694: return (NavigatorContentDescriptor) getContributionMemory()
0695: .get(element);
0696: }
0697:
0698: /**
0699: * @return Returns the contributionMemory.
0700: */
0701: public Map getContributionMemory() {
0702: if (contributionMemory != null) {
0703: return contributionMemory;
0704: }
0705: synchronized (this ) {
0706: if (contributionMemory == null) {
0707: contributionMemory = new WeakHashMap();
0708: }
0709: }
0710:
0711: return contributionMemory;
0712: }
0713:
0714: /**
0715: * Search for extensions that declare the given element in their
0716: * <b>triggerPoints</b> expression.
0717: *
0718: * @param anElement
0719: * The element to use in the query
0720: *
0721: * @return The set of {@link INavigatorContentDescriptor}s that are
0722: * <i>visible</i> and <i>active</i> for this content service and
0723: * have a <b>triggerPoints</b> expression that is <i>enabled</i>
0724: * for the given element.
0725: */
0726: public Set findDescriptorsByTriggerPoint(Object anElement) {
0727:
0728: NavigatorContentDescriptor descriptor = getSourceOfContribution(anElement);
0729: Set result = new TreeSet(ExtensionPriorityComparator.INSTANCE);
0730: if (descriptor != null) {
0731: result.add(descriptor);
0732: }
0733: result.addAll(CONTENT_DESCRIPTOR_REGISTRY
0734: .findDescriptorsForTriggerPoint(anElement, assistant));
0735: return result;
0736: }
0737:
0738: /**
0739: * Search for extensions that declare the given element in their
0740: * <b>possibleChildren</b> expression.
0741: *
0742: * @param anElement
0743: * The element to use in the query
0744: * @return The set of {@link INavigatorContentDescriptor}s that are
0745: * <i>visible</i> and <i>active</i> for this content service and
0746: * have a <b>possibleChildren</b> expression that is <i>enabled</i>
0747: * for the given element.
0748: */
0749: public Set findDescriptorsWithPossibleChild(Object anElement) {
0750: return findDescriptorsWithPossibleChild(anElement, true);
0751: }
0752:
0753: /**
0754: * Search for extensions that declare the given element in their
0755: * <b>possibleChildren</b> expression.
0756: *
0757: * @param anElement
0758: * The element to use in the query
0759: * @param toComputeOverrides
0760: * True indicates the overridden tree should be traversed.
0761: * @return The set of {@link INavigatorContentDescriptor}s that are
0762: * <i>visible</i> and <i>active</i> for this content service and
0763: * have a <b>possibleChildren</b> expression that is <i>enabled</i>
0764: * for the given element.
0765: */
0766: public Set findDescriptorsWithPossibleChild(Object anElement,
0767: boolean toComputeOverrides) {
0768:
0769: NavigatorContentDescriptor descriptor = getSourceOfContribution(anElement);
0770: Set result = new TreeSet(ExtensionPriorityComparator.INSTANCE);
0771: if (descriptor != null) {
0772: result.add(descriptor);
0773: }
0774: result.addAll(CONTENT_DESCRIPTOR_REGISTRY
0775: .findDescriptorsForPossibleChild(anElement, assistant,
0776: toComputeOverrides));
0777: return result;
0778: }
0779:
0780: /*
0781: * (non-Javadoc)
0782: *
0783: * @see org.eclipse.ui.internal.navigator.INavigatorContentService#onExtensionActivation(java.lang.String,
0784: * java.lang.String, boolean)
0785: */
0786: public void onExtensionActivation(String aViewerId,
0787: String[] aNavigatorExtensionId, boolean toEnable) {
0788: synchronized (this ) {
0789: try {
0790: NavigatorContentDescriptor key;
0791: NavigatorContentExtension extension;
0792: for (Iterator iter = contentExtensions.keySet()
0793: .iterator(); iter.hasNext();) {
0794: key = (NavigatorContentDescriptor) iter.next();
0795: INavigatorActivationService activation = getActivationService();
0796: if (!activation.isNavigatorExtensionActive(key
0797: .getId())) {
0798: extension = (NavigatorContentExtension) contentExtensions
0799: .get(key);
0800: iter.remove();
0801: /* There really shouldn't be any way that this
0802: can be null, but just to be safe */
0803: if (extension != null) {
0804: extension.dispose();
0805: }
0806: }
0807: }
0808: } catch (RuntimeException e) {
0809: String msg = e.getMessage() != null ? e.getMessage()
0810: : e.toString();
0811: NavigatorPlugin.logError(0, msg, e);
0812: }
0813: }
0814: update();
0815: }
0816:
0817: /*
0818: * (non-Javadoc)
0819: *
0820: * @see org.eclipse.ui.internal.navigator.INavigatorContentService#update()
0821: */
0822: public void update() {
0823: rootContentProviders = null;
0824: if (structuredViewerManager != null) {
0825: structuredViewerManager.safeRefresh();
0826: }
0827: }
0828:
0829: /*
0830: * (non-Javadoc)
0831: *
0832: * @see org.eclipse.ui.internal.navigator.INavigatorContentService#getViewerId()
0833: */
0834: public final String getViewerId() {
0835: return viewerDescriptor.getViewerId();
0836: }
0837:
0838: /**
0839: *
0840: * @param aDescriptorKey
0841: * A descriptor
0842: * @return The cached NavigatorContentExtension from the descriptor
0843: */
0844: public final NavigatorContentExtension getExtension(
0845: INavigatorContentDescriptor aDescriptorKey) {
0846: return getExtension(aDescriptorKey, true);
0847: }
0848:
0849: /**
0850: *
0851: * @param aDescriptorKey
0852: * @param toLoadIfNecessary
0853: * True if the extension should be loaded if it is not already.
0854: * @return The instance of the extension for the given descriptor key.
0855: */
0856: public final NavigatorContentExtension getExtension(
0857: INavigatorContentDescriptor aDescriptorKey,
0858: boolean toLoadIfNecessary) {
0859: /* Query and return the relevant descriptor instance */
0860: NavigatorContentExtension extension = (NavigatorContentExtension) contentExtensions
0861: .get(aDescriptorKey);
0862: if (extension != null || !toLoadIfNecessary) {
0863: return extension;
0864: }
0865:
0866: /*
0867: * If the descriptor instance hasn't been created yet, then we need to
0868: * (1) verify that it wasn't added by another thread, (2) create and add
0869: * the result into the map
0870: */
0871: synchronized (this ) {
0872: extension = (NavigatorContentExtension) contentExtensions
0873: .get(aDescriptorKey);
0874: if (extension == null) {
0875: contentExtensions
0876: .put(
0877: aDescriptorKey,
0878: (extension = new NavigatorContentExtension(
0879: (NavigatorContentDescriptor) aDescriptorKey,
0880: this , structuredViewerManager)));
0881: notifyListeners(extension);
0882: }
0883: }
0884: return extension;
0885:
0886: }
0887:
0888: /*
0889: * (non-Javadoc)
0890: *
0891: * @see org.eclipse.ui.internal.navigator.INavigatorContentService#getViewerDescriptor()
0892: */
0893: public INavigatorViewerDescriptor getViewerDescriptor() {
0894: return viewerDescriptor;
0895: }
0896:
0897: /*
0898: * (non-Javadoc)
0899: *
0900: * @see org.eclipse.ui.internal.navigator.INavigatorContentService#restoreState(org.eclipse.ui.IMemento)
0901: */
0902: public void restoreState(final IMemento aMemento) {
0903: synchronized (this ) {
0904: for (Iterator extensionItr = getExtensions().iterator(); extensionItr
0905: .hasNext();) {
0906: final NavigatorContentExtension element = (NavigatorContentExtension) extensionItr
0907: .next();
0908: ISafeRunnable runnable = new ISafeRunnable() {
0909: public void run() throws Exception {
0910: element.restoreState(aMemento);
0911:
0912: }
0913:
0914: public void handleException(Throwable exception) {
0915: NavigatorPlugin.logError(0,
0916: "Could not restore state for Common Navigator content extension" //$NON-NLS-1$
0917: + element.getId(), exception);
0918:
0919: }
0920: };
0921: SafeRunner.run(runnable);
0922:
0923: }
0924: }
0925: }
0926:
0927: /*
0928: * (non-Javadoc)
0929: *
0930: * @see org.eclipse.ui.internal.navigator.INavigatorContentService#saveState(org.eclipse.ui.IMemento)
0931: */
0932: public void saveState(IMemento aMemento) {
0933: synchronized (this ) {
0934: for (Iterator extensionItr = getExtensions().iterator(); extensionItr
0935: .hasNext();) {
0936: NavigatorContentExtension element = (NavigatorContentExtension) extensionItr
0937: .next();
0938: element.saveState(aMemento);
0939: }
0940: }
0941: }
0942:
0943: public boolean isActive(String anExtensionId) {
0944: return assistant.isActive(anExtensionId);
0945: }
0946:
0947: public boolean isVisible(String anExtensionId) {
0948: return assistant.isVisible(anExtensionId);
0949: }
0950:
0951: protected final Collection getExtensions() {
0952: return (contentExtensions.size() > 0) ? Collections
0953: .unmodifiableCollection(contentExtensions.values())
0954: : Collections.EMPTY_LIST;
0955: }
0956:
0957: /*
0958: * (non-Javadoc)
0959: *
0960: * @see org.eclipse.ui.internal.navigator.INavigatorContentService#addListener(org.eclipse.ui.internal.navigator.extensions.INavigatorContentServiceListener)
0961: */
0962: public void addListener(INavigatorContentServiceListener aListener) {
0963: listeners.add(aListener);
0964: }
0965:
0966: /*
0967: * (non-Javadoc)
0968: *
0969: * @see org.eclipse.ui.navigator.INavigatorContentService#getFilterService()
0970: */
0971: public INavigatorFilterService getFilterService() {
0972: if (navigatorFilterService == null) {
0973: navigatorFilterService = new NavigatorFilterService(this );
0974: }
0975: return navigatorFilterService;
0976: }
0977:
0978: /*
0979: * (non-Javadoc)
0980: *
0981: * @see org.eclipse.ui.navigator.INavigatorContentService#getFilterService()
0982: */
0983: public INavigatorSorterService getSorterService() {
0984: if (navigatorSorterService == null) {
0985: navigatorSorterService = new NavigatorSorterService(this );
0986: }
0987: return navigatorSorterService;
0988: }
0989:
0990: /*
0991: * (non-Javadoc)
0992: *
0993: * @see org.eclipse.ui.navigator.INavigatorContentService#getFilterService()
0994: */
0995: public INavigatorPipelineService getPipelineService() {
0996: if (navigatorPipelineService == null) {
0997: navigatorPipelineService = new NavigatorPipelineService(
0998: this );
0999: }
1000: return navigatorPipelineService;
1001: }
1002:
1003: /*
1004: * (non-Javadoc)
1005: *
1006: * @see org.eclipse.ui.navigator.INavigatorContentService#getDnDService()
1007: */
1008: public INavigatorDnDService getDnDService() {
1009: if (navigatorDnDService == null) {
1010: navigatorDnDService = new NavigatorDnDService(this );
1011: }
1012: return navigatorDnDService;
1013: }
1014:
1015: /*
1016: * (non-Javadoc)
1017: *
1018: * @see org.eclipse.ui.navigator.INavigatorContentService#getActivationService()
1019: */
1020: public INavigatorActivationService getActivationService() {
1021:
1022: if (navigatorActivationService == null) {
1023: navigatorActivationService = new NavigatorActivationService(
1024: this );
1025: }
1026: return navigatorActivationService;
1027: }
1028:
1029: /* (non-Javadoc)
1030: * @see org.eclipse.ui.navigator.INavigatorContentService#getSaveableService()
1031: */
1032: public INavigatorSaveablesService getSaveablesService() {
1033: synchronized (this ) {
1034: if (navigatorSaveablesService == null) {
1035: navigatorSaveablesService = new NavigatorSaveablesService(
1036: this );
1037: assistant.addListener(navigatorSaveablesService);
1038: }
1039: return navigatorSaveablesService;
1040: }
1041: }
1042:
1043: /**
1044: * Not API as of 3.3.
1045: * @return The extension state service for this content service.
1046: *
1047: */
1048: public NavigatorExtensionStateService getExtensionStateService() {
1049: if (navigatorExtensionStateService == null) {
1050: navigatorExtensionStateService = new NavigatorExtensionStateService(
1051: this );
1052: }
1053: return navigatorExtensionStateService;
1054: }
1055:
1056: /**
1057: * Non-API method to return a shell.
1058: * @return A shell associated with the current viewer (if any) or <b>null</b>.
1059: */
1060: public Shell getShell() {
1061: if (structuredViewerManager != null
1062: && structuredViewerManager.getViewer() != null) {
1063: return structuredViewerManager.getViewer().getControl()
1064: .getShell();
1065: }
1066: return null;
1067: }
1068:
1069: protected boolean isRootExtension(String anExtensionId) {
1070: return assistant.isRootExtension(anExtensionId);
1071: }
1072:
1073: /*
1074: * (non-Javadoc)
1075: *
1076: * @see org.eclipse.ui.internal.navigator.INavigatorContentService#removeListener(org.eclipse.ui.internal.navigator.extensions.INavigatorContentServiceListener)
1077: */
1078: public void removeListener(
1079: INavigatorContentServiceListener aListener) {
1080: listeners.remove(aListener);
1081: }
1082:
1083: /*
1084: * (non-Javadoc)
1085: *
1086: * @see java.lang.Object#toString()
1087: */
1088: public String toString() {
1089: return "ContentService[" + viewerDescriptor.getViewerId() + "]"; //$NON-NLS-1$//$NON-NLS-2$
1090: }
1091:
1092: private void notifyListeners(
1093: NavigatorContentExtension aDescriptorInstance) {
1094:
1095: if (listeners.size() == 0) {
1096: return;
1097: }
1098: INavigatorContentServiceListener listener = null;
1099: List failedListeners = null;
1100: for (Iterator listenersItr = listeners.iterator(); listenersItr
1101: .hasNext();) {
1102: try {
1103: listener = (INavigatorContentServiceListener) listenersItr
1104: .next();
1105: listener.onLoad(aDescriptorInstance);
1106: } catch (RuntimeException re) {
1107: if (failedListeners == null) {
1108: failedListeners = new ArrayList();
1109: }
1110: failedListeners.add(listener);
1111: }
1112: }
1113: if (failedListeners != null) {
1114: listeners.removeAll(failedListeners);
1115: }
1116: }
1117:
1118: private ITreeContentProvider[] extractContentProviders(
1119: Set theDescriptorInstances) {
1120: if (theDescriptorInstances.size() == 0) {
1121: return NO_CONTENT_PROVIDERS;
1122: }
1123: List resultProvidersList = new ArrayList();
1124: for (Iterator itr = theDescriptorInstances.iterator(); itr
1125: .hasNext();) {
1126: resultProvidersList.add(((NavigatorContentExtension) itr
1127: .next()).internalGetContentProvider());
1128: }
1129: return (ITreeContentProvider[]) resultProvidersList
1130: .toArray(new ITreeContentProvider[resultProvidersList
1131: .size()]);
1132: }
1133:
1134: private Set extractDescriptorInstances(Set theDescriptors,
1135: boolean toLoadAllIfNecessary) {
1136: if (theDescriptors.size() == 0) {
1137: return Collections.EMPTY_SET;
1138: }
1139: Set resultInstances = new TreeSet(
1140: ExtensionPriorityComparator.INSTANCE);
1141: for (Iterator descriptorIter = theDescriptors.iterator(); descriptorIter
1142: .hasNext();) {
1143: NavigatorContentExtension extension = getExtension(
1144: (NavigatorContentDescriptor) descriptorIter.next(),
1145: toLoadAllIfNecessary);
1146: if (extension != null) {
1147: resultInstances.add(extension);
1148:
1149: }
1150: }
1151: return resultInstances;
1152: }
1153:
1154: private ILabelProvider[] extractLabelProviders(
1155: Set theDescriptorInstances) {
1156: if (theDescriptorInstances.size() == 0) {
1157: return NO_LABEL_PROVIDERS;
1158: }
1159: List resultProvidersList = new ArrayList();
1160: for (Iterator itr = theDescriptorInstances.iterator(); itr
1161: .hasNext();) {
1162: resultProvidersList.add(((NavigatorContentExtension) itr
1163: .next()).getLabelProvider());
1164: }
1165: return (ILabelProvider[]) resultProvidersList
1166: .toArray(new ILabelProvider[resultProvidersList.size()]);
1167: }
1168:
1169: }
|