Index: /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/gui/JunctionPane.java
===================================================================
--- /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/gui/JunctionPane.java	(revision 26181)
+++ /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/gui/JunctionPane.java	(revision 26182)
@@ -33,5 +33,6 @@
         
         public void mousePressed(MouseEvent e) {
-            setFocusable(true);
+            JunctionPane.this.requestFocus();
+            
             button = e.getButton();
             
@@ -158,4 +159,6 @@
         setJunction(container);
         
+        setFocusable(true);
+        
         getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0), "refresh");
         getActionMap().put("refresh", new AbstractAction() {
@@ -229,4 +232,14 @@
                 rotation += Math.PI / 180;
                 setState(new State.Dirty(state));
+            }
+        });
+        
+        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete");
+        getActionMap().put("delete", new AbstractAction() {
+            private static final long serialVersionUID = 1L;
+            
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                setState(state.delete());
             }
         });
@@ -276,4 +289,5 @@
     
     private void setState(State state) {
+        
         if (state instanceof State.AllTurns) {
             dirty = true;
@@ -282,10 +296,10 @@
             container = container.recalculate();
             dirty = true;
-            this.state = new State.Default();
+            setState(((State.Invalid) state).unwrap());
         } else if (state instanceof State.Dirty) {
             dirty = true;
-            this.state = ((State.Dirty) state).unwrap();
+            setState(((State.Dirty) state).unwrap());
         } else {
-            this.state = state;
+            this.state = state.carryOver(container);
         }
         
@@ -431,3 +445,9 @@
         dot(g2d, p, r, Color.RED);
     }
+    
+    void refresh() {
+        if (state != null) {
+            setState(new State.Invalid(state));
+        }
+    }
 }
Index: /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/gui/LaneGui.java
===================================================================
--- /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/gui/LaneGui.java	(revision 26181)
+++ /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/gui/LaneGui.java	(revision 26182)
@@ -39,5 +39,5 @@
                 g2d.fill(circle);
                 
-                final String len = METER_FORMAT.format(getModel().getLength());
+                final String len = METER_FORMAT.format(getLength() * getRoad().getContainer().getMpp());
                 final Rectangle2D bounds = circle.getBounds2D();
                 g2d.setFont(g2d.getFont().deriveFont(Font.BOLD, (float) bounds.getHeight()));
@@ -72,14 +72,23 @@
         @Override
         State drag(double x, double y, InteractiveElement target, State old) {
-            move(x + dragDelta.getX(), y + dragDelta.getY());
+            move(x + dragDelta.getX(), y + dragDelta.getY(), false);
             return new State.Dirty(old);
         }
         
