Index: /src/org/openstreetmap/josm/Main.java
===================================================================
--- /src/org/openstreetmap/josm/Main.java	(revision 30)
+++ /src/org/openstreetmap/josm/Main.java	(revision 31)
@@ -19,4 +19,5 @@
 import org.openstreetmap.josm.actions.OpenOsmServerAction;
 import org.openstreetmap.josm.actions.PreferencesAction;
+import org.openstreetmap.josm.actions.RedoAction;
 import org.openstreetmap.josm.actions.SaveAction;
 import org.openstreetmap.josm.actions.UndoAction;
@@ -61,4 +62,7 @@
 	 */
 	private MapFrame mapFrame;
+
+	public final UndoAction undoAction;
+	public final RedoAction redoAction;
 	
 	/**
@@ -79,5 +83,6 @@
 		SaveAction saveAction = new SaveAction();
 		ExitAction exitAction = new ExitAction();
-		UndoAction undoAction = new UndoAction();
+		undoAction = new UndoAction();
+		redoAction = new RedoAction();
 		PreferencesAction preferencesAction = new PreferencesAction();
 		AboutAction aboutAction = new AboutAction();
@@ -104,4 +109,5 @@
 		editMenu.setMnemonic('E');
 		editMenu.add(undoAction);
+		editMenu.add(redoAction);
 		editMenu.addSeparator();
 		editMenu.add(preferencesAction);
@@ -122,4 +128,5 @@
 		toolBar.addSeparator();
 		toolBar.add(undoAction);
+		toolBar.add(redoAction);
 		toolBar.addSeparator();
 		toolBar.add(preferencesAction);
Index: /src/org/openstreetmap/josm/actions/RedoAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/RedoAction.java	(revision 31)
+++ /src/org/openstreetmap/josm/actions/RedoAction.java	(revision 31)
@@ -0,0 +1,33 @@
+package org.openstreetmap.josm.actions;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+
+import javax.swing.KeyStroke;
+
+import org.openstreetmap.josm.Main;
+
+
+/**
+ * Redoes the last command.
+ * 
+ * @author imi
+ */
+public class RedoAction extends JosmAction {
+
+	/**
+	 * Construct the action with "Undo" as label.
+	 */
+	public RedoAction() {
+		super("Redo", "redo", "Redo the last undone action.", null, KeyStroke.getAWTKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
+		setEnabled(false);
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		if (Main.main.getMapFrame() == null)
+			return;
+		Main.main.getMapFrame().repaint();
+		Main.main.getMapFrame().mapView.editLayer().redo();
+	}
+}
Index: /src/org/openstreetmap/josm/actions/UndoAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/UndoAction.java	(revision 30)
+++ /src/org/openstreetmap/josm/actions/UndoAction.java	(revision 31)
@@ -22,6 +22,7 @@
 	public UndoAction() {
 		super("Undo", "undo", "Undo the last action.", null, KeyStroke.getAWTKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK));
+		setEnabled(false);
 	}
-	
+
 	public void actionPerformed(ActionEvent e) {
 		if (Main.main.getMapFrame() == null)
Index: /src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java	(revision 30)
+++ /src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java	(revision 31)
@@ -149,5 +149,5 @@
 		Track t = new Track();
 		for (LineSegment ls : sortedLineSegments)
-			t.add(ls);
+			t.segments.add(ls);
 		mv.editLayer().add(new AddCommand(Main.main.ds, t));
 		Main.main.ds.clearSelection();
Index: /src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 30)
+++ /src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 31)
@@ -4,8 +4,6 @@
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
+import java.util.Collections;
 import java.util.LinkedList;
 
@@ -13,43 +11,26 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.CombineAndDeleteCommand;
+import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.command.DeleteCommand;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.LineSegment;
-import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.command.SequenceCommand;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Track;
+import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor;
 import org.openstreetmap.josm.gui.MapFrame;
 
 /**
  * An action that enables the user to delete nodes and other objects.
- * 
+ *
  * The user can click on an object, which get deleted if possible. When Ctrl is 
  * pressed when releasing the button, the objects and all its references are 
- * deleted as well. The exact definition of "all its references" are in 
+ * deleted. The exact definition of "all its references" are in 
  * @see #deleteWithReferences(OsmPrimitive)
  *
  * Pressing Alt will select the track instead of a line segment, as usual.
+ * 
+ * If the user did not press Ctrl and the object has any references, the user
+ * is informed and nothing is deleted.
  *
- * If the user presses Ctrl, no combining is possible. Otherwise, DeleteAction 
- * tries to combine the referencing objects as follows:
- *
- * If a node is part of exactly two line segments, the two line segments are 
- * combined into one. The first line segment spans now to the end of the 
- * second and the second line segment gets deleted.
- * 
- * Combining is only possible, if both objects that should be combined have no
- * key with a different property value. The remaining keys are merged together.
- * 
- * If a node is part of an area with more than 3 nodes, the node is removed from 
- * the area and the area has now one fewer node.
- * 
- * If combining fails, the node has still references and the user did not hold
- * Ctrl down, the deleting fails, the action informs the user and nothing is
- * deleted.
- * 
- * 
  * If the user enters the mapmode and any object is selected, all selected
- * objects that can be deleted will. Combining applies to the selected objects.
+ * objects that can be deleted will.
  * 
  * @author imi
@@ -62,5 +43,5 @@
 	 */
 	public DeleteAction(MapFrame mapFrame) {
-		super("Delete", "delete", "Delete nodes, streets or areas.", KeyEvent.VK_D, mapFrame);
+		super("Delete", "delete", "Delete nodes, streets or segments.", KeyEvent.VK_D, mapFrame);
 	}
 
