blob: 5448da5da31a668e3f113325daf0cbe1e9b6cb5d [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;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.commands.operations.OperationHistoryFactory;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
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.internal.CommonUIDebugOptions;
import org.eclipse.gmf.runtime.common.ui.internal.CommonUIPlugin;
import org.eclipse.gmf.runtime.common.ui.internal.CommonUIStatusCodes;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.custom.BusyIndicator;
/**
* Responsible for managing the running of actions. All
* actions (delegates and handlers) channel their run requests through an action
* manager. An action manager keeps track of the action that was last run and
* fires events to interested listeners whenever an action is run.
*
* @author khussey
*/
public class ActionManager {
/**
* The empty string.
*/
protected static final String EMPTY_STRING = ""; //$NON-NLS-1$
/**
* A string containing only a space character.
*/
protected static final String SPACE = " "; //$NON-NLS-1$
/**
* The default action manager.
*/
private static ActionManager actionManager = null;
private final IOperationHistory operationHistory;
/**
* The last action that was run.
*/
private IActionWithProgress action = null;
/**
* The action manager change listeners.
*/
private final List listeners =
Collections.synchronizedList(new ArrayList());
/**
* Intializes me with an operation history.
*
* @param operationHistory The operation history for this action manager.
*/
public ActionManager(IOperationHistory operationHistory) {
super();
assert null != operationHistory;
this.operationHistory = operationHistory;
}
/**
* Retrieves the default action manager.
*
* @return The default action manager.
*/
public static ActionManager getDefault() {
if (null == actionManager) {
actionManager = new ActionManager(OperationHistoryFactory.getOperationHistory());
}
return actionManager;
}
/**
* Gets my operation history.
*
* @return my operation history
*/
public final IOperationHistory getOperationHistory() {
return operationHistory;
}
/**
* Retrieves the value of the <code>action</code> instance variable.
*
* @return The value of the <code>action</code> instance variable.
*/
protected final IActionWithProgress 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(IActionWithProgress action) {
this.action = action;
}
/**
* Retrieves the value of the <code>listeners</code> instance variable.
*
* @return The value of the <code>listeners</code> instance varible.
*/
protected final List getListeners() {
return listeners;
}
/**
* Adds the specified listener to the list of action manager change
* listeners for this action manager.
*
* @param listener The listener to be added.
*/
public void addActionManagerChangeListener(IActionManagerChangeListener listener) {
assert null != listener;
getListeners().add(listener);
}
/**
* Removes the specified listener from the list of action manager change
* listeners for this action manager.
*
* @param listener The listener to be removed.
*/
public void removeActionManagerChangeListener(IActionManagerChangeListener listener) {
assert null != listener;
getListeners().remove(listener);
}
/**
* Notifies the listeners for this action manager that the specified
* event has occurred.
*
* @param event The action manager change event to be fired.
*/
protected void fireActionManagerChange(ActionManagerChangeEvent event) {
assert null != event;
List targets = null;
synchronized (getListeners()) {
targets = new ArrayList(getListeners());
}
for (Iterator i = targets.iterator(); i.hasNext();) {
((IActionManagerChangeListener) i.next()).actionManagerChanged(
event);
}
}
/**
* Clears this action manager by discarding the last action that was run.
*/
public void clear() {
setAction(null);
fireActionManagerChange(new ActionManagerChangeEvent(this));
}
/**
* Runs the specified action.
*
* @param theAction The action to be run.
* @exception UnsupportedOperationException If the action cannot be run.
* @exception RuntimeException if any exception or error occurs
* while running the action
*/
public void run(final IActionWithProgress theAction) {
if (!theAction.isRunnable()) {
UnsupportedOperationException uoe =
new UnsupportedOperationException();
Trace.throwing(CommonUIPlugin.getDefault(), CommonUIDebugOptions.EXCEPTIONS_THROWING, getClass(), "run", uoe); //$NON-NLS-1$
throw uoe;
}
boolean setup = theAction.setup();
if (!setup) {
// The setup did not occur (e.g. the user cancelled
// a dialog presented in the setup). Do not proceed.
return;
}
IActionWithProgress.WorkIndicatorType type =
theAction.getWorkIndicatorType();
if (type == IActionWithProgress.WorkIndicatorType.PROGRESS_MONITOR) {
runActionInProgressMonitorDialog(theAction, false);
} else if (
type
== IActionWithProgress
.WorkIndicatorType
.CANCELABLE_PROGRESS_MONITOR) {
runActionInProgressMonitorDialog(theAction, true);
} else if (type == IActionWithProgress.WorkIndicatorType.BUSY) {
// display hourglass cursor
BusyIndicator.showWhile(null, new Runnable() {
public void run() {
theAction.run(new NullProgressMonitor());
}
});
} else {
theAction.run(new NullProgressMonitor());
}
setAction(theAction);
fireActionManagerChange(new ActionManagerChangeEvent(this, theAction));
Trace.trace(CommonUIPlugin.getDefault(), CommonUIDebugOptions.ACTIONS_RUN, "Action '" + String.valueOf(getAction()) + "' run."); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Runs <code>runnable</code> in a progress monitor dialog. The runnable runs in
* the same thread as the dialog. The cancel button on the dialog is enabled
* if <code>cancelable</code> is <code>true</code>.
*
* @param runnable the runnable to run in the context of the progress dialog
* @param cancelable <code>true</code> if the progress monitor should have
* an enabled cancel button, <code>false</code> otherwise.
*
* @exception RuntimeException if any exception or error occurs
* while running the runnable
*/
private void runInProgressMonitorDialog(
IRunnableWithProgress runnable,
boolean cancelable) {
try {
if (System.getProperty("RUN_PROGRESS_IN_UI_HACK") != null) { //$NON-NLS-1$
new ProgressMonitorDialog(null).run(false, cancelable, runnable);
} else {
new ProgressMonitorDialog(null).run(true, cancelable, runnable);
}
} catch (InvocationTargetException ite) {
Trace.catching(CommonUIPlugin.getDefault(), CommonUIDebugOptions.EXCEPTIONS_CATCHING, getClass(), "run", ite); //$NON-NLS-1$
Log.error(CommonUIPlugin.getDefault(), CommonUIStatusCodes.SERVICE_FAILURE, "run", ite); //$NON-NLS-1$
RuntimeException cre =
new RuntimeException(ite.getTargetException());
Trace.throwing(CommonUIPlugin.getDefault(), CommonUIDebugOptions.EXCEPTIONS_THROWING, getClass(), "run", cre); //$NON-NLS-1$
throw cre;
} catch (InterruptedException ie) {
Trace.catching(CommonUIPlugin.getDefault(), CommonUIDebugOptions.EXCEPTIONS_CATCHING, getClass(), "run", ie); //$NON-NLS-1$
}
}
/**
* Runs <code>action</code> in the context of a progress monitor dialog.
* The action runs in the same thread as the dialog. The cancel button on
* the dialog is enabled if <code>cancelable</code> is <code>true</code>.
*
* @param act the action to repeat
* @param cancelable <code>true</code> if the progress monitor should have
* an enabled cancel button, <code>false</code> otherwise.
*
* @exception RuntimeException if any exception or error occurs
* while running the action
*/
private void runActionInProgressMonitorDialog(
final IActionWithProgress act,
boolean cancelable) {
IRunnableWithProgress runnable = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) {
act.run(monitor);
}
};
runInProgressMonitorDialog(runnable, cancelable);
}
}