-        void move(double x, double y) {
+        @Override
+        State drop(double x, double y, InteractiveElement target, State old) {
+            move(x + dragDelta.getX(), y + dragDelta.getY(), true);
+            return old;
+        }
+        
+        void move(double x, double y, boolean updateModel) {
             final double r = getRoad().connectorRadius;
             
             final double offset = getRoad().getOffset(x, y);
-            final double newLength = getModel().getOutgoingRoadEnd().isFromEnd() ? offset : getRoad().getLength() - offset;
-            if (newLength > 0) {
+            final double newLength = getModel().getOutgoingRoadEnd().isFromEnd() ? offset : getRoad().getLength()
+                    - offset;
+            
+            length = newLength;
+            if (updateModel && newLength > 0) {
                 getModel().setLength(newLength * getRoad().getContainer().getMpp());
             }
@@ -169,5 +178,6 @@
         
         private boolean isActive(State state) {
-            return state instanceof State.OutgoingActive && LaneGui.this.equals(((State.OutgoingActive) state).getLane());
+            return state instanceof State.OutgoingActive
+                    && LaneGui.this.equals(((State.OutgoingActive) state).getLane());
         }
         
@@ -234,5 +244,5 @@
                 final RoadGui.ViaConnector a = s.getViaConnectors().get(i);
                 final RoadGui.ViaConnector b = s.getViaConnectors().get(i + 1);
-                assert a.getRoadEnd().getOppositeEnd().equals(b);
+                assert a.getRoadEnd().getOppositeEnd().equals(b.getRoadEnd());
                 via.add(a.getRoadEnd().getRoad());
             }
@@ -271,4 +281,5 @@
     
     private Shape clip;
+    private double length;
     
     public LaneGui(RoadGui road, Lane lane) {
@@ -276,8 +287,9 @@
         this.lane = lane;
         this.lengthSlider = lane.isExtra() ? new LengthSlider() : null;
+        this.length = lane.isExtra() ? lane.getLength() / road.getContainer().getMpp() : Double.NaN;
     }
     
     public double getLength() {
-        return getModel().isExtra() ? lane.getLength() / getRoad().getContainer().getMpp() : getRoad().getLength();
+        return lane.isExtra() ? length : road.getLength();
     }
     
@@ -305,6 +317,6 @@
         final Lane leftModel = left == null ? null : left.getModel();
         final double leftLength = leftModel == null
-            || !leftModel.getOutgoingRoadEnd().equals(getModel().getOutgoingRoadEnd()) ? Double.NEGATIVE_INFINITY
-            : leftModel.getKind() == Lane.Kind.EXTRA_LEFT ? left.getLength() : L;
+                || !leftModel.getOutgoingRoadEnd().equals(getModel().getOutgoingRoadEnd()) ? Double.NEGATIVE_INFINITY
+                : leftModel.getKind() == Lane.Kind.EXTRA_LEFT ? left.getLength() : L;
         
         final Path outer;
@@ -320,5 +332,5 @@
             if (L > leftLength) {
                 innerLine.append(inner.subpath(max(0, leftLength + WW), L).getIterator(), leftLength >= 0
-                    || getModel().getOutgoingRoadEnd().isFromEnd());
+                        || getModel().getOutgoingRoadEnd().isFromEnd());
                 final Point2D op = outer.getPoint(L + WW);
                 innerLine.lineTo(op.getX(), op.getY());
@@ -335,5 +347,5 @@
             if (leftLength < L) {
                 innerLine.append(inner.subpath(max(0, leftLength + WW), L).getIterator(), leftLength >= 0
-                    || getModel().getOutgoingRoadEnd().isFromEnd());
+                        || getModel().getOutgoingRoadEnd().isFromEnd());
             }
         }
Index: /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/gui/State.java
===================================================================
--- /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/gui/State.java	(revision 26181)
+++ /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/gui/State.java	(revision 26182)
@@ -11,6 +11,6 @@
 import org.openstreetmap.josm.plugins.turnlanes.model.Road;
 