@@ -82,22 +63,8 @@
 		super.actionPerformed(e);
 		boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
-		Collection<OsmPrimitive> selection = Main.main.ds.getSelected();
-		
-		int selSize = 0;
-		// loop as long as the selection size changes
-		while(selSize != selection.size()) {
-			selSize = selection.size();
-
-			for (Iterator<OsmPrimitive> it = selection.iterator(); it.hasNext();) {
-				OsmPrimitive osm = it.next();
-				if (ctrl) {
-					deleteWithReferences(osm);
-					it.remove();
-				} else {
-					if (delete(osm, false))
-						it.remove();
-				}
-			}
-		}
+		if (ctrl)
+			deleteWithReferences(Main.main.ds.getSelected());
+		else
+			delete(Main.main.ds.getSelected(), false);
 		mv.repaint();
 	}
@@ -117,7 +84,7 @@
 
 		if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0)
-			deleteWithReferences(sel);
+			deleteWithReferences(Collections.singleton(sel));
 		else
-			delete(sel, true);
+			delete(Collections.singleton(sel), true);
 
 		mv.repaint();
@@ -125,165 +92,46 @@
 
 	/**
-	 * Delete the primitive and everything it references or beeing directly 
-	 * referenced by, except of nodes which are deleted only if passed 
-	 * directly or become unreferenced while deleting other objects.
-	 *
-	 * Nothing is combined as in @see #delete(OsmPrimitive).
+	 * Delete the primitives and everything they references.
 	 * 
-	 * Example (A is a track of line segment a and b. z is a node):
-	 *
-	 *              A
-	 *   B   x        z
-	 *  -----*--------+-----
-	 *       |     a      b
-	 *       |C
-	 *       |
-	 *       *y
-	 *       
-	 * If you delete C, C and y (since now unreferenced) gets deleted.
-	 * If you delete A, then A, a, b and z (since now unreferenced) gets deleted.
-	 * If you delete y, then y and C gets deleted.
-	 * TODO If you delete x, then a,B,C and x gets deleted. A now consist of b only.
-	 * If you delete a or b, then A, a, b and z gets deleted.
+	 * If a node is deleted, the node and all line segments, tracks and areas
+	 * the node is part of are deleted as well.
 	 * 
-	 * @param osm The object to delete.
+	 * If a line segment is deleted, all tracks the line segment is part of 
+	 * are deleted as well. No nodes are deleted.
+	 * 
+	 * If a track is deleted, only the track and no line segments or nodes are 
+	 * deleted.
+	 * 
+	 * If an area is deleted, only the area gets deleted.
+	 * 
+	 * @param selection The list of all object to be deleted.
 	 */
