/****************************************************************************** * 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.emf.ui.action; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.operations.IUndoableOperation; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.emf.transaction.TransactionalEditingDomain; 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.AbstractActionDelegate; import org.eclipse.gmf.runtime.common.ui.action.IActionWithProgress; import org.eclipse.gmf.runtime.emf.ui.internal.MslUIDebugOptions; import org.eclipse.gmf.runtime.emf.ui.internal.MslUIPlugin; import org.eclipse.gmf.runtime.emf.ui.internal.MslUIStatusCodes; /** * The abstract parent of all concrete action delegates that execute model * commands. Concrete subclasses must provide a definition of the * <code>doRun()</code> method to gather any required input and execute a * model command. * <P> * Subclasses that execute a command must return <code>false</code>from * {@link #isReadOnly()}. The superclass performs the * {@link #doRun(IProgressMonitor)} method in an EMF operation executed on the * operation history. Subclasses should set the action delegate status using * {@link #setStatus(IStatus)} to their command execution status. * <P> * Subclasses that only want to read from the model must return * <code>true</code> from {@link #isReadOnly()}. * * @author khussey * @auther ldamus */ public abstract class AbstractModelActionDelegate extends AbstractActionDelegate { private IStatus status; /** * Intializes me with the singleton editing domain. */ protected AbstractModelActionDelegate() { super(); } /** * Runs this model action delegate as a read action. * * @see IActionWithProgress#run(IProgressMonitor) */ public final void run(final IProgressMonitor progressMonitor) { if (isReadOnly()) { // run exclusive so that subclasses can only read from the model try { getEditingDomain().runExclusive(new Runnable() { public void run() { AbstractModelActionDelegate.super.run(progressMonitor); } }); } catch (InterruptedException e) { Trace .catching(MslUIPlugin.getDefault(), MslUIDebugOptions.EXCEPTIONS_CATCHING, getClass(), "run", e); //$NON-NLS-1$ } } else { // Run in a composite transactional operation so that subclasses can // both read and write to the model. Commands executed by subclasses // to modify the model will be appended to this composite // transactional operation. Runnable runnable = new Runnable() { public void run() { AbstractModelActionDelegate.super .run(progressMonitor); } }; WriteCommand write = new WriteCommand(getEditingDomain(), getLabel(), getActionManager().getOperationHistory(), runnable) { public IStatus getStatus() { return AbstractModelActionDelegate.this.getStatus(); } }; execute(write, new NullProgressMonitor(), null); } } /** * Gets my editing domain. Can be <code>null</code> if I don't modify * model resources. * * @return my editing domain. */ protected abstract TransactionalEditingDomain getEditingDomain(); /** * Answers whether or not I am a read-only action. Returns * <code>false</code> by default. Subclasses may override. * * @return <code>false</code> */ protected boolean isReadOnly() { return false; } /** * Gets the status of running this action delegate. * * @return my status */ protected IStatus getStatus() { if (status == null) { return Status.OK_STATUS; } return status; } /** * Sets the action delegate status. Subclasses should set the status when they * execute a command. * * @param status * the new status */ protected void setStatus(IStatus status) { this.status = status; } /** * Convenience method for subclasses to execute an undoable operation on the * action manager's operation history. Sets my status to the status of the * operation execution, and returns that status. * * @param operation * the operation to be executed * @param progressMonitor * the progress monitor * @param info * the adaptable info, may be <code>null</code> * @return the status of the operation execution. */ protected IStatus execute(IUndoableOperation operation, IProgressMonitor progressMonitor, IAdaptable info) { try { setStatus(getActionManager().getOperationHistory().execute( operation, progressMonitor, info)); } catch (ExecutionException e) { setStatus(new Status(Status.ERROR, MslUIPlugin.getPluginId(), MslUIStatusCodes.IGNORED_EXCEPTION_WARNING, e .getLocalizedMessage(), e)); Trace .catching(MslUIPlugin.getDefault(), MslUIDebugOptions.EXCEPTIONS_CATCHING, getClass(), "run", e); //$NON-NLS-1$ Log.error(MslUIPlugin.getDefault(), MslUIStatusCodes.IGNORED_EXCEPTION_WARNING, e .getLocalizedMessage(), e); } return getStatus(); } }