Prevent single-node ways from being created by undo.
authorRichard Fairhurst <richard@systemeD.net>
Fri, 17 Jun 2011 15:48:50 +0000 (16:48 +0100)
committerRichard Fairhurst <richard@systemeD.net>
Fri, 17 Jun 2011 15:48:50 +0000 (16:48 +0100)
Could be polished more but the undo system makes it enough of a brainfuck that this'll do for now.

net/systemeD/halcyon/connection/MainUndoStack.as
net/systemeD/halcyon/connection/Way.as
net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
net/systemeD/halcyon/connection/actions/DeleteWayAction.as
net/systemeD/potlatch2/controller/NoSelection.as
potlatch2.mxml

index be75b6d..38f87ff 100644 (file)
@@ -103,6 +103,12 @@ package net.systemeD.halcyon.connection {
                                return false;
                        }
                }
+               
+               public function removeLastIfAction(action:Class):void {
+                       if (undoActions.length && undoActions[undoActions.length-1] is action) {
+                               undoActions.pop();
+                       }
+               }
 
         [Bindable(event="new_undo_item")]
                public function getUndoDescription():String {
@@ -111,6 +117,13 @@ package net.systemeD.halcyon.connection {
                        return null;
                }
 
+        [Bindable(event="new_redo_item")]
+               public function getRedoDescription():String {
+                       if (redoActions.length==0) return null;
+                       if (redoActions[redoActions.length-1].name) return redoActions[redoActions.length-1].name;
+                       return null;
+               }
+
         /**
         * Takes the action most recently undone, does it, and adds it to the undo stack
         */
index d5f991c..0f97958 100644 (file)
@@ -94,12 +94,12 @@ package net.systemeD.halcyon.connection {
         }
 
         public function appendNode(node:Node, performAction:Function):uint {
-                       if (node!=getLastNode()) performAction(new AddNodeToWayAction(this, node, nodes, -1));
+                       insertNode(nodes.length, node, performAction);
             return nodes.length + 1;
         }
         
         public function prependNode(node:Node, performAction:Function):uint {
-                       if (node!=getFirstNode()) performAction(new AddNodeToWayAction(this, node, nodes, 0));
+                       insertNode(0, node, performAction);
             return nodes.length + 1;
         }
         
index 7e291e9..185bf55 100644 (file)
@@ -6,6 +6,7 @@ package net.systemeD.halcyon.connection.actions {
         private var node:Node;
         private var nodeList:Array;
         private var index:int;
+        private var firstNode:Node;
         
         public function AddNodeToWayAction(way:Way, node:Node, nodeList:Array, index:int) {
             super(way, "Add node "+node.id+" to");
@@ -16,8 +17,17 @@ package net.systemeD.halcyon.connection.actions {
             
         public override function doAction():uint {
             var way:Way = entity as Way;
-            if ( index == -1 )
-                index = nodeList.length;
+
+                       // undelete way if it was deleted before (only happens on redo)
+                       if (way.deleted) {
+                               way.setDeletedState(false);
+                               if (!firstNode.hasParentWays) firstNode.connection.unregisterPOI(firstNode);
+                               firstNode.addParent(way);
+                               way.connection.dispatchEvent(new EntityEvent(Connection.NEW_WAY, way));
+                       }
+
+                       // add node
+            if ( index == -1 ) index = nodeList.length;
             node.addParent(way);
             nodeList.splice(index, 0, node);
             markDirty();
@@ -29,13 +39,32 @@ package net.systemeD.halcyon.connection.actions {
             
         public override function undoAction():uint {
             var way:Way = entity as Way;
+
+                       // ** FIXME: if the user undoes adding the 2nd node, then we delete the way and create a POI from the
+                       //           one remaining node (see below). _However_, when we delete the way, we also need to remove 
+                       //           it from any relations... and to do that, this needs to be a CompositeUndoableAction.
+                       //           Which it isn't (because we want all the markDirty/markClean stuff). So, for now, we'll
+                       //           simply refuse to undo adding the 2nd node if the way is in any relations. (This should
+                       //           be a vanishingly small case anyway, because usually the AddMemberToRelationAction will
+                       //           have been undone already.)
+                       if (way.length==2 && way.parentRelations.length) return FAIL;
+
+                       // remove node
             var removed:Array=nodeList.splice(index, 1);
                        if (nodeList.indexOf(removed[0])==-1) { removed[0].removeParent(way); }
                        markClean();
             way.dispatchEvent(new WayNodeEvent(Connection.WAY_NODE_REMOVED, removed[0], way, index));
             
-            return SUCCESS;
+                       // delete way if it's now 1-length, and convert the one remaining node to a POI
+                       if (way.length==1) {
+                               way.setDeletedState(true);
+                               way.dispatchEvent(new EntityEvent(Connection.WAY_DELETED, way));
+                               firstNode=way.getNode(0);
+                               firstNode.removeParent(way);
+                               if (!firstNode.hasParentWays) firstNode.connection.registerPOI(firstNode);
+                               MainUndoStack.getGlobalStack().removeLastIfAction(BeginWayAction);
+                       }
+                       return SUCCESS;
         }
     }
 }
-
index 331826a..f2fd1bc 100644 (file)
@@ -57,7 +57,7 @@ package net.systemeD.halcyon.connection.actions {
               markClean();
             }
             entity.connection.dispatchEvent(new EntityEvent(Connection.NEW_WAY, way));
-            effects.undoAction();
+            if (effects) effects.undoAction();
             for each(var node:Node in oldNodeList) {
                 nodeList.push(node);
                node.addParent(way);
index 5c5072d..b780bd2 100644 (file)
@@ -25,6 +25,7 @@ package net.systemeD.potlatch2.controller {
 
                        if (event.type==MouseEvent.MOUSE_UP && (focus==null || (paint && paint.isBackground)) && map.dragstate!=map.DRAGGING) {
                                map.dragstate=map.NOT_DRAGGING;
+                               // ** FIXME: BeginWayAction ought to be a discrete class
                                var undo:CompositeUndoableAction = new BeginWayAction();
                                var conn:Connection = layer.connection;
                                var startNode:Node = conn.createNode(
index 055f0a6..4754b11 100644 (file)
@@ -51,7 +51,8 @@
             enabled="{MainUndoStack.getGlobalStack().canUndo()}"
             toolTip="{MainUndoStack.getGlobalStack().getUndoDescription() ? 'Undo '+MainUndoStack.getGlobalStack().getUndoDescription() : 'Undo last action'}" />
         <mx:Button id="redo" label="Redo" click="MainUndoStack.getGlobalStack().redo();" styleName="appBarButton"
-            enabled="{MainUndoStack.getGlobalStack().canRedo()}"/>
+            enabled="{MainUndoStack.getGlobalStack().canRedo()}"
+            toolTip="{MainUndoStack.getGlobalStack().getRedoDescription() ? 'Redo '+MainUndoStack.getGlobalStack().getRedoDescription() : 'Redo last action'}" />
         <mx:Spacer width="100%"/>
         <mx:Button id="helpButton" label="Help" click="new HelpDialog().init();" styleName="appBarButton" />
         <mx:Button id="optionsButton" label="Options" click="new OptionsDialog().init();" styleName="appBarButton" />