command processor

Most actions from the users which result in changes to a document, are done via commands. For this there are several reasons.

Undo and Redo

A command is a class, and each command issued to make a change to documents result in a new instance being stored on the undo stack. The command stores enough information to reverse the change it did when submitted. So the command brings the document from one state into another, and it can be submitted reverse to get the previous state. All handling of commands is via <<Dox(a2dCommandProcessor), it stores commands submitted to it, and also implements undo and redoing those commands. In general at least every document has its own command processor. The reason for this is simple. Imagine drawing into one document, and next click on a view of a second document and start drawing there, a bit later going back to draw in the first document. One wants to be able to undo all changes in the first document, without undoing changes to the second document. To be able to do this one needs to have two separate undo stack, since commands can only be undone in reverse sequence. At the same time one likes to be able to submit commands to open files, close files etc. For this a central command processor is used. Commands issued to that, in general can not be undone, but still are very useful for scripting and recording, and communicating changes in an application.

tree of grouped commands

Commands in a command processor are stored as a sequence, but at the same time a tree. Each group of commands, can become a new branch in the tree. The leafs on the tree are the actual commands. Why is it important to be able to group commands? There are situations where one action needs to be build up using several commands. As an example: drag an object which is connected by wires to other objects. Changing the position of an object is one command, but the changing wires are rewired, and all those changes are submitted from several locations inside the code. So a command can result in extra commands being submitted, and the command itself does not know this. Now by grouping such commands, makes it possible to undo the whole set of commands at once. The commands which did place the dragged object at a new position, and the commands which resulted indirectly from wires being replaced/rerouted, can be undone as if it was just one command. If we did not have such a grouping mechanism, the user could only undo the rewiring one wire at the time, and at last undo the actual drag of the object. This is not what he expects. One the other hand when drawing a polygon, one segment at a time, the user wants to be able to undo/redo the drawing one segment at a time. As soon as the polygon is finished and some other objects are drawn, undo should result in removing the polygons at once and not segment per segment. Again the segments drawing commands are placed inside a group, and as long as drawing the polygon is in action, the commands inside the group can be undone/redone. But when the polygon is finished, the group is closed, and a next polygon draw is placed in its own group. Undoing commands at the group level here, result in undoing the whole groups at once. Undoing a group commands is nothing more the automatically take all commands in the group and undoing them one by one.

In the end we have a tree structure, a grouped command contains several commands, which them selfs can be groups again.

where and when

As explained above a change in a document can result in more changes to other objects. And those changes are triggered by, but unknown to the first change. And in most cases they can not even be issued as a range of commands in one part of the code. In fact the commands for the changes are distributed in various part of the library, and the can only be combined by grouping the up front. Grouping such distributed submitted commands, is simply a matter of opening a new command group in the command processor.

groups of commands in a menu

A second use of a group is, to combine several commands in a group command first, without submitting it right away. Such a combined command can be attached to a menu. And when submitting the group command, all individual commands in the group will be submitted.

command classes with arguments

For commands a special way of adding arguments to the command are used. This makes it appear as a hash list of arguments. The advantage is that not all arguments need to be given, and the order is also not important. Here two examples of two commands which are prepared to be submitted:

   1 a2dCommand_GroupAB* command = new a2dCommand_GroupAB(     a2dCommand_GroupAB::Args().
   2         what( a2dCommand_GroupAB::BoolOperation_GroupAB ).
   3         operation( BOOL_A_SUB_B ).
   4         selectedA( true ).
   5         selectedB( true ) );

   1 a2dCommand_AskFile* command = new a2dCommand_AskFile( a2dCommand_AskFile::Args().
   2         message( _("Give Name of input Layer file") ).
   3         defaultDir( _T("%{layerFileSavePath}") ).
   4         extension( _T("*.cvg") ).
   5         fileFilter( _T("*.cvg") ).
   6         flags( wxOPEN | wxFILE_MUST_EXIST ).
   7         storeInVariable( _T("ask_file_result") ) ); 

As you you see, the period separates the arguments for the command. Although this does look like standard C++, it still is. Not all commands use this way to set the arguments to the command, and writing the command class to use this system is a bit more complicated, the advantages become clear when there are many options to a command. Study the code of a2dCommand__AskFile to see how its done.