Prevent single-node ways from being created by undo.
[potlatch2.git] / net / systemeD / halcyon / connection / MainUndoStack.as
1 package net.systemeD.halcyon.connection {
2
3     import flash.events.*;
4
5
6     /**
7     * The main undo stack controls which actions can be undone or redone from the current situation.
8     *
9     * @see UndoableAction All actions inherit from undoable action
10     */
11
12     public class MainUndoStack extends EventDispatcher {
13         private static const GLOBAL_INSTANCE:MainUndoStack = new MainUndoStack();
14         
15         public static function getGlobalStack():MainUndoStack {
16             return GLOBAL_INSTANCE;
17         }
18         
19         private var undoActions:Array = [];
20         private var redoActions:Array = [];
21
22         /**
23          * Performs the action, then puts it on the undo stack.
24          *
25          * If you want to delay execution don't put it on this
26          * stack -- find another one.
27          */
28         public function addAction(action:UndoableAction):void {
29             var result:uint = action.doAction();
30             
31             switch ( result ) {
32             
33             case UndoableAction.FAIL:
34                 throw new Error("Failure performing "+action);
35                 
36             case UndoableAction.NO_CHANGE:
37                 // nothing to do, and don't add to stack
38                 break;
39                 
40             case UndoableAction.SUCCESS:
41             default:
42                 if ( undoActions.length > 0 ) {
43                     var previous:UndoableAction = undoActions[undoActions.length - 1];
44                     var isMerged:Boolean = action.mergePrevious(previous);
45                     if ( isMerged ) {
46                                                 UndoableEntityAction(action).wasDirty = UndoableEntityAction(previous).wasDirty;
47                                                 UndoableEntityAction(action).connectionWasDirty = UndoableEntityAction(previous).connectionWasDirty;
48                         undoActions.pop();
49                                         }
50                 }
51                 undoActions.push(action);
52                 redoActions = [];
53                 dispatchEvent(new Event("new_undo_item"));
54                 dispatchEvent(new Event("new_redo_item"));
55                 break;
56                 
57             }
58         }
59         
60         /**
61          * Call to kill the undo and redo stacks -- the user will not be able to undo
62          * anything they previously did after this is called.
63          */
64         public function breakUndo():void {
65             undoActions = [];
66             redoActions = [];
67             dispatchEvent(new Event("new_undo_item"));
68             dispatchEvent(new Event("new_redo_item"));
69         }
70         
71         [Bindable(event="new_undo_item")]
72         public function canUndo():Boolean {
73             return undoActions.length > 0;
74         }
75         
76         [Bindable(event="new_redo_item")]
77         public function canRedo():Boolean {
78             return redoActions.length > 0;
79         }
80
81         /**
82         * Undo the most recent action, and add it to the top of the redo stack
83         */
84         public function undo():void {
85                         if (!undoActions.length) { return; }
86             var action:UndoableAction = undoActions.pop();
87             action.undoAction();
88             redoActions.push(action);
89             dispatchEvent(new Event("new_undo_item"));
90             dispatchEvent(new Event("new_redo_item"));
91         }
92
93         /**
94         * Undo the most recent action, but only if it's a particular class
95         * @param action The class of the previous action, for testing
96         */
97                 public function undoIfAction(action:Class):Boolean {
98                         if (!undoActions.length) { return false; }
99                         if (undoActions[undoActions.length-1] is action) {
100                                 undo();
101                                 return true;
102                         } else {
103                                 return false;
104                         }
105                 }
106                 
107                 public function removeLastIfAction(action:Class):void {
108                         if (undoActions.length && undoActions[undoActions.length-1] is action) {
109                                 undoActions.pop();
110                         }
111                 }
112
113         [Bindable(event="new_undo_item")]
114                 public function getUndoDescription():String {
115                         if (undoActions.length==0) return null;
116                         if (undoActions[undoActions.length-1].name) return undoActions[undoActions.length-1].name;
117                         return null;
118                 }
119
120         [Bindable(event="new_redo_item")]
121                 public function getRedoDescription():String {
122                         if (redoActions.length==0) return null;
123                         if (redoActions[redoActions.length-1].name) return redoActions[redoActions.length-1].name;
124                         return null;
125                 }
126
127         /**
128         * Takes the action most recently undone, does it, and adds it to the undo stack
129         */
130         public function redo():void {
131                         if (!redoActions.length) { return; }
132             var action:UndoableAction = redoActions.pop();
133             action.doAction();
134             undoActions.push(action);
135             dispatchEvent(new Event("new_undo_item"));
136             dispatchEvent(new Event("new_redo_item"));
137         }
138        
139     }
140 }