Command Classes

This section describes the VkAction class, which supports ViewKit ObjectPak command classes. Command classes allow you to implement actions as objects.

Overview

Nearly every user action in an interactive application can be thought of as a "command." Programmers typically implement commands as functions (callback functions, for example) that are invoked as a result of some user action. This section explores an approach in which each command in a system is modeled as an object.

Advantages of representing commands

Representing commands as objects has many advantages. Many commands have some state or data associated with the command, while others may involve a set of related functions. In both cases, a class allows the data and functions associated with a single logical operation to be encapsulated in one place. Because command objects are complete and self-contained, you can queue them for later execution, store them in "history" lists, re-exec might need to save some state data before executing the command. When you model commands as objects, you can store this information in data members.

The VkMenuAction class (described in "Menu Actions" ) implements the command class model to a certain extent in that it allows you to specify callback functions both for performing an action and undoing that action. But the VkMenuAction class does not provide a true command class in that it does not allow you to encapsulate any data or support functions the action might need within a discrete object. Furthermore, you must use the VkMenuAction class within a menu; it does not allow you to implement command classes activated by pushbuttons, text fields, or other input mechanisms.

ObjectPak provides two abstract classes to implement command classes in an application: VkAction and VkMenuActionObject. VkAction supports commands that do not appear in menus and VkMenuActionObject supports commands that appear in menus. VkAction does not inherit from any other classes, whereas VkMenuActionObject is a subclass of VkMenuAction, which allows you to add instances of it to a menu and manipulate them as you would any other menu item.

You can encapsulate with a subclass of VkAction or VkMenuActionObject any data or support functions required to perform an action. Additionally, commands implemented as subclasses of VkAction and VkMenuActionObject automatically register themselves with the ViewKit ObjectPak undo manager whenever you execute them.

Using Command Classes in ViewKit ObjectPak

To use command classes in ViewKit ObjectPak, you must create a separate subclass for each command in your application.

Command class constructors

The syntax of the VkAction constructor is:

VkAction(const char *name)

Each class derived from VkAction should provide a constructor that takes at least one argument: the object's name. All derived class constructors should pass the name to the VkAction constructor to initialize the basic class data members, and then initialize any subclass-specific data members.

The syntax of the VkMenuActionObject constructor is as follows:

VkMenuActionObject(const char *name, XtPointer clientData = NULL)

Each class derived from VkMenuActionObject should provide a constructor that takes two arguments: the object's name and optional client data. All derived class constructors should pass the name and the client data to the VkMenuActionObject constructor to initialize the basic class data members, and then initialize any subclass-specific data members.

The VkMenuActionObject constructor stores the client data in the protected data member _clientData:

void *_clientData

VkMenuActionObject objects do not use the _clientData data member for callback functions. Instead it is simply an untyped pointer that you can use to pass any information your command object might need. For example, you could pass a pointer to another object, a value, a string, or any other value. You can access and manipulate _clientData from member functions of your command subclass.

Overriding virtual functions

Both VkAction and VkMenuActionObject have two protected pure virtual functions that you must override: doit() and undoit():

virtual void doit()
virtual void undoit()

doit() performs the command class's action; undoit() undoes the action.

Using command classes as menu items

You can use command classes derived only from VkMenuActionObject in a ViewKit ObjectPak menu. Because VkAction is not derived from VkMenuItem, it does not provide the services required of a menu item.

You cannot specify VkMenuActionObject objects in a static menu description; you must add them dynamically using VkMenu::add(), which is described in "Creating a Menubar Using a Static Description" .

Activating command classes

When a user selects a VkMenuActionObject command object from a menu, ObjectPak executes the command by calling the object's doit() function. ObjectPak also automatically registers the command with the undo manager.

To activate a command object that is a subclass of VkAction, call that action's execute() member function:

void execute()

execute() calls the object's doit() function and registers the command with the undo manager.


Note: Do not call a command object's doit() function directly. Otherwise ObjectPak cannot register the command with the undo manager.


Setting the label used by command classes

Set the label of a VkMenuActionObject command object as you would any other VkMenuItem item (by setting the object's XmNlabelString resource or by calling the object's setLabel() function). "Common Features of Menu Items" describes how to set the label for a menu item.

Because VkAction objects are command classes and not interface classes, they technically do not have labels; however, the undo manager requires a label that it can display after you have executed a VkAction command. Therefore, ObjectPak allows you to set the value of a "labelString" resource for VkAction objects, qualified by the object's name. For example, if you have an instance of a VkAction named "formatPara", you can set the label for this object by providing a value for the "formatPara.labelString" resource:

*formatPara: Format Paragraph

If you do not provide a value for a VkAction object's "labelString" resource, the undo manager uses the object's name as the label.


Note: The VkAction "labelString" resource is a "synthetic" resource, not a widget resource. The only way that you can set the value of this resource is through a resource file. You can't use XtSetValues() because the object contains no widgets, and you can't use setDefaultResources() because VkAction is not a subclass of VkComponent.