3D PLM Enterprise Architecture |
User Interface - Commands |
Managing Undo/RedoHow to undo and redo end user input, transition actions, and command results |
Technical Article |
AbstractThis article shows how to enable the end user to undo and redo interactions in the active command, and to undo and redo previous command results. |
Undo/redo is managed at two levels:
Input undo/redo is available for the current state dialog command only. It enables the end user to successively undo each input, that is to cancel previous input and associated action to restore the document content as it was in each state the command passes through, up to the beginning of the command, and of course to redo, that is to replay canceled input and execute associated actions up to the state where the undo began. If successive undos reach the initial state, the command is deleted and the default command, usually Select, becomes the current one. Command undo/redo takes place to undo previous command global effects, up to the last recorded command. Each command can also be redone in one step, except the command that was current when the end user began to undo, since it was not completed and its effect was not recorded.
An object undo/redo can be added to both input and command undo/redo. It is available when the object created or modified by the state dialog command implements the CATIUndoTransaction interface. In this case, the object manages itself its own undo/redo.
[Top]
The state dialog command records an input history that allows the end user to undo previous input up to its initial state. Since an input is most of the time an agent valuation, an input usually triggers a transition, and if the guard condition evaluates True, the transition fires and executes an action. Whe the end user clicks Undo, the state dialog command reverses this transition to restore the transition's source state and unvaluates the dialog agent. To reverse the transition, an undo action must be associated with the transition. The dialog agent unvaluation is automatic. In the same way, to enable for redo, that is, to take again the input into account, and restores the transition's final state, a redo action must be associated with the transition.
As a result, you must provide an undo action for each action in order to restore the document as it was in the previous state, and a redo action to redo what is undone, along with the corresponding methods.
The undo and redo action methods are declared using the second and third
parameters of the Action
method. For example, the transition
between two states of a state dialog command that creates triangles could be.
... AddTransition(stStartState, stSecondState, AndCondition( IsOutputSetCondition(_daPathElement), Condition((ConditionMethod) & CAACreateTriangleCmd::CheckPoint1)), Action( (ActionMethod) & CAACreateTriangleCmd::CreatePoint, (ActionMethod) & CAACreateTriangleCmd::UndoCreatePoint, (ActionMethod) & CAACreateTriangleCmd::RedoCreatePoint)) ; ... |
[Top]
In this case, the object(s) modified by the command implement the CATIUndoTransaction
interface and manage themselves their undo and redo. As a result, the action
methods you provide for undo/redo must not modify them. You can provide these
methods as in Input Undo/Redo without Object Undo/Redo.
They are executed before the undo and redo methods of the CATIUndoTransaction
interface. You can also create the action using the Action
method,
and use the SetBeforeUndo
and SetBeforeRedo
methods.
... MyAction = Action((ActionMethod) & CAACreateTriangleCmd::CreatePoint); MyAction->SetBeforeUndo((ActionMethod) & CAACreateTriangleCmd::BeforeUndoCreatePoint); MyAction->SetBeforeRedo((ActionMethod) & CAACreateTriangleCmd::BeforeRedoCreatePoint); ... AddTransition(stStartState, stSecondState, AndCondition( IsOutputSetCondition(_daPathElement), Condition((ConditionMethod) & CAACreateTriangleCmd::CheckPoint1)), MyAction); ... |
Since the action is created using the Action
method, it is
automatically deleted by the state dialog command.
Additional undo and redo methods can be executed after the undo/redo methods
of the CATIUndoTransaction interface. They are declared using the SetAfterUndo
and SetAfterRedo
methods.
... MyAction->SetAfterUndo((ActionMethod) & CAACreateTriangleCmd::AfterUndoCreatePoint); MyAction->SetAfterRedo((ActionMethod) & CAACreateTriangleCmd::AfterRedoCreatePoint); ... |
[Top]
A command history is managed for command undo/redo. This makes it possible to
cancel the effects of the last state dialog commands recorded in this history,
and to redo them. For example, the Point command undo deletes the point created,
and its redo recreates the deleted point. To make this possible, the command
should provide an undo/redo object, instance of the CATCommandGlobalUndo
class, using the GetGlobalUndo
method overridden from the CATStateCommand
class. This undo/redo object has, as function members, the methods to be called
when the command undo or redo is requested by the end user, and a method
to manage the memory used. The GetGlobalUndo
method is called when
the command completes to put the undo/redo object in the command history ready
for use.
Command undo/redo is illustrated using a command that creates a triangle.
[Top]
This is possible by overriding the GetGlobalUndo
method to
return an instance of the CATCommandGlobalUndo class with appropriate
methods to undo and redo the triangle command effect.
CATCommandGlobalUndo * CAACreateTriangleCmd::GetGlobalUndo() { CATCommandGlobalUndo * CAACreateTriangleCmdGlobalUndo = NULL; if ( _EltTriangle ) { CAACreateTriangleCmdGlobalUndo = new CATCommandGlobalUndo( (CATGlobalUndoMethod) & CAACreateTriangleCmd::UndoCreateTriangle, (CATGlobalUndoMethod) & CAACreateTriangleCmd::RedoCreateTriangle, (void *) _EltTriangle, (CATGlobalUndoMethod) & CAACreateTriangleCmd::DeallocateTriangle); } return CAACreateTriangleCmdGlobalUndo; } |
The argument of the CATCommandGlobalUndo constructor are:
[Top]
The undo and redo methods are static, since the command is deleted when undo and redo occur, with the following signatures.
static void UndoCreateTriangle(void * iUsefulData); static void RedoCreateTriangle(void * iUsefulData); |
These methods are called with the _EltTriangle
object passed as
the third argument of the GetGlobalUndo
method. They should manage
the object deletion and creation in the document.
[Top]
Like the undo and redo method, the deallocation method is also static. It has the following signature:
static void DeallocateTriangle(void * iUsefulData); |
It is called when the command undo/redo object is removed from the command history. It should simply delete the object used by the undo and redo method.
void CAACreateTriangleCmd::DesallocatTriangle(void * iUsefulData) { if (iUsefulData) { // iUsefulData is the object to deallocate CAAIPolyline * Elt = (CAAIPolyline *) iUsefulData; if (Elt) Elt->Release(); } } |
[Top]
As with input undo/redo, the objects that implement the CATIUndoTransaction interface manage themselves their undo and redo, and the action methods you provide for undo/redo must not modify them. These object undos are automatically registered when a command that modifies them completes.
[Top]
The GetGlobalUndo
method can be used to return an instance of
the CATCommandGlobalUndo class with appropriate methods. These methods
are executed before the object undo/redo methods and must not modify the object.
CATCommandGlobalUndo * CAACreateTriangleCmd::GetGlobalUndo() { CATCommandGlobalUndo * CAACreateTriangleCmdGlobalUndo = NULL; if ( _EltTriangle ) { CAACreateTriangleCmdGlobalUndo = new CATCommandGlobalUndo( (CATGlobalUndoMethod) & CAACreateTriangleCmd::BeforeUndoCreateTriangle, (CATGlobalUndoMethod) & CAACreateTriangleCmd::BeforeRedoCreateTriangle, (void *) UsefulObject, (CATGlobalUndoMethod) & CAACreateTriangleCmd::Deallocate); } return CAACreateTriangleCmdGlobalUndo; } |
The argument of the CATCommandGlobalUndo constructor are:
You can also declare methods to execute after the object undo/redo. This is
possible using the SetAfterUndoMeth
and SetAfterRedoMeth
methods.
... SetAfterUndoMeth((CATGlobalUndoMethod) & CAACreateTriangleCmd::AfterUndoCreateTriangle); SetAfterRedoMeth((CATGlobalUndoMethod) & CAACreateTriangleCmd::AfterRedoCreateTriangle); ... |
[Top]
The undo and redo methods are static, since the command is deleted when undo and redo occur, with the following signatures.
static void BeforeUndoCreateTriangle(void * iUsefulData); static void BeforeRedoCreateTriangle(void * iUsefulData); static void AfterUndoCreateTriangle(void * iUsefulData); static void AfterRedoCreateTriangle(void * iUsefulData); |
These methods are called with the _EltTriangle
object passed as
the third argument of the GetGlobalUndo
method. They should manage
the object deletion and creation in the document.
[Top]
Like the undo and redo method, the deallocation method is also static. It has the following signature:
static void Deallocate(void * iUsefulData); |
It is called when the command undo/redo object is removed from the command history. It should simply delete the object used by the undo and redo methods.
[Top]
Another way of providing command global undo is to create your own class deriving from the CATCommandGlobalUndo class. In this case, you need to override its undo/redo methods.
class MyCommandGlobalUndo : public CATCommandGlobalUndo { CATDeclareClass; public : MyCommandGlobalUndo(); virtual ~MyCommandGlobalUndo(); virtual HRESULT BeforeUndo(); virtual HRESULT BeforeRedo(); virtual HRESULT AfterUndo(); virtual HRESULT AfterRedo(); }; |
BeforeUndo
and BeforeRedo
are executed before the
object undo/redo methods, and AfterUndo
and AfterRedo
are executed after these methods.
[Top]
The undo/redo can be managed for each end user input and for the whole command. If the used object implements the CATIUndoTransaction interface, it manages its own undo/redo by itself, and the methods that implement undo/redo don't need to deal with object undo/redo. Otherwise, they do.
The input undo/redo takes place as long as the command is active, and undo/redo methods are provided for each transition. The command undo redo is implemented in a CATGlobalUndoRedo class instance to which pointers to the appropriate undo/redo methods are passed.
[Top]
Version: 1 [Jan 2000] | Document created |
[Top] |
Copyright © 2000, Dassault Systèmes. All rights reserved.