TSE3 Commands
The TSE3::Cmd namespace contains classes that implement a
GoF Command pattern. You can use this in applications that use the
TSE3 library to provide a command history with undo/redo facilities.
However, in order to use these classes there are a number of provisos
that you must take care to note:
- The commands
There is a TSE3::Cmd class for every useful operation
on the Song data structure and it's subcomponents. There
are not commands for alterations to the state of objects like
Transport and Metronome since they are
system wide settings, not Song alterations.
- The
CommandHistory class
The CommandHistory class holds the list of commands.
For any operation, you create a Command object for it
(with new), call execute() on the command,
and then add it to the CommandHistory class.
For now on you can call undo and redo on the
CommandHistory to undo/redo the history of operations.
Remember that your application will be kept up to date with the
resulting changes to the Song through the
Notifier interface mechanism.
- Multiple
Songs
If you support multiple Song objects in your application
you can either use one CommandHistory class for all
operations, or create a separate CommandHistory for
each Song. It is this latter operation that is the most
logical, and the TSE3_Application::Application class
contains support for it.
- If you use commands, don't directly use the TSE3 API
If you are using TSE3 Commands then any change to a Song
or it's subcomponents must be done through commands. Otherwise,
if the state of the Song changes between a command
being executed and undone unpredicatable
results may occur.
- Writing your own commands
If you implement your own commands that are creational or destrutional
(if that is a word ;-) you must take care. If you, for example, create
a new Part in execute you should not
delete it in undo and then create a different
Part in a subsequent call to execute. Why?
If any subsequent commands act on that Part and take a
Part* parameter to identify it, by deleting the
Part and creating a new different one on a 'redo' you
will cause the later command to be invalid.
Creational patterns should create objects in the constructors,
put them into the Song in undo, and delete the object
in the destructor only if the object is deleted after having
been undone.
Destructional commands should merely remove the object in
execute and put the same object back in in
undo. The object may only be deleted in the destructor
if the command has not been undone.
However, despite these provisos and the extra care that you must take when
using the command pattern in your application, the benefits are great:
the undo/redo facility is a really user-friendly useful facility that sets
a good application appart from a great one.