-interface State {
-    public class AllTurns implements State {
+abstract class State {
+    static class AllTurns extends State {
         private final State wrapped;
         
@@ -22,7 +22,12 @@
             return wrapped;
         }
-    }
-    
-    public class Connecting implements State {
+        
+        @Override
+        State carryOver(GuiContainer newContainer) {
+            return new AllTurns(wrapped.carryOver(newContainer));
+        }
+    }
+    
+    static class Connecting extends State {
         private final Lane lane;
         private final List<RoadGui.ViaConnector> vias;
@@ -91,5 +96,5 @@
     }
     
-    public class Invalid implements State {
+    static class Invalid extends State {
         private final State wrapped;
         
@@ -103,5 +108,5 @@
     }
     
-    public class Dirty implements State {
+    static class Dirty extends State {
         private final State wrapped;
         
@@ -113,11 +118,16 @@
             return wrapped;
         }
-    }
-    
-    class Default implements State {
+        
+        @Override
+        State carryOver(GuiContainer newContainer) {
+            return new Dirty(wrapped.carryOver(newContainer));
+        }
+    }
+    
+    static class Default extends State {
         public Default() {}
     }
     
-    class IncomingActive implements State {
+    static class IncomingActive extends State {
         private final Road.End roadEnd;
         
@@ -129,7 +139,24 @@
             return roadEnd;
         }
-    }
-    
-    class OutgoingActive implements State {
+        
+        @Override
+        State carryOver(GuiContainer newContainer) {
+            if (newContainer.getModel().equals(roadEnd.getRoad().getContainer())) {
+                return this;
+            }
+            
+            final Junction newJunction = newContainer.getModel().getJunction(roadEnd.getJunction().getNode());
+            
+            for (Road.End e : newJunction.getRoadEnds()) {
+                if (e.isToEnd() && e.getWay().equals(roadEnd.getWay())) {
+                    return new IncomingActive(e);
+                }
+            }
+            
+            return new Default();
+        }
+    }
+    
+    static class OutgoingActive extends State {
         private final LaneGui lane;
         
@@ -141,4 +168,47 @@
             return lane;
         }
+        
+        @Override
+        State delete() {
+            if (!lane.getModel().isExtra()) {
+                return this;
+            }
+            
+            lane.getModel().remove();
+            
+            return new Invalid(this);
+        }
+        
+        @Override
+        State carryOver(GuiContainer newContainer) {
+            if (newContainer.equals(lane.getContainer())) {
+                return this;
+            }
+            
+            final Lane model = lane.getModel();
+            final Junction newJunction = newContainer.getModel().getJunction(model.getOutgoingJunction().getNode());
+            
+            for (Road.End e : newJunction.getRoadEnds()) {
+                if (e.isToEnd() && e.getWay().equals(model.getOutgoingRoadEnd().getWay())) {
+                    for (Lane l : e.getLanes()) { // e.getLane(...) can fail on lane removal
+                        if (l.getKind() == model.getKind() && l.getIndex() == model.getIndex()) {
+                            return new OutgoingActive(newContainer.getGui(l));
+                        }
+                    }
+                    
+                    break;
+                }
+            }
+            
+            return new Default();
+        }
+    }
+    
+    State delete() {
+        return this;
+    }
+    
+    State carryOver(GuiContainer newContainer) {
+        return this;
     }
 }
Index: /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/gui/TurnLanesDialog.java
===================================================================
--- /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/gui/TurnLanesDialog.java	(revision 26181)
+++ /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/gui/TurnLanesDialog.java	(revision 26182)
@@ -9,5 +9,7 @@
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import javax.swing.Action;
@@ -17,6 +19,6 @@
 import javax.swing.JToggleButton;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.JosmAction;
-import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -24,17 +26,31 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
+import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
+import org.openstreetmap.josm.data.osm.event.DataSetListener;
+import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
+import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
+import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
+import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
+import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
+import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.MapView.EditLayerChangeListener;
 import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.plugins.turnlanes.model.ModelContainer;
+import org.openstreetmap.josm.plugins.turnlanes.model.UnexpectedDataException;
 
 public class TurnLanesDialog extends ToggleDialog {
     private class EditAction extends JosmAction {
         private static final long serialVersionUID = 4114119073563457706L;
+        
         public EditAction() {
-            super(tr("Edit"), "dialogs/edit",
-            tr("Edit turn relations and lane lengths for selected node."), null, false);
+            super(tr("Edit"), "dialogs/edit", tr("Edit turn relations and lane lengths for selected node."), null,
+                    false);
             putValue("toolbar", "turnlanes/edit");
             Main.toolbar.register(this);
         }
-
+        
         @Override
         public void actionPerformed(ActionEvent e) {
@@ -42,16 +58,18 @@
             cl.show(body, CARD_EDIT);
             editing = true;
-        }
-    }
-
+            editButton.setSelected(true);
+        }
+    }
+    
     private class ValidateAction extends JosmAction {
         private static final long serialVersionUID = 7510740945725851427L;
+        
         public ValidateAction() {
-            super(tr("Validate"), "dialogs/validator",
-            tr("Validate turn- and lane-length-relations for consistency."), null, false);
+            super(tr("Validate"), "dialogs/validator", tr("Validate turn- and lane-length-relations for consistency."),
+                    null, false);
             putValue("toolbar", "turnlanes/validate");
             Main.toolbar.register(this);
         }
-
+        
         @Override
         public void actionPerformed(ActionEvent e) {
@@ -59,39 +77,116 @@
             cl.show(body, CARD_VALIDATE);
             editing = false;
-        }
-    }
-
+            validateButton.setSelected(true);
+        }
+    }
+    
+    private final DataSetListener dataSetListener = new DataSetListener() {
+        @Override
+        public void wayNodesChanged(WayNodesChangedEvent event) {
+            refresh();
+        }
+        
+        @Override
+        public void tagsChanged(TagsChangedEvent event) {
+            refresh();
+            
+        }
+        
+        @Override
+        public void relationMembersChanged(RelationMembersChangedEvent event) {
+            refresh();
+        }
+        
+        @Override
+        public void primtivesRemoved(PrimitivesRemovedEvent event) {
+            refresh();
+        }
+        
+        @Override
+        public void primtivesAdded(PrimitivesAddedEvent event) {
+            refresh();
+        }
+        
+        @Override
+        public void otherDatasetChange(AbstractDatasetChangedEvent event) {
+            refresh();
+        }
+        
+        @Override
+        public void nodeMoved(NodeMovedEvent event) {
+            refresh();
+        }
+        
+        @Override
+        public void dataChanged(DataChangedEvent event) {
+            refresh();
+        }
+        
+        private void refresh() {
+            if (editing) {
+                junctionPane.refresh();
+            }
+        }
+    };
+    
     private final Action editAction = new EditAction();
     private final Action validateAction = new ValidateAction();
