Rogue Wave banner
Previous fileTop of DocumentContentsIndex pageNext file
Objective Grid User's Guide
Rogue Wave web site:  Home Page  |  Main Documentation Page

12.7 Undo/Redo Architecture

It is essential for user-friendly applications to support Undo and Redo. Therefore, we wanted to implement this feature in Objective Grid. One advanced requirement for Undo and Redo is the need for a transaction like behavior in the grid. This means, several commands should be packed together and undone or redone in one step.

The solution to this problem was to create command objects for each operation. Each operation executed in the grid creates a command object and stores information how to undo the operation in the command object. The command object will be stored in a history list. Every time a command needs to be undone, the command object will be popped from the history list and executed.

Objective Grid provides many operations that let you change the data in the grid. Some examples for operations in the grid are: changing the cell contents, insert, remove or move rows or columns, freeze rows or columns, cut and paste cells and much more. As we mentioned earlier, we took care to separate user interactions from commands, which perform changes in the grid. The code for performing the command is not part of the user interaction code itself. That means, when the user performs an action in the grid, this action will result in a call to a command method. A consequence of this approach is that grid operations can easily be executed programmatically and through user interactions. For example, when the user changes the row height of a row, the grid will execute the command SetRowHeight(). SetRowHeight() can also be called directly from within the grid without user interaction.

The CGXCommand class is an abstract base class for command objects. For every type of operation in the grid, a special CGXCommand-derivative has been implemented which stores all information necessary for undoing the operation into the command.

In Objective Grid, commands are methods in the grid class which instantiate a CGXCommand object only for Undo support. When the user clicks on a menu item, a command method is executed which creates the command object with Undo information.

All the functionality for the grid operations is implemented in the command methods in the grid. Command objects only store information how to call a command method in the grid.

The following sample code illustrates how CGXCommand objects are implemented. The Undo information is passed to the CGXSetFrozenRowsCmd object when the constructor is called. The Execute() method will be called when the command needs to be undone.

In the associated command method, the CGXCommand-derived object will be instantiated and initialized with the previous state in the grid. The object will then be added to the Undo/Redo list by calling AddCommand().

The ctCmd parameter tells the command method if the operation is executed the first time, if it is undone or redone or if should be rolled back (that is, undone without creating Redo information).

AddCommand() interpretes the ctCmd parameter. If the command is executed the first time (= gxDo) or if it is redone (= gxRedo), the command object will be placed in the Undo list. If the command is undone (= gxUndo), the command object will be placed in the Redo list.

The Undo() operation pops a command object from the Undo list and calls its execute method. The implementation is straightforward:

The Redo operation is implemented in the same way.

Figure 122: Schematic Structure for the Undo/Redo Implementation in Objective Grid

One advanced requirement for Undo/Redo was the need for a transaction like behavior in the grid. This means, several commands should be packed together and undone/redone with one call. The command pattern suggests creating a MacroCommand which can hold several command objects. This approach could also be used in Objective Grid for implementing the CGXBlockCmd command. The CGXBlockCmd class owns a list of command objects. When the Execute command of the CGXBlockCmd is called, it loops through all commands in the lists and calls each commands Execute() method.

The Undo operation is designed to work for the grid, but not for individual edit cells within the grid. In general, changes in the current cell will simply be discarded and no Undo information will be generated. For instance, if you type in several different cells and then fire Undo several times, the focus will move in reverse order from one cell to another inside the grid, performing the Undo operation for a sequence of cells. If you want to be able to undo changes in the current active cell, you must add the following line to your code:

pGrid->TransferCurrentCell();

The following citation from source code demonstrates this technique:

12.7.1 Other Issues Related to the Undo/Redo Architecture

Also, it should be noted that it is not possible to add new commands without changing the grid class. The user will have to subclass the grid and add a command method to the grid and also subclass the CGXCommand class and create a command class. You can do this if you have a discrete action that causes a state change that you would like to have Undo/Redo capability.



Previous fileTop of DocumentContentsNo linkNext file

Copyright © Rogue Wave Software, Inc. All Rights Reserved.

The Rogue Wave name and logo, and Stingray, are registered trademarks of Rogue Wave Software. All other trademarks are the property of their respective owners.
Provide feedback to Rogue Wave about its documentation.