Mercurial > projects > dwt-addons
view dwtx/core/commands/Command.d @ 90:7ffeace6c47f
Update 3.4M7 to 3.4
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 06 Jul 2008 23:30:07 +0200 |
parents | 4878bef4a38e |
children |
line wrap: on
line source
/******************************************************************************* * Copyright (c) 2004, 2008 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 * Port to the D programming language: * Frank Benoit <benoit@tionex.de> *******************************************************************************/ module dwtx.core.commands.Command; // import java.io.BufferedWriter; // import java.io.IOException; // import java.io.StringWriter; import dwtx.core.commands.common.NotDefinedException; import dwtx.core.commands.util.Tracing; import dwtx.core.internal.commands.util.Util; import dwtx.core.runtime.ISafeRunnable; import dwtx.core.runtime.ListenerList; import dwtx.core.runtime.SafeRunner; import dwtx.core.commands.IParameter; import dwtx.core.commands.IHandlerListener; import dwtx.core.commands.NotEnabledException; import dwtx.core.commands.NotHandledException; import dwtx.core.commands.ExecutionException; import dwtx.core.commands.CommandEvent; import dwtx.core.commands.State; import dwtx.core.commands.Category; import dwtx.core.commands.NamedHandleObjectWithState; import dwtx.core.commands.ExecutionEvent; import dwtx.core.commands.ParameterType; import dwtx.core.commands.IExecutionListener; import dwtx.core.commands.ICommandListener; import dwtx.core.commands.IHandler; import dwtx.core.commands.IHandler2; import dwtx.core.commands.IObjectWithState; import dwtx.core.commands.IExecutionListenerWithChecks; import dwtx.core.commands.ITypedParameter; import dwtx.core.commands.HandlerEvent; import dwt.dwthelper.utils; import tango.text.convert.Format; import tango.io.Stdout; /** * <p> * A command is an abstract representation for some semantic behaviour. It is * not the actual implementation of this behaviour, nor is it the visual * appearance of this behaviour in the user interface. Instead, it is a bridge * between the two. * </p> * <p> * The concept of a command is based on the command design pattern. The notable * difference is how the command delegates responsibility for execution. Rather * than allowing concrete subclasses, it uses a handler mechanism (see the * <code>handlers</code> extension point). This provides another level of * indirection. * </p> * <p> * A command will exist in two states: defined and undefined. A command is * defined if it is declared in the XML of a resolved plug-in. If the plug-in is * unloaded or the command is simply not declared, then it is undefined. Trying * to reference an undefined command will succeed, but trying to access any of * its functionality will fail with a <code>NotDefinedException</code>. If * you need to know when a command changes from defined to undefined (or vice * versa), then attach a command listener. * </p> * <p> * Commands are mutable and will change as their definition changes. * </p> * * @since 3.1 */ public final class Command : NamedHandleObjectWithState, Comparable { /** * This flag can be set to <code>true</code> if commands should print * information to <code>System.out</code> when executing. */ public static bool DEBUG_COMMAND_EXECUTION = false; /** * This flag can be set to <code>true</code> if commands should print * information to <code>System.out</code> when changing handlers. */ public static bool DEBUG_HANDLERS = false; /** * This flag can be set to a particular command identifier if only that * command should print information to <code>System.out</code> when * changing handlers. */ public static String DEBUG_HANDLERS_COMMAND_ID = null; /** * The category to which this command belongs. This value should not be * <code>null</code> unless the command is undefined. */ private Category category = null; /** * A collection of objects listening to the execution of this command. This * collection is <code>null</code> if there are no listeners. */ private /+transient+/ ListenerList executionListeners = null; /** * The handler currently associated with this command. This value may be * <code>null</code> if there is no handler currently. */ private /+transient+/ IHandler handler = null; /** * The help context identifier for this command. This can be * <code>null</code> if there is no help currently associated with the * command. * * @since 3.2 */ private String helpContextId; /** * The ordered array of parameters understood by this command. This value * may be <code>null</code> if there are no parameters, or if the command * is undefined. It may also be empty. */ private IParameter[] parameters = null; /** * The type of the return value of this command. This value may be * <code>null</code> if the command does not declare a return type. * * @since 3.2 */ private ParameterType returnType = null; /** * Our command will listen to the active handler for enablement changes so * that they can be fired from the command itself. * * @since 3.3 */ private IHandlerListener handlerListener; /** * Constructs a new instance of <code>Command</code> based on the given * identifier. When a command is first constructed, it is undefined. * Commands should only be constructed by the <code>CommandManager</code> * to ensure that the identifier remains unique. * * @param id * The identifier for the command. This value must not be * <code>null</code>, and must be unique amongst all commands. */ this(String id) { super(id); } /** * Adds a listener to this command that will be notified when this command's * state changes. * * @param commandListener * The listener to be added; must not be <code>null</code>. */ public final void addCommandListener(ICommandListener commandListener) { if (commandListener is null) { throw new NullPointerException("Cannot add a null command listener"); //$NON-NLS-1$ } addListenerObject(cast(Object)commandListener); } /** * Adds a listener to this command that will be notified when this command * is about to execute. * * @param executionListener * The listener to be added; must not be <code>null</code>. */ public final void addExecutionListener( IExecutionListener executionListener) { if (executionListener is null) { throw new NullPointerException( "Cannot add a null execution listener"); //$NON-NLS-1$ } if (executionListeners is null) { executionListeners = new ListenerList(ListenerList.IDENTITY); } executionListeners.add(cast(Object)executionListener); } /** * <p> * Adds a state to this command. This will add this state to the active * handler, if the active handler is an instance of {@link IObjectWithState}. * </p> * <p> * A single instance of {@link State} cannot be registered with multiple * commands. Each command requires its own unique instance. * </p> * * @param id * The identifier of the state to add; must not be * <code>null</code>. * @param state * The state to add; must not be <code>null</code>. * @since 3.2 */ public override void addState(String id, State state) { super.addState(id, state); state.setId(id); if ( auto h = cast(IObjectWithState)handler) { h.addState(id, state); } } /** * Compares this command with another command by comparing each of its * non-transient attributes. * * @param object * The object with which to compare; must be an instance of * <code>Command</code>. * @return A negative integer, zero or a postivie integer, if the object is * greater than, equal to or less than this command. */ public final int compareTo(Object object) { Command castedObject = cast(Command) object; int compareTo = Util.compare(category, castedObject.category); if (compareTo is 0) { compareTo = Util.compare(defined, castedObject.defined); if (compareTo is 0) { compareTo = Util.compare(description, castedObject.description); if (compareTo is 0) { compareTo = Util.compare(cast(Object)handler, cast(Object)castedObject.handler); if (compareTo is 0) { compareTo = Util.compare(id, castedObject.id); if (compareTo is 0) { compareTo = Util.compare(name, castedObject.name); if (compareTo is 0) { Object[] left, right; foreach( p; parameters ){ left ~= cast(Object)p; } foreach( p; castedObject.parameters ){ right ~= cast(Object)p; } compareTo = Util.compare(left, right); } } } } } } return compareTo; } /** * <p> * Defines this command by giving it a name, and possibly a description as * well. The defined property automatically becomes <code>true</code>. * </p> * <p> * Notification is sent to all listeners that something has changed. * </p> * * @param name * The name of this command; must not be <code>null</code>. * @param description * The description for this command; may be <code>null</code>. * @param category * The category for this command; must not be <code>null</code>. * @since 3.2 */ public final void define(String name, String description, Category category) { define(name, description, category, null); } /** * <p> * Defines this command by giving it a name, and possibly a description as * well. The defined property automatically becomes <code>true</code>. * </p> * <p> * Notification is sent to all listeners that something has changed. * </p> * * @param name * The name of this command; must not be <code>null</code>. * @param description * The description for this command; may be <code>null</code>. * @param category * The category for this command; must not be <code>null</code>. * @param parameters * The parameters understood by this command. This value may be * either <code>null</code> or empty if the command does not * accept parameters. */ public final void define(String name, String description, Category category, IParameter[] parameters) { define(name, description, category, parameters, null); } /** * <p> * Defines this command by giving it a name, and possibly a description as * well. The defined property automatically becomes <code>true</code>. * </p> * <p> * Notification is sent to all listeners that something has changed. * </p> * * @param name * The name of this command; must not be <code>null</code>. * @param description * The description for this command; may be <code>null</code>. * @param category * The category for this command; must not be <code>null</code>. * @param parameters * The parameters understood by this command. This value may be * either <code>null</code> or empty if the command does not * accept parameters. * @param returnType * The type of value returned by this command. This value may be * <code>null</code> if the command does not declare a return * type. * @since 3.2 */ public final void define(String name, String description, Category category, IParameter[] parameters, ParameterType returnType) { define(name, description, category, parameters, returnType, null); } /** * <p> * Defines this command by giving it a name, and possibly a description as * well. The defined property automatically becomes <code>true</code>. * </p> * <p> * Notification is sent to all listeners that something has changed. * </p> * * @param name * The name of this command; must not be <code>null</code>. * @param description * The description for this command; may be <code>null</code>. * @param category * The category for this command; must not be <code>null</code>. * @param parameters * The parameters understood by this command. This value may be * either <code>null</code> or empty if the command does not * accept parameters. * @param returnType * The type of value returned by this command. This value may be * <code>null</code> if the command does not declare a return * type. * @param helpContextId * The identifier of the help context to associate with this * command; may be <code>null</code> if this command does not * have any help associated with it. * @since 3.2 */ public final void define(String name, String description, Category category, IParameter[] parameters, ParameterType returnType, String helpContextId) { if (name is null) { throw new NullPointerException( "The name of a command cannot be null"); //$NON-NLS-1$ } if (category is null) { throw new NullPointerException( "The category of a command cannot be null"); //$NON-NLS-1$ } bool definedChanged = !this.defined; this.defined = true; bool nameChanged = !Util.equals(this.name, name); this.name = name; bool descriptionChanged = !Util.equals(this.description, description); this.description = description; bool categoryChanged = !Util.equals(this.category, category); this.category = category; Object[] pLeft, pRight; foreach( p; this.parameters ){ pLeft ~= cast(Object)p; } foreach( p; parameters ){ pRight ~= cast(Object)p; } bool parametersChanged = !Util.equals(pLeft, pRight); this.parameters = parameters; bool returnTypeChanged = !Util.equals(this.returnType, returnType); this.returnType = returnType; bool helpContextIdChanged = !Util.equals(this.helpContextId, helpContextId); this.helpContextId = helpContextId; fireCommandChanged(new CommandEvent(this, categoryChanged, definedChanged, descriptionChanged, false, nameChanged, parametersChanged, returnTypeChanged, helpContextIdChanged)); } /** * Executes this command by delegating to the current handler, if any. If * the debugging flag is set, then this method prints information about * which handler is selected for performing this command. This method will * succeed regardless of whether the command is enabled or defined. It is * generally preferred to call {@link #executeWithChecks(ExecutionEvent)}. * * @param event * An event containing all the information about the current * state of the application; must not be <code>null</code>. * @return The result of the execution; may be <code>null</code>. This * result will be available to the client executing the command, and * execution listeners. * @throws ExecutionException * If the handler has problems executing this command. * @throws NotHandledException * If there is no handler. * @deprecated Please use {@link #executeWithChecks(ExecutionEvent)} * instead. */ public final Object execute(ExecutionEvent event) { firePreExecute(event); IHandler handler = this.handler; // Perform the execution, if there is a handler. if ((handler !is null) && (handler.isHandled())) { try { Object returnValue = handler.execute(event); firePostExecuteSuccess(returnValue); return returnValue; } catch (ExecutionException e) { firePostExecuteFailure(e); throw e; } } NotHandledException e = new NotHandledException( "There is no handler to execute. " ~ getId()); //$NON-NLS-1$ fireNotHandled(e); throw e; } /** * Executes this command by delegating to the current handler, if any. If * the debugging flag is set, then this method prints information about * which handler is selected for performing this command. This does checks * to see if the command is enabled and defined. If it is not both enabled * and defined, then the execution listeners will be notified and an * exception thrown. * * @param event * An event containing all the information about the current * state of the application; must not be <code>null</code>. * @return The result of the execution; may be <code>null</code>. This * result will be available to the client executing the command, and * execution listeners. * @throws ExecutionException * If the handler has problems executing this command. * @throws NotDefinedException * If the command you are trying to execute is not defined. * @throws NotEnabledException * If the command you are trying to execute is not enabled. * @throws NotHandledException * If there is no handler. * @since 3.2 */ public final Object executeWithChecks(ExecutionEvent event) { firePreExecute(event); IHandler handler = this.handler; if (!isDefined()) { NotDefinedException exception = new NotDefinedException( "Trying to execute a command that is not defined. " //$NON-NLS-1$ ~ getId()); fireNotDefined(exception); throw exception; } // Perform the execution, if there is a handler. if ((handler !is null) && (handler.isHandled())) { setEnabled(event.getApplicationContext()); if (!isEnabled()) { NotEnabledException exception = new NotEnabledException( "Trying to execute the disabled command " ~ getId()); //$NON-NLS-1$ fireNotEnabled(exception); throw exception; } try { Object returnValue = handler.execute(event); firePostExecuteSuccess(returnValue); return returnValue; } catch (ExecutionException e) { firePostExecuteFailure(e); throw e; } } NotHandledException e = new NotHandledException( "There is no handler to execute for command " ~ getId()); //$NON-NLS-1$ fireNotHandled(e); throw e; } /** * Notifies the listeners for this command that it has changed in some way. * * @param commandEvent * The event to send to all of the listener; must not be * <code>null</code>. */ private final void fireCommandChanged(CommandEvent commandEvent) { if (commandEvent is null) { throw new NullPointerException("Cannot fire a null event"); //$NON-NLS-1$ } Object[] listeners = getListeners(); for (int i = 0; i < listeners.length; i++) { ICommandListener listener = cast(ICommandListener) listeners[i]; SafeRunner.run(new class(listener) ISafeRunnable { ICommandListener listener_; this(ICommandListener a){ this.listener_ = a; } public void handleException(Exception exception) { } public void run() { listener_.commandChanged(commandEvent); } }); } } /** * Notifies the execution listeners for this command that an attempt to * execute has failed because the command is not defined. * * @param e * The exception that is about to be thrown; never * <code>null</code>. * @since 3.2 */ private final void fireNotDefined(NotDefinedException e) { // Debugging output if (DEBUG_COMMAND_EXECUTION) { Tracing.printTrace("COMMANDS", "execute" ~ Tracing.SEPARATOR //$NON-NLS-1$ //$NON-NLS-2$ ~ "not defined: id=" ~ getId() ~ "; exception=" ~ e.toString ); //$NON-NLS-1$ //$NON-NLS-2$ } if (executionListeners !is null) { Object[] listeners = executionListeners.getListeners(); for (int i = 0; i < listeners.length; i++) { Object object = listeners[i]; if ( auto listener = cast(IExecutionListenerWithChecks)object ) { listener.notDefined(getId(), e); } } } } /** * Notifies the execution listeners for this command that an attempt to * execute has failed because there is no handler. * * @param e * The exception that is about to be thrown; never * <code>null</code>. * @since 3.2 */ private final void fireNotEnabled(NotEnabledException e) { // Debugging output if (DEBUG_COMMAND_EXECUTION) { Tracing.printTrace("COMMANDS", "execute" ~ Tracing.SEPARATOR //$NON-NLS-1$ //$NON-NLS-2$ ~ "not enabled: id=" ~ getId() ~ "; exception=" ~ e.toString ); //$NON-NLS-1$ //$NON-NLS-2$ } if (executionListeners !is null) { Object[] listeners = executionListeners.getListeners(); for (int i = 0; i < listeners.length; i++) { Object object = listeners[i]; if ( auto listener = cast(IExecutionListenerWithChecks)object ) { listener.notEnabled(getId(), e); } } } } /** * Notifies the execution listeners for this command that an attempt to * execute has failed because there is no handler. * * @param e * The exception that is about to be thrown; never * <code>null</code>. */ private final void fireNotHandled(NotHandledException e) { // Debugging output if (DEBUG_COMMAND_EXECUTION) { Tracing.printTrace("COMMANDS", "execute" ~ Tracing.SEPARATOR //$NON-NLS-1$ //$NON-NLS-2$ ~ "not handled: id=" ~ getId() ~ "; exception=" ~ e.toString ); //$NON-NLS-1$ //$NON-NLS-2$ } if (executionListeners !is null) { Object[] listeners = executionListeners.getListeners(); for (int i = 0; i < listeners.length; i++) { IExecutionListener listener = cast(IExecutionListener) listeners[i]; listener.notHandled(getId(), e); } } } /** * Notifies the execution listeners for this command that an attempt to * execute has failed during the execution. * * @param e * The exception that has been thrown; never <code>null</code>. * After this method completes, the exception will be thrown * again. */ private final void firePostExecuteFailure(ExecutionException e) { // Debugging output if (DEBUG_COMMAND_EXECUTION) { Tracing.printTrace("COMMANDS", "execute" ~ Tracing.SEPARATOR //$NON-NLS-1$ //$NON-NLS-2$ ~ "failure: id=" ~ getId() ~ "; exception=" ~ e.toString ); //$NON-NLS-1$ //$NON-NLS-2$ } if (executionListeners !is null) { Object[] listeners = executionListeners.getListeners(); for (int i = 0; i < listeners.length; i++) { IExecutionListener listener = cast(IExecutionListener) listeners[i]; listener.postExecuteFailure(getId(), e); } } } /** * Notifies the execution listeners for this command that an execution has * completed successfully. * * @param returnValue * The return value from the command; may be <code>null</code>. */ private final void firePostExecuteSuccess(Object returnValue) { // Debugging output if (DEBUG_COMMAND_EXECUTION) { Tracing.printTrace("COMMANDS", "execute" ~ Tracing.SEPARATOR //$NON-NLS-1$ //$NON-NLS-2$ ~ "success: id=" ~ getId() ~ "; returnValue=" //$NON-NLS-1$ //$NON-NLS-2$ ~ returnValue.toString ); } if (executionListeners !is null) { Object[] listeners = executionListeners.getListeners(); for (int i = 0; i < listeners.length; i++) { IExecutionListener listener = cast(IExecutionListener) listeners[i]; listener.postExecuteSuccess(getId(), returnValue); } } } /** * Notifies the execution listeners for this command that an attempt to * execute is about to start. * * @param event * The execution event that will be used; never <code>null</code>. */ private final void firePreExecute(ExecutionEvent event) { // Debugging output if (DEBUG_COMMAND_EXECUTION) { Tracing.printTrace("COMMANDS", "execute" ~ Tracing.SEPARATOR //$NON-NLS-1$ //$NON-NLS-2$ ~ "starting: id=" ~ getId() ~ "; event=" ~ event.toString ); //$NON-NLS-1$ //$NON-NLS-2$ } if (executionListeners !is null) { Object[] listeners = executionListeners.getListeners(); for (int i = 0; i < listeners.length; i++) { IExecutionListener listener = cast(IExecutionListener) listeners[i]; listener.preExecute(getId(), event); } } } /** * Returns the category for this command. * * @return The category for this command; never <code>null</code>. * @throws NotDefinedException * If the handle is not currently defined. */ public final Category getCategory() { if (!isDefined()) { throw new NotDefinedException( "Cannot get the category from an undefined command. " //$NON-NLS-1$ ~ id); } return category; } /** * Returns the current handler for this command. This is used by the command * manager for determining the appropriate help context identifiers and by * the command service to allow handlers to update elements. * <p> * This value can change at any time and should never be cached. * </p> * * @return The current handler for this command; may be <code>null</code>. * @since 3.3 */ public final IHandler getHandler() { return handler; } /** * Returns the help context identifier associated with this command. This * method should not be called by clients. Clients should use * {@link CommandManager#getHelpContextId(Command)} instead. * * @return The help context identifier for this command; may be * <code>null</code> if there is none. * @since 3.2 */ final String getHelpContextId() { return helpContextId; } /** * Returns the parameter with the provided id or <code>null</code> if this * command does not have a parameter with the id. * * @param parameterId * The id of the parameter to retrieve. * @return The parameter with the provided id or <code>null</code> if this * command does not have a parameter with the id. * @throws NotDefinedException * If the handle is not currently defined. * @since 3.2 */ public final IParameter getParameter(String parameterId) { if (!isDefined()) { throw new NotDefinedException( "Cannot get a parameter from an undefined command. " //$NON-NLS-1$ ~ id); } if (parameters is null) { return null; } for (int i = 0; i < parameters.length; i++) { IParameter parameter = parameters[i]; if (parameter.getId().equals(parameterId)) { return parameter; } } return null; } /** * Returns the parameters for this command. This call triggers provides a * copy of the array, so excessive calls to this method should be avoided. * * @return The parameters for this command. This value might be * <code>null</code>, if the command has no parameters. * @throws NotDefinedException * If the handle is not currently defined. */ public final IParameter[] getParameters() { if (!isDefined()) { throw new NotDefinedException( "Cannot get the parameters from an undefined command. " //$NON-NLS-1$ ~ id); } if ((parameters is null) || (parameters.length is 0)) { return null; } IParameter[] returnValue = new IParameter[parameters.length]; SimpleType!(IParameter).arraycopy(parameters, 0, returnValue, 0, parameters.length); return returnValue; } /** * Returns the {@link ParameterType} for the parameter with the provided id * or <code>null</code> if this command does not have a parameter type * with the id. * * @param parameterId * The id of the parameter to retrieve the {@link ParameterType} * of. * @return The {@link ParameterType} for the parameter with the provided id * or <code>null</code> if this command does not have a parameter * type with the provided id. * @throws NotDefinedException * If the handle is not currently defined. * @since 3.2 */ public final ParameterType getParameterType(String parameterId) { IParameter parameter = getParameter(parameterId); if ( auto parameterWithType = cast(ITypedParameter)parameter ) { return parameterWithType.getParameterType(); } return null; } /** * Returns the {@link ParameterType} for the return value of this command or * <code>null</code> if this command does not declare a return value * parameter type. * * @return The {@link ParameterType} for the return value of this command or * <code>null</code> if this command does not declare a return * value parameter type. * @throws NotDefinedException * If the handle is not currently defined. * @since 3.2 */ public final ParameterType getReturnType() { if (!isDefined()) { throw new NotDefinedException( "Cannot get the return type of an undefined command. " //$NON-NLS-1$ ~ id); } return returnType; } /** * Returns whether this command has a handler, and whether this handler is * also handled and enabled. * * @return <code>true</code> if the command is handled; <code>false</code> * otherwise. */ public final bool isEnabled() { if (handler is null) { return false; } try { return handler.isEnabled(); } catch (Exception e) { if (DEBUG_HANDLERS) { // since this has the ability to generate megs of logs, only // provide information if tracing Tracing.printTrace("HANDLERS", "Handler " ~ (cast(Object)handler).toString() ~ " for " //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ ~ id ~ " threw unexpected exception"); //$NON-NLS-1$ ExceptionPrintStackTrace( e, Stdout ); } } return false; } /** * Called be the framework to allow the handler to update its enabled state. * * @param evaluationContext * the state to evaluate against. May be <code>null</code> * which indicates that the handler can query whatever model that * is necessary. This context must not be cached. * @since 3.4 */ public void setEnabled(Object evaluationContext) { if (null !is cast(IHandler2)handler ) { (cast(IHandler2) handler).setEnabled(evaluationContext); } } /** * Returns whether this command has a handler, and whether this handler is * also handled. * * @return <code>true</code> if the command is handled; <code>false</code> * otherwise. */ public final bool isHandled() { if (handler is null) { return false; } return handler.isHandled(); } /** * Removes a listener from this command. * * @param commandListener * The listener to be removed; must not be <code>null</code>. * */ public final void removeCommandListener( ICommandListener commandListener) { if (commandListener is null) { throw new NullPointerException( "Cannot remove a null command listener"); //$NON-NLS-1$ } removeListenerObject(cast(Object)commandListener); } /** * Removes a listener from this command. * * @param executionListener * The listener to be removed; must not be <code>null</code>. * */ public final void removeExecutionListener( IExecutionListener executionListener) { if (executionListener is null) { throw new NullPointerException( "Cannot remove a null execution listener"); //$NON-NLS-1$ } if (executionListeners !is null) { executionListeners.remove(cast(Object)executionListener); if (executionListeners.isEmpty()) { executionListeners = null; } } } /** * <p> * Removes a state from this command. This will remove the state from the * active handler, if the active handler is an instance of * {@link IObjectWithState}. * </p> * * @param stateId * The identifier of the state to remove; must not be * <code>null</code>. * @since 3.2 */ public override void removeState(String stateId) { if ( auto h = cast(IObjectWithState)handler ) { h.removeState(stateId); } super.removeState(stateId); } /** * Changes the handler for this command. This will remove all the state from * the currently active handler (if any), and add it to <code>handler</code>. * If debugging is turned on, then this will also print information about * the change to <code>System.out</code>. * * @param handler * The new handler; may be <code>null</code> if none. * @return <code>true</code> if the handler changed; <code>false</code> * otherwise. */ public final bool setHandler(IHandler handler) { if (Util.equals(cast(Object)handler, cast(Object)this.handler)) { return false; } // Swap the state around. String[] stateIds = getStateIds(); if (stateIds !is null) { for (int i = 0; i < stateIds.length; i++) { String stateId = stateIds[i]; if ( auto h = cast(IObjectWithState)this.handler ) { h.removeState(stateId); } if ( auto h = cast(IObjectWithState)handler ) { State stateToAdd = getState(stateId); h.addState(stateId, stateToAdd); } } } bool enabled = isEnabled(); if (this.handler !is null) { this.handler.removeHandlerListener(getHandlerListener()); } // Update the handler, and flush the string representation. this.handler = handler; if (this.handler !is null) { this.handler.addHandlerListener(getHandlerListener()); } string = null; // Debugging output if ((DEBUG_HANDLERS) && ((DEBUG_HANDLERS_COMMAND_ID is null) || (DEBUG_HANDLERS_COMMAND_ID .equals(id)))) { StringBuffer buffer = new StringBuffer("Command('"); //$NON-NLS-1$ buffer.append(id); buffer.append("') has changed to "); //$NON-NLS-1$ if (handler is null) { buffer.append("no handler"); //$NON-NLS-1$ } else { buffer.append('\''); buffer.append(( cast(Object)handler).toString); buffer.append("' as its handler"); //$NON-NLS-1$ } Tracing.printTrace("HANDLERS", buffer.toString()); //$NON-NLS-1$ } // Send notification fireCommandChanged(new CommandEvent(this, false, false, false, true, false, false, false, false, enabled !is isEnabled())); return true; } /** * @return the handler listener */ private IHandlerListener getHandlerListener() { if (handlerListener is null) { handlerListener = new class IHandlerListener { public void handlerChanged(HandlerEvent handlerEvent) { bool enabledChanged = handlerEvent.isEnabledChanged(); bool handledChanged = handlerEvent.isHandledChanged(); fireCommandChanged(new CommandEvent(this.outer, false, false, false, handledChanged, false, false, false, false, enabledChanged)); } }; } return handlerListener; } /** * The string representation of this command -- for debugging purposes only. * This string should not be shown to an end user. * * @return The string representation; never <code>null</code>. */ public override final String toString() { if (string is null) { String parms; foreach( p; parameters ){ parms ~= "{"~(cast(Object)p).toString~"}"; } string = Format("Command({},{},\n\t\t{},\n\t\t{},\n\t\t{},\n\t\t{},{},{})", id, name is null ? "":name, description is null?"":description, category is null?"":category.toString(), handler is null?"": (cast(Object)handler).toString(), parms, returnType is null?"":returnType.toString(), defined ); } return string; } /** * Makes this command become undefined. This has the side effect of changing * the name and description to <code>null</code>. This also removes all * state and disposes of it. Notification is sent to all listeners. */ public override final void undefine() { bool enabledChanged = isEnabled(); string = null; bool definedChanged = defined; defined = false; bool nameChanged = name !is null; name = null; bool descriptionChanged = description !is null; description = null; bool categoryChanged = category !is null; category = null; bool parametersChanged = parameters !is null; parameters = null; bool returnTypeChanged = returnType !is null; returnType = null; String[] stateIds = getStateIds(); if (stateIds !is null) { if ( auto handlerWithState = cast(IObjectWithState)handler ) { for (int i = 0; i < stateIds.length; i++) { String stateId = stateIds[i]; handlerWithState.removeState(stateId); State state = getState(stateId); removeState(stateId); state.dispose(); } } else { for (int i = 0; i < stateIds.length; i++) { String stateId = stateIds[i]; State state = getState(stateId); removeState(stateId); state.dispose(); } } } fireCommandChanged(new CommandEvent(this, categoryChanged, definedChanged, descriptionChanged, false, nameChanged, parametersChanged, returnTypeChanged, false, enabledChanged)); } }