-	private void deleteWithReferences(OsmPrimitive osm) {
-		// collect all tracks, areas and line segments that should be deleted
-		ArrayList<Track> tracksToDelete = new ArrayList<Track>();
-		ArrayList<LineSegment> lineSegmentsToDelete = new ArrayList<LineSegment>();
-
-		if (osm instanceof Node) {
-			// delete any track and line segment the node is in.
-			for (Track t : Main.main.ds.tracks)
-				for (LineSegment ls : t.segments)
-					if (ls.start == osm || ls.end == osm)
-						tracksToDelete.add(t);
-			for (LineSegment ls : Main.main.ds.lineSegments)
-				if (ls.start == osm || ls.end == osm)
-					lineSegmentsToDelete.add(ls);
-				
-		} else if (osm instanceof LineSegment) {
-			LineSegment lineSegment = (LineSegment)osm;
-			lineSegmentsToDelete.add(lineSegment);
-			for (Track t : Main.main.ds.tracks)
-				for (LineSegment ls : t.segments)
-					if (lineSegment == ls)
-						tracksToDelete.add(t);
-		} else if (osm instanceof Track) {
-			tracksToDelete.add((Track)osm);
-		}
-		// collect all nodes, that could be unreferenced after deletion
-		ArrayList<Node> checkUnreferencing = new ArrayList<Node>();
-		for (Track t : tracksToDelete) {
-			for (LineSegment ls : t.segments) {
-				checkUnreferencing.add(ls.start);
-				checkUnreferencing.add(ls.end);
-			}
-		}
-		for (LineSegment ls : lineSegmentsToDelete) {
-			checkUnreferencing.add(ls.start);
-			checkUnreferencing.add(ls.end);
-		}
-
-		Collection<OsmPrimitive> deleteData = new LinkedList<OsmPrimitive>();
-		deleteData.addAll(tracksToDelete);
-		deleteData.addAll(lineSegmentsToDelete);
-		// removing all unreferenced nodes
-		for (Node n : checkUnreferencing)
-			if (!isReferenced(n))
-				deleteData.add(n);
-		// now, all references are killed. Delete the node (if it was a node)
-		if (osm instanceof Node)
-			deleteData.add(osm);
-
-		mv.editLayer().add(new DeleteCommand(Main.main.ds, deleteData));
+	private void deleteWithReferences(Collection<OsmPrimitive> selection) {
+		Collection<Command> deleteCommands = new LinkedList<Command>();
+		for (OsmPrimitive osm : selection)
+			deleteCommands.add(new DeleteCommand(Main.main.ds, osm));
+		mv.editLayer().add(new SequenceCommand(deleteCommands));
 	}
 
 	/**
-	 * Try to delete the given primitive. If the primitive is a node and
-	 * used somewhere, try to combine the references to make the node unused.
-	 * If this fails, inform the user and do not delete.
+	 * Try to delete all given primitives. If a primitive is
+	 * used somewhere and that "somewhere" is not going to be deleted,
+	 * inform the user and do not delete.
 	 * 
-	 * @param osm The object to delete.
+	 * @param selection The objects to delete.
 	 * @param msgBox Whether a message box for errors should be shown
-	 * @return <code>true</code> if the object could be deleted
 	 */
-	private boolean delete(OsmPrimitive osm, boolean msgBox) {
-		if (osm instanceof Node && isReferenced((Node)osm))
-			return combineAndDelete((Node)osm, msgBox);
-		Collection<OsmPrimitive> c = new LinkedList<OsmPrimitive>();
-		c.add(osm);
-		mv.editLayer().add(new DeleteCommand(Main.main.ds, c));
-		return true;
-	}
-
-	
-	/**
-	 * Return <code>true</code>, if the node is used by anything in the map.
-	 * @param n The node to check.
-	 * @return Whether the node is used by a track or area.
-	 */
-	private boolean isReferenced(Node n) {
-		for (LineSegment ls : Main.main.ds.lineSegments)
-			if (ls.start == n || ls.end == n)
-				return true;
-		// TODO areas
-		return false;
-	}
-
-	/**
-	 * Try to combine all objects when deleting the node n. If combining is not
-	 * possible, return an error string why. Otherwise, combine it and return 
-	 * <code>null</code>.
-	 *
-	 * @param n The node that is going to be deleted.
-	 * @param msgBox Whether a message box should be displayed in case of problems
-	 * @return <code>true</code> if combining suceded.
-	 */
-	private boolean combineAndDelete(Node n, boolean msgBox) {
-		DataSet ds = Main.main.ds;
-		Collection<LineSegment> lineSegmentsUsed = new HashSet<LineSegment>();
-		for (LineSegment ls : ds.lineSegments)
-			if (ls.start == n || ls.end == n)
-				lineSegmentsUsed.add(ls);
-
-		if (lineSegmentsUsed.isEmpty())
-			// should not be called
-			throw new IllegalStateException();
-		
-		if (lineSegmentsUsed.size() == 1) {
-			if (msgBox)
-				JOptionPane.showMessageDialog(Main.main, "Node used by a line segment. Delete this first.");
-			return false;
+	private void delete(Collection<OsmPrimitive> selection, boolean msgBox) {
+		Collection<Command> deleteCommands = new LinkedList<Command>();
+		for (OsmPrimitive osm : selection) {
+			CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.main.ds);
+			osm.visit(v);
+			if (!selection.containsAll(v.data)) {
+				if (msgBox)
+					JOptionPane.showMessageDialog(Main.main, "This object is in use.");
+			} else
+				deleteCommands.add(new DeleteCommand(Main.main.ds, osm));
 		}
-			
-		if (lineSegmentsUsed.size() > 2) {
-			if (msgBox)
-				JOptionPane.showMessageDialog(Main.main, "Node used by more than two line segments. Delete them first.");
-			return false;
-		}
-		
-		Iterator<LineSegment> it = lineSegmentsUsed.iterator();
-		LineSegment first = it.next();
-		LineSegment second = it.next();
-		
-		// wrong direction?
-		if (first.start == second.end) {
-			LineSegment t = first;
-			first = second;
-			second = t;
-		}
-		
-		// combinable?
-		if (first.end != second.start || !first.end.keyPropertiesMergable(second.start)) {
-			if (msgBox)
-				JOptionPane.showMessageDialog(Main.main, "Node used by line segments that cannot be combined.");
-			return false;
-		}
-
-		// Ok, we can combine. Do it.
-		mv.editLayer().add(new CombineAndDeleteCommand(ds, first, second));
-		return true;
+		mv.editLayer().add(new SequenceCommand(deleteCommands));
 	}
 }
Index: /src/org/openstreetmap/josm/actions/mapmode/MoveAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/mapmode/MoveAction.java	(revision 30)
+++ /src/org/openstreetmap/josm/actions/mapmode/MoveAction.java	(revision 31)
@@ -8,4 +8,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.command.MoveCommand;
 import org.openstreetmap.josm.data.GeoPoint;
@@ -83,5 +84,9 @@
 
 		Collection<OsmPrimitive> selection = Main.main.ds.getSelected();
-		mv.editLayer().add(new MoveCommand(selection, dx, dy));
+		Command c = mv.editLayer().lastCommand();
+		if (c instanceof MoveCommand && MoveCommand.getAffectedNodes(selection).equals(((MoveCommand)c).objects))
+			((MoveCommand)c).moveAgain(dx,dy);
+		else
+			mv.editLayer().add(new MoveCommand(selection, dx, dy));
 		
 		mv.repaint();
Index: /src/org/openstreetmap/josm/command/AddCommand.java
===================================================================
--- /src/org/openstreetmap/josm/command/AddCommand.java	(revision 30)
+++ /src/org/openstreetmap/josm/command/AddCommand.java	(revision 31)
@@ -1,17 +1,10 @@
 package org.openstreetmap.josm.command;
 
-import java.awt.Component;
 import java.util.Collection;
 
-import javax.swing.JLabel;
-
 import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.Key;
-import org.openstreetmap.josm.data.osm.LineSegment;
-import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Track;
-import org.openstreetmap.josm.data.osm.visitor.SelectionComponentVisitor;
-import org.openstreetmap.josm.data.osm.visitor.Visitor;
+import org.openstreetmap.josm.data.osm.visitor.AddVisitor;
+import org.openstreetmap.josm.data.osm.visitor.DeleteVisitor;
 
 /**
@@ -26,28 +19,6 @@
 	 * The dataset this command operates on.
 	 */
-	DataSet ds;
+	private DataSet ds;
 
-	/**
-	 * Helper that adds the object
-	 * @author imi
-	 */
-	private final class AddVisitor implements Visitor {
-		public void visit(Node n) {ds.nodes.add(n);}
-		public void visit(LineSegment ls) {ds.lineSegments.add(ls);}
-		public void visit(Track t) {ds.tracks.add(t);}
-		public void visit(Key k) {throw new IllegalStateException("Keys are added by using ChangeKeyValueCommand");}
-	}
-
-	/**
-	 * Helper that deletes the object (for undo)
-	 * @author imi
-	 */
-	private final class RemoveVisitor implements Visitor {
-		public void visit(Node n) {ds.nodes.remove(n);}
-		public void visit(LineSegment ls) {ds.lineSegments.remove(ls);}
-		public void visit(Track t) {ds.tracks.remove(t);}
-		public void visit(Key k) {throw new IllegalStateException("Keys are added by using ChangeKeyValueCommand");}
-	}
-	
 	/**
 	 * The primitive to add to the dataset.
@@ -64,17 +35,11 @@
 
 	public void executeCommand() {
-		osm.visit(new AddVisitor());
+		osm.visit(new AddVisitor(ds));
 	}
 
 	public void undoCommand() {
-		osm.visit(new RemoveVisitor());
+		osm.visit(new DeleteVisitor(ds));
 	}
 
-	public Component commandDescription() {
-		SelectionComponentVisitor v = new SelectionComponentVisitor();
-		osm.visit(v);
-		return new JLabel("Add "+v.name, v.icon, JLabel.LEADING);
-	}
-	
 	public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
 		added.add(osm);
Index: /src/org/openstreetmap/josm/command/ChangeKeyValueCommand.java
===================================================================
--- /src/org/openstreetmap/josm/command/ChangeKeyValueCommand.java	(revision 30)
+++ /src/org/openstreetmap/josm/command/ChangeKeyValueCommand.java	(revision 31)
@@ -1,5 +1,4 @@
 package org.openstreetmap.josm.command;
 
-import java.awt.Component;
 import java.util.Collection;
 import java.util.HashMap;
@@ -8,6 +7,4 @@
 import java.util.List;
 import java.util.Map;
-
-import javax.swing.JLabel;
 
 import org.openstreetmap.josm.data.osm.Key;
@@ -77,11 +74,4 @@
 	}
 
-	public Component commandDescription() {
-		String objStr = objects.size()+" object" + (objects.size()==1?"":"s");
-		if (value == null)
-			return new JLabel("Delete the key '"+key+"' of "+objStr);
-		return new JLabel("Change the key '"+key+"' of "+objStr+" to '"+value+"'");
-	}
-
 	public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
 		modified.addAll(objects);
Index: c/org/openstreetmap/josm/command/CombineAndDeleteCommand.java
===================================================================
--- /src/org/openstreetmap/josm/command/CombineAndDeleteCommand.java	(revision 30)
+++ 	(revision )
@@ -1,151 +1,0 @@
-package org.openstreetmap.josm.command;
-
-import java.awt.Component;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import javax.swing.JLabel;
-
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.Key;
-import org.openstreetmap.josm.data.osm.LineSegment;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Track;
-import org.openstreetmap.josm.data.osm.visitor.SelectionComponentVisitor;
-
-/**
- * This is a combination of first combining objects to get a node free of 
- * references and then delete that node. It is used by the delete action.
- * 
- * The rules is as follow:
- * If the node to delete is between exact two line segments, which are
- * in a straight (not pointing together), the second line segment is deleted
- * and the first now spans to the last node of the second line segment.
- * 
- * @author imi
- */
-public class CombineAndDeleteCommand implements Command {
-
-	/**
-	 * The dataset, this command operates on.
-	 */
-	private DataSet ds;
-	/**
-	 * This line segment is combined with the second line segment.
-	 * The node that get deleted is the end of this segment.
-	 */
-	private LineSegment first;
-	/**
-	 * This line segment is deleted by the combining.
-	 * The node that get deleted is the start of this segment.
-	 */
-	private LineSegment second;
-
-	/**
-	 * The tracks (if any) the line segments are part of.
-	 */
-	private List<Track> track;
-
-	
-	// stuff for undo
-
-	/**
-	 * The old properties of the first line segment (for undo)
-	 */
-	private Map<Key, String> oldProperties;
-	/**
-	 * The positions of the second line segment in the tracks (if any track)
-	 */
-	private List<Integer> lineSegmentTrackPos;
-	
-	/**
-	 * Create the command and assign the data entries.
-	 * @param ds     The dataset this command operates on.
-	 * @param first  The line segment that remain alive
-	 * @param second The line segment that get deleted
-	 */
-	public CombineAndDeleteCommand(DataSet ds, LineSegment first, LineSegment second) {
-		this.ds = ds;
-		this.first = first;
-		this.second = second;
-		if (first.end != second.start)
-			throw new IllegalArgumentException();
-	}
-	
-	public void executeCommand() {
-		first.end = second.end;
-		oldProperties = new HashMap<Key, String>(first.keys);
-		first.keys = mergeKeys(first.keys, second.keys);
-
-		// delete second line segment
-		for (Track t : ds.tracks) {
-			if (t.segments.contains(second)) {
-				if (track == null)
-					track = new LinkedList<Track>();
-				track.add(t);
-			}
-		}
-		if (track != null) {
-			lineSegmentTrackPos = new LinkedList<Integer>();
-			for (Track t : track) {
-				int i = t.segments.indexOf(second);
-				if (i != -1)
-					t.segments.remove(second);
-				lineSegmentTrackPos.add(i);
-			}
-		}
-		ds.lineSegments.remove(second);
-		
-		// delete node
-		ds.nodes.remove(second.start);
-	}
-
-	public void undoCommand() {
-		ds.nodes.add(second.start);
-		ds.lineSegments.add(second);
-		
-		if (track != null) {
-			Iterator<Track> it = track.iterator();
-			for (int i : lineSegmentTrackPos) {
-				Track t = it.next();
-				if (i != -1)
-					t.segments.add(i, second);
-			}
-		}
-		first.keys = oldProperties;
-		first.end = second.start;
-	}
-
-	/**
-	 * Merges the second parameter into the first and return the merged map.
-	 * @param first The first map that will hold keys.
-	 * @param second The map to merge with the first.
-	 * @return The merged key map.
-	 */
-	private Map<Key, String> mergeKeys(Map<Key, String> first, Map<Key, String> second) {
-		if (first == null)
-			first = second;
-		else if (second != null && first != null)
-			first.putAll(second);
-		return first;
-	}
-
-	public Component commandDescription() {
-		SelectionComponentVisitor v = new SelectionComponentVisitor();
-		v.visit(second.start);
-		return new JLabel("Remove "+v.name, v.icon, JLabel.LEADING);
-	}
-
-	public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
-		deleted.add(second);
-		deleted.add(second.start);
-		modified.add(first);
-		if (track != null)
-			modified.addAll(track);
-	}
-
-}
Index: /src/org/openstreetmap/josm/command/Command.java
===================================================================
--- /src/org/openstreetmap/josm/command/Command.java	(revision 30)
+++ /src/org/openstreetmap/josm/command/Command.java	(revision 31)
@@ -1,5 +1,4 @@
 package org.openstreetmap.josm.command;
 
