blob: 9fd797d4f603bd38782f4cfea83878908694f02c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2007 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
*******************************************************************************/
package org.eclipse.ui.internal;
import java.util.List;
import org.eclipse.core.expressions.EvaluationContext;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionConverter;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.SelectionEnabler;
import org.eclipse.ui.internal.misc.Policy;
import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
import org.eclipse.ui.internal.util.Util;
import org.eclipse.ui.model.IWorkbenchAdapter;
/**
* This class describes the object contribution element within the popup menu
* action registry.
*/
public class ObjectActionContributor extends PluginActionBuilder implements
IObjectActionContributor, IAdaptable {
private static final String P_TRUE = "true"; //$NON-NLS-1$
private IConfigurationElement config;
private boolean configRead = false;
private boolean adaptable = false;
private String objectClass;
/**
* The constructor.
*
* @param config the element
*/
public ObjectActionContributor(IConfigurationElement config) {
this.config = config;
this.adaptable = P_TRUE.equalsIgnoreCase(config
.getAttribute(IWorkbenchRegistryConstants.ATT_ADAPTABLE));
this.objectClass = config.getAttribute(IWorkbenchRegistryConstants.ATT_OBJECTCLASS);
}
/* (non-Javadoc)
* Method declared on IObjectContributor.
*/
public boolean canAdapt() {
return adaptable;
}
/**
* Return the object class for this contributor.
*
* @return the object class
*/
public String getObjectClass() {
return objectClass;
}
/* (non-Javadoc)
* Method declared on IObjectActionContributor.
*/
public void contributeObjectActionIdOverrides(List actionIdOverrides) {
if (!configRead) {
readConfigElement();
}
// Easy case out if no actions
if (currentContribution.actions != null) {
for (int i = 0; i < currentContribution.actions.size(); i++) {
ActionDescriptor ad = (ActionDescriptor) currentContribution.actions
.get(i);
String id = ad.getAction().getOverrideActionId();
if (id != null) {
actionIdOverrides.add(id);
}
}
}
}
/**
* Contributes actions applicable for the current selection.
*/
public boolean contributeObjectActions(final IWorkbenchPart part,
IMenuManager menu, ISelectionProvider selProv,
List actionIdOverrides) {
if (!configRead) {
readConfigElement();
}
// Easy case out if no actions
if (currentContribution.actions == null) {
return false;
}
// Get a structured selection.
ISelection sel = selProv.getSelection();
if ((sel == null) || !(sel instanceof IStructuredSelection)) {
return false;
}
IStructuredSelection ssel = (IStructuredSelection) sel;
if(canAdapt()) {
IStructuredSelection newSelection = LegacyResourceSupport.adaptSelection(ssel, getObjectClass());
if(newSelection.size() != ssel.size()) {
if (Policy.DEBUG_CONTRIBUTIONS) {
WorkbenchPlugin.log("Error adapting selection to " + getObjectClass() + //$NON-NLS-1$
". Contribution " + getID(config) + " is being ignored"); //$NON-NLS-1$ //$NON-NLS-2$
}
return false;
}
ssel = newSelection;
}
final IStructuredSelection selection = ssel;
// Generate menu.
for (int i = 0; i < currentContribution.actions.size(); i++) {
ActionDescriptor ad = (ActionDescriptor) currentContribution.actions
.get(i);
if (!actionIdOverrides.contains(ad.getId())) {
currentContribution.contributeMenuAction(ad, menu, true);
// Update action for the current selection and part.
if (ad.getAction() instanceof ObjectPluginAction) {
final ObjectPluginAction action = (ObjectPluginAction) ad
.getAction();
ISafeRunnable runnable = new ISafeRunnable() {
public void handleException(Throwable exception) {
WorkbenchPlugin.log("Failed to update action " //$NON-NLS-1$
+ action.getId(), exception);
}
public void run() throws Exception {
action.setActivePart(part);
action.selectionChanged(selection);
}
};
SafeRunner.run(runnable);
}
}
}
return true;
}
/**
* Contributes menus applicable for the current selection.
*/
public boolean contributeObjectMenus(IMenuManager menu,
ISelectionProvider selProv) {
if (!configRead) {
readConfigElement();
}
// Easy case out if no menus
if (currentContribution.menus == null) {
return false;
}
// Get a structured selection.
ISelection sel = selProv.getSelection();
if ((sel == null) || !(sel instanceof IStructuredSelection)) {
return false;
}
// Generate menu.
for (int i = 0; i < currentContribution.menus.size(); i++) {
IConfigurationElement menuElement = (IConfigurationElement) currentContribution.menus
.get(i);
currentContribution.contributeMenu(menuElement, menu, true);
}
return true;
}
/* (non-Javadoc)
* Method declared on PluginActionBuilder.
*/
protected ActionDescriptor createActionDescriptor(
IConfigurationElement element) {
return new ActionDescriptor(element, ActionDescriptor.T_POPUP);
}
/* (non-Javadoc)
* Method declared on PluginActionBuilder.
*/
protected BasicContribution createContribution() {
return new ObjectContribution();
}
/**
* Returns true if name filter is not specified for the contribution
* or the current selection matches the filter.
*/
public boolean isApplicableTo(Object object) {
if (!configRead) {
readConfigElement();
}
// Perform all tests with an instance of the objectClass and not
// the actual selected object.
if (canAdapt()) {
Object adapted = LegacyResourceSupport.getAdapter(object, getObjectClass());
if (adapted == null) {
if (Policy.DEBUG_CONTRIBUTIONS) {
WorkbenchPlugin
.log("Error adapting " + object.getClass().getName() + //$NON-NLS-1$
" to " //$NON-NLS-1$
+ getObjectClass()
+ ". Contribution " + getID(config) + " is being ignored"); //$NON-NLS-1$ //$NON-NLS-2$
}
} else {
object = adapted;
}
}
if (!testName(object)) {
return false;
}
return ((ObjectContribution) currentContribution)
.isApplicableTo(object);
}
/**
* Reads the configuration element and all the children.
* This creates an action descriptor for every action in the extension.
*/
private void readConfigElement() {
currentContribution = createContribution();
readElementChildren(config);
configRead = true;
}
/* (non-Javadoc)
* Method declared on PluginActionBuilder.
*/
protected boolean readElement(IConfigurationElement element) {
String tag = element.getName();
// Found visibility sub-element
if (tag.equals(IWorkbenchRegistryConstants.TAG_VISIBILITY)) {
((ObjectContribution) currentContribution)
.setVisibilityTest(element);
return true;
}
// Found filter sub-element
if (tag.equals(IWorkbenchRegistryConstants.TAG_FILTER)) {
((ObjectContribution) currentContribution).addFilterTest(element);
return true;
}
if (tag.equals(IWorkbenchRegistryConstants.TAG_ENABLEMENT)) {
((ObjectContribution) currentContribution)
.setEnablementTest(element);
return true;
}
return super.readElement(element);
}
/**
* Returns whether the current selection matches the contribution name filter.
*/
private boolean testName(Object object) {
String nameFilter = config.getAttribute(IWorkbenchRegistryConstants.ATT_NAME_FILTER);
if (nameFilter == null) {
return true;
}
String objectName = null;
IWorkbenchAdapter de = (IWorkbenchAdapter)Util.getAdapter(object, IWorkbenchAdapter.class);
if (de != null) {
objectName = de.getLabel(object);
}
if (objectName == null) {
objectName = object.toString();
}
return SelectionEnabler.verifyNameMatch(objectName, nameFilter);
}
/**
* Helper class to collect the menus and actions defined within a
* contribution element.
*/
private static class ObjectContribution extends BasicContribution {
private ObjectFilterTest filterTest;
private ActionExpression visibilityTest;
private Expression enablement;
/**
* Add a filter test.
*
* @param element the element
*/
public void addFilterTest(IConfigurationElement element) {
if (filterTest == null) {
filterTest = new ObjectFilterTest();
}
filterTest.addFilterElement(element);
}
/**
* Set the visibility test.
*
* @param element the element
*/
public void setVisibilityTest(IConfigurationElement element) {
visibilityTest = new ActionExpression(element);
}
/**
* Set the enablement test.
*
* @param element the element
*/
public void setEnablementTest(IConfigurationElement element) {
try {
enablement = ExpressionConverter.getDefault().perform(element);
} catch (CoreException e) {
WorkbenchPlugin.log(e);
}
}
/**
* Returns true if name filter is not specified for the contribution
* or the current selection matches the filter.
*
* @param object the object to test
* @return whether we're applicable
*/
public boolean isApplicableTo(Object object) {
boolean result = true;
if (visibilityTest != null) {
result = result && visibilityTest.isEnabledFor(object);
if (!result) {
return result;
}
} else if (filterTest != null) {
result = result && filterTest.matches(object, true);
if (!result) {
return result;
}
}
if (enablement != null) {
try {
IEvaluationContext context = new EvaluationContext(null,
object);
context.setAllowPluginActivation(true);
context.addVariable("selection", object); //$NON-NLS-1$
EvaluationResult evalResult = enablement.evaluate(context);
if (evalResult == EvaluationResult.FALSE) {
return false;
}
} catch (CoreException e) {
enablement = null;
WorkbenchPlugin.log(e);
result = false;
}
}
return result;
}
}
/**
* Debugging helper that will print out the contribution names for this
* contributor.
*/
public String toString() {
StringBuffer buffer = new StringBuffer();
IConfigurationElement[] children = config.getChildren();
for (int i = 0; i < children.length; i++) {
IConfigurationElement element = children[i];
String label = element.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
if(label != null) {
buffer.append(label);
buffer.append('\n');
}
}
return buffer.toString();
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
if (adapter.equals(IConfigurationElement.class)) {
return config;
}
return null;
}
}