Adding One-Line UndoNano provides an efficient type-safe undo mechanism, bringing unlimited undo/redo to Carbon applications with one line of code. This is achieved through the NUndoManager class, an instance of which is contained within each NDocument. OverviewThe basic model for undo is that methods that can perform an undo-able action should first inform the undo manager how to undo it. Nano captures actions as functors, self-contained objects that represent an arbitrary function call. This approach allows applications to achieve "one-line undo", since methods that perform an action can simply record themselves with the current state in order to revert the action:
void CShape::SetColor(const NColor &theColor)
{
RecordUndo(BindSelf(CShape::SetColor, mColor), kColorChangeKey);
mColor = theColor;
}
The equivalent code using Cocoa's NSUndoManager is:
- (void) setColor:(const NSColor *) theColor
{
[[[self undoManager] prepareWithInvocationTarget:self] setColor:mColor];
[[self undoManager] setActionName:NSLocalizedString(@kColorChangeKey, @"Color Change")];
[mColor release];
mColor = [theColor copy];
}
In Nano, an undo action captures an object, a method, and an arbitrary list of parameters. The captured method does not need to be declared as static, and will be invoked dynamically with the specified parameters on the captured object. When the user selects a new color, SetColor will record an action that sets the color to its current value and supplies an (optional) localized string for the Edit menu. When the user performs an undo, this action will be invoked and the shape restored to the previous color. NUndoManagerNUndoManager is the core undo object within Nano. It maintains a pair of stacks to hold undo actions, and moves actions between these stacks as the user performs undo or redo operations. Each stack is allowed to grow indefinitely, or up to some limit. NUndoManager also handles user interface interaction, by responding to undo/redo commands or updating the appearance of their menu items. Since NUndoManager knows when an undo or redo is being performed, it can also ensure that recorded actions are added to the appropriate stack. I.e., when an action is undone, it will typically record another action to undo the undo-ing - which is automatically placed on the redo stack. Document UndoEach NWindowController object, and by extension each NDocument, contains an instance of NUndoManager. This ensures that each window automatically maintains its own undo history, allowing the user to make changes in one window without affecting the history of other windows. As well as containing an undo manager, NWindowController also provides a simplified interface for recording actions. This allows callers to capture both an action to undo, and a localized string to name that action, in one line of code. NDocument will also monitor changes to its undo manager, automatically updating the document "dirty" state as operations are undone or redone. Undo GroupsThe undo manager can capture multiple actions as a single group, allowing complex operations to appear as a single action to the user. Undo groups can contain an arbitrary number of actions; each item on the undo stack is in fact a group of actions, and size limits imposed on the stack do not affect the number of actions that can be grouped. Groups can be opened/closed around a sequence of actions, or will be opened/closed automatically around individual actions as required. Interactive UndoOne common problem with action-based undo is how to efficiently represent interactive operations, where a large number of actions may be captured due to user input. For example, dragging the mouse around a color picker wheel may trigger hundreds of calls to SetColor before the mouse is released. Each of these actions should be placed within one group, to ensure they appear as a single operation to the user. Although this is straightforward to arrange, undoing or redoing that operation will still need to invoke hundreds of actions each time it is performed. To improve the efficiency of this process, NWindowController::TrackUndo can be used to capture actions within a mouse tracking sequence into a single group. When the mouse is released, TrackUndo will consolidate the group into a single action, ensuring that the group placed on the undo/redo stacks is a more efficient representation of the operation. |
|
| Copyright © 2006-2007 refNum Software | |