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.util.Iterator;
013: import java.util.Set;
014: import java.util.TreeSet;
015:
016: import org.eclipse.core.expressions.ElementHandler;
017: import org.eclipse.core.expressions.EvaluationContext;
018: import org.eclipse.core.expressions.EvaluationResult;
019: import org.eclipse.core.expressions.Expression;
020: import org.eclipse.core.expressions.ExpressionConverter;
021: import org.eclipse.core.runtime.CoreException;
022: import org.eclipse.core.runtime.IConfigurationElement;
023: import org.eclipse.core.runtime.IStatus;
024: import org.eclipse.jface.viewers.ILabelProvider;
025: import org.eclipse.jface.viewers.IStructuredSelection;
026: import org.eclipse.jface.viewers.ITreeContentProvider;
027: import org.eclipse.osgi.util.NLS;
028: import org.eclipse.ui.IPluginContribution;
029: import org.eclipse.ui.WorkbenchException;
030: import org.eclipse.ui.internal.navigator.CommonNavigatorMessages;
031: import org.eclipse.ui.internal.navigator.CustomAndExpression;
032: import org.eclipse.ui.internal.navigator.NavigatorPlugin;
033: import org.eclipse.ui.navigator.ICommonContentProvider;
034: import org.eclipse.ui.navigator.ICommonLabelProvider;
035: import org.eclipse.ui.navigator.INavigatorContentDescriptor;
036: import org.eclipse.ui.navigator.Priority;
037:
038: /**
039: * Encapsulates the <code>org.eclipse.ui.navigator.navigatorContent</code>
040: * extension point.
041: * <p>
042: * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
043: * part of a work in progress. There is a guarantee neither that this API will
044: * work nor that it will remain the same. Please do not use this API without
045: * consulting with the Platform/UI team.
046: * </p>
047: *
048: * @since 3.2
049: */
050: public final class NavigatorContentDescriptor implements
051: INavigatorContentDescriptor, INavigatorContentExtPtConstants {
052:
053: private static final int HASH_CODE_NOT_COMPUTED = -1;
054: private String id;
055:
056: private String name;
057:
058: private IConfigurationElement configElement;
059:
060: private int priority = Priority.NORMAL_PRIORITY_VALUE;
061:
062: private Expression enablement;
063:
064: private Expression possibleChildren;
065:
066: private String icon;
067:
068: private boolean activeByDefault;
069:
070: private IPluginContribution contribution;
071:
072: private Set overridingExtensions;
073:
074: private OverridePolicy overridePolicy;
075:
076: private String suppressedExtensionId;
077:
078: private INavigatorContentDescriptor overriddenDescriptor;
079:
080: private int hashCode = HASH_CODE_NOT_COMPUTED;
081:
082: private boolean providesSaveables;
083:
084: /**
085: * Creates a new content descriptor from a configuration element.
086: *
087: * @param configElement
088: * configuration element to create a descriptor from
089: *
090: * @throws WorkbenchException
091: * if the configuration element could not be parsed. Reasons
092: * include:
093: * <ul>
094: * <li>A required attribute is missing.</li>
095: * <li>More elements are define than is allowed.</li>
096: * </ul>
097: */
098: /* package */NavigatorContentDescriptor(
099: IConfigurationElement configElement)
100: throws WorkbenchException {
101: super ();
102: this .configElement = configElement;
103: init();
104: }
105:
106: /*
107: * (non-Javadoc)
108: *
109: * @see org.eclipse.ui.internal.navigator.extensions.INavigatorContentDescriptor#getId()
110: */
111: public String getId() {
112: return id;
113: }
114:
115: /*
116: * (non-Javadoc)
117: *
118: * @see org.eclipse.ui.internal.navigator.extensions.INavigatorContentDescriptor#getName()
119: */
120: public String getName() {
121: return name;
122: }
123:
124: /*
125: * (non-Javadoc)
126: *
127: * @see org.eclipse.ui.internal.navigator.extensions.INavigatorContentDescriptor#getPriority()
128: */
129: public int getPriority() {
130: return priority;
131: }
132:
133: /**
134: * Parses the configuration element.
135: *
136: * @throws WorkbenchException
137: * if the configuration element could not be parsed. Reasons
138: * include:
139: * <ul>
140: * <li>A required attribute is missing.</li>
141: * <li>More elements are define than is allowed.</li>
142: * </ul>
143: */
144: private void init() throws WorkbenchException {
145: id = configElement.getAttribute(ATT_ID);
146: name = configElement.getAttribute(ATT_NAME);
147: String priorityString = configElement
148: .getAttribute(ATT_PRIORITY);
149: icon = configElement.getAttribute(ATT_ICON);
150:
151: String activeByDefaultString = configElement
152: .getAttribute(ATT_ACTIVE_BY_DEFAULT);
153: activeByDefault = (activeByDefaultString != null && activeByDefaultString
154: .length() > 0) ? Boolean.valueOf(
155: configElement.getAttribute(ATT_ACTIVE_BY_DEFAULT))
156: .booleanValue() : true;
157:
158: String providesSaveablesString = configElement
159: .getAttribute(ATT_PROVIDES_SAVEABLES);
160: providesSaveables = (providesSaveablesString != null && providesSaveablesString
161: .length() > 0) ? Boolean.valueOf(
162: providesSaveablesString).booleanValue() : false;
163:
164: if (priorityString != null) {
165: try {
166: Priority p = Priority.get(priorityString);
167: priority = p != null ? p.getValue()
168: : Priority.NORMAL_PRIORITY_VALUE;
169: } catch (NumberFormatException exception) {
170: priority = Priority.NORMAL_PRIORITY_VALUE;
171: }
172: }
173: if (id == null) {
174: throw new WorkbenchException(NLS.bind(
175: CommonNavigatorMessages.Attribute_Missing_Warning,
176: new Object[] {
177: ATT_ID,
178: id,
179: configElement.getDeclaringExtension()
180: .getNamespaceIdentifier() }));
181: }
182:
183: IConfigurationElement[] children = configElement
184: .getChildren(TAG_ENABLEMENT);
185: if (children.length == 0) {
186:
187: children = configElement.getChildren(TAG_TRIGGER_POINTS);
188: if (children.length == 1) {
189: enablement = new CustomAndExpression(children[0]);
190: } else {
191: throw new WorkbenchException(
192: NLS
193: .bind(
194: CommonNavigatorMessages.Attribute_Missing_Warning,
195: new Object[] {
196: TAG_TRIGGER_POINTS,
197: id,
198: configElement
199: .getDeclaringExtension()
200: .getNamespaceIdentifier() }));
201: }
202:
203: children = configElement.getChildren(TAG_POSSIBLE_CHILDREN);
204: if (children.length == 1) {
205: possibleChildren = new CustomAndExpression(children[0]);
206: } else if (children.length > 1) {
207: throw new WorkbenchException(
208: NLS
209: .bind(
210: CommonNavigatorMessages.Attribute_Missing_Warning,
211: new Object[] {
212: TAG_POSSIBLE_CHILDREN,
213: id,
214: configElement
215: .getDeclaringExtension()
216: .getNamespaceIdentifier() }));
217: }
218: } else if (children.length == 1) {
219: try {
220: enablement = ElementHandler.getDefault().create(
221: ExpressionConverter.getDefault(), children[0]);
222: } catch (CoreException e) {
223: NavigatorPlugin
224: .log(IStatus.ERROR, 0, e.getMessage(), e);
225: }
226: } else if (children.length > 1) {
227: throw new WorkbenchException(NLS.bind(
228: CommonNavigatorMessages.Attribute_Missing_Warning,
229: new Object[] {
230: TAG_ENABLEMENT,
231: id,
232: configElement.getDeclaringExtension()
233: .getNamespaceIdentifier() }));
234: }
235:
236: contribution = new IPluginContribution() {
237:
238: public String getLocalId() {
239: return getId();
240: }
241:
242: public String getPluginId() {
243: return configElement.getDeclaringExtension()
244: .getNamespaceIdentifier();
245: }
246:
247: };
248:
249: children = configElement.getChildren(TAG_OVERRIDE);
250: if (children.length == 1) {
251: suppressedExtensionId = children[0]
252: .getAttribute(ATT_SUPPRESSED_EXT_ID);
253: overridePolicy = OverridePolicy.get(children[0]
254: .getAttribute(ATT_POLICY));
255: }
256: }
257:
258: /**
259: * @return Returns the icon.
260: */
261: public String getIcon() {
262: return icon;
263: }
264:
265: /**
266: * @return Returns the suppressedExtensionId or null if none specified.
267: */
268: public String getSuppressedExtensionId() {
269: return suppressedExtensionId;
270: }
271:
272: /**
273: * @return Returns the overridePolicy or null if this extension does not
274: * override another extension.
275: */
276: public OverridePolicy getOverridePolicy() {
277: return overridePolicy;
278: }
279:
280: /**
281: * @return Returns the contribution.
282: */
283: public IPluginContribution getContribution() {
284: return contribution;
285: }
286:
287: /**
288: * The content provider could be an instance of
289: * {@link ICommonContentProvider}, but only {@link ITreeContentProvider} is
290: * required.
291: *
292: *
293: * @return An instance of the Content provider defined for this extension.
294: * @throws CoreException
295: * if an instance of the executable extension could not be
296: * created for any reason
297: *
298: */
299: public ITreeContentProvider createContentProvider()
300: throws CoreException {
301: return (ITreeContentProvider) configElement
302: .createExecutableExtension(ATT_CONTENT_PROVIDER);
303: }
304:
305: /**
306: *
307: * The content provider could be an instance of {@link ICommonLabelProvider},
308: * but only {@link ILabelProvider} is required.
309: *
310: * @return An instance of the Label provider defined for this extension
311: * @throws CoreException
312: * if an instance of the executable extension could not be
313: * created for any reason
314: */
315: public ILabelProvider createLabelProvider() throws CoreException {
316: return (ILabelProvider) configElement
317: .createExecutableExtension(ATT_LABEL_PROVIDER);
318: }
319:
320: /*
321: * (non-Javadoc)
322: *
323: * @see org.eclipse.ui.internal.navigator.extensions.INavigatorContentDescriptor#isEnabledByDefault()
324: */
325: public boolean isActiveByDefault() {
326: return activeByDefault;
327: }
328:
329: /**
330: * Determine if this content extension would be able to provide children for
331: * the given element.
332: *
333: * @param anElement
334: * The element that should be used for the evaluation.
335: * @return True if and only if the extension is enabled for the element.
336: */
337: public boolean isTriggerPoint(Object anElement) {
338:
339: if (enablement == null || anElement == null) {
340: return false;
341: }
342:
343: try {
344: EvaluationContext context = new EvaluationContext(null,
345: anElement);
346: context.setAllowPluginActivation(true);
347: return (enablement.evaluate(context) == EvaluationResult.TRUE);
348: } catch (CoreException e) {
349: NavigatorPlugin.logError(0, e.getMessage(), e);
350: }
351: return false;
352: }
353:
354: /**
355: * Determine if this content extension could provide the given element as a
356: * child.
357: *
358: * <p>
359: * This method is used to determine what the parent of an element could be
360: * for Link with Editor support.
361: * </p>
362: *
363: * @param anElement
364: * The element that should be used for the evaluation.
365: * @return True if and only if the extension might provide an object of this
366: * type as a child.
367: */
368: public boolean isPossibleChild(Object anElement) {
369:
370: if ((enablement == null && possibleChildren == null)
371: || anElement == null) {
372: return false;
373: } else if (anElement instanceof IStructuredSelection) {
374: return arePossibleChildren((IStructuredSelection) anElement);
375: }
376:
377: try {
378: EvaluationContext context = new EvaluationContext(null,
379: anElement);
380: context.setAllowPluginActivation(true);
381: if (possibleChildren != null) {
382: return (possibleChildren.evaluate(context) == EvaluationResult.TRUE);
383: } else if (enablement != null) {
384: return (enablement.evaluate(context) == EvaluationResult.TRUE);
385: }
386: } catch (CoreException e) {
387: NavigatorPlugin.logError(0, e.getMessage(), e);
388: }
389: return false;
390: }
391:
392: /**
393: * A convenience method to check all elements in a selection.
394: *
395: * @param aSelection A non-null selection
396: * @return True if and only if every element in the selection is a possible child.
397: */
398: public boolean arePossibleChildren(IStructuredSelection aSelection) {
399: if (aSelection.isEmpty()) {
400: return false;
401: }
402: for (Iterator iter = aSelection.iterator(); iter.hasNext();) {
403: Object element = iter.next();
404: if (!isPossibleChild(element)) {
405: return false;
406: }
407: }
408: return true;
409: }
410:
411: /**
412: *
413: * Does not force the creation of the set of overriding extensions.
414: *
415: * @return True if this extension has overridding extensions.
416: */
417: public boolean hasOverridingExtensions() {
418: return overridingExtensions != null
419: && overridingExtensions.size() > 0;
420: }
421:
422: /**
423: * @return The set of overridding extensions (of type
424: * {@link INavigatorContentDescriptor}
425: */
426: public Set getOverriddingExtensions() {
427: if (overridingExtensions == null) {
428: overridingExtensions = new TreeSet(
429: ExtensionPriorityComparator.DESCENDING);
430: }
431: return overridingExtensions;
432: }
433:
434: /*
435: * (non-Javadoc)
436: *
437: * @see java.lang.Object#toString()
438: */
439: public String toString() {
440: return "Content[" + id + ", \"" + name + "\"]"; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$
441: }
442:
443: /* (non-Javadoc)
444: * @see java.lang.Object#hashCode()
445: */
446: public int hashCode() {
447: if (hashCode == HASH_CODE_NOT_COMPUTED) {
448: String hashCodeString = configElement
449: .getNamespaceIdentifier()
450: + getId();
451: hashCode = hashCodeString.hashCode();
452: if (hashCode == HASH_CODE_NOT_COMPUTED)
453: hashCode++;
454: }
455: return hashCode;
456: }
457:
458: /**
459: * @return The descriptor of the <code>suppressedExtensionId</code> if
460: * non-null.
461: */
462: public INavigatorContentDescriptor getOverriddenDescriptor() {
463: return overriddenDescriptor;
464: }
465:
466: /**
467: * @param theOverriddenDescriptor
468: * The overriddenDescriptor to set.
469: */
470: /* package */void setOverriddenDescriptor(
471: INavigatorContentDescriptor theOverriddenDescriptor) {
472: overriddenDescriptor = theOverriddenDescriptor;
473: }
474:
475: /* (non-Javadoc)
476: * @see org.eclipse.ui.navigator.INavigatorContentDescriptor#hasSaveablesProvider()
477: */
478: public boolean hasSaveablesProvider() {
479: return providesSaveables;
480: }
481:
482: }
|