blob: 561e64e160192fbc481336b827715f94ebf1863c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2015 Wind River Systems 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:
* Wind River Systems - initial API and implementation
* IBM Corporation - bug fixing
*******************************************************************************/
package org.eclipse.debug.ui.actions;
import java.util.Map;
import java.util.WeakHashMap;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.HandlerEvent;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.debug.core.IRequest;
import org.eclipse.debug.internal.ui.commands.actions.DebugCommandService;
import org.eclipse.debug.internal.ui.commands.actions.ICommandParticipant;
import org.eclipse.debug.internal.ui.commands.actions.IEnabledTarget;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.contexts.DebugContextEvent;
import org.eclipse.debug.ui.contexts.IDebugContextListener;
import org.eclipse.debug.ui.contexts.IDebugContextService;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.ISources;
import org.eclipse.ui.IWindowListener;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
/**
* Abstract base class for re-targeting command framework handlers, which
* delegate execution to {@link org.eclipse.debug.core.commands.IDebugCommandHandler}
* handlers. The specific type of <code>IDebugCommandHandler</code> is
* determined by the abstract {@link #getCommandType()} method.
*
* <p> Note: This class is not an implementation of the <code>IDebugCommandHandler</code>
* interface, which was somewhat unfortunately named. <code>IDebugCommandHandler</code>
* is an interface that used only by the debugger plug-ins. This class implements
* {@link org.eclipse.core.commands.IHandler} interface and is to be used with the
* platform commands framework. </p>
*
* <p>
* Clients may subclass this class.
* </p>
* @see org.eclipse.debug.core.commands.IDebugCommandHandler
* @see org.eclipse.core.commands.IHandler
*
* @since 3.6
*/
public abstract class DebugCommandHandler extends AbstractHandler {
/**
* The DebugCommandService is able to evaluate the command handler
* enablement in each workbench window separately, however the workbench
* command framework uses only a single handler instance for all windows.
* This IEnabledTarget implementation tracks enablement of the command
* for a given window. When the handler enablement is tested, the
* currently active window is used to determine which enabled target
* to use.
*/
private class EnabledTarget implements IEnabledTarget, IDebugContextListener {
boolean fEnabled = getInitialEnablement();
IWorkbenchWindow fWindow;
EnabledTarget(IWorkbenchWindow window) {
fWindow = window;
}
void init() {
DebugCommandService.getService(fWindow).updateCommand(getCommandType(), this);
getContextService(fWindow).addDebugContextListener(this);
}
@Override
public void setEnabled(boolean enabled) {
boolean oldEnabled = fEnabled;
fEnabled = enabled;
if (fEnabled != oldEnabled && fCurrentEnabledTarget == this) {
fireHandlerChanged(new HandlerEvent(DebugCommandHandler.this, true, false));
}
}
@Override
public void debugContextChanged(DebugContextEvent event) {
DebugCommandService.getService(fWindow).postUpdateCommand(getCommandType(), this);
}
void dispose() {
if (isDisposed()) {
return;
}
getContextService(fWindow).removeDebugContextListener(this);
fWindow = null;
}
boolean isDisposed() {
return fWindow == null;
}
}
/**
* Window listener is used to make sure that the handler enablement
* is updated when the active workbench window is changed.
*/
private IWindowListener fWindowListener = new IWindowListener() {
@Override
public void windowOpened(IWorkbenchWindow w) {
}
@Override
public void windowDeactivated(IWorkbenchWindow w) {
}
@Override
public void windowClosed(IWorkbenchWindow w) {
EnabledTarget enabledTarget = fEnabledTargetsMap.get(w);
if (enabledTarget != null) {
enabledTarget.dispose();
}
}
@Override
public void windowActivated(IWorkbenchWindow w) {
fCurrentEnabledTarget = fEnabledTargetsMap.get(w);
fireHandlerChanged(new HandlerEvent(DebugCommandHandler.this, true, false));
}
};
/**
* Map of enabled targets keyed by workbench window.
*/
private Map<IWorkbenchWindow, EnabledTarget> fEnabledTargetsMap = new WeakHashMap<IWorkbenchWindow, EnabledTarget>();
/**
* The current enabled target, based on the active
* workbench window.
*/
private EnabledTarget fCurrentEnabledTarget = null;
/**
* The constructor adds the handler as the
*/
public DebugCommandHandler() {
super();
PlatformUI.getWorkbench().addWindowListener(fWindowListener);
}
/* (non-Javadoc)
* @see org.eclipse.core.commands.AbstractHandler#setEnabled(java.lang.Object)
*/
@Override
public void setEnabled(Object evaluationContext) {
// This method is called with the current evaluation context
// just prior to the isEnabled() being called. Check the active
// window and update the current enabled target based on it
fCurrentEnabledTarget = null;
if (!(evaluationContext instanceof IEvaluationContext)) {
return;
}
IEvaluationContext context = (IEvaluationContext) evaluationContext;
Object _window = context.getVariable(ISources.ACTIVE_WORKBENCH_WINDOW_NAME);
if (_window instanceof IWorkbenchWindow) {
IWorkbenchWindow window = (IWorkbenchWindow)_window;
fCurrentEnabledTarget = getEnabledTarget(window);
}
}
/* (non-Javadoc)
* @see org.eclipse.core.commands.AbstractHandler#isEnabled()
*/
@Override
public boolean isEnabled() {
if (fCurrentEnabledTarget == null) {
return false;
}
return fCurrentEnabledTarget.fEnabled;
}
private EnabledTarget getEnabledTarget(IWorkbenchWindow window) {
EnabledTarget target = fEnabledTargetsMap.get(window);
if (target == null) {
target = new EnabledTarget(window);
fEnabledTargetsMap.put(window, target);
target.init();
}
return target;
}
/* (non-Javadoc)
* @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
*/
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
if (window == null) {
throw new ExecutionException("No active workbench window."); //$NON-NLS-1$
}
fCurrentEnabledTarget = getEnabledTarget(window);
ISelection selection = getContextService(window).getActiveContext();
if (selection instanceof IStructuredSelection && isEnabled()) {
IStructuredSelection ss = (IStructuredSelection) selection;
boolean enabledAfterExecute = execute(window, ss.toArray());
// enable/disable the action according to the command
fCurrentEnabledTarget.setEnabled(enabledAfterExecute);
}
return null;
}
private IDebugContextService getContextService(IWorkbenchWindow window) {
return DebugUITools.getDebugContextManager().getContextService(window);
}
/**
* Executes this action on the given target objects
* @param window the window
* @param targets the targets to execute this action on
* @return if the command stays enabled while the command executes
*/
private boolean execute(IWorkbenchWindow window, final Object[] targets) {
DebugCommandService service = DebugCommandService.getService(window);
return service.executeCommand(
getCommandType(), targets,
new ICommandParticipant() {
@Override
public void requestDone(org.eclipse.debug.core.IRequest request) {
DebugCommandHandler.this.postExecute(request, targets);
}
});
}
/**
* This method is called after the completion of the execution of this
* command. Extending classes may override this method to perform additional
* operation after command execution.
*
* @param request The completed request object which was given the the
* debug command handler.
* @param targets Objects which were the targets of this action
*/
protected void postExecute(IRequest request, Object[] targets) {
// do nothing by default
}
/**
* Returns the {@link org.eclipse.debug.core.commands.IDebugCommandHandler}
* command handler that type this action executes.
*
* @return command class.
*
* @see org.eclipse.debug.core.commands.IDebugCommandHandler
*/
abstract protected Class<?> getCommandType();
/**
* Returns whether this action should be enabled when initialized
* and there is no active debug context.
*
* @return false, by default
*/
protected boolean getInitialEnablement() {
return false;
}
/**
* Clean up when removing
*/
@Override
public void dispose() {
PlatformUI.getWorkbench().removeWindowListener(fWindowListener);
for(EnabledTarget target : fEnabledTargetsMap.values()) {
if (!target.isDisposed()) {
target.dispose();
}
}
fEnabledTargetsMap.clear();
fCurrentEnabledTarget = null;
}
}