-import java.awt.Component;
 import java.util.Collection;
 
@@ -32,9 +31,4 @@
 	
 	/**
-	 * Give a description of the command as component to draw
-	 */
-	Component commandDescription();
-	
-	/**
 	 * Fill in the changed data this command operates on.
 	 * Add to the lists, don't clear them.
Index: /src/org/openstreetmap/josm/command/DeleteCommand.java
===================================================================
--- /src/org/openstreetmap/josm/command/DeleteCommand.java	(revision 30)
+++ /src/org/openstreetmap/josm/command/DeleteCommand.java	(revision 31)
@@ -1,15 +1,12 @@
 package org.openstreetmap.josm.command;
 
-import java.awt.Component;
 import java.util.Collection;
-
-import javax.swing.JLabel;
+import java.util.HashSet;
 
 import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.Key;
-import org.openstreetmap.josm.data.osm.LineSegment;
-import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Track;
+import org.openstreetmap.josm.data.osm.visitor.AddVisitor;
+import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor;
+import org.openstreetmap.josm.data.osm.visitor.DeleteVisitor;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
 
@@ -23,42 +20,20 @@
 	 * The dataset this command operates on.
 	 */
-	DataSet ds;
+	final DataSet ds;
+	/**
+	 * The primitive that get deleted.
+	 */
+	final Collection<OsmPrimitive> data = new HashSet<OsmPrimitive>();
 