-
+    
     private static final long serialVersionUID = -1998375221636611358L;
-
+    
     private static final String CARD_EDIT = "EDIT";
     private static final String CARD_VALIDATE = "VALIDATE";
     private static final String CARD_ERROR = "ERROR";
-
+    
     private final JPanel body = new JPanel();
     private final JunctionPane junctionPane = new JunctionPane(null);
     private final JLabel error = new JLabel();
-
+    
+    private final JToggleButton editButton = new JToggleButton(editAction);
+    private final JToggleButton validateButton = new JToggleButton(validateAction);
+    
+    private final Set<OsmPrimitive> selected = new HashSet<OsmPrimitive>();
+    
     private boolean editing = true;
-
+    
     public TurnLanesDialog() {
         super(tr("Turn Lanes"), "turnlanes.png", tr("Edit turn lanes"), null, 200);
-
+        
+        MapView.addEditLayerChangeListener(new EditLayerChangeListener() {
+            @Override
+            public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
+                if (oldLayer != null) {
+                    oldLayer.data.removeDataSetListener(dataSetListener);
+                }
+                
+                if (newLayer != null) {
+                    newLayer.data.addDataSetListener(dataSetListener);
+                }
+            }
+        });
+        
         DataSet.addSelectionListener(new SelectionChangedListener() {
             @Override
             public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+                if (selected.equals(new HashSet<OsmPrimitive>(newSelection))) {
+                    return;
+                }
+                selected.clear();
+                selected.addAll(newSelection);
+                
                 final Collection<OsmPrimitive> s = Collections.unmodifiableCollection(newSelection);
                 final List<Node> nodes = OsmPrimitive.getFilteredList(s, Node.class);
                 final List<Way> ways = OsmPrimitive.getFilteredList(s, Way.class);
-
+                
                 if (nodes.isEmpty()) {
                     setJunction(null);
                     return;
                 }
-
+                
                 try {
                     setJunction(ModelContainer.create(nodes, ways));
+                } catch (UnexpectedDataException e) {
+                    displayError(e);
+                    return;
                 } catch (RuntimeException e) {
                     displayError(e);
@@ -100,39 +195,53 @@
             }
         });
-
+        
         final JPanel buttonPanel = new JPanel(new GridLayout(1, 2, 4, 4));
         final ButtonGroup group = new ButtonGroup();
-        final JToggleButton editButton = new JToggleButton(editAction);
-        final JToggleButton validateButton = new JToggleButton(validateAction);
         group.add(editButton);
         group.add(validateButton);
         buttonPanel.add(editButton);
         buttonPanel.add(validateButton);
-
+        
         body.setLayout(new CardLayout(4, 4));
-
+        
         add(buttonPanel, BorderLayout.SOUTH);
         add(body, BorderLayout.CENTER);
-
+        
         body.add(junctionPane, CARD_EDIT);
         body.add(new ValidationPanel(), CARD_VALIDATE);
         body.add(error, CARD_ERROR);
-
+        
         editButton.doClick();
     }
-
+    
+    void displayError(UnexpectedDataException e) {
+        if (editing) {
+            if (e.getKind() == UnexpectedDataException.Kind.MISSING_TAG
+                    && UnexpectedDataException.Kind.MISSING_TAG.format("lanes").equals(e.getMessage())) {
+                
+                error.setText("<html>The number of lanes is not specified for one or more roads;"
+                        + " please add missing lanes tags.</html>");
+            } else {
+                displayError((RuntimeException) e);
+            }
+            
+            final CardLayout cl = (CardLayout) body.getLayout();
+            cl.show(body, CARD_ERROR);
+        }
+    }
+    
     void displayError(RuntimeException e) {
         if (editing) {
             e.printStackTrace();
-
+            
             error.setText("<html>An error occured while constructing the model."
-                + " Please run the validator to make sure the data is consistent.<br><br>Error: " + e.getMessage()
-                + "</html>");
-
+                    + " Please run the validator to make sure the data is consistent.<br><br>Error: " + e.getMessage()
+                    + "</html>");
+            
             final CardLayout cl = (CardLayout) body.getLayout();
             cl.show(body, CARD_ERROR);
         }
     }
