01: package abbot.editor.actions;
02:
03: import java.util.ArrayList;
04:
05: /** Keep a history of commands, enabling potentially unlimited undo.
06: This class is not synchronized.<p>
07:
08: Note that undo is itself an undoable action.<p>
09: */
10:
11: public class CommandHistory {
12: private ArrayList list = new ArrayList();
13: /** The index of the most recent command "undone", or the size of the
14: * history if the most recent action was "execute".
15: */
16: private int cursor = 0;
17:
18: private Command get(int idx) {
19: return ((Command) list.get(idx));
20: }
21:
22: public boolean canUndo() {
23: return cursor > 0 && (get(cursor - 1) instanceof Undoable);
24: }
25:
26: public void undo() throws NoUndoException {
27: if (canUndo()) {
28: UndoableCommand undoable = (UndoableCommand) get(--cursor);
29: undoable.undo();
30: // Add the undo to the end of the history
31: list.add(new CommandComplement(undoable));
32: } else {
33: // Reset the cursor to the end of the history
34: cursor = list.size();
35: throw new NoUndoException();
36: }
37: }
38:
39: /** Add the given command to the command history. */
40: public void add(Command command) {
41: // If the command can't be undone, then clear the undo history
42: if (!(command instanceof Undoable)) {
43: clear();
44: }
45: list.add(command);
46: // Put the cursor at the end of the command history
47: cursor = list.size();
48: }
49:
50: public void clear() {
51: list.clear();
52: cursor = 0;
53: }
54:
55: /** Simple wrapper around an existing command to swap the sense of its
56: execute/undo.
57: */
58: private class CommandComplement implements UndoableCommand {
59: private UndoableCommand cmd;
60:
61: public CommandComplement(UndoableCommand orig) {
62: cmd = orig;
63: }
64:
65: public void execute() {
66: cmd.undo();
67: }
68:
69: public void undo() {
70: cmd.execute();
71: }
72: }
73: }
|