public function insertNode(index:uint, node:Node, performAction:Function):void {
if (index>0 && getNode(index-1)==node) return;
if (index<nodes.length-1 && getNode(index)==node) return;
- performAction(new AddNodeToWayAction(this, node, nodes, index));
+ performAction(new AddNodeToWayAction(this, node, nodes, index, false));
}
public function appendNode(node:Node, performAction:Function):uint {
private var nodeList:Array;
private var index:int;
private var firstNode:Node;
+ private var autoDelete:Boolean; /* automatically delete way when undoing addition of node 2? */
- public function AddNodeToWayAction(way:Way, node:Node, nodeList:Array, index:int) {
+ public function AddNodeToWayAction(way:Way, node:Node, nodeList:Array, index:int, autoDelete:Boolean=true) {
super(way, "Add node "+node.id+" to");
this.node = node;
this.nodeList = nodeList;
this.index = index;
+ this.autoDelete = autoDelete;
}
public override function doAction():uint {
// 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;
+ if (autoDelete && way.length==2 && way.parentRelations.length) return FAIL;
// remove node
var removed:Array=nodeList.splice(index, 1);
way.dispatchEvent(new WayNodeEvent(Connection.WAY_NODE_REMOVED, removed[0], way, index));
// delete way if it's now 1-length, and convert the one remaining node to a POI
- if (way.length==1) {
+ if (autoDelete && way.length==1) {
way.setDeletedState(true);
way.dispatchEvent(new EntityEvent(Connection.WAY_DELETED, way));
firstNode=way.getNode(0);
/** Revert all selected items to previously saved state, via a dialog box. */
protected function revertSelection():void {
- if (selectCount==0) return;
- Alert.show("Revert selected items to the last saved version, discarding your changes?","Are you sure?",Alert.YES | Alert.CANCEL,null,revertHandler);
+ var revertable:Boolean=false;
+ for each (var item:Entity in _selection)
+ if (item.id>0) revertable=true;
+ if (revertable)
+ Alert.show("Revert selected items to the last saved version, discarding your changes?","Are you sure?",Alert.YES | Alert.CANCEL,null,revertHandler);
}
protected function revertHandler(event:CloseEvent):void {
if (event.detail==Alert.CANCEL) return;
for each (var item:Entity in _selection) {
- item.connection.loadEntity(item);
+ if (item.id>0) item.connection.loadEntity(item);
}
}
case Keyboard.DELETE:
case Keyboard.BACKSPACE:
case 189: /* minus */ return backspaceNode(MainUndoStack.getGlobalStack().addAction);
+ case 79: /* O */ return new SelectedWayNode(firstSelected as Way, editEnd ? Way(firstSelected).length-1 : 0); //, event);
case 82: /* R */ repeatTags(firstSelected); return this;
case 70: /* F */ followWay(); return this;
}
if ( editEnd )
Way(firstSelected).appendNode(node, performAction);
else
- Way(firstSelected).insertNode(0, node, performAction);
+ Way(firstSelected).prependNode(node, performAction);
}
protected function backspaceNode(performAction:Function):ControllerState {
switch (event.keyCode) {
case 189: return removeNode(); // '-'
case 88: return splitWay(); // 'X'
+ case 79: return replaceNode(); // 'O'
case 81: /* Q */ Quadrilateralise.quadrilateralise(parentWay, MainUndoStack.getGlobalStack().addAction); return this;
case 82: repeatTags(firstSelected); return this; // 'R'
case 87: return new SelectedWay(parentWay); // 'W'
return new DrawWay(selectedWay, isLast, true);
}
+ /** Replace the selected node with a new one created at the mouse position.
+ FIXME: currently two actions - should be undoable as one, but we need to execute the first action before we can run getNode(). */
+ public function replaceNode():ControllerState {
+ // create a new node
+ var newPoiAction:CreatePOIAction = new CreatePOIAction(
+ layer.connection,
+ {},
+ controller.map.coord2lat(layer.mouseY),
+ controller.map.coord2lon(layer.mouseX));
+ MainUndoStack.getGlobalStack().addAction(newPoiAction);
+
+ // replace old node
+ var oldNode:Node=firstSelected as Node;
+ var newNode:Node=newPoiAction.getNode();
+ oldNode.replaceWith(newNode, MainUndoStack.getGlobalStack().addAction);
+
+ // start dragging
+ // we fake a MouseEvent because DragWayNode expects the x/y co-ords to be passed that way
+ var d:DragWayNode=new DragWayNode(parentWay, parentWay.indexOfNode(newNode), new MouseEvent(MouseEvent.CLICK, true, false, layer.mouseX, layer.mouseY), true);
+ d.forceDragStart();
+ return d;
+ }
+
/** Splits a way into two separate ways, at the currently selected node. Handles simple loops and P-shapes. Untested for anything funkier. */
public function splitWay():ControllerState {
var n:Node=firstSelected as Node;
var msg:String = "Nodes merged"
if (MergeNodesAction.lastTagsMerged) msg += ": check conflicting tags";
controller.dispatchEvent(new AttentionEvent(AttentionEvent.ALERT, null, msg));
+ if (n.isDeleted()) n=Node(firstSelected);
return new SelectedWayNode(n.parentWays[0], Way(n.parentWays[0]).indexOfNode(n));
}