Next: CommandQueue
Up: User interface objects
Previous: User interface objects
  Contents
Subsections
Command
Files: |
Command.h, Command.C, Cmd*.h,
Cmd*.C |
Derived from: |
none |
Global instance (if any): |
none |
Used in optional component: |
Part of main VMD code |
This is a base class for all the objects used in VMD to peform actions
(commands) on the molecules or program state. Each time a request is to
be made to do some command (i.e. rotate the current scene, load a new
molecule, change a color, etc), an instance of a class derived from
Command is created, and given to a CommandQueue object. The
queue will then call virtual routines within Command to perform
the action it knows how to do. There are a large number of relatively
small classes derived from Command, each one used to perform a
particular type of action. These objects are all in the files with names
starting with 'Cmd', for example CmdDisplay.h and .C.
Each class derived from Command has these characteristics and abilities:
- A unique integer code, which must be one of the items in the
enumeration Cmdtype located at the top of the Command.h file.
The code for the particular subclass of Command is passed to
the Command constuctor, and available via the gettype()
function.
- The data necessary to perform the required action. This data must
be given to the object via the constructor when it is created.
- A textual equivalent of the command. This is created after the
object is instantiated, based on the particular data given to that
instance. This string is used to echo commands to the console or to
a file.
- The ability to perform the command itself. The virtual function
execute() is used to request the Command object to do its
stuff.
The basic philosophy behind the use of Command is that each action
that the user may possibly request to do should be encapsulated within
a class derived from Command. Each subclass should know also how
to create a text equivalent of the command. User interface objects in
VMD (those derived from UIObject must use these Command's
to do the actions requested by the user, by creating new Command
instances and giving them to a CommandQueue object to execute.
- Command::Command(Cmdtype, int)
The first argument specifies the type code for the command, while the
second argument is the ID of the user interface object which created
this Command instance (see section 27.4).
There is one large enumeration Cmdtype in Command, which contains
a set of unique ID's for each derived class of Command. This is done
as an enumeration here so that other objects in the program (notably
UIObjects) .. can be written with explicit codes to allow them to
check what type of command they may be working with. When a new Command
object is being written, a new value must be added to this list.
- Cmdtype mytype - unique code for this derived class.
- int textExists - whether or not the text equivalent of this
command has been created yet. This only needs to be done at most once,
and sometimes not at all (if commands are not being logged to a file or
the screen, for example).
- int hasTextCmd - whether or not this command even HAS a text
equivalent ... some commands do not, for example Event's.
- char cmdtextbuf[256] - character buffer to hold the text
equivalent string. This can be at most 256 characters.
- ostrstream *cmdText - character stream used to format the
text equivalent.
- virtual int do_execute(void) - the `heart' of each class
derived from Command. This function performs the required task
(if possible), and returns TRUE if successful, FALSE if there is an error.
When errors occur, messages should be printed to msgErr in this
function, and preferrably NOT within the lower-level objects (i.e. the
Molecule or DisplayDevice objects).
- virtual void create_text(void) - formats the text equivalent
of the command, writing the text to the cmdText stream.
Whenever an action is to be performed,
you create a new instance of the particular Command derivative with
a `new' operation:
Command* cmd = new CmdTranslate(x, y, z, 0);
Then, the command is queued, by adding it to a CommandQueue object,
by appending it to the queue:
commandQueue->append(cmd);
When doing this in a UIObject, there is a member function
addcommand(Command *) to do this more easily.
Once queued, the command will be executed during the main event loop in VMD,
and then the instance will be deleted after it is done executing. Do NOT
queue a static Command object, it must have been created using new.
(But see the description of the runcommand function in
CommandQueue, section 27.2.)
The following
`checklist' should be followed when creating a new type of command:
- Identify the `type' of command ... to affect the display, the
molecules, the on-screen forms, or whatever. There are several Cmd*
files, find one where it belongs, or create a new one of the form
CmdXXXX.h and .C
- Create a text equivalent of the commands. Text commands in VMD consist of one or more words separated by whitespace, and terminated
by a newline. The first word of the command should be an `identifying'
word to indicate the general type of action to be performed, and the
other words should be arguments to describe exactly what action to do
in the general category.
- Put a new code in the Cmdtype enumeration in Command.h
- Create the class definition in CmdXXXX.h. The only functions that
are needed are the constructor/destructor, and the virtual functions
do_execute and create_text. If the command does not have
a text equivalent, you do not need to provide a version of the latter.
- Put the member functions in the file CmdXXXX.C. The easiest thing
to do is to follow the patters in the Cmd*.C files.
- All commands must be understood by the text parser (UIText).
The parser reads in new commands, looks at the first word, and calls
a text callback function to process that command. If the new command
is just a variant of another existing command (i.e. the first word of this
new command is the same as some existing command), then it should be put
in an existing Cmd* file, and the function 'text_cmd_WWWW' at the top
of the respective .C file (where WWWW is the first word of the command)
should be updated to understand the new command. Add code to look for
the proper strings, to create a new instance of the new command, and to
add it to the given CommandQueue. If this command contains instead
a new word for the VMD vocabulary, go on the next step, otherwise the
next step can be skipped.
- For commands which contain a new starting word, so that they are
placed in new files CmdXXXX.h and .C, two things must be done to allow
VMD to be aware of the text versions of these commands and to be able
to execute them:
- At the beginning of CmdXXX.h and .C, a new function
`text_cmd_WWWW(int argc, char **argv, CommandQueue *cq, int id)'
must be defined and written. This routine must know how to examine
the text command (as provided in token form in argc and argv) and
create instances of the proper Command object to be added to
the command queue. Other Cmd* files contain examples.
- In the file UIText.C, there is a section where all the words
that are at the beginning of VMD commands are `registered', with
the callback function to call when that word is seen. Add a line
similar to the others in this section, to register the new word and
to specify the new function `text_cmd_WWWW'.
- If other user interfaces (other than the text interface) are to
have the ability to execute this same command, add this ability to them
as well.
- Finally, update the on-line help file vmd_help.html, and
the User's Guide.
The printing of error message is right now very uneven. Some commands do
so in the do_execute routine, others leave it to the objects being
operated upon to do the error message printing. It would be best if all
error messages were printed (if possible) in do_execute routines,
with the underlying objects just returning error codes to allow
do_execute to tell what is going wrong.
Next: CommandQueue
Up: User interface objects
Previous: User interface objects
  Contents
vmd@ks.uiuc.edu