Memento for Undo/Redo

The Memento design pattern is a standard approach to saving and reapplying states of a component or an application in order to create undo/redo functionality. The AdvancedTree component offers this built in through the use of two methods, getMemento() and setMemento(). getMemento() returns a memento object that you can pass back into the tree at a later time through the setMemento() method. You need not do anything with the mementos except store them for reapplication later. Each memento stores not only the data represented in the tree, but also the open/closed state of each node.

An example of mementos used for undo/redo can be found in the xml_manager.fla included with the component. The steps below show how this is implemented.

  1. First, a constant is initialized to allow a maximum level of undos, then several variables are set up to hold a reference to the different mementos, and which index within the colleciton is currently displayed. The TreeMemento class is also imported so it may be referenced later in the code.
  2. import com.flashloaded.ui.tree.TreeMemento;

    const MAX_UNDOS:uint = 20;
    var states:Array;
    var stateIndex:int;

  3. Next, a main initialization function is called which initializes the variables set up in the previous step as well sets up the enabled state of the undo and redo buttons. The function that handles that enabling follows. This enableStatebuttons() function merely enables or disables the undo or redo button depending on the current state displayed, which determines if undo or redo are possible.
  4. main();

    function main():void {
      states = [];
      stateIndex = 0;
      enableStateButtons();
    }

    function enableStateButtons():void {
      undo_bn.enabled = stateIndex > 0;
      redo_bn.enabled = stateIndex < states.length-1;
    }

  5. Whenever a change is made in the tree that requires a state to be saved (e.g., a node is opened or closed, added or deleted), a saveState() function is called. This function pushes into the states array a new memento. If the number of saved mementos exceeds the maximum level allowed, the collection is reduced to match the maximum level. This function follows.
  6. function addState():void {
      states.push(tree.getMemento());
      if (states.length > MAX_UNDOS) {
        states = states.slice(-MAX_UNDOS);
      }
      stateIndex = states.length-1;
      enableStateButtons();
    }

  7. Finally, when either the undo or redo button is clicked, the tree is populated with a former memento using the setMemento() method.
  8. undo_bn.addEventListener(MouseEvent.CLICK, onUndo);
    function onUndo(event:Event):void {
      tree.setMemento(states[--stateIndex] as TreeMemento);
      enableStateButtons();
    }

    redo_bn.addEventListener(MouseEvent.CLICK, onRedo);
    function onRedo(event:Event):void {
      tree.setMemento(states[++stateIndex] as TreeMemento);
      enableStateButtons();
    }