-
+    
     void setJunction(ModelContainer mc) {
         if (mc != null && editing) {
Index: /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/GenericCommand.java
===================================================================
--- /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/GenericCommand.java	(revision 26182)
+++ /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/GenericCommand.java	(revision 26182)
@@ -0,0 +1,102 @@
+package org.openstreetmap.josm.plugins.turnlanes.model;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.swing.JLabel;
+
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.osm.AbstractPrimitive;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.PrimitiveData;
+
+public class GenericCommand extends Command {
+    private static final class BeforeAfter {
+        final PrimitiveData before;
+        final AbstractPrimitive after;
+        
+        public BeforeAfter(PrimitiveData before, AbstractPrimitive after) {
+            this.before = before;
+            this.after = after;
+        }
+        
+        public OsmPrimitive afterPrimitive() {
+            return (OsmPrimitive) after;
+        }
+        
+        public PrimitiveData afterData() {
+            return (PrimitiveData) after;
+        }
+    }
+    
+    private final DataSet dataSet;
+    private final String description;
+    private final Map<OsmPrimitive, BeforeAfter> beforeAfters = new HashMap<OsmPrimitive, BeforeAfter>();
+    
+    public GenericCommand(DataSet dataSet, String description) {
+        this.dataSet = dataSet;
+        this.description = description;
+    }
+    
+    void add(OsmPrimitive p) {
+        beforeAfters.put(p, new BeforeAfter(null, p));
+    }
+    
+    AbstractPrimitive backup(OsmPrimitive p) {
+        final BeforeAfter ba = beforeAfters.get(p);
+        
+        if (ba == null) {
+            final BeforeAfter newBa = new BeforeAfter(p.save(), p.save());
+            beforeAfters.put(p, newBa);
+            return newBa.after;
+        } else {
+            return ba.after;
+        }
+    }
+    
+    @Override
+    public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted,
+            Collection<OsmPrimitive> added) {}
+    
+    @Override
+    public JLabel getDescription() {
+        return new JLabel(description, null, JLabel.HORIZONTAL);
+    }
+    
+    @Override
+    public boolean executeCommand() {
+        for (Entry<OsmPrimitive, BeforeAfter> e : beforeAfters.entrySet()) {
+            if (e.getValue().before == null) {
+                dataSet.addPrimitive(e.getValue().afterPrimitive());
+            } else {
+                e.getKey().load(e.getValue().afterData());
+            }
+        }
+        return true;
+    }
+    
+    @Override
+    public void undoCommand() {
+        for (Entry<OsmPrimitive, BeforeAfter> e : beforeAfters.entrySet()) {
+            if (e.getValue().before == null) {
+                dataSet.removePrimitive(e.getValue().afterPrimitive().getPrimitiveId());
+            } else {
+                e.getKey().load(e.getValue().before);
+            }
+        }
+    }
+    
+    @Override
+    public PrimitiveData getOrig(OsmPrimitive osm) {
+        return beforeAfters.get(osm).before;
+    }
+    
+    @Override
+    public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
+        return Collections.unmodifiableSet(beforeAfters.keySet());
+    }
+}
Index: /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/Lane.java
===================================================================
--- /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/Lane.java	(revision 26181)
+++ /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/Lane.java	(revision 26182)
@@ -1,13 +1,17 @@
 package org.openstreetmap.josm.plugins.turnlanes.model;
 
