blob: 7397ef7fd5024438be53140ab76443cdaf20080c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 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.ui.internal.handlers;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.CommandEvent;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.ICommandListener;
import org.eclipse.core.commands.INamedHandleStateIds;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.State;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.jface.action.AbstractAction;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.bindings.keys.KeySequence;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.commands.RadioState;
import org.eclipse.jface.commands.ToggleState;
import org.eclipse.jface.menus.IMenuStateIds;
import org.eclipse.jface.menus.TextState;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.Util;
import org.eclipse.swt.events.HelpListener;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.internal.commands.CommandImageManager;
import org.eclipse.ui.internal.commands.ICommandImageService;
import org.eclipse.ui.keys.IBindingService;
import org.eclipse.ui.services.IServiceLocator;
/**
* <p>
* A wrapper around the new command infrastructure that imitates the old
* <code>IAction</code> interface.
* </p>
* <p>
* Clients may instantiate this class, but must not extend.
* </p>
* <p>
* <strong>PROVISIONAL</strong>. This class or interface has been added as
* part of a work in progress. There is a guarantee neither that this API will
* work nor that it will remain the same. Please do not use this API without
* consulting with the Platform/UI team.
* </p>
* <p>
* This class is eventually intended to exist in
* <code>org.eclipse.ui.handlers</code>.
* </p>
*
* @since 3.2
*/
public final class CommandLegacyActionWrapper extends AbstractAction {
/**
* Listens to changes to one or more commands, and forwards them out through
* the property change event mechanism.
*/
private final class CommandListener implements ICommandListener {
public final void commandChanged(final CommandEvent commandEvent) {
final Command baseCommand = commandEvent.getCommand();
// Check if the name changed.
if (commandEvent.isNameChanged()) {
String newName = null;
if (baseCommand.isDefined()) {
try {
newName = baseCommand.getName();
} catch (final NotDefinedException e) {
// Not defined, so leave as null.
}
}
firePropertyChange(IAction.TEXT, null, newName);
}
// Check if the description changed.
if (commandEvent.isDescriptionChanged()) {
String newDescription = null;
if (baseCommand.isDefined()) {
try {
newDescription = baseCommand.getDescription();
} catch (final NotDefinedException e) {
// Not defined, so leave as null.
}
}
firePropertyChange(IAction.DESCRIPTION, null, newDescription);
firePropertyChange(IAction.TOOL_TIP_TEXT, null, newDescription);
}
// Check if the handled property changed.
if (commandEvent.isHandledChanged()) {
if (baseCommand.isHandled()) {
firePropertyChange(IAction.HANDLED, Boolean.FALSE,
Boolean.TRUE);
} else {
firePropertyChange(IAction.HANDLED, Boolean.TRUE,
Boolean.FALSE);
}
}
}
}
/**
* The command with which this action is associated; never <code>null</code>.
*/
private ParameterizedCommand command;
/**
* Listens to changes in a command, and forwards them out through the
* property change event mechanism.
*/
private final ICommandListener commandListener = new CommandListener();
/**
* Whether this action has been marked as enabled.
*/
private boolean enabled = true;
/**
* The identifier for the action. This may be <code>null</code>.
*/
private String id;
/**
* A service locator that can be used for retrieving command-based services.
* This value is never <code>null</code>.
*/
private final IServiceLocator serviceLocator;
/**
* The image style to use for this action. This value may be
* <code>null</code>.
*/
private final String style;
/**
* Constructs a new instance of <code>ActionProxy</code>.
*
* @param id
* The initial action identifier; may be <code>null</code>.
* @param command
* The command with which this action is associated; must not be
* <code>null</code>.
* @param style
* The image style to use for this action, may be
* <code>null</code>.
* @param serviceLocator
* A service locator that can be used to find various
* command-based services; must not be <code>null</code>.
*/
public CommandLegacyActionWrapper(final String id,
final ParameterizedCommand command, final String style,
final IServiceLocator serviceLocator) {
if (command == null) {
throw new NullPointerException(
"An action proxy can't be created without a command"); //$NON-NLS-1$
}
if (serviceLocator == null) {
throw new NullPointerException(
"An action proxy can't be created without a service locator"); //$NON-NLS-1$
}
this.command = command;
this.id = id;
this.style = style;
this.serviceLocator = serviceLocator;
// TODO Needs to listen to command, state, binding and image changes.
command.getCommand().addCommandListener(commandListener);
}
public final int getAccelerator() {
final String commandId = getActionDefinitionId();
final IBindingService bindingService = (IBindingService) serviceLocator
.getService(IBindingService.class);
final TriggerSequence triggerSequence = bindingService
.getBestActiveBindingFor(commandId);
if (triggerSequence instanceof KeySequence) {
final KeySequence keySequence = (KeySequence) triggerSequence;
final KeyStroke[] keyStrokes = keySequence.getKeyStrokes();
if (keyStrokes.length == 1) {
final KeyStroke keyStroke = keyStrokes[0];
return keyStroke.getModifierKeys() | keyStroke.getNaturalKey();
}
}
return 0;
}
public final String getActionDefinitionId() {
return command.getId();
}
public final String getDescription() {
try {
return command.getCommand().getDescription();
} catch (final NotDefinedException e) {
return null;
}
}
public final ImageDescriptor getDisabledImageDescriptor() {
final String commandId = getActionDefinitionId();
final ICommandImageService commandImageService = (ICommandImageService) serviceLocator
.getService(ICommandImageService.class);
return commandImageService.getImageDescriptor(commandId,
CommandImageManager.TYPE_DISABLED, style);
}
public final HelpListener getHelpListener() {
// TODO Help. Addressing help on commands.
return null;
}
public final ImageDescriptor getHoverImageDescriptor() {
final String commandId = getActionDefinitionId();
final ICommandImageService commandImageService = (ICommandImageService) serviceLocator
.getService(ICommandImageService.class);
return commandImageService.getImageDescriptor(commandId,
CommandImageManager.TYPE_HOVER, style);
}
public final String getId() {
return id;
}
public final ImageDescriptor getImageDescriptor() {
final String commandId = getActionDefinitionId();
final ICommandImageService commandImageService = (ICommandImageService) serviceLocator
.getService(ICommandImageService.class);
return commandImageService.getImageDescriptor(commandId, style);
}
public final IMenuCreator getMenuCreator() {
// TODO Pulldown. What kind of callback is needed here?
return null;
}
public final int getStyle() {
// TODO Pulldown. This does not currently support the pulldown style.
final State state = command.getCommand().getState(IMenuStateIds.STYLE);
if (state instanceof RadioState) {
return IAction.AS_RADIO_BUTTON;
} else if (state instanceof ToggleState) {
return IAction.AS_CHECK_BOX;
}
return IAction.AS_PUSH_BUTTON;
}
public final String getText() {
try {
return command.getName();
} catch (final NotDefinedException e) {
return null;
}
}
public final String getToolTipText() {
return getDescription();
}
public final boolean isChecked() {
final State state = command.getCommand().getState(IMenuStateIds.STYLE);
if (state instanceof ToggleState) {
final Boolean currentValue = (Boolean) state.getValue();
return currentValue.booleanValue();
}
return false;
}
public final boolean isEnabled() {
final Command baseCommand = command.getCommand();
return baseCommand.isEnabled() && enabled;
}
/**
* Whether this action's local <code>enabled</code> property is set. This
* can be used by handlers that are trying to check if
* {@link #setEnabled(boolean)} has been called. This is typically used by
* legacy action proxies who are trying to avoid a <a
* href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=117496">stack
* overflow</a>.
*
* @return <code>false</code> if someone has called
* {@link #setEnabled(boolean)} with <code>false</code>;
* <code>true</code> otherwise.
*/
public final boolean isEnabledDisregardingCommand() {
return enabled;
}
public final boolean isHandled() {
final Command baseCommand = command.getCommand();
return baseCommand.isHandled();
}
public final void run() {
runWithEvent(null);
}
public final void runWithEvent(final Event event) {
final Command baseCommand = command.getCommand();
final ExecutionEvent executionEvent = new ExecutionEvent(command
.getCommand(), command.getParameterMap(), event, null);
try {
baseCommand.execute(executionEvent);
firePropertyChange(IAction.RESULT, null, Boolean.TRUE);
} catch (final NotHandledException e) {
firePropertyChange(IAction.RESULT, null, Boolean.FALSE);
} catch (final ExecutionException e) {
firePropertyChange(IAction.RESULT, null, Boolean.FALSE);
// TODO Should this be logged?
}
}
public final void setAccelerator(final int keycode) {
// TODO Binding. This is hopefully not essential.
}
public final void setActionDefinitionId(final String id) {
// Get the old values.
final boolean oldChecked = isChecked();
final String oldDescription = getDescription();
final boolean oldEnabled = isEnabled();
final boolean oldHandled = isHandled();
final ImageDescriptor oldDefaultImage = getImageDescriptor();
final ImageDescriptor oldDisabledImage = getDisabledImageDescriptor();
final ImageDescriptor oldHoverImage = getHoverImageDescriptor();
final String oldText = getText();
// Update the command.
final Command oldBaseCommand = command.getCommand();
oldBaseCommand.removeCommandListener(commandListener);
final ICommandService commandService = (ICommandService) serviceLocator
.getService(ICommandService.class);
final Command newBaseCommand = commandService.getCommand(id);
command = new ParameterizedCommand(newBaseCommand, null);
newBaseCommand.addCommandListener(commandListener);
// Get the new values.
final boolean newChecked = isChecked();
final String newDescription = getDescription();
final boolean newEnabled = isEnabled();
final boolean newHandled = isHandled();
final ImageDescriptor newDefaultImage = getImageDescriptor();
final ImageDescriptor newDisabledImage = getDisabledImageDescriptor();
final ImageDescriptor newHoverImage = getHoverImageDescriptor();
final String newText = getText();
// Fire property change events, as necessary.
if (newChecked != oldChecked) {
if (oldChecked) {
firePropertyChange(IAction.CHECKED, Boolean.TRUE, Boolean.FALSE);
} else {
firePropertyChange(IAction.CHECKED, Boolean.FALSE, Boolean.TRUE);
}
}
if (!Util.equals(oldDescription, newDescription)) {
firePropertyChange(IAction.DESCRIPTION, oldDescription,
newDescription);
firePropertyChange(IAction.TOOL_TIP_TEXT, oldDescription,
newDescription);
}
if (newEnabled != oldEnabled) {
if (oldEnabled) {
firePropertyChange(IAction.ENABLED, Boolean.TRUE, Boolean.FALSE);
} else {
firePropertyChange(IAction.ENABLED, Boolean.FALSE, Boolean.TRUE);
}
}
if (newHandled != oldHandled) {
if (oldHandled) {
firePropertyChange(IAction.HANDLED, Boolean.TRUE, Boolean.FALSE);
} else {
firePropertyChange(IAction.HANDLED, Boolean.FALSE, Boolean.TRUE);
}
}
if (!Util.equals(oldDefaultImage, newDefaultImage)) {
firePropertyChange(IAction.IMAGE, oldDefaultImage, newDefaultImage);
}
if (!Util.equals(oldDisabledImage, newDisabledImage)) {
firePropertyChange(IAction.IMAGE, oldDisabledImage,
newDisabledImage);
}
if (!Util.equals(oldHoverImage, newHoverImage)) {
firePropertyChange(IAction.IMAGE, oldHoverImage, newHoverImage);
}
if (!Util.equals(oldText, newText)) {
firePropertyChange(IAction.TEXT, oldText, newText);
}
}
public final void setChecked(final boolean checked) {
final State state = command.getCommand().getState(IMenuStateIds.STYLE);
if (state instanceof ToggleState) {
final Boolean currentValue = (Boolean) state.getValue();
if (checked != currentValue.booleanValue()) {
if (checked) {
state.setValue(Boolean.TRUE);
} else {
state.setValue(Boolean.FALSE);
}
}
}
}
public final void setDescription(final String text) {
final State state = command.getCommand().getState(
INamedHandleStateIds.DESCRIPTION);
if (state instanceof TextState) {
final String currentValue = (String) state.getValue();
if (!Util.equals(text, currentValue)) {
state.setValue(text);
}
}
}
public final void setDisabledImageDescriptor(final ImageDescriptor newImage) {
final String commandId = getActionDefinitionId();
final int type = CommandImageManager.TYPE_DISABLED;
final ICommandImageService commandImageService = (ICommandImageService) serviceLocator
.getService(ICommandImageService.class);
commandImageService.bind(commandId, type, style, newImage);
}
public final void setEnabled(final boolean enabled) {
if (enabled != this.enabled) {
final Boolean oldValue = this.enabled ? Boolean.TRUE
: Boolean.FALSE;
final Boolean newValue = enabled ? Boolean.TRUE : Boolean.FALSE;
this.enabled = enabled;
firePropertyChange(ENABLED, oldValue, newValue);
}
}
public final void setHelpListener(final HelpListener listener) {
// TODO Help Haven't even started to look at help yet.
}
public final void setHoverImageDescriptor(final ImageDescriptor newImage) {
final String commandId = getActionDefinitionId();
final int type = CommandImageManager.TYPE_HOVER;
final ICommandImageService commandImageService = (ICommandImageService) serviceLocator
.getService(ICommandImageService.class);
commandImageService.bind(commandId, type, style, newImage);
}
public final void setId(final String id) {
this.id = id;
}
public final void setImageDescriptor(final ImageDescriptor newImage) {
final String commandId = getActionDefinitionId();
final int type = CommandImageManager.TYPE_DEFAULT;
final ICommandImageService commandImageService = (ICommandImageService) serviceLocator
.getService(ICommandImageService.class);
commandImageService.bind(commandId, type, style, newImage);
}
public final void setMenuCreator(final IMenuCreator creator) {
// TODO Pulldown. This is complicated
}
public final void setText(final String text) {
final State state = command.getCommand().getState(
INamedHandleStateIds.NAME);
if (state instanceof TextState) {
final String currentValue = (String) state.getValue();
if (!Util.equals(text, currentValue)) {
state.setValue(text);
}
}
}
public final void setToolTipText(final String text) {
setDescription(text);
}
}