Documentation for the undo system
authorAndy Allan <gravitystorm@gmail.com>
Mon, 6 Dec 2010 19:08:58 +0000 (19:08 +0000)
committerAndy Allan <gravitystorm@gmail.com>
Mon, 6 Dec 2010 19:08:58 +0000 (19:08 +0000)
net/systemeD/halcyon/connection/CompositeUndoableAction.as
net/systemeD/halcyon/connection/MainUndoStack.as
net/systemeD/halcyon/connection/UndoableAction.as
net/systemeD/halcyon/connection/UndoableEntityAction.as

index b5394ab..d204324 100644 (file)
@@ -1,23 +1,55 @@
 package net.systemeD.halcyon.connection {
 
+    /**
+    * A CompositeUndoableAction is an UndoableAction that is made up of multiple individual actions.
+    * You want to use one where you have multiple entities being altered in a given situation that you
+    * want to treat as one overall action (e.g. they are all done together, and should be undone in one go too).
+    *
+    * A CompositeUndoableAction will store the stack of individual actions, and when doAction is called will go through each one of
+    * them and call doAction on the individual action.
+    *
+    * Sometimes a composite action can be made without further ado, and actions pushed into this one and this one added to
+    * the relevant undo stack. But often more complex things needs to be done, so this is often extended into a more specific action.
+    */
+
     public class CompositeUndoableAction extends UndoableAction {
         
         private var name:String;
         private var actions:Array = [];
         private var actionsDone:Boolean = false;
-    
+
+        /**
+        * @param name The name you want to give to this CompositeUndoableAction - useful for debugging
+        */
         public function CompositeUndoableAction(name:String) {
             this.name = name;
         }
-        
+
+        /**
+        * Add an action to the list of actions that make up this CompositeUndoableAction
+        */
         public function push(action:UndoableAction):void {
             actions.push(action);
         }
-        
+
+        /**
+        * Clear the list of actions
+        */
         public function clearActions():void {
             actions = [];
         }
-        
+
+        /**
+        * Do all the actions on the list. Can be overridden by an specific implementation, usually to manage
+        * the suspending and resuming of entities. If so, you'll want to call super.doAction from that implementation
+        * to actually execute the list of actions that you've added via push
+        *
+        * If any action fails while exectuing, the preceeding actions will be undone and this composite will return FAIL
+        *
+        * @return whether the entire stack of actions succeeded, failed or resulted in nothing changing.
+        *
+        * @see #push
+        */
         public override function doAction():uint {
             if ( actionsDone )
                 return UndoableAction.FAIL;
@@ -41,7 +73,10 @@ package net.systemeD.halcyon.connection {
             actionsDone = true;
             return somethingDone ? UndoableAction.SUCCESS : UndoableAction.NO_CHANGE;
         }
-        
+
+        /**
+        * Undo the actions on the list. If overridden call super.undoAction
+        */
         public override function undoAction():uint {
             if ( !actionsDone )
                 return UndoableAction.FAIL;
@@ -49,7 +84,11 @@ package net.systemeD.halcyon.connection {
             undoFrom(actions.length);
             return UndoableAction.SUCCESS;
         }
-        
+
+        /**
+        * Undo the actions from a given index. Used when the composite needs to be aborted when one of the
+        * individual actions fails
+        */
         public function undoFrom(index:int):void {
             for ( var i:int = index - 1; i >= 0; i-- ) {
                 var action:UndoableAction = actions[i];
@@ -58,7 +97,10 @@ package net.systemeD.halcyon.connection {
             }
             actionsDone = false;
         }
-        
+
+        /**
+        * Returns the name of this composite action, along with the (recursive) description of all the sub actions
+        */
         public function toString():String {
             var str:String = " {" + actions.join(",") + "}";
             return name + str;
index b2450fe..1561821 100644 (file)
@@ -2,6 +2,13 @@ package net.systemeD.halcyon.connection {
 
     import flash.events.*;
 
+
+    /**
+    * The main undo stack controls which actions can be undone or redone from the current situation.
+    *
+    * @see UndoableAction All actions inherit from undoable action
+    */
+
     public class MainUndoStack extends EventDispatcher {
         private static const GLOBAL_INSTANCE:MainUndoStack = new MainUndoStack();
         
@@ -12,7 +19,7 @@ package net.systemeD.halcyon.connection {
         private var undoActions:Array = [];
         private var redoActions:Array = [];
 
-        /*
+        /**
          * Performs the action, then puts it on the undo stack.
          *
          * If you want to delay execution don't put it on this
@@ -50,8 +57,8 @@ package net.systemeD.halcyon.connection {
             }
         }
         
-        /*
-         * Call to kill the undo queue -- the user will not be able to undo
+        /**
+         * Call to kill the undo and redo stacks -- the user will not be able to undo
          * anything they previously did after this is called.
          */
         public function breakUndo():void {
@@ -70,7 +77,10 @@ package net.systemeD.halcyon.connection {
         public function canRedo():Boolean {
             return redoActions.length > 0;
         }
-        
+
+        /**
+        * Undo the most recent action, and add it to the top of the redo stack
+        */
         public function undo():void {
                        if (!undoActions.length) { return; }
             var action:UndoableAction = undoActions.pop();
@@ -79,7 +89,11 @@ package net.systemeD.halcyon.connection {
             dispatchEvent(new Event("new_undo_item"));
             dispatchEvent(new Event("new_redo_item"));
         }
-        
+
+        /**
+        * Undo the most recent action, but only if it's a particular class
+        * @param action The class of the previous action, for testing
+        */
                public function undoIfAction(action:Class):Boolean {
                        if (!undoActions.length) { return false; }
                        if (undoActions[undoActions.length-1] is action) {
@@ -90,6 +104,9 @@ package net.systemeD.halcyon.connection {
                        }
                }
 
+        /**
+        * Takes the action most recently undone, does it, and adds it to the undo stack
+        */
         public function redo():void {
                        if (!redoActions.length) { return; }
             var action:UndoableAction = redoActions.pop();
index 774967b..3b86709 100644 (file)
@@ -1,15 +1,53 @@
 package net.systemeD.halcyon.connection {
 
+    /**
+    * UndoableAction is the base class from which other actions types inherit. An undoable action
+    * is an object that can be added to a list of actions, for example the MainUndoStack or any
+    * other list of actions.
+    *
+    * @see CompositeUndoableAction
+    * @see UndoableEntityAction
+    */
+
     public class UndoableAction {
-    
+
+
+        /** Something went wrong while attempting the action */
         public static const FAIL:uint = 0;
+        /** The action worked, and entities were changed */
         public static const SUCCESS:uint = 1;
+        /** No entity was altered by this action */
         public static const NO_CHANGE:uint = 2; 
-    
+
+        /**
+        * The doAction function is called when it is time to execute this action or
+        * combination of actions. It is usually triggered by either MainUndoStack.addAction
+        * or by MainUndoStack.redo.
+        *
+        * This should be overridden.
+        *
+        * @return whether the action succeed, failed or nothing happened
+        */
         public function doAction():uint { return FAIL; }
-        
+
+        /**
+        * The undoAction function is called in order to undo this action or combination
+        * of actions. It is usually triggered by MainUndoStack.undo.
+        *
+        * This should be overridden.
+        *
+        * @return whether undoing the action succeed, failed or nothing happened
+        */
         public function undoAction():uint { return FAIL; }
-        
+
+        /**
+        * Can this action be merged with the previous action? This is sometimes wanted, such as
+        * when moving nodes around.
+        *
+        * This is overridden when needed.
+        *
+        * @see net.systemeD.halcyon.connection.actions.MoveNodeAction#mergePrevious
+        */
         public function mergePrevious(previous:UndoableAction):Boolean {
             return false;
         }
index 769758c..b72c58b 100644 (file)
@@ -1,17 +1,33 @@
 package net.systemeD.halcyon.connection {
 
+    /**
+    * An UndoableEntityAction is an action that affects an entity. The allows the clean/dirty status of both the individual entity and
+    * the connection as a whole to be tracked correctly when doing an action, undoing it and redoing it.
+    *
+    * Individual entity actions extend this class in order to do useful things.
+    */
+
     public class UndoableEntityAction extends UndoableAction {
         public var wasDirty:Boolean;
                public var connectionWasDirty:Boolean;
         private var initialised:Boolean = false;
         protected var name:String;
         protected var entity:Entity;
-            
+
+        /**
+        * Create a new UndoableEntityAction. Usually called as super() from a subclass
+        *
+        * @param entity The entity that it being modified
+        * @param name The name of this action, useful for debugging.
+        */
         public function UndoableEntityAction(entity:Entity, name:String) {
             this.entity = entity;
             this.name = name;
         }
-            
+
+        /**
+        * Mark this action as dirty. This will mark the entity and/or connection dirty, as appropriate.
+        */
         protected function markDirty():void {
             if ( !initialised ) init();
 
@@ -23,7 +39,11 @@ package net.systemeD.halcyon.connection {
               Connection.getConnectionInstance().markDirty();
             }
         }
-            
+
+        /**
+        * Mark this action as clean. This will entity and/or connection clean, as appropriate,
+        * based on whether they were clean before this action started.
+        */
         protected function markClean():void {
             if ( !initialised ) init();
 
@@ -35,7 +55,11 @@ package net.systemeD.halcyon.connection {
               Connection.getConnectionInstance().markClean();
             }
         }
-        
+
+        /**
+        * Record whether or not the entity and connection were clean before this action started.
+        * This allows the correct state to be restored when undo/redo is called
+        */
         private function init():void {
             wasDirty = entity.isDirty;
             connectionWasDirty = Connection.getConnectionInstance().isDirty;