001: /*******************************************************************************
002: * Copyright (c) 2003, 2007 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.actions;
011:
012: import java.util.Collections;
013: import java.util.Comparator;
014: import java.util.Iterator;
015: import java.util.LinkedHashSet;
016: import java.util.Set;
017: import java.util.TreeSet;
018:
019: import org.eclipse.core.expressions.ElementHandler;
020: import org.eclipse.core.expressions.EvaluationContext;
021: import org.eclipse.core.expressions.EvaluationResult;
022: import org.eclipse.core.expressions.Expression;
023: import org.eclipse.core.expressions.ExpressionConverter;
024: import org.eclipse.core.expressions.IEvaluationContext;
025: import org.eclipse.core.runtime.Assert;
026: import org.eclipse.core.runtime.CoreException;
027: import org.eclipse.core.runtime.IConfigurationElement;
028: import org.eclipse.core.runtime.IStatus;
029: import org.eclipse.core.runtime.Status;
030: import org.eclipse.jface.viewers.IStructuredSelection;
031: import org.eclipse.ui.internal.navigator.CustomAndExpression;
032: import org.eclipse.ui.internal.navigator.NavigatorPlugin;
033: import org.eclipse.ui.internal.navigator.extensions.INavigatorContentExtPtConstants;
034: import org.eclipse.ui.internal.navigator.extensions.SkeletonActionProvider;
035: import org.eclipse.ui.navigator.CommonActionProvider;
036: import org.eclipse.ui.navigator.Priority;
037:
038: /**
039: *
040: *
041: * @since 3.2
042: */
043: public class CommonActionProviderDescriptor implements
044: INavigatorContentExtPtConstants {
045:
046: private static final String DEFAULT_ID = "org.eclipse.ui.navigator.actionProvider"; //$NON-NLS-1$
047:
048: private static int count = 0;
049:
050: private final IConfigurationElement configurationElement;
051:
052: private final boolean isNested;
053:
054: private Set dependentDescriptors;
055:
056: private Set overridingDescriptors;
057:
058: private IConfigurationElement enablementElement;
059:
060: private Expression enablement;
061:
062: private boolean hasLoadingFailed;
063:
064: private String definedId;
065:
066: private String visibilityId;
067:
068: private String dependsOnId;
069:
070: private String overridesId;
071:
072: private String toString;
073:
074: private Priority priority;
075:
076: /**
077: * @param aConfigElement
078: * A configuration element with the name "actionProvider" and a
079: * "class" attribute which subclasses
080: * {@link CommonActionProvider}.
081: */
082: public CommonActionProviderDescriptor(
083: IConfigurationElement aConfigElement) {
084: super ();
085: Assert.isTrue(TAG_ACTION_PROVIDER.equals(aConfigElement
086: .getName()));
087: configurationElement = aConfigElement;
088: isNested = false;
089: init();
090: }
091:
092: /**
093: * @param aConfigElement
094: * A configuration element with the name "actionProvider" and a
095: * "class" attribute which subclasses
096: * {@link CommonActionProvider}.
097: * @param anEnablementExpression
098: * A configuration element with the name 'enablement' or
099: * 'triggerPoints' and containing an Eclipse Core Expression
100: * @param defaultPriority
101: * @param anOverrideId
102: * A unique identifier for this descriptor. Ids can be used as a
103: * filtering device for activities or viewer***Bindings.
104: * @param nestedUnderNavigatorContent
105: * A value of <b>true</b> indicates that this
106: * CommonActionProvider was declared as a nested
107: * <actionProvider /> element under a <navigatorContent
108: * /> element.
109: */
110: public CommonActionProviderDescriptor(
111: IConfigurationElement aConfigElement,
112: IConfigurationElement anEnablementExpression,
113: Priority defaultPriority, String anOverrideId,
114: boolean nestedUnderNavigatorContent) {
115: super ();
116: Assert.isTrue(TAG_ACTION_PROVIDER.equals(aConfigElement
117: .getName()));
118: Assert.isTrue(TAG_POSSIBLE_CHILDREN
119: .equals(anEnablementExpression.getName())
120: || TAG_ENABLEMENT.equals(anEnablementExpression
121: .getName()));
122: configurationElement = aConfigElement;
123: enablementElement = anEnablementExpression;
124: visibilityId = anOverrideId;
125: isNested = nestedUnderNavigatorContent;
126: priority = defaultPriority;
127: init();
128: }
129:
130: private void init() {
131:
132: try {
133:
134: definedId = configurationElement.getAttribute(ATT_ID);
135:
136: // if there was no id attribute, use the default id.
137: if (definedId == null) {
138: definedId = DEFAULT_ID + "." + count++; //$NON-NLS-1$
139: }
140:
141: // we try the id attribute if no override id was supplied.
142: if (visibilityId == null) {
143: visibilityId = definedId;
144: }
145:
146: dependsOnId = configurationElement
147: .getAttribute(ATT_DEPENDS_ON);
148:
149: overridesId = configurationElement
150: .getAttribute(ATT_OVERRIDES);
151:
152: if (priority == null) {
153: String prio = configurationElement
154: .getAttribute(ATT_PRIORITY);
155: if (prio != null)
156: priority = Priority.get(prio);
157: else
158: priority = Priority.NORMAL;
159: }
160:
161: IConfigurationElement[] children = configurationElement
162: .getChildren(TAG_ENABLEMENT);
163: // if no child enablement is specified, and we have an override, use
164: // it
165: if (children.length == 0 && enablementElement != null) {
166: enablement = new CustomAndExpression(enablementElement);
167: // otherwise the child enablement takes priority
168: } else if (children.length == 1) {
169: enablement = ElementHandler.getDefault().create(
170: ExpressionConverter.getDefault(), children[0]);
171:
172: } else {
173: System.err.println("Incorrect number of expressions: " + //$NON-NLS-1$
174: TAG_ENABLEMENT
175: + " in navigator extension: " + //$NON-NLS-1$
176: configurationElement.getDeclaringExtension()
177: .getUniqueIdentifier()
178: + " in plugin " + //$NON-NLS-1$
179: configurationElement.getDeclaringExtension()
180: .getNamespaceIdentifier());
181: }
182: } catch (CoreException e) {
183: NavigatorPlugin.log(IStatus.ERROR, 0, e.getMessage(), e);
184: }
185: }
186:
187: /**
188: *
189: * @return The instantiated CommonActionProvider for this descriptor as
190: * declared in the ATT_CLASS attribute or
191: * {@link SkeletonActionProvider} if a problem occurs while loading
192: * the instance.
193: */
194: public CommonActionProvider createActionProvider() {
195: if (hasLoadingFailed) {
196: return SkeletonActionProvider.INSTANCE;
197: }
198: CommonActionProvider provider = null;
199: try {
200: provider = (CommonActionProvider) configurationElement
201: .createExecutableExtension(ATT_CLASS);
202: } catch (CoreException exception) {
203: NavigatorPlugin.log(exception.getStatus());
204: hasLoadingFailed = true;
205: provider = SkeletonActionProvider.INSTANCE;
206: } catch (Exception e) {
207: NavigatorPlugin.log(new Status(IStatus.ERROR,
208: NavigatorPlugin.PLUGIN_ID, 0, e.getMessage(), e));
209: hasLoadingFailed = true;
210: provider = SkeletonActionProvider.INSTANCE;
211: }
212:
213: return provider;
214: }
215:
216: /**
217: * Determine if this content extension is enabled for the given selection.
218: * The content extension is enabled for the selection if and only if it is
219: * enabled for each element in the selection.
220: *
221: * @param aStructuredSelection
222: * The selection from the viewer
223: * @return True if and only if the extension is enabled for each element in
224: * the selection.
225: */
226: public boolean isEnabledFor(
227: IStructuredSelection aStructuredSelection) {
228: if (enablement == null) {
229: return false;
230: }
231:
232: if (aStructuredSelection.isEmpty()) {
233: IEvaluationContext context = null;
234: context = new EvaluationContext(null,
235: Collections.EMPTY_LIST);
236: context.setAllowPluginActivation(true);
237: try {
238: if (enablement.evaluate(context) != EvaluationResult.TRUE) {
239: return false;
240: }
241: } catch (CoreException e) {
242: NavigatorPlugin
243: .log(IStatus.ERROR, 0, e.getMessage(), e);
244: return false;
245: }
246: } else {
247:
248: IEvaluationContext context = null;
249: Iterator elements = aStructuredSelection.iterator();
250: while (elements.hasNext()) {
251: context = new EvaluationContext(null, elements.next());
252: context.setAllowPluginActivation(true);
253: try {
254: if (enablement.evaluate(context) != EvaluationResult.TRUE) {
255: return false;
256: }
257: } catch (CoreException e) {
258: NavigatorPlugin.log(IStatus.ERROR, 0, e
259: .getMessage(), e);
260: return false;
261: }
262: }
263: }
264: return true;
265: }
266:
267: /**
268: * Determine if this content extension is enabled for the given element.
269: *
270: * @param anElement
271: * The element that should be used for the evaluation.
272: * @return True if and only if the extension is enabled for the element.
273: */
274: public boolean isEnabledFor(Object anElement) {
275: if (enablement == null || anElement == null) {
276: return false;
277: }
278:
279: try {
280: EvaluationContext context = new EvaluationContext(null,
281: anElement);
282: context.setAllowPluginActivation(true);
283: return (enablement.evaluate(context) == EvaluationResult.TRUE);
284: } catch (CoreException e) {
285: NavigatorPlugin.log(IStatus.ERROR, 0, e.getMessage(), e);
286: }
287: return false;
288: }
289:
290: /**
291: *
292: * @return An identifier for this ICommonActionProvider. Defaults to
293: * "org.eclipse.ui.navigator.actionProvider". May not be unique.
294: * Used to filter the actionProvider using the visibility state
295: * information.
296: */
297: public String getId() {
298: return visibilityId;
299: }
300:
301: /**
302: *
303: * @return An identifier for this ICommonActionProvider. Defaults to
304: * 'org.eclipse.ui.navigator.actionProvider'. May not be unique.
305: * Used to determine override or depends on cases.
306: */
307: public String getDefinedId() {
308: return definedId;
309: }
310:
311: /**
312: *
313: * @return True if this is a nested <actionProvider /> element.
314: */
315: public boolean isNested() {
316: return isNested;
317: }
318:
319: /**
320: *
321: * @return The value specified by the <i>dependsOn</i> attribute of the
322: * <actionProvider /> element.
323: */
324: public String getDependsOnId() {
325: return dependsOnId;
326: }
327:
328: /**
329: *
330: * @return The value specified by the <i>overridesId</i> attribute of the
331: * <actionProvider /> element.
332: */
333: public String getOverridesId() {
334: return overridesId;
335: }
336:
337: /**
338: * Only nested Action Providers have priority (as of 3.2.1).
339: *
340: * @return The priority associated with this Action Provider Descriptor.
341: */
342: public Priority getPriority() {
343: return priority;
344: }
345:
346: public int hashCode() {
347: final int PRIME = 31;
348: int result = 1;
349: result = PRIME * result
350: + ((definedId == null) ? 0 : definedId.hashCode());
351: result = PRIME
352: * result
353: + ((visibilityId == null) ? 0 : visibilityId.hashCode());
354: return result;
355: }
356:
357: public boolean equals(Object obj) {
358: if (this == obj)
359: return true;
360: if (!super .equals(obj))
361: return false;
362: if (getClass() != obj.getClass())
363: return false;
364: final CommonActionProviderDescriptor other = (CommonActionProviderDescriptor) obj;
365: if (definedId == null) {
366: if (other.definedId != null)
367: return false;
368: } else if (!definedId.equals(other.definedId))
369: return false;
370: if (visibilityId == null) {
371: if (other.visibilityId != null)
372: return false;
373: } else if (!visibilityId.equals(other.visibilityId))
374: return false;
375: return true;
376: }
377:
378: protected void addDependentDescriptor(
379: CommonActionProviderDescriptor dependentDescriptor) {
380: Assert.isTrue(this != dependentDescriptor);
381: if (dependentDescriptors == null) {
382: dependentDescriptors = new LinkedHashSet();
383: }
384: dependentDescriptors.add(dependentDescriptor);
385: }
386:
387: protected void addOverridingDescriptor(
388: CommonActionProviderDescriptor overridingDescriptor) {
389: Assert.isTrue(this != overridingDescriptor);
390: if (overridingDescriptors == null) {
391: overridingDescriptors = new TreeSet(
392: CommonActionProviderDescriptorCompator.INSTANCE);
393: }
394: overridingDescriptors.add(overridingDescriptor);
395: }
396:
397: protected boolean hasDependentDescriptors() {
398: return dependentDescriptors != null
399: && !dependentDescriptors.isEmpty();
400: }
401:
402: protected boolean hasOverridingDescriptors() {
403: return overridingDescriptors != null
404: && !overridingDescriptors.isEmpty();
405: }
406:
407: protected Iterator dependentDescriptors() {
408: return dependentDescriptors.iterator();
409: }
410:
411: protected Iterator overridingDescriptors() {
412: return overridingDescriptors.iterator();
413: }
414:
415: public String toString() {
416: if (toString == null) {
417: toString = "CommonActionProviderDescriptor[definedId=" + getDefinedId() + ", visibilityId=" + getId() + ", dependsOn=" + getDependsOnId() + ", overrides=" + getOverridesId() + "]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
418: }
419: return toString;
420: }
421:
422: /**
423: * Sorts CommonActionProviderDescriptors by priority, and then by defined id.
424: * @since 3.2
425: *
426: */
427: public static class CommonActionProviderDescriptorCompator
428: implements Comparator {
429:
430: /**
431: * The singleton instance.
432: */
433: public static final CommonActionProviderDescriptorCompator INSTANCE = new CommonActionProviderDescriptorCompator();
434:
435: private static final int LESS_THAN = -1;
436: private static final int EQUALS = 0;
437:
438: /* (non-Javadoc)
439: * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
440: */
441: public int compare(Object o1, Object o2) {
442: CommonActionProviderDescriptor lvalue = null, rvalue = null;
443:
444: if (o1 instanceof CommonActionProviderDescriptor)
445: lvalue = (CommonActionProviderDescriptor) o1;
446:
447: if (o2 instanceof CommonActionProviderDescriptor)
448: rvalue = (CommonActionProviderDescriptor) o2;
449:
450: if (lvalue == null || rvalue == null)
451: return LESS_THAN;
452: if (lvalue.equals(rvalue))
453: return EQUALS;
454: int comparison = lvalue.getPriority().getValue()
455: - rvalue.getPriority().getValue();
456: if (comparison == 0)
457: return lvalue.getDefinedId().compareTo(
458: rvalue.getDefinedId());
459: return comparison;
460:
461: }
462:
463: }
464:
465: }
|