001: /*******************************************************************************
002: * Copyright (c) 2000, 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;
011:
012: import java.util.List;
013:
014: import org.eclipse.core.expressions.EvaluationContext;
015: import org.eclipse.core.expressions.EvaluationResult;
016: import org.eclipse.core.expressions.Expression;
017: import org.eclipse.core.expressions.ExpressionConverter;
018: import org.eclipse.core.expressions.IEvaluationContext;
019: import org.eclipse.core.runtime.CoreException;
020: import org.eclipse.core.runtime.IAdaptable;
021: import org.eclipse.core.runtime.IConfigurationElement;
022: import org.eclipse.core.runtime.ISafeRunnable;
023: import org.eclipse.core.runtime.SafeRunner;
024: import org.eclipse.jface.action.IMenuManager;
025: import org.eclipse.jface.viewers.ISelection;
026: import org.eclipse.jface.viewers.ISelectionProvider;
027: import org.eclipse.jface.viewers.IStructuredSelection;
028: import org.eclipse.ui.IWorkbenchPart;
029: import org.eclipse.ui.SelectionEnabler;
030: import org.eclipse.ui.internal.misc.Policy;
031: import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
032: import org.eclipse.ui.internal.util.Util;
033: import org.eclipse.ui.model.IWorkbenchAdapter;
034:
035: /**
036: * This class describes the object contribution element within the popup menu
037: * action registry.
038: */
039: public class ObjectActionContributor extends PluginActionBuilder
040: implements IObjectActionContributor, IAdaptable {
041:
042: private static final String P_TRUE = "true"; //$NON-NLS-1$
043:
044: private IConfigurationElement config;
045:
046: private boolean configRead = false;
047:
048: private boolean adaptable = false;
049:
050: private String objectClass;
051:
052: /**
053: * The constructor.
054: *
055: * @param config the element
056: */
057: public ObjectActionContributor(IConfigurationElement config) {
058: this .config = config;
059: this .adaptable = P_TRUE
060: .equalsIgnoreCase(config
061: .getAttribute(IWorkbenchRegistryConstants.ATT_ADAPTABLE));
062: this .objectClass = config
063: .getAttribute(IWorkbenchRegistryConstants.ATT_OBJECTCLASS);
064: }
065:
066: /* (non-Javadoc)
067: * Method declared on IObjectContributor.
068: */
069: public boolean canAdapt() {
070: return adaptable;
071: }
072:
073: /**
074: * Return the object class for this contributor.
075: *
076: * @return the object class
077: */
078: public String getObjectClass() {
079: return objectClass;
080: }
081:
082: /* (non-Javadoc)
083: * Method declared on IObjectActionContributor.
084: */
085: public void contributeObjectActionIdOverrides(List actionIdOverrides) {
086: if (!configRead) {
087: readConfigElement();
088: }
089:
090: // Easy case out if no actions
091: if (currentContribution.actions != null) {
092: for (int i = 0; i < currentContribution.actions.size(); i++) {
093: ActionDescriptor ad = (ActionDescriptor) currentContribution.actions
094: .get(i);
095: String id = ad.getAction().getOverrideActionId();
096: if (id != null) {
097: actionIdOverrides.add(id);
098: }
099: }
100: }
101: }
102:
103: /**
104: * Contributes actions applicable for the current selection.
105: */
106: public boolean contributeObjectActions(final IWorkbenchPart part,
107: IMenuManager menu, ISelectionProvider selProv,
108: List actionIdOverrides) {
109: if (!configRead) {
110: readConfigElement();
111: }
112:
113: // Easy case out if no actions
114: if (currentContribution.actions == null) {
115: return false;
116: }
117:
118: // Get a structured selection.
119: ISelection sel = selProv.getSelection();
120: if ((sel == null) || !(sel instanceof IStructuredSelection)) {
121: return false;
122: }
123: IStructuredSelection ssel = (IStructuredSelection) sel;
124:
125: if (canAdapt()) {
126: IStructuredSelection newSelection = LegacyResourceSupport
127: .adaptSelection(ssel, getObjectClass());
128: if (newSelection.size() != ssel.size()) {
129: if (Policy.DEBUG_CONTRIBUTIONS) {
130: WorkbenchPlugin
131: .log("Error adapting selection to " + getObjectClass() + //$NON-NLS-1$
132: ". Contribution " + getID(config)
133: + " is being ignored"); //$NON-NLS-1$ //$NON-NLS-2$
134: }
135: return false;
136: }
137: ssel = newSelection;
138: }
139:
140: final IStructuredSelection selection = ssel;
141:
142: // Generate menu.
143: for (int i = 0; i < currentContribution.actions.size(); i++) {
144: ActionDescriptor ad = (ActionDescriptor) currentContribution.actions
145: .get(i);
146: if (!actionIdOverrides.contains(ad.getId())) {
147: currentContribution
148: .contributeMenuAction(ad, menu, true);
149: // Update action for the current selection and part.
150: if (ad.getAction() instanceof ObjectPluginAction) {
151: final ObjectPluginAction action = (ObjectPluginAction) ad
152: .getAction();
153: ISafeRunnable runnable = new ISafeRunnable() {
154: public void handleException(Throwable exception) {
155: WorkbenchPlugin
156: .log("Failed to update action " //$NON-NLS-1$
157: + action.getId(), exception);
158: }
159:
160: public void run() throws Exception {
161: action.setActivePart(part);
162: action.selectionChanged(selection);
163: }
164: };
165: SafeRunner.run(runnable);
166: }
167: }
168: }
169: return true;
170: }
171:
172: /**
173: * Contributes menus applicable for the current selection.
174: */
175: public boolean contributeObjectMenus(IMenuManager menu,
176: ISelectionProvider selProv) {
177: if (!configRead) {
178: readConfigElement();
179: }
180:
181: // Easy case out if no menus
182: if (currentContribution.menus == null) {
183: return false;
184: }
185:
186: // Get a structured selection.
187: ISelection sel = selProv.getSelection();
188: if ((sel == null) || !(sel instanceof IStructuredSelection)) {
189: return false;
190: }
191:
192: // Generate menu.
193: for (int i = 0; i < currentContribution.menus.size(); i++) {
194: IConfigurationElement menuElement = (IConfigurationElement) currentContribution.menus
195: .get(i);
196: currentContribution.contributeMenu(menuElement, menu, true);
197: }
198: return true;
199: }
200:
201: /* (non-Javadoc)
202: * Method declared on PluginActionBuilder.
203: */
204: protected ActionDescriptor createActionDescriptor(
205: IConfigurationElement element) {
206: return new ActionDescriptor(element, ActionDescriptor.T_POPUP);
207: }
208:
209: /* (non-Javadoc)
210: * Method declared on PluginActionBuilder.
211: */
212: protected BasicContribution createContribution() {
213: return new ObjectContribution();
214: }
215:
216: /**
217: * Returns true if name filter is not specified for the contribution
218: * or the current selection matches the filter.
219: */
220: public boolean isApplicableTo(Object object) {
221: if (!configRead) {
222: readConfigElement();
223: }
224:
225: // Perform all tests with an instance of the objectClass and not
226: // the actual selected object.
227: if (canAdapt()) {
228: Object adapted = LegacyResourceSupport.getAdapter(object,
229: getObjectClass());
230: if (adapted == null) {
231: if (Policy.DEBUG_CONTRIBUTIONS) {
232: WorkbenchPlugin
233: .log("Error adapting " + object.getClass().getName() + //$NON-NLS-1$
234: " to " //$NON-NLS-1$
235: + getObjectClass()
236: + ". Contribution " + getID(config) + " is being ignored"); //$NON-NLS-1$ //$NON-NLS-2$
237: }
238: } else {
239: object = adapted;
240: }
241: }
242:
243: if (!testName(object)) {
244: return false;
245: }
246:
247: return ((ObjectContribution) currentContribution)
248: .isApplicableTo(object);
249: }
250:
251: /**
252: * Reads the configuration element and all the children.
253: * This creates an action descriptor for every action in the extension.
254: */
255: private void readConfigElement() {
256: currentContribution = createContribution();
257: readElementChildren(config);
258: configRead = true;
259: }
260:
261: /* (non-Javadoc)
262: * Method declared on PluginActionBuilder.
263: */
264: protected boolean readElement(IConfigurationElement element) {
265: String tag = element.getName();
266:
267: // Found visibility sub-element
268: if (tag.equals(IWorkbenchRegistryConstants.TAG_VISIBILITY)) {
269: ((ObjectContribution) currentContribution)
270: .setVisibilityTest(element);
271: return true;
272: }
273:
274: // Found filter sub-element
275: if (tag.equals(IWorkbenchRegistryConstants.TAG_FILTER)) {
276: ((ObjectContribution) currentContribution)
277: .addFilterTest(element);
278: return true;
279: }
280:
281: if (tag.equals(IWorkbenchRegistryConstants.TAG_ENABLEMENT)) {
282: ((ObjectContribution) currentContribution)
283: .setEnablementTest(element);
284: return true;
285: }
286:
287: return super .readElement(element);
288: }
289:
290: /**
291: * Returns whether the current selection matches the contribution name filter.
292: */
293: private boolean testName(Object object) {
294: String nameFilter = config
295: .getAttribute(IWorkbenchRegistryConstants.ATT_NAME_FILTER);
296: if (nameFilter == null) {
297: return true;
298: }
299: String objectName = null;
300: IWorkbenchAdapter de = (IWorkbenchAdapter) Util.getAdapter(
301: object, IWorkbenchAdapter.class);
302: if (de != null) {
303: objectName = de.getLabel(object);
304: }
305: if (objectName == null) {
306: objectName = object.toString();
307: }
308: return SelectionEnabler.verifyNameMatch(objectName, nameFilter);
309: }
310:
311: /**
312: * Helper class to collect the menus and actions defined within a
313: * contribution element.
314: */
315: private static class ObjectContribution extends BasicContribution {
316: private ObjectFilterTest filterTest;
317:
318: private ActionExpression visibilityTest;
319:
320: private Expression enablement;
321:
322: /**
323: * Add a filter test.
324: *
325: * @param element the element
326: */
327: public void addFilterTest(IConfigurationElement element) {
328: if (filterTest == null) {
329: filterTest = new ObjectFilterTest();
330: }
331: filterTest.addFilterElement(element);
332: }
333:
334: /**
335: * Set the visibility test.
336: *
337: * @param element the element
338: */
339: public void setVisibilityTest(IConfigurationElement element) {
340: visibilityTest = new ActionExpression(element);
341: }
342:
343: /**
344: * Set the enablement test.
345: *
346: * @param element the element
347: */
348: public void setEnablementTest(IConfigurationElement element) {
349: try {
350: enablement = ExpressionConverter.getDefault().perform(
351: element);
352: } catch (CoreException e) {
353: WorkbenchPlugin.log(e);
354: }
355: }
356:
357: /**
358: * Returns true if name filter is not specified for the contribution
359: * or the current selection matches the filter.
360: *
361: * @param object the object to test
362: * @return whether we're applicable
363: */
364: public boolean isApplicableTo(Object object) {
365: boolean result = true;
366: if (visibilityTest != null) {
367: result = result && visibilityTest.isEnabledFor(object);
368: if (!result) {
369: return result;
370: }
371: } else if (filterTest != null) {
372: result = result && filterTest.matches(object, true);
373: if (!result) {
374: return result;
375: }
376: }
377: if (enablement != null) {
378: try {
379: IEvaluationContext context = new EvaluationContext(
380: null, object);
381: context.setAllowPluginActivation(true);
382: context.addVariable("selection", object); //$NON-NLS-1$
383: EvaluationResult evalResult = enablement
384: .evaluate(context);
385: if (evalResult == EvaluationResult.FALSE) {
386: return false;
387: }
388: } catch (CoreException e) {
389: enablement = null;
390: WorkbenchPlugin.log(e);
391: result = false;
392: }
393: }
394: return result;
395: }
396: }
397:
398: /**
399: * Debugging helper that will print out the contribution names for this
400: * contributor.
401: */
402: public String toString() {
403: StringBuffer buffer = new StringBuffer();
404: IConfigurationElement[] children = config.getChildren();
405: for (int i = 0; i < children.length; i++) {
406: IConfigurationElement element = children[i];
407: String label = element
408: .getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
409: if (label != null) {
410: buffer.append(label);
411: buffer.append('\n');
412: }
413: }
414: return buffer.toString();
415: }
416:
417: /* (non-Javadoc)
418: * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
419: */
420: public Object getAdapter(Class adapter) {
421: if (adapter.equals(IConfigurationElement.class)) {
422: return config;
423: }
424: return null;
425: }
426: }
|