package abbot.editor.actions; import java.util.ArrayList; /** Keep a history of commands, enabling potentially unlimited undo. This class is not synchronized.<p> Note that undo is itself an undoable action.<p> */ public class CommandHistory { private ArrayList list = new ArrayList(); /** The index of the most recent command "undone", or the size of the * history if the most recent action was "execute". */ private int cursor = 0; private Command get(int idx) { return ((Command)list.get(idx)); } public boolean canUndo() { return cursor > 0 && (get(cursor-1) instanceof Undoable); } public void undo() throws NoUndoException { if (canUndo()) { UndoableCommand undoable = (UndoableCommand)get(--cursor); undoable.undo(); // Add the undo to the end of the history list.add(new CommandComplement(undoable)); } else { // Reset the cursor to the end of the history cursor = list.size(); throw new NoUndoException(); } } /** Add the given command to the command history. */ public void add(Command command) { // If the command can't be undone, then clear the undo history if (!(command instanceof Undoable)) { clear(); } list.add(command); // Put the cursor at the end of the command history cursor = list.size(); } public void clear() { list.clear(); cursor = 0; } /** Simple wrapper around an existing command to swap the sense of its execute/undo. */ private class CommandComplement implements UndoableCommand { private UndoableCommand cmd; public CommandComplement(UndoableCommand orig) { cmd = orig; } public void execute() { cmd.undo(); } public void undo() { cmd.execute(); } } }