/****************************************************************************** * Copyright (c) 2002, 2009 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 net.enilink.komma.edit.ui.action; import org.eclipse.core.commands.operations.IOperationHistory; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IPartListener; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import net.enilink.komma.common.util.Log; import net.enilink.komma.common.util.Trace; import net.enilink.komma.edit.ui.KommaEditUIPlugin; import net.enilink.komma.edit.ui.internal.EditUIDebugOptions; import net.enilink.komma.edit.ui.internal.EditUIStatusCodes; /** * The abstract parent of all concrete action delegates that execute commands. * Logging and exception handling are done in a uniform way in the * <code>run()</code> method. Concrete subclasses must provide a definition of * the <code>doRun()</code> method to gather any required input and execute a * command. As an implementer of the <code>IRepeatableAction</code> interface, * this class implements the <code>isRepeatable()</code> method to return * <code>true</code> if its plug-in action is enabled, and implements the * <code>repeat()</code> method to run the delegate's action. Subclasses that * aren't repeatable or require special repeat behavior must override the * default implementations of these interface methods. * <p> * This class provides definitions for the methods that are found in four of the * five action delegate interfaces in Eclipse. Hence, in most cases, adding a * new action delegate is simply a matter of subclassing this class and * declaring that the new class implements the desired action delegate * interface. * * @author khussey * * @see org.eclipse.ui.IActionDelegate * @see org.eclipse.ui.IEditorActionDelegate * @see org.eclipse.ui.IObjectActionDelegate * @see org.eclipse.ui.IViewActionDelegate * @see org.eclipse.ui.IWorkbenchWindowActionDelegate * @see org.eclipse.ui.IActionDelegate2 */ public abstract class AbstractActionDelegate implements IPartListener, IActionWithProgress { /** * Flag to indicate whether or not this action has been set up. */ private boolean setup; /** * The action for which this is a delegate. */ private IAction action = null; /** * The workbench part to which this action delegate applies. */ private IWorkbenchPart workbenchPart = null; /** * The workbench window to which this action delegate applies. */ private IWorkbenchWindow workbenchWindow = null; /** * Constructs a new action delegate. */ protected AbstractActionDelegate() { super(); setSetup(false); } /** * Retrieves the value of the <code>action</code> instance variable. * * @return The value of the <code>action</code> instance variable. */ protected final IAction getAction() { return action; } /** * Sets the <code>action</code> instance variable to the specified value. * * @param action * The new value for the <code>action</code> instance variable. */ protected final void setAction(IAction action) { this.action = action; } /** * Retrieves the value of the <code>workbenchPart</code> instance variable. * * @return The value of the <code>workbenchPart</code> instance variable. */ protected final IWorkbenchPart getWorkbenchPart() { return workbenchPart; } /** * Sets the <code>workbenchPart</code> instance variable to the specified * value. * * @param workbenchPart * The new value for the <code>workbenchPart</code> instance * variable. */ protected void setWorkbenchPart(IWorkbenchPart workbenchPart) { this.workbenchPart = workbenchPart; } /** * Retrieves the value of the <code>workbenchWindow</code> instance * variable. * * @return The value of the <code>workbenchWindow</code> instance variable. */ protected final IWorkbenchWindow getWorkbenchWindow() { return workbenchWindow; } /** * Sets the <code>workbenchWindow</code> instance variable to the specified * value. * * @param workbenchWindow * The new value for the <code>workbenchWindow</code> instance * variable. */ protected final void setWorkbenchWindow(IWorkbenchWindow workbenchWindow) { this.workbenchWindow = workbenchWindow; } /** * Retrieves the action manager for this action delegate from its workbench * part. * * @return The action manager for this action delegate. */ protected ActionManager getActionManager() { IWorkbenchPart wbp = getWorkbenchPart(); if (wbp != null) { ActionManager manager = (ActionManager) wbp .getAdapter(ActionManager.class); if (manager != null) { return manager; } } return ActionManager.getDefault(); } /** * Gets the operation history for this action delegate from its action * manager. * * @return the operation history */ protected IOperationHistory getOperationHistory() { return getActionManager().getOperationHistory(); } /** * Retrieves the current selection. * * @return The current selection. */ protected ISelection getSelection() { ISelection selection = null; IWorkbenchPart wbp = getWorkbenchPart(); if (wbp != null) { IWorkbenchPartSite wbps = wbp.getSite(); if (wbps != null) { ISelectionProvider selectionProvider = wbps .getSelectionProvider(); if (selectionProvider != null) { selection = selectionProvider.getSelection(); if (selection != null) return selection; } } } return StructuredSelection.EMPTY; } /** * Retrieves the current structured selection. * * @return The current structured selection. */ protected IStructuredSelection getStructuredSelection() { IStructuredSelection selection = null; IWorkbenchPart wbp = getWorkbenchPart(); if (wbp != null) { ISelectionProvider selectionProvider = wbp.getSite() .getSelectionProvider(); if (selectionProvider != null && selectionProvider.getSelection() instanceof IStructuredSelection) { selection = (IStructuredSelection) selectionProvider .getSelection(); if (selection != null) return selection; } } return StructuredSelection.EMPTY; } /** * Performs this action. This method is called when the delegating action * has been triggered. * * @param act * The action proxy that handles the presentation portion of the * action. */ public void run(IAction act) { getActionManager().run(this); } /** * Notifies this action delegate that the selection in the workbench has * changed. * * @param act * The action proxy that handles presentation portion of the * action. * @param selection * The current selection, or <code>null</code> if there is no * selection. */ public void selectionChanged(IAction act, ISelection selection) { setAction(act); } /** * Sets the active editor for this action delegate. * * @param action * The action proxy that handles presentation portion of the * action. * @param targetEditor * The new editor target. */ public void setActiveEditor(IAction action, IEditorPart targetEditor) { setAction(action); setWorkbenchPart(targetEditor); } /** * Sets the active part for this delegate. The active part is commonly used * to get a working context for the action, such as the shell for any dialog * which is needed. * * @param action * The action proxy that handles presentation portion of the * action. * @param targetPart * The new part target. */ public void setActivePart(IAction action, IWorkbenchPart targetPart) { setAction(action); setWorkbenchPart(targetPart); } /** * Notifies this action delegate that the given part has been activated. * * @param part * The part that was activated. */ public void partActivated(IWorkbenchPart part) { setWorkbenchPart(part); } /** * Notifies this action delegate that the given part has been brought to the * top. * * @param part * The part that was surfaced. */ public void partBroughtToTop(IWorkbenchPart part) { /* not implemented */ } /** * Notifies this action delegate that the given part has been closed. * * @param part * The part that was closed. */ public void partClosed(IWorkbenchPart part) { if (getWorkbenchPart() == part) { setWorkbenchPart(null); } } /** * Notifies this action delegate that the given part has been deactivated. * * @param part * The part that was deactivated. */ public void partDeactivated(IWorkbenchPart part) { /* method not implemented */ } /** * Notifies this action delegate that the given part has been opened. * * @param part * The part that was opened. */ public void partOpened(IWorkbenchPart part) { /* method not implemented */ } /** * Initializes this action delegate with the view it will work in. * * @param view * The view that provides the context for this delegate. */ public void init(IViewPart view) { setWorkbenchPart(view); } /** * Disposes this action delegate. */ public void dispose() { if (null != getWorkbenchWindow()) { getWorkbenchWindow().getPartService().removePartListener(this); } setWorkbenchPart(null); setWorkbenchWindow(null); setAction(null); } /** * Initializes this action delegate with the workbench window it will work * in. * * @param window * The window that provides the context for this delegate. */ public void init(IWorkbenchWindow window) { setWorkbenchWindow(window); if (null != window.getActivePage()) { setWorkbenchPart(window.getActivePage().getActivePart()); } window.getPartService().addPartListener(this); } /** * Retrieves the label for this action delegate. * * @return The label for this action delegate. */ public String getLabel() { return getAction().getText(); } /** * Retrieves a Boolean indicating whether this action delegate can be run. * * @return <code>true</code> if the action for this delegate is enabled; * <code>false</code> otherwise. */ public boolean isRunnable() { return getAction().isEnabled(); } /** * @inheritDoc */ public void refresh() { /* method not implemented */ } /** * Runs this action delegate. */ public void run(IProgressMonitor progressMonitor) { if (isSetup() || !needsSetup()) { try { doRun(progressMonitor); } catch (Exception e) { handle(e); } setSetup(false); } else { throw new IllegalStateException( "action must be setup before it is run"); //$NON-NLS-1$ } } /** * Answers whether or not this action should be setup before it is run. * Subclasses should override if they provide vital behaviour in the setup * method. * * @return <code>true</code> if the action has a setup, <code>false</code> * otherwise. */ protected boolean needsSetup() { return false; } /** * Handles the specified exception. * * @param exception * The exception to be handled. */ protected void handle(Exception exception) { Trace.catching(KommaEditUIPlugin.getPlugin(), EditUIDebugOptions.EXCEPTIONS_CATCHING, getClass(), "handle", exception); //$NON-NLS-1$ IStatus status = new Status(IStatus.ERROR, KommaEditUIPlugin.PLUGIN_ID, EditUIStatusCodes.ACTION_FAILURE, String.valueOf(exception .getMessage()), exception); Log.log(KommaEditUIPlugin.getPlugin(), status); openErrorDialog(status); } /** * Opens an error dialog for the specified status object. * * @param status * The status object for which to open an error dialog. * */ protected void openErrorDialog(final IStatus status) { final Display display = getDisplay(); if (display.getThread() == Thread.currentThread()) { // we're already on the UI thread ErrorDialog.openError(display.getActiveShell(), Action .removeMnemonics(getLabel()), null, status); } else { // we're not on the UI thread display.asyncExec(new Runnable() { public void run() { ErrorDialog.openError(display.getActiveShell(), Action .removeMnemonics(getLabel()), null, status); } }); } } private Display getDisplay() { Display display = Display.getCurrent(); if (display == null && PlatformUI.isWorkbenchRunning()) { display = PlatformUI.getWorkbench().getDisplay(); } return display; } /** * Performs the actual work when this action delegate is run. Subclasses * must override this method to do some work. * * @param progressMonitor * A progress monitor for tracking the progress of the action's * execution. */ protected abstract void doRun(IProgressMonitor progressMonitor); /** * @see org.eclipse.gmf.runtime.common.ui.action.IActionWithProgress#getWorkIndicatorType() */ public WorkIndicatorType getWorkIndicatorType() { return WorkIndicatorType.BUSY; } /** * @see org.eclipse.gmf.runtime.common.ui.action.IActionWithProgress#setup() */ public boolean setup() { setSetup(true); return true; } /** * Returns the setup state of this action. * * @return <code>true</code> if the action has been setup, * <code>false</code> otherwise. */ public boolean isSetup() { return setup; } /** * Sets the setup state of this action. * * @param setup * <code>true</code> if the action has been setup, * <code>false</code> otherwise. */ protected void setSetup(boolean setup) { this.setup = setup; } /* * * mgoyal: Fixing the memory leak caused in subclasses that implement * IEditorActionDelegate. This will provide the functionality to also * implement IActionDelegate2 and get notified of Lifecycle events. */ /** * Allows the action delegate to initialize itself after being created by * the proxy action. This lifecycle method is called after the action * delegate has been created and before any other method of the action * delegate is called. * * @param anAction * the proxy action that handles the presentation portion of the * action. */ public void init(IAction anAction) { setAction(anAction); } /** * Performs this action, passing the SWT event which triggered it. This * method is called by the proxy action when the action has been triggered. * Implement this method to do the actual work. * <p> * <b>Note:</b> This method is called instead of <code>run(IAction)</code>. * </p> * * @param anAction * the action proxy that handles the presentation portion of the * action * @param event * the SWT event which triggered this action being run */ public void runWithEvent(IAction anAction, Event event) { run(anAction); } }