blob: 3b0e7503f416bad6fd393249a88c5a06c1541dd6 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2002, 2006 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.gmf.runtime.common.ui.action.global;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.operations.IUndoContext;
import org.eclipse.core.commands.operations.IUndoableOperation;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.common.core.util.Log;
import org.eclipse.gmf.runtime.common.core.util.Trace;
import org.eclipse.gmf.runtime.common.ui.action.AbstractActionHandler;
import org.eclipse.gmf.runtime.common.ui.action.internal.CommonUIActionDebugOptions;
import org.eclipse.gmf.runtime.common.ui.action.internal.CommonUIActionPlugin;
import org.eclipse.gmf.runtime.common.ui.action.internal.CommonUIActionStatusCodes;
import org.eclipse.gmf.runtime.common.ui.action.internal.global.GlobalActionHandlerData;
import org.eclipse.gmf.runtime.common.ui.services.action.global.GlobalActionContext;
import org.eclipse.gmf.runtime.common.ui.services.action.global.GlobalActionHandlerContext;
import org.eclipse.gmf.runtime.common.ui.services.action.global.GlobalActionHandlerService;
import org.eclipse.gmf.runtime.common.ui.services.action.global.IGlobalActionContext;
import org.eclipse.gmf.runtime.common.ui.services.action.global.IGlobalActionHandler;
import org.eclipse.gmf.runtime.common.ui.services.action.global.IGlobalActionHandlerProvider;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
/**
* The abstract parent of all concrete global actions. A concrete global action
* needs to override the <code>getActionId()</code> method. The concrete
* global action could override the <code>createContext()</code> and
* <code>createCompoundCommand()</code> methods.
*
* @author Vishy Ramaswamy
*/
public abstract class GlobalAction
extends AbstractActionHandler {
/**
* Associated IWorkbenchActionConstant if one exists
*/
private final String workbenchActionConstant = getActionId();
/**
* Default label for this global action.
*/
private String defaultLabel;
/**
* Creates a GlobalAction.
*
* @param workbenchPart
* The part associated with this action
*/
public GlobalAction(IWorkbenchPart workbenchPart) {
super(workbenchPart);
assert null != workbenchPart;
/* Disable the action when it is created */
setEnabled(false);
}
/**
* Creates a GlobalAction.
*
* @param workbenchPage
* The part associated with this action
*/
public GlobalAction(IWorkbenchPage workbenchPage) {
super(workbenchPage);
assert null != workbenchPage;
/* Disable the action when it is created */
setEnabled(false);
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.common.ui.action.AbstractActionHandler#doRun(org.eclipse.core.runtime.IProgressMonitor)
*/
protected void doRun(IProgressMonitor progressMonitor) {
Vector list = new Vector();
/* Get the handler data */
List handlerInfo = getGlobalActionHandlerData();
for (Iterator i = handlerInfo.iterator(); i.hasNext();) {
/* get the next element */
GlobalActionHandlerData data = (GlobalActionHandlerData) i.next();
/* Get the command */
ICommand command = data.getHandler().getCommand(data.getContext());
if (command != null) {
list.addElement(command);
}
}
if (list.size() <= 0) {
return;
}
/* Create the composite operation */
IUndoableOperation operation = createCompositeCommand(list).reduce();
try {
IStatus status = getOperationHistory()
.execute(operation, progressMonitor, null);
if (!status.isOK()) {
/* log status error */
Log.log(CommonUIActionPlugin.getDefault(), status);
}
} catch (ExecutionException e) {
Trace.catching(CommonUIActionPlugin.getDefault(),
CommonUIActionDebugOptions.EXCEPTIONS_CATCHING, getClass(),
"doRun", e); //$NON-NLS-1$
Log.error(CommonUIActionPlugin.getDefault(),
CommonUIActionStatusCodes.ACTION_FAILURE, e
.getLocalizedMessage(), e);
}
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.common.ui.action.IRepeatableAction#refresh()
*/
public void refresh() {
boolean enable = false;
try {
/* Get the handler data */
List handlerInfo = getGlobalActionHandlerData();
// Reset the label to the default
if (defaultLabel != null) {
setText(defaultLabel);
}
/* Check the handlers for enablement status */
for (Iterator i = handlerInfo.iterator(); i.hasNext();) {
/* Get the next element */
GlobalActionHandlerData data = (GlobalActionHandlerData) i
.next();
/* Check the enablement */
if (data.getHandler().canHandle(data.getContext())) {
if (!enable) {
enable = true;
}
}
/* Update the label, if appropriate */
if (handlerInfo.size() == 1) {
String label = data.getHandler()
.getLabel(data.getContext());
if (label != null) {
setText(label);
}
}
}
} catch (Throwable exception) {
enable = false;
Trace.catching(CommonUIActionPlugin.getDefault(),
CommonUIActionDebugOptions.EXCEPTIONS_CATCHING, getClass(),
"refresh", exception); //$NON-NLS-1$
IStatus status = new Status(IStatus.WARNING, CommonUIActionPlugin
.getPluginId(), CommonUIActionStatusCodes.GENERAL_UI_FAILURE, String
.valueOf(exception.getMessage()), exception);
Log.log(CommonUIActionPlugin.getDefault(), status);
}
/* Set the enablement of the action */
setEnabled(enable);
}
/**
* Returns the <code>GlobalActionId</code> handled by this action
*
* @return int
*/
public abstract String getActionId();
/**
* Returns a <code>CompositeCommand</code> whose undo context is derived from my workbench part.
*
* @param commands a list of commands to compose into a <code>CompositeCommand</code>
* @return the CompositeCommand
*/
protected CompositeCommand createCompositeCommand(List commands) {
assert null != commands;
CompositeCommand result = new CompositeCommand(getLabel(), commands);
IUndoContext undoContext = getUndoContext();
if (undoContext != null) {
result.addContext(undoContext);
}
return result;
}
/**
* Gets the undo context from my workbench part. May be <code>null</code>.
*
* @return my undo context
*/
protected IUndoContext getUndoContext() {
IWorkbenchPart part = getWorkbenchPart();
if (part != null) {
return (IUndoContext) part.getAdapter(IUndoContext.class);
}
return null;
}
/**
* Returns a <code>IGlobalActionContext</code>
*
* @return IGlobalActionContext
*/
protected IGlobalActionContext createContext() {
/* Create the global action context */
return new GlobalActionContext(getWorkbenchPart(), getSelection(),
getLabel(), getActionId());
}
/**
* Returns a list of <code>GlobalActionHandlerData</code>. Handles
* different types of selections
*
* @return List
*/
protected List getGlobalActionHandlerData() {
/* Check if the selection is a text selection */
if (getSelection() instanceof ITextSelection) {
return getGlobalActionHandlerData((ITextSelection) getSelection());
} else if (getSelection() instanceof IStructuredSelection) {
return getGlobalActionHandlerData((IStructuredSelection) getSelection());
}
return new ArrayList();
}
/**
* Returns a list of <code>GlobalActionHandlerData</code> for a given list
* of element types
*
* @param listOfElementTypes
* list of unique element types
* @return List
*/
private List getGlobalActionHandlerData(List listOfElementTypes) {
assert null != listOfElementTypes;
/* Get the global action handler for unique element types */
ArrayList listOfHandlers = new ArrayList();
Iterator iterator = listOfElementTypes.iterator();
while (iterator.hasNext()) {
/* Get the element type */
Class clazz = (Class) iterator.next();
/* Create the global action handler context */
GlobalActionHandlerContext context = new GlobalActionHandlerContext(
getWorkbenchPart(), getActionId(), clazz, false);
/* Get the handler */
IGlobalActionHandler handler = GlobalActionHandlerService
.getInstance().getGlobalActionHandler(context);
/* Get a compatible one if no handler is found for a direct match */
if (handler == null) {
/* Create the global action handler context */
context = new GlobalActionHandlerContext(getWorkbenchPart(),
getActionId(), clazz, true);
/* Get the handler */
handler = GlobalActionHandlerService.getInstance()
.getGlobalActionHandler(context);
}
/* Add to the list */
if (handler != null && !listOfHandlers.contains(handler)) {
listOfHandlers.add(handler);
}
}
/* Create the global action handler data and add it to the list */
ArrayList handlerData = new ArrayList();
IGlobalActionContext actionContext = createContext();
for (int i = 0; i < listOfHandlers.size(); i++) {
/* Get the next handler */
IGlobalActionHandler handler = (IGlobalActionHandler) listOfHandlers
.get(i);
/* Create the global action handler data */
handlerData
.add(new GlobalActionHandlerData(handler, actionContext));
}
/* Return the handler data */
return handlerData;
}
/**
* Returns a list of <code>GlobalActionHandlerData</code> for selection of
* type <code>IStructuredSelection</code>. This methods queries the
* <code>GlobalActionHandlerService</code> for all the global action
* handlers associated with this action.
*
* @param selection
* The <code>IStructuredSelection</code>
* @return List
*/
private List getGlobalActionHandlerData(IStructuredSelection selection) {
assert null != selection;
/* Create a unique list of element types */
ArrayList listOfElementTypes = new ArrayList();
if (selection.isEmpty()) {
// Use the NullElementType to signify that global action handlers
// should be found that provide regardless of the selected types.
listOfElementTypes.add(IGlobalActionHandlerProvider.NullElementType.class);
} else {
/* Get the selection as an object array */
Object[] array = selection.toArray();
for (int i = 0; i < array.length; i++) {
if (!listOfElementTypes.contains(array[i].getClass())) {
listOfElementTypes.add(array[i].getClass());
}
}
}
/* Get the global action handler for unique element types */
return getGlobalActionHandlerData(listOfElementTypes);
}
/**
* Returns a list of <code>GlobalActionHandlerData</code> for selection of
* type <code>ITextSelection</code>. This methods queries the
* <code>GlobalActionHandlerService</code> for all the global action
* handlers associated with this action.
*
* @param selection
* The <code>ITextSelection</code>
* @return List
*/
private List getGlobalActionHandlerData(ITextSelection selection) {
assert null != selection;
/* Get the element type */
Class clazz = selection.getClass();
/* Create a unique list of element types */
ArrayList listOfElementTypes = new ArrayList();
listOfElementTypes.add(clazz);
/* Get the global action handler for unique element types */
return getGlobalActionHandlerData(listOfElementTypes);
}
/**
* Returns the workbenchActionConstant.
*
* @return String
*/
protected String getWorkbenchActionConstant() {
return workbenchActionConstant;
}
/**
* Returns a list with a GlobalActionHandlerData object containing a context
* of Object. You can have getObjectContextGlobalActionHandlerData call this
* instead.
*
* @return List with a GlobalActionHandlerData object containing a context
* of Object
*/
protected List getObjectContextGlobalActionHandlerData() {
GlobalActionHandlerContext context = new GlobalActionHandlerContext(
getWorkbenchPart(), getActionId(), Object.class, false);
IGlobalActionHandler globalActionHandler = GlobalActionHandlerService
.getInstance().getGlobalActionHandler(context);
if (globalActionHandler == null) {
//an error may occur, OK because someone is playing with the xml
return new ArrayList();
}
GlobalActionHandlerData data = new GlobalActionHandlerData(
globalActionHandler, createContext());
ArrayList list = new ArrayList();
list.add(data);
return list;
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.common.ui.action.IDisposableAction#init()
*/
public void init() {
super.init();
defaultLabel = getLabel();
}
}