/******************************************************************************
* 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.commands;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.commands.operations.IUndoContext;
import org.eclipse.core.commands.operations.OperationHistoryFactory;
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.jface.action.Action;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import net.enilink.komma.common.util.Log;
import net.enilink.komma.common.util.StringStatics;
import net.enilink.komma.common.util.Trace;
import net.enilink.komma.edit.domain.IEditingDomain;
import net.enilink.komma.edit.domain.IEditingDomainProvider;
import net.enilink.komma.edit.ui.KommaEditUIPlugin;
import net.enilink.komma.edit.ui.internal.EditUIDebugOptions;
import net.enilink.komma.edit.ui.internal.EditUIStatusCodes;
import net.enilink.komma.edit.ui.util.StatusLineUtil;
public abstract class AbstractHandler extends
org.eclipse.core.commands.AbstractHandler {
/**
* Enumerated type for work indicator type
*/
public static enum WorkIndicatorType {
/** No work indicator. */
NONE("None"),
/** Busy work indicator. */
BUSY("Busy"),
/** Progress monitor work indicator. */
PROGRESS_MONITOR("Progress Monitor"),
/** Cancelable progress monitor work indicator. */
CANCELABLE_PROGRESS_MONITOR("Cancelable Progress Monitor");
String name;
/**
* Constructor for WorkIndicatorType.
*
* @param name
* The name for the WorkIndicatorType
*/
WorkIndicatorType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
/**
* Runs the specified action.
*
* @exception UnsupportedOperationException
* If the action cannot be run.
* @exception RuntimeException
* if any exception or error occurs while running the action
*/
private void doExecute(final ExecutionEvent event)
throws ExecutionException {
WorkIndicatorType type = getWorkIndicatorType();
switch (type) {
case PROGRESS_MONITOR:
runInProgressMonitorDialog(event, false);
break;
case CANCELABLE_PROGRESS_MONITOR:
runInProgressMonitorDialog(event, true);
break;
case BUSY:
// display hourglass cursor
BusyIndicator.showWhile(null, new Runnable() {
public void run() {
try {
execute(event, new NullProgressMonitor());
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
});
break;
default:
execute(event, new NullProgressMonitor());
}
Trace.trace(KommaEditUIPlugin.getPlugin(),
EditUIDebugOptions.ACTIONS_RUN,
"Command '" + String.valueOf(event.getCommand()) + "' run."); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Executes this handler.
*/
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
try {
StatusLineUtil.outputErrorMessage(getWorkbenchPart(event),
StringStatics.BLANK);
doExecute(event);
} catch (Exception e) {
handle(event, e);
}
return null;
}
/**
* Performs the actual work when this action handler is run. Subclasses must
* override this method to do some work.
*
* @param progressMonitor
* the progress monitor for tracking the progress of this action
* when it is run.
*/
abstract public void execute(ExecutionEvent event, IProgressMonitor monitor)
throws ExecutionException;
private Display getDisplay() {
Display display = Display.getCurrent();
if (display == null && PlatformUI.isWorkbenchRunning()) {
display = PlatformUI.getWorkbench().getDisplay();
}
return display;
}
/**
* Retrieves the label for this action handler.
*
* @return The label for this action handler.
*/
public String getLabel(ExecutionEvent event) {
try {
return event.getCommand().getName();
} catch (NotDefinedException e) {
return null;
}
}
/**
* Returns the editing domain which is associated with the current active
* workbench part.
*/
protected IEditingDomain getEditingDomain(ExecutionEvent event)
throws ExecutionException {
IWorkbenchPart wbPart = getWorkbenchPart(event);
IEditingDomainProvider provider = null;
if (wbPart != null) {
provider = (IEditingDomainProvider) wbPart
.getAdapter(IEditingDomainProvider.class);
}
return provider != null ? provider.getEditingDomain() : null;
}
/**
* Returns the editing domain which is associated with the current active
* workbench part.
*
* @throws ExecutionException
* if no editing domain was found for the current execution
* context
*/
protected IEditingDomain getEditingDomainChecked(ExecutionEvent event)
throws ExecutionException {
IEditingDomain editingDomain = getEditingDomain(event);
if (editingDomain == null) {
throw new ExecutionException(
"No editing domain found for the current execution context.");
}
return editingDomain;
}
/**
* Returns the operation history for this action handler from its action
* manager.
*
* @return the operation history
*/
protected IOperationHistory getOperationHistory(ExecutionEvent event)
throws ExecutionException {
IOperationHistory history = null;
IWorkbenchPart wbPart = getWorkbenchPart(event);
if (wbPart != null) {
history = (IOperationHistory) wbPart
.getAdapter(IOperationHistory.class);
}
return null == history ? OperationHistoryFactory.getOperationHistory()
: history;
}
/**
* Retrieves the current selection.
*
* @return The current selection.
*/
protected ISelection getSelection(ExecutionEvent event) {
ISelection selection = HandlerUtil.getCurrentSelection(event);
if (selection instanceof IStructuredSelection) {
return (IStructuredSelection) selection;
}
return StructuredSelection.EMPTY;
}
/**
* Retrieves the current structured selection.
*
* @return The current structured selection.
*/
protected IStructuredSelection getStructuredSelection(ExecutionEvent event) {
ISelection selection = getSelection(event);
return (selection instanceof StructuredSelection) ? (StructuredSelection) selection
: StructuredSelection.EMPTY;
}
/**
* Gets the undo context from my workbench part.
*
* @return the undo context
*/
protected IUndoContext getUndoContext(ExecutionEvent event)
throws ExecutionException {
IWorkbenchPart part = getWorkbenchPart(event);
if (part != null) {
return (IUndoContext) part.getAdapter(IUndoContext.class);
}
return null;
}
/**
* Retrieves the value of the <code>workbenchPart</code> instance variable.
*
* @return The value of the <code>workbenchPart</code> instance variable.
*/
protected final IWorkbenchPart getWorkbenchPart(ExecutionEvent event)
throws ExecutionException {
return HandlerUtil.getActivePartChecked(event);
}
/**
* Gets type of work indicator (progress monitor, hourglass, or none).
*
* @return type of work indicator
*/
public WorkIndicatorType getWorkIndicatorType() {
return WorkIndicatorType.BUSY;
}
/**
* Handles the specified exception.
*
* @param event
*
* @param exception
* The exception to be handled.
*/
protected void handle(ExecutionEvent event, 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(event, status);
}
/**
* Opens an error dialog for the specified status object.
*
* @param event
*
* @param status
* The status object for which to open an error dialog.
*
*/
protected void openErrorDialog(final ExecutionEvent event,
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(event)), null, status);
} else {
// we're not on the UI thread
display.asyncExec(new Runnable() {
public void run() {
ErrorDialog.openError(display.getActiveShell(), Action
.removeMnemonics(getLabel(event)), null, status);
}
});
}
}
// /**
// * Refreshes me if the history event has my workbench part's context, and
// * the event is one of:
// * <UL>
// * <LI>{@link OperationHistoryEvent#UNDONE}</LI>
// * <LI>{@link OperationHistoryEvent#REDONE}</LI>
// * <LI>{@link OperationHistoryEvent#OPERATION_ADDED}</LI>
// * <LI>{@link OperationHistoryEvent#OPERATION_CHANGED}</LI>
// * <LI>{@link OperationHistoryEvent#OPERATION_NOT_OK}</LI>
// * <LI>{@link OperationHistoryEvent#OPERATION_REMOVED}</LI>
// * </UL>
// * The other operation history events are ignored because they are
// * intermediate events that will be followed by one of those listed above.
// * We only want to refresh the action handler once for each change to the
// * operation history.
// */
// public void historyNotification(OperationHistoryEvent event) {
// int type = event.getEventType();
// if (type == OperationHistoryEvent.UNDONE
// || type == OperationHistoryEvent.REDONE
// || type == OperationHistoryEvent.DONE
// || type == OperationHistoryEvent.OPERATION_ADDED
// || type == OperationHistoryEvent.OPERATION_CHANGED
// || type == OperationHistoryEvent.OPERATION_NOT_OK
// || type == OperationHistoryEvent.OPERATION_REMOVED) {
//
// IUndoableOperation operation = event.getOperation();
//
// if (operation != null) {
// IUndoContext partContext = getUndoContext(event);
//
// if (partContext != null && operation.hasContext(partContext)) {
// refresh();
// }
// }
// }
// }
/**
* 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 runInProgressMonitorDialog(final ExecutionEvent event,
boolean cancelable) {
IRunnableWithProgress runnable = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor)
throws InvocationTargetException {
try {
execute(event, monitor);
} catch (ExecutionException e) {
throw new InvocationTargetException(e);
}
}
};
runInProgressMonitorDialog(runnable, cancelable);
}
/**
* 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(KommaEditUIPlugin.getPlugin(),
EditUIDebugOptions.EXCEPTIONS_CATCHING, getClass(),
"run", ite); //$NON-NLS-1$
Log.error(KommaEditUIPlugin.getPlugin(),
EditUIStatusCodes.SERVICE_FAILURE, "run", ite); //$NON-NLS-1$
RuntimeException cre = new RuntimeException(ite
.getTargetException());
Trace.throwing(KommaEditUIPlugin.getPlugin(),
EditUIDebugOptions.EXCEPTIONS_THROWING, getClass(),
"run", cre); //$NON-NLS-1$
throw cre;
} catch (InterruptedException ie) {
Trace.catching(KommaEditUIPlugin.getPlugin(),
EditUIDebugOptions.EXCEPTIONS_CATCHING, getClass(),
"run", ie); //$NON-NLS-1$
}
}
}