| /******************************************************************************* |
| * 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; |
| } |
| } |