+import static org.openstreetmap.josm.tools.I18n.tr;
+
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.plugins.turnlanes.CollectionUtils;
 
 public class Lane {
@@ -27,7 +31,8 @@
         
         i = 0;
-        for (double l : CollectionUtils.reverse(roadEnd.getLengths(Kind.EXTRA_LEFT))) {
+        for (double l : roadEnd.getLengths(Kind.EXTRA_LEFT)) {
             result.add(new Lane(roadEnd, --i, Kind.EXTRA_LEFT, l));
         }
+        Collections.reverse(result);
         
         final int regulars = getRegularCount(roadEnd.getWay(), roadEnd.getJunction().getNode());
@@ -53,5 +58,5 @@
                 final Double length = Double.parseDouble(s.trim());
                 
-                if (length > lengthBound) {
+                if (length >= lengthBound) {
                     result.add(length);
                 }
@@ -139,8 +144,8 @@
         }
         
+        this.length = length;
+        
         // TODO if needed, increase length of other lanes
         getOutgoingRoadEnd().updateLengths();
-        
-        this.length = length;
     }
     
@@ -174,5 +179,5 @@
     
     public void addTurn(List<Road> via, Road.End to) {
-        assert equals(to.getJunction());
+        final GenericCommand cmd = new GenericCommand(getOutgoingJunction().getNode().getDataSet(), tr("Add turn"));
         
         Relation existing = null;
@@ -203,5 +208,5 @@
             r.addMember(new RelationMember(Constants.TURN_ROLE_TO, to.getWay()));
             
-            getOutgoingJunction().getNode().getDataSet().addPrimitive(r);
+            cmd.add(r);
         } else {
             r = existing;
@@ -211,9 +216,38 @@
         final List<Integer> lanes = Turn.indices(r, key);
         lanes.add(getIndex());
-        r.put(key, Turn.join(lanes));
+        cmd.backup(r).put(key, Turn.join(lanes));
+        
+        Main.main.undoRedo.add(cmd);
     }
     
     public Set<Turn> getTurns() {
-        return Turn.load(getContainer(), Constants.TURN_ROLE_FROM, getOutgoingRoadEnd().getWay());
+        final Set<Turn> turns = Turn.load(getContainer(), Constants.TURN_ROLE_FROM, getOutgoingRoadEnd().getWay());
+        
+        final Iterator<Turn> it = turns.iterator();
+        while (it.hasNext()) {
+            final Turn t = it.next();
+            
+            if (!t.getFrom().equals(this)) {
+                it.remove();
+            }
+        }
+        
+        return turns;
+    }
+    
+    public void remove() {
+        if (!isExtra()) {
+            throw new UnsupportedOperationException();
+        }
+        
+        final GenericCommand cmd = new GenericCommand(getOutgoingJunction().getNode().getDataSet(), tr("Delete lane."));
+        
+        for (Turn t : getTurns()) {
+            t.remove(cmd);
+        }
+        
+        getOutgoingRoadEnd().removeLane(cmd, this);
+        
+        Main.main.undoRedo.add(cmd);
     }
 }
Index: /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/ModelContainer.java
===================================================================
--- /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/ModelContainer.java	(revision 26181)
+++ /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/ModelContainer.java	(revision 26182)
@@ -33,5 +33,5 @@
             closed = true;
             
-            for (Node n : closedNodes) {
+            for (Node n : new ArrayList<Node>(closedNodes)) {
                 for (Way w : Utils.filterRoads(n.getReferrers())) {
                     if (w.isFirstLastNode(n)) {
@@ -41,5 +41,5 @@
                 }
                 
-                for (Way w : closedWays) {
+                for (Way w : new ArrayList<Way>(closedWays) ) {
                     closed &= close(closedNodes, closedWays, w, Constants.TURN_ROLE_VIA);
                 }
Index: /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/Road.java
===================================================================
--- /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/Road.java	(revision 26181)
+++ /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/Road.java	(revision 26182)
@@ -9,4 +9,6 @@
 import java.util.Set;
 
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.AbstractPrimitive;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -109,4 +111,6 @@
             assert kind == Lane.Kind.EXTRA_LEFT || kind == Lane.Kind.EXTRA_RIGHT;
             
+            final GenericCommand cmd = new GenericCommand(getJunction().getNode().getDataSet(), "Add lane");
+            
             final boolean left = kind == Lane.Kind.EXTRA_LEFT;
             final Relation rel = left ? lengthsLeft : lengthsRight;
@@ -129,8 +133,10 @@
             final String old = target.get(key);
             if (old == null) {
-                target.put(key, lengthStr);
+                cmd.backup(target).put(key, lengthStr);
             } else {
-                target.put(key, old + Constants.SEPARATOR + lengthStr);
-            }
+                cmd.backup(target).put(key, old + Constants.SEPARATOR + lengthStr);
+            }
+            
+            Main.main.undoRedo.add(cmd);
         }
         
@@ -152,4 +158,6 @@
         
         void updateLengths() {
+            final GenericCommand cmd = new GenericCommand(getJunction().getNode().getDataSet(), "Change lane length");
+            
             for (final boolean left : Arrays.asList(true, false)) {
                 final Lane.Kind kind = left ? Lane.Kind.EXTRA_LEFT : Lane.Kind.EXTRA_RIGHT;
@@ -169,6 +177,9 @@
                 
                 lengths.setLength(lengths.length() - Constants.SEPARATOR.length());
-                r.put(left ? Constants.LENGTHS_KEY_LENGTHS_LEFT : Constants.LENGTHS_KEY_LENGTHS_RIGHT, lengths.toString());
-            }
+                cmd.backup(r).put(left ? Constants.LENGTHS_KEY_LENGTHS_LEFT : Constants.LENGTHS_KEY_LENGTHS_RIGHT,
+                        lengths.toString());
+            }
+            
+            Main.main.undoRedo.add(cmd);
         }
         
@@ -220,4 +231,35 @@
             }
         }
