d204324248a8ff7eac67caa449bce99be6ecd7ce
[potlatch2.git] / net / systemeD / halcyon / connection / CompositeUndoableAction.as
1 package net.systemeD.halcyon.connection {
2
3     /**
4     * A CompositeUndoableAction is an UndoableAction that is made up of multiple individual actions.
5     * You want to use one where you have multiple entities being altered in a given situation that you
6     * want to treat as one overall action (e.g. they are all done together, and should be undone in one go too).
7     *
8     * A CompositeUndoableAction will store the stack of individual actions, and when doAction is called will go through each one of
9     * them and call doAction on the individual action.
10     *
11     * Sometimes a composite action can be made without further ado, and actions pushed into this one and this one added to
12     * the relevant undo stack. But often more complex things needs to be done, so this is often extended into a more specific action.
13     */
14
15     public class CompositeUndoableAction extends UndoableAction {
16         
17         private var name:String;
18         private var actions:Array = [];
19         private var actionsDone:Boolean = false;
20
21         /**
22         * @param name The name you want to give to this CompositeUndoableAction - useful for debugging
23         */
24         public function CompositeUndoableAction(name:String) {
25             this.name = name;
26         }
27
28         /**
29         * Add an action to the list of actions that make up this CompositeUndoableAction
30         */
31         public function push(action:UndoableAction):void {
32             actions.push(action);
33         }
34
35         /**
36         * Clear the list of actions
37         */
38         public function clearActions():void {
39             actions = [];
40         }
41
42         /**
43         * Do all the actions on the list. Can be overridden by an specific implementation, usually to manage
44         * the suspending and resuming of entities. If so, you'll want to call super.doAction from that implementation
45         * to actually execute the list of actions that you've added via push
46         *
47         * If any action fails while exectuing, the preceeding actions will be undone and this composite will return FAIL
48         *
49         * @return whether the entire stack of actions succeeded, failed or resulted in nothing changing.
50         *
51         * @see #push
52         */
53         public override function doAction():uint {
54             if ( actionsDone )
55                 return UndoableAction.FAIL;
56                 
57             var somethingDone:Boolean = false;
58             for ( var i:int = 0; i < actions.length; i++ ) {
59                 var action:UndoableAction = actions[i];
60                 
61                 var result:uint = action.doAction();
62                 if ( result == UndoableAction.NO_CHANGE ) {
63                     // splice this one out as it doesn't do anything
64                     actions.splice(i, 1)
65                     i --;
66                 } else if ( result == UndoableAction.FAIL ) {
67                     undoFrom(i);
68                     return UndoableAction.FAIL;
69                 } else {
70                     somethingDone = true;
71                 }
72             }
73             actionsDone = true;
74             return somethingDone ? UndoableAction.SUCCESS : UndoableAction.NO_CHANGE;
75         }
76
77         /**
78         * Undo the actions on the list. If overridden call super.undoAction
79         */
80         public override function undoAction():uint {
81             if ( !actionsDone )
82                 return UndoableAction.FAIL;
83                 
84             undoFrom(actions.length);
85             return UndoableAction.SUCCESS;
86         }
87
88         /**
89         * Undo the actions from a given index. Used when the composite needs to be aborted when one of the
90         * individual actions fails
91         */
92         public function undoFrom(index:int):void {
93             for ( var i:int = index - 1; i >= 0; i-- ) {
94                 var action:UndoableAction = actions[i];
95                 
96                 action.undoAction();
97             }
98             actionsDone = false;
99         }
100
101         /**
102         * Returns the name of this composite action, along with the (recursive) description of all the sub actions
103         */
104         public function toString():String {
105             var str:String = " {" + actions.join(",") + "}";
106             return name + str;
107         }
108     }
109
110 }
111