-	/**
-	 * Helper that adds the object.
-	 * @author imi
-	 */
-	private final class AddVisitor implements Visitor {
-		public void visit(Node n) {ds.nodes.add(n);}
-		public void visit(LineSegment ls) {ds.lineSegments.add(ls);}
-		public void visit(Track t) {ds.tracks.add(t);}
-		public void visit(Key k) {throw new IllegalStateException("Keys are added by using ChangeKeyValueCommand");}
-	}
-
-	/**
-	 * Helper that deletes the object. Does not respect back reference cache.
-	 * @author imi
-	 */
-	private final class DeleteVisitor implements Visitor {
-		public void visit(Node n) {ds.nodes.remove(n);}
-		public void visit(LineSegment ls) {ds.lineSegments.remove(ls);}
-		public void visit(Track t) {ds.tracks.remove(t);}
-		public void visit(Key k) {throw new IllegalStateException("Keys are added by using ChangeKeyValueCommand");}
-	}
-	
-	
-	
-	/**
-	 * The primitives that are going to deleted.
-	 */
-	private final Collection<OsmPrimitive> data;
-	
-	public DeleteCommand(DataSet ds, Collection<OsmPrimitive> data) {
+	public DeleteCommand(DataSet ds, OsmPrimitive osm) {
 		this.ds = ds;
-		this.data = data;
+		CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(ds);
+		osm.visit(v);
+		data.addAll(v.data);
+		data.add(osm);
 	}
 	
 	public void executeCommand() {
-		Visitor v = new DeleteVisitor();
+		Visitor v = new DeleteVisitor(ds);
 		for (OsmPrimitive osm : data)
 			osm.visit(v);
@@ -66,11 +41,7 @@
 
 	public void undoCommand() {
-		Visitor v = new AddVisitor();
+		Visitor v = new AddVisitor(ds);
 		for (OsmPrimitive osm : data)
 			osm.visit(v);
-	}
-
-	public Component commandDescription() {
-		return new JLabel("Delete "+data.size()+" primitives");
 	}
 
Index: /src/org/openstreetmap/josm/command/MoveCommand.java
===================================================================
--- /src/org/openstreetmap/josm/command/MoveCommand.java	(revision 30)
+++ /src/org/openstreetmap/josm/command/MoveCommand.java	(revision 31)
@@ -1,5 +1,4 @@
 package org.openstreetmap.josm.command;
 
-import java.awt.Component;
 import java.awt.geom.Point2D;
 import java.util.Collection;
@@ -7,6 +6,4 @@
 import java.util.LinkedList;
 import java.util.List;
-
-import javax.swing.JLabel;
 
 import org.openstreetmap.josm.data.osm.Node;
@@ -25,5 +22,5 @@
 	 * The objects that should be moved.
 	 */
-	private List<OsmPrimitive> objects;
+	public List<Node> objects = new LinkedList<Node>();
 	/**
 	 * x difference movement. Coordinates are in northern/eastern 
@@ -38,20 +35,47 @@
 	 * x/y List of all old positions of the objects.
 	 */
-	private List<Point2D.Double> oldPositions;
-	
+	private List<Point2D.Double> oldPositions = new LinkedList<Point2D.Double>();
+
 	/**
 	 * Create a MoveCommand and assign the initial object set and movement vector.
 	 */
 	public MoveCommand(Collection<OsmPrimitive> objects, double x, double y) {
-		this.objects = new LinkedList<OsmPrimitive>(objects);
 		this.x = x;
 		this.y = y;
+		this.objects = getAffectedNodes(objects);
+		for (Node n : this.objects)
+			oldPositions.add(new Point2D.Double(n.coor.x, n.coor.y));
 	}
 
-	public void executeCommand() {
+	/**
+	 * @return a list of all nodes that will be moved if using the given set of
+	 * objects.
+	 */
+	public static List<Node> getAffectedNodes(Collection<OsmPrimitive> objects) {
 		AllNodesVisitor visitor = new AllNodesVisitor();
 		for (OsmPrimitive osm : objects)
 			osm.visit(visitor);
-		for (Node n : visitor.nodes) {
+		return new LinkedList<Node>(visitor.nodes);
+	}
+	
+	/**
+	 * Move the same set of objects again by the specified vector. The vectors
+	 * are added together and so the resulting will be moved to the previous
+	 * vector plus this one.
+	 * 
+	 * The move is immediatly executed and any undo will undo both vectors to
+	 * the original position the objects had before first moving.
+	 */
+	public void moveAgain(double x, double y) {
+		for (Node n : objects) {
+			n.coor.x += x;
+			n.coor.y += y;
+		}
+		this.x += x;
+		this.y += y;
+	}
+	
+	public void executeCommand() {
+		for (Node n : objects) {
 			n.coor.x += x;
 			n.coor.y += y;
@@ -60,9 +84,6 @@
 
 	public void undoCommand() {
-		AllNodesVisitor visitor = new AllNodesVisitor();
-		for (OsmPrimitive osm : objects)
-			osm.visit(visitor);
 		Iterator<Point2D.Double> it = oldPositions.iterator();
-		for (Node n : visitor.nodes) {
+		for (Node n : objects) {
 			Point2D.Double p = it.next();
 			n.coor.x = p.x;
@@ -71,14 +92,7 @@
 	}
 
-	public Component commandDescription() {
-		String xstr = Math.abs(x) + (x < 0 ? "W" : "E");
-		String ystr = Math.abs(y) + (y < 0 ? "S" : "N");
-		return new JLabel("Move "+objects.size()+" primitives "+xstr+" "+ystr);
-	}
-
 	public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
 		for (OsmPrimitive osm : objects)
-			if (!modified.contains(osm))
-				modified.add(osm);
+			modified.add(osm);
 	}
 }
Index: /src/org/openstreetmap/josm/command/SequenceCommand.java
===================================================================
--- /src/org/openstreetmap/josm/command/SequenceCommand.java	(revision 31)
+++ /src/org/openstreetmap/josm/command/SequenceCommand.java	(revision 31)
@@ -0,0 +1,44 @@
+package org.openstreetmap.josm.command;
+
+import java.util.Collection;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+
+/**
+ * A command consisting of a sequenz of other commands. Executes the other commands
+ * and undo them in reverse order.
+ * @author imi
+ */
+public class SequenceCommand implements Command {
+
+	/**
+	 * The command sequenz to be executed.
+	 */
+	private Command[] sequenz;
+
+	/**
+	 * Create the command by specifying the list of commands to execute.
+	 * @param sequenz The sequenz that should be executed.
+	 */
+	public SequenceCommand(Collection<Command> sequenz) {
+		this.sequenz = new Command[sequenz.size()];
+		this.sequenz = sequenz.toArray(this.sequenz);
+	}
+	
+	public void executeCommand() {
+		for (Command c : sequenz)
+			c.executeCommand();
+	}
+
+	public void undoCommand() {
+		for (int i = sequenz.length-1; i >= 0; --i)
+			sequenz[i].undoCommand();
+	}
+
+	public void fillModifiedData(Collection<OsmPrimitive> modified,
+			Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+		for (Command c : sequenz)
+			c.fillModifiedData(modified, deleted, added);
+	}
+
+}
Index: /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 30)
+++ /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 31)
@@ -15,4 +15,9 @@
 abstract public class OsmPrimitive {
 
+	private static int idcount = 0;
+	public OsmPrimitive() {
+		id = ++idcount;
+	}
+	
 	/**
 	 * The key/value list for this primitive.
Index: /src/org/openstreetmap/josm/data/osm/Track.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/Track.java	(revision 30)
+++ /src/org/openstreetmap/josm/data/osm/Track.java	(revision 31)
@@ -19,11 +19,4 @@
 
 	
-	/**
-	 * Add the line segment to the track.
-	 */
-	public void add(LineSegment ls) {
-		segments.add(ls);
-	}
-
 	/**
 	 * Return the last node in the track. This is the node, which no line segment
Index: /src/org/openstreetmap/josm/data/osm/visitor/AddVisitor.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/visitor/AddVisitor.java	(revision 31)
+++ /src/org/openstreetmap/josm/data/osm/visitor/AddVisitor.java	(revision 31)
@@ -0,0 +1,36 @@
+/**
+ */
+package org.openstreetmap.josm.data.osm.visitor;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Key;
+import org.openstreetmap.josm.data.osm.LineSegment;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Track;
+
+/**
+ * Visitor, that adds the visited object to the dataset given at constructor.
+ * 
+ * Is not capable of adding keys.
+ * 
+ * @author imi
+ */
+public class AddVisitor implements Visitor {
+	
+	private final DataSet ds;
+	
+	public AddVisitor(DataSet ds) {
+		this.ds = ds;
+	}
+	
+	public void visit(Node n) {
+		ds.nodes.add(n);
+	}
+	public void visit(LineSegment ls) {
+		ds.lineSegments.add(ls);
+	}
+	public void visit(Track t) {
+		ds.tracks.add(t);
+	}
+	public void visit(Key k) {}
+}
Index: /src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java	(revision 31)
+++ /src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java	(revision 31)
@@ -0,0 +1,51 @@
+package org.openstreetmap.josm.data.osm.visitor;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Key;
+import org.openstreetmap.josm.data.osm.LineSegment;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Track;
+
+/**
+ * Helper that collect all line segments a node is part of, all tracks
+ * a node or line segment is part of and all areas a node is part of. 
+ * @author imi
+ */
+public class CollectBackReferencesVisitor implements Visitor {
+
+	private final DataSet ds;
+	
+	/**
+	 * The result list of primitives stored here.
+	 */
+	public final Collection<OsmPrimitive> data = new HashSet<OsmPrimitive>();
+
+	public CollectBackReferencesVisitor(DataSet ds) {
+		this.ds = ds;
+	}
+	
+	public void visit(Node n) {
+		for (Track t : ds.tracks) {
+			for (LineSegment ls : t.segments) {
+				if (ls.start == n || ls.end == n) {
+					data.add(t);
+					break;
+				}
+			}
+		}
+		for (LineSegment ls : ds.lineSegments)
+			if (ls.start == n || ls.end == n)
+				data.add(ls);
+	}
+	public void visit(LineSegment ls) {
+		for (Track t : ds.tracks)
+			if (t.segments.contains(ls))
+				data.add(t);
+	}
+	public void visit(Track t) {}
+	public void visit(Key k) {}
+}
Index: /src/org/openstreetmap/josm/data/osm/visitor/DeleteVisitor.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/visitor/DeleteVisitor.java	(revision 31)
+++ /src/org/openstreetmap/josm/data/osm/visitor/DeleteVisitor.java	(revision 31)
@@ -0,0 +1,36 @@
+/**
+ */
+package org.openstreetmap.josm.data.osm.visitor;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Key;
+import org.openstreetmap.josm.data.osm.LineSegment;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Track;
+
+/**
+ * Visitor, that removes the visited object from the dataset given at constructor.
+ * 
+ * Is not capable of removing keys.
+ * 
+ * @author imi
+ */
+public class DeleteVisitor implements Visitor {
+	
+	private final DataSet ds;
+	
+	public DeleteVisitor(DataSet ds) {
+		this.ds = ds;
+	}
+	
+	public void visit(Node n) {
+		ds.nodes.remove(n);
+	}
+	public void visit(LineSegment ls) {
+		ds.lineSegments.remove(ls);
+	}
+	public void visit(Track t) {
+		ds.tracks.remove(t);
+	}
+	public void visit(Key k) {}
+}
Index: /src/org/openstreetmap/josm/gui/PreferenceDialog.java
===================================================================
--- /src/org/openstreetmap/josm/gui/PreferenceDialog.java	(revision 30)
+++ /src/org/openstreetmap/josm/gui/PreferenceDialog.java	(revision 31)
@@ -243,5 +243,5 @@
 		map.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
 
-		
+
 		tabPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
 	
@@ -261,5 +261,5 @@
 		pack();
 		Dimension s = Main.main.getSize();
-		setLocation(s.width/2-getWidth()/2, s.height/2-getHeight()/2);
+		setLocation(Main.main.getX()+s.width/2-getWidth()/2, Main.main.getY()+s.height/2-getHeight()/2);
 	}
 
Index: /src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- /src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 30)
+++ /src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 31)
@@ -2,7 +2,6 @@
 
 import java.awt.Graphics;
-import java.io.FileWriter;
-import java.io.StringWriter;
 import java.util.LinkedList;
+import java.util.Stack;
 
 import javax.swing.Icon;
@@ -16,5 +15,4 @@
 import org.openstreetmap.josm.data.osm.Track;
 import org.openstreetmap.josm.data.osm.visitor.BoundingVisitor;
-import org.openstreetmap.josm.data.osm.visitor.CsvVisitor;
 import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor;
 import org.openstreetmap.josm.data.projection.Projection;
@@ -41,5 +39,8 @@
 	 */
 	private LinkedList<Command> commands = new LinkedList<Command>();
-	private LinkedList<String> debugDsBefore = new LinkedList<String>();
+	/**
+	 * The stack for redoing commands
+	 */
+	private Stack<Command> redoCommands = new Stack<Command>();
 
 	/**
@@ -71,8 +72,8 @@
 		SimplePaintVisitor visitor = new SimplePaintVisitor(g, mv, null);
 
+		for (LineSegment ls : data.lineSegments)
+			visitor.visit(ls);
 		for (Track t : data.tracks)
 			visitor.visit(t);
-		for (LineSegment ls : data.lineSegments)
-			visitor.visit(ls);
 		for (Node n : data.nodes)
 			visitor.visit(n);
@@ -117,26 +118,21 @@
 
 	/**
+	 * @return the last command added or <code>null</code> if no command in queue.
+	 */
+	public Command lastCommand() {
+		return commands.isEmpty() ? null : commands.getLast();
+	}
+	
+	/**
 	 * Execute the command and add it to the intern command queue. Also mark all
 	 * primitives in the command as modified.
 	 */
 	public void add(Command c) {
-		StringWriter sw = new StringWriter();
-		CsvVisitor v = new CsvVisitor(sw);
-		for (Node n : Main.main.ds.nodes) {
-			v.visit(n);
-			sw.append('\n');
-		}
-		for (LineSegment ls : Main.main.ds.lineSegments) {
-			v.visit(ls);
-			sw.append('\n');
-		}
-		for (Track t : Main.main.ds.tracks) {
-			v.visit(t);
-			sw.append('\n');
-		}
-		debugDsBefore.add(sw.getBuffer().toString());
-		
 		c.executeCommand();
 		commands.add(c);
+		redoCommands.clear();
+		// TODO: Replace with listener scheme
+		Main.main.undoAction.setEnabled(true);
+		Main.main.redoAction.setEnabled(false);
 	}
 
@@ -149,33 +145,21 @@
 		Command c = commands.removeLast();
 		c.undoCommand();
-		
-		//DEBUG
-		StringWriter sw = new StringWriter();
-		CsvVisitor v = new CsvVisitor(sw);
-		for (Node n : Main.main.ds.nodes) {
-			v.visit(n);
-			sw.append('\n');
-		}
-		for (LineSegment ls : Main.main.ds.lineSegments) {
-			v.visit(ls);
-			sw.append('\n');
-		}
-		for (Track t : Main.main.ds.tracks) {
-			v.visit(t);
-			sw.append('\n');
-		}
-		String s = Main.main.getMapFrame().mapView.editLayer().debugDsBefore.removeLast();
-		if (!s.equals(sw.getBuffer().toString())) {
-			try {
-				FileWriter fw = new FileWriter("/home/imi/richtig");
-				fw.append(sw.getBuffer().toString());
-				fw.close();
-				fw = new FileWriter("/home/imi/falsch");
-				fw.append(s);
-				fw.close();
-			} catch (Exception x) {
-				x.printStackTrace();
-			}
-		}
+		redoCommands.push(c);
+		//TODO: Replace with listener scheme
+		Main.main.undoAction.setEnabled(!commands.isEmpty());
+		Main.main.redoAction.setEnabled(true);
+	}
+	/**
+	 * Redoes the last undoed command.
+	 */
+	public void redo() {
+		if (redoCommands.isEmpty())
+			return;
+		Command c = redoCommands.pop();
+		c.executeCommand();
+		commands.add(c);
+		//TODO: Replace with listener scheme
+		Main.main.undoAction.setEnabled(true);
+		Main.main.redoAction.setEnabled(!redoCommands.isEmpty());
 	}
 }
Index: /src/org/openstreetmap/josm/io/GpxReader.java
===================================================================
--- /src/org/openstreetmap/josm/io/GpxReader.java	(revision 30)
+++ /src/org/openstreetmap/josm/io/GpxReader.java	(revision 31)
@@ -130,5 +130,5 @@
 						LineSegment lineSegment = new LineSegment(start, node);
 						parseKeyValueExtensions(lineSegment, child.getChild("extensions", GPX));
-						track.add(lineSegment);
+						track.segments.add(lineSegment);
 						start = null;
 					}
Index: /src/org/openstreetmap/josm/io/OsmServerReader.java
===================================================================
--- /src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 30)
+++ /src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 31)
@@ -94,5 +94,4 @@
 	 */
 	private Reader getReader(String urlStr) throws IOException {
-		System.out.println(urlStr);
 		initAuthentication();
 		URL url = new URL(urlStr);