+        
+        void removeLane(GenericCommand cmd, Lane lane) {
+            assert lane.getKind() == Lane.Kind.EXTRA_LEFT || lane.getKind() == Lane.Kind.EXTRA_RIGHT;
+            
+            final boolean left = lane.getKind() == Lane.Kind.EXTRA_LEFT;
+            final Relation rel = left ? lengthsLeft : lengthsRight;
+            
+            for (Turn t : Turn.load(getContainer(), Constants.TURN_ROLE_FROM, getWay())) {
+                t.fixReferences(cmd, left, lane.getIndex());
+            }
+            
+            final double extraLength = left ? extraLengthLeft : extraLengthRight;
+            final List<Double> newLengths = new ArrayList<Double>();
+            int i = Math.abs(lane.getIndex());
+            final String key = left ? Constants.LENGTHS_KEY_LENGTHS_LEFT : Constants.LENGTHS_KEY_LENGTHS_RIGHT;
+            for (double l : Lane.loadLengths(rel, key, 0)) {
+                if (l < extraLength) {
+                    newLengths.add(l);
+                } else if (--i != 0) {
+                    newLengths.add(l);
+                }
+            }
+            
+            final AbstractPrimitive bRel = cmd.backup(rel);
+            bRel.put(key, join(newLengths));
+            
+            if (bRel.get(Constants.LENGTHS_KEY_LENGTHS_LEFT) == null
+                    && bRel.get(Constants.LENGTHS_KEY_LENGTHS_RIGHT) == null) {
+                bRel.setDeleted(true);
+            }
+        }
     }
     
@@ -247,15 +289,15 @@
         if (left.size() > 1) {
             throw new IllegalArgumentException("Way is in " + left.size()
-                + " lengths relations for given direction, both specifying left lane lengths.");
+                    + " lengths relations for given direction, both specifying left lane lengths.");
         }
         
         if (right.size() > 1) {
             throw new IllegalArgumentException("Way is in " + right.size()
-                + " lengths relations for given direction, both specifying right lane lengths.");
+                    + " lengths relations for given direction, both specifying right lane lengths.");
         }
         
         return new Pair<Relation, Relation>( //
-            left.isEmpty() ? null : left.get(0), //
-            right.isEmpty() ? null : right.get(0) //
+                left.isEmpty() ? null : left.get(0), //
+                right.isEmpty() ? null : right.get(0) //
         );
     }
@@ -263,9 +305,9 @@
     /**
      * @param r
-     *          lengths relation
+     *            lengths relation
      * @param w
-     *          the way to check for
+     *            the way to check for
      * @param n
-     *          first or last node of w, determines the direction
+     *            first or last node of w, determines the direction
      * @return whether the turn lane goes into the direction of n
      */
@@ -293,6 +335,6 @@
         
         this.container = container;
-        this.route = lengthsRelations.a == null && lengthsRelations.b == null ? Route.create(Arrays.asList(w), n) : Route
-            .load(lengthsRelations.a, lengthsRelations.b, w);
+        this.route = lengthsRelations.a == null && lengthsRelations.b == null ? Route.create(Arrays.asList(w), n)
+                : Route.load(lengthsRelations.a, lengthsRelations.b, w);
         this.fromEnd = new End(true, container.getOrCreateJunction(route.getFirstSegment().getStart()));
         this.toEnd = new End(false, j, lengthsRelations.a, lengthsRelations.b);
@@ -322,5 +364,20 @@
     }
     
-    private String toLengthString(double length) {
+    private static String join(List<Double> list) {
+        if (list.isEmpty()) {
+            return null;
+        }
+        
+        final StringBuilder builder = new StringBuilder(list.size() * (4 + Constants.SEPARATOR.length()));
+        
+        for (double e : list) {
+            builder.append(toLengthString(e)).append(Constants.SEPARATOR);
+        }
+        
+        builder.setLength(builder.length() - Constants.SEPARATOR.length());
+        return builder.toString();
+    }
+    
+    private static String toLengthString(double length) {
         final DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance();
         dfs.setDecimalSeparator('.');
Index: /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/Turn.java
===================================================================
--- /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/Turn.java	(revision 26181)
+++ /applications/editors/josm/plugins/turnlanes/src/org/openstreetmap/josm/plugins/turnlanes/model/Turn.java	(revision 26182)
@@ -1,3 +1,5 @@
 package org.openstreetmap.josm.plugins.turnlanes.model;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.util.ArrayList;
@@ -9,4 +11,5 @@
 import java.util.Set;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -21,5 +24,5 @@
         
         for (Relation r : OsmPrimitive.getFilteredList(primitive.getReferrers(), Relation.class)) {
-            if (!r.get("type").equals(Constants.TYPE_TURNS)) {
+            if (!r.isUsable() || !r.get("type").equals(Constants.TYPE_TURNS)) {
                 continue;
             }
@@ -71,5 +74,5 @@
             
             final Iterator<Route.Segment> it2 = (v.getRoute().getFirstSegment().getWay().equals(w) ? v.getRoute()
-                .getSegments() : CollectionUtils.reverse(v.getRoute().getSegments())).iterator();
+                    .getSegments() : CollectionUtils.reverse(v.getRoute().getSegments())).iterator();
             it2.next(); // first is done
             
@@ -123,5 +126,7 @@
         final Set<Turn> result = new HashSet<Turn>();
         for (int i : indices(r, Constants.TURN_KEY_LANES)) {
-            result.add(new Turn(r, fromRoadEnd.getLane(Lane.Kind.REGULAR, i), Collections.<Road> emptyList(), toRoadEnd));
+            result
+                    .add(new Turn(r, fromRoadEnd.getLane(Lane.Kind.REGULAR, i), Collections.<Road> emptyList(),
+                            toRoadEnd));
         }
         for (int i : indices(r, Constants.TURN_KEY_EXTRA_LANES)) {
@@ -176,9 +181,19 @@
     
     public void remove() {
+        final GenericCommand cmd = new GenericCommand(relation.getDataSet(), tr("Delete turn."));
+        
+        remove(cmd);
+        
+        Main.main.undoRedo.add(cmd);
+    }
+    
+    void remove(GenericCommand cmd) {
         final List<Integer> lanes = indices(relation, Constants.TURN_KEY_LANES);
         final List<Integer> extraLanes = indices(relation, Constants.TURN_KEY_EXTRA_LANES);
         
+        // TODO understand & document
         if (lanes.size() + extraLanes.size() == 1 && (from.isExtra() ^ !lanes.isEmpty())) {
-            relation.getDataSet().removePrimitive(relation.getPrimitiveId());
+            cmd.backup(relation).setDeleted(true);
+            // relation.getDataSet().removePrimitive(relation.getPrimitiveId());
         } else if (from.isExtra()) {
             extraLanes.remove(Integer.valueOf(from.getIndex()));
@@ -187,6 +202,19 @@
         }
         
-        relation.put(Constants.TURN_KEY_LANES, lanes.isEmpty() ? null : join(lanes));
-        relation.put(Constants.TURN_KEY_EXTRA_LANES, extraLanes.isEmpty() ? null : join(extraLanes));
+        cmd.backup(relation).put(Constants.TURN_KEY_LANES, lanes.isEmpty() ? null : join(lanes));
+        cmd.backup(relation).put(Constants.TURN_KEY_EXTRA_LANES, extraLanes.isEmpty() ? null : join(extraLanes));
+    }
+    
+    void fixReferences(GenericCommand cmd, boolean left, int index) {
+        final List<Integer> fixed = new ArrayList<Integer>();
+        for (int i : indices(relation, Constants.TURN_KEY_EXTRA_LANES)) {
+            if (left ? i < index : i > index) {
+                fixed.add(left ? i + 1 : i - 1);
+            } else {
+                fixed.add(i);
+            }
+        }
+        
+        cmd.backup(relation).put(Constants.TURN_KEY_EXTRA_LANES, join(fixed));
     }
 }
