Index: /src/org/openstreetmap/josm/Main.java
===================================================================
--- /src/org/openstreetmap/josm/Main.java	(revision 21)
+++ /src/org/openstreetmap/josm/Main.java	(revision 22)
@@ -4,4 +4,6 @@
 import java.awt.BorderLayout;
 import java.awt.Container;
+import java.util.Collection;
+import java.util.LinkedList;
 
 import javax.swing.JFrame;
@@ -20,4 +22,6 @@
 import org.openstreetmap.josm.actions.PreferencesAction;
 import org.openstreetmap.josm.actions.SaveGpxAction;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.DataSet;
 import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.data.Preferences.PreferencesException;
@@ -26,5 +30,5 @@
 
 /**
- * Main window class consisting of the mainframe MDI application.
+ * Main window class application.
  *  
  * @author imi
@@ -41,4 +45,16 @@
 	 */
 	public final static Preferences pref = new Preferences();
+
+	/**
+	 * The global command queue since last save. So if you reload the data from disk
+	 * (or from OSM server, if nothing changed on server) and reapply the commands,
+	 * you should get the same result as currently displaying.
+	 */
+	public Collection<Command> commands = new LinkedList<Command>();
+
+	/**
+	 * The global dataset.
+	 */
+	public DataSet ds = new DataSet();
 	
 	/**
@@ -105,5 +121,5 @@
 		// creating toolbar
 		JToolBar toolBar = new JToolBar();
-		toolBar.setFloatable(false);
+		toolBar.setFloatable(true);
 		toolBar.add(openServerAction);
 		toolBar.add(openGpxAction);
Index: /src/org/openstreetmap/josm/actions/OpenOsmServerAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/OpenOsmServerAction.java	(revision 21)
+++ /src/org/openstreetmap/josm/actions/OpenOsmServerAction.java	(revision 22)
@@ -44,10 +44,10 @@
 public class OpenOsmServerAction extends AbstractAction {
 
-	private JTextField[] latlon = new JTextField[]{
+	JTextField[] latlon = new JTextField[]{
 			new JTextField(9),
 			new JTextField(9),
 			new JTextField(9),
 			new JTextField(9)};
-	private JCheckBox rawGps = new JCheckBox("Open as raw gps data", false);
+	JCheckBox rawGps = new JCheckBox("Open as raw gps data", false);
 
 	public OpenOsmServerAction() {
@@ -178,5 +178,5 @@
 	 * 		checkbox.
 	 */
-	private Bookmark readBookmark() {
+	Bookmark readBookmark() {
 		try {
 			Bookmark b = new Bookmark();
Index: /src/org/openstreetmap/josm/actions/SaveGpxAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/SaveGpxAction.java	(revision 21)
+++ /src/org/openstreetmap/josm/actions/SaveGpxAction.java	(revision 22)
@@ -47,5 +47,5 @@
 		try {
 			FileWriter fileWriter = new FileWriter(gpxFile);
-			GpxWriter out = new GpxWriter(fileWriter, Main.main.getMapFrame().mapView.getActiveDataSet());
+			GpxWriter out = new GpxWriter(fileWriter);
 			out.output();
 			fileWriter.close();
Index: /src/org/openstreetmap/josm/actions/mapmode/AddLineSegmentAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/mapmode/AddLineSegmentAction.java	(revision 21)
+++ /src/org/openstreetmap/josm/actions/mapmode/AddLineSegmentAction.java	(revision 22)
@@ -11,5 +11,6 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.DataSet;
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.data.osm.LineSegment;
 import org.openstreetmap.josm.data.osm.Node;
@@ -130,8 +131,6 @@
 		
 		if (start != end) {
-			DataSet ds = mv.getActiveDataSet();
-
 			// try to find a line segment
-			for (Track t : ds.tracks())
+			for (Track t : Main.main.ds.tracks())
 				for (LineSegment ls : t.segments())
 					if (start == ls.getStart() && end == ls.getEnd()) {
@@ -141,25 +140,7 @@
 
 			LineSegment ls = new LineSegment(start, end);
-			boolean foundTrack = false;
-
-			if (((e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0)) {
-				// find a track for the new line segment
-				for (Track t : ds.tracks()) {
-					if (t.getEndingNode() == start) {
-						t.add(ls);
-						foundTrack = true;
-					}
-				}
-				if (!foundTrack) {
-					for (Track t : ds.tracks()) {
-						if (t.getStartingNode() == end) {
-							t.addStart(ls);
-							foundTrack = true;
-						}
-					}
-				}
-			}
-			if (!foundTrack)
-				ds.addPendingLineSegment(ls);
+			Command c = new AddCommand(ls);
+			c.executeCommand();
+			Main.main.commands.add(c);
 		}
 		
Index: /src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java	(revision 21)
+++ /src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java	(revision 22)
@@ -4,4 +4,7 @@
 import java.awt.event.MouseEvent;
 
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.gui.MapFrame;
@@ -48,5 +51,7 @@
 			Node node = new Node();
 			node.coor = mv.getPoint(e.getX(), e.getY(), true);
-			mv.getActiveDataSet().nodes.add(node);
+			Command c = new AddCommand(node);
+			c.executeCommand();
+			Main.main.commands.add(c);
 			mv.repaint();
 		}
Index: /src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java	(revision 21)
+++ /src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java	(revision 22)
@@ -6,5 +6,7 @@
 import java.util.LinkedList;
 
-import org.openstreetmap.josm.command.DataSet;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.data.osm.LineSegment;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -76,12 +78,10 @@
 			return; // not allowed together
 
-		DataSet ds = mv.getActiveDataSet();
-		
 		if (!ctrl && !shift)
-			ds.clearSelection(); // new selection will replace the old.
+			Main.main.ds.clearSelection(); // new selection will replace the old.
 
 		Collection<OsmPrimitive> selectionList = selectionManager.getObjectsInRectangle(r,alt);
 		for (OsmPrimitive osm : selectionList)
-			osm.setSelected(!ctrl, ds);
+			osm.setSelected(!ctrl);
 
 		mv.repaint(); // from now on, the map has to be repainted.
@@ -90,5 +90,5 @@
 			return; // no new track yet.
 		
-		Collection<OsmPrimitive> selection = ds.getSelected();
+		Collection<OsmPrimitive> selection = Main.main.ds.getSelected();
 		if (selection.isEmpty())
 			return;
@@ -104,7 +104,9 @@
 		Track t = new Track();
 		for (LineSegment ls : lineSegments)
-			ds.assignPendingLineSegment(ls, t, true);
-		ds.addTrack(t);
-		ds.clearSelection();
+			t.add(ls);
+		Command c = new AddCommand(t);
+		c.executeCommand();
+		Main.main.commands.add(c);
+		Main.main.ds.clearSelection();
 	}
 
Index: /src/org/openstreetmap/josm/actions/mapmode/CombineAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/mapmode/CombineAction.java	(revision 21)
+++ /src/org/openstreetmap/josm/actions/mapmode/CombineAction.java	(revision 22)
@@ -10,5 +10,6 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.DataSet;
+import org.openstreetmap.josm.command.CombineCommand;
+import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.data.osm.LineSegment;
 import org.openstreetmap.josm.data.osm.Node;
@@ -83,5 +84,5 @@
 		mv.addMouseListener(this);
 		mv.addMouseMotionListener(this);
-		mv.getActiveDataSet().clearSelection();
+		Main.main.ds.clearSelection();
 	}
 
@@ -147,41 +148,12 @@
 		if (first instanceof LineSegment && second instanceof LineSegment)
 			JOptionPane.showMessageDialog(Main.main, "Cannot combine two line segments. To create tracks use 'Add Track'.");
-		else if (first instanceof LineSegment && second instanceof Track)
-			combine((LineSegment)first, (Track)second);
-		else if (first instanceof Track && second instanceof LineSegment)
-			combine((LineSegment)second, (Track)first);
-		else if (first instanceof Track && second instanceof Track) {
-			if (!first.keyPropertiesMergable(second))
-				JOptionPane.showMessageDialog(Main.main, "Cannot combine because of different properties.");
-			else {
-				Track t1 = (Track)first;
-				Track t2 = (Track)second;
-				if (t1.getStartingNode() == t2.getEndingNode()) {
-					t1 = t2;
-					t2 = (Track)first;
-				}
-				t1.addAll(t2.segments());
-				if (t1.keys == null)
-					t1.keys = t2.keys;
-				else	
-					t1.keys.putAll(t2.keys);
-				mv.getActiveDataSet().removeTrack(t2);
-			}
+		else if (first instanceof Track && second instanceof Track && !first.keyPropertiesMergable(second))
+			JOptionPane.showMessageDialog(Main.main, "Cannot combine because of different properties.");
+		else {
+			Command c = new CombineCommand(first, second);
+			c.executeCommand();
+			Main.main.commands.add(c);
 		}
 		mv.repaint();
-	}
-
-
-	/**
-	 * Add the line segment to the track and remove it from the pending segments.
-	 * @param ls The line segment to add
-	 * @param t The track to add the line segment to
-	 */
-	private void combine(LineSegment ls, Track t) {
-		DataSet ds = mv.getActiveDataSet();
-		if (!ds.pendingLineSegments().contains(ls))
-			throw new IllegalStateException("Should not be able to select non-pending line segments.");
-		
-		ds.assignPendingLineSegment(ls, t, t.getStartingNode() != ls.getEnd());
 	}
 
@@ -218,5 +190,5 @@
 			Point start = mv.getScreenPoint(ls.getStart().coor);
 			Point end = mv.getScreenPoint(ls.getEnd().coor);
-			if (mv.getActiveDataSet().pendingLineSegments().contains(osm) && g.getColor() == Color.GRAY)
+			if (Main.main.ds.pendingLineSegments().contains(osm) && g.getColor() == Color.GRAY)
 				g.drawLine(start.x, start.y, end.x, end.y);
 			else
Index: /src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 21)
+++ /src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 22)
@@ -11,5 +11,4 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.DataSet;
 import org.openstreetmap.josm.data.osm.Key;
 import org.openstreetmap.josm.data.osm.LineSegment;
@@ -94,10 +93,8 @@
 			return;
 
-		DataSet ds = mv.getActiveDataSet();
-
 		if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0)
-			deleteWithReferences(sel, ds);
+			deleteWithReferences(sel);
 		else
-			delete(sel, ds);
+			delete(sel);
 
 		mv.repaint();
@@ -129,5 +126,5 @@
 	 * @param osm The object to delete.
 	 */
-	private void deleteWithReferences(OsmPrimitive osm, DataSet ds) {
+	private void deleteWithReferences(OsmPrimitive osm) {
 		// collect all tracks, areas and pending line segments that should be deleted
 		ArrayList<Track> tracksToDelete = new ArrayList<Track>();
@@ -136,9 +133,9 @@
 		if (osm instanceof Node) {
 			// delete any track and line segment the node is in.
-			for (Track t : ds.tracks())
+			for (Track t : Main.main.ds.tracks())
 				for (LineSegment ls : t.segments())
 					if (ls.getStart() == osm || ls.getEnd() == osm)
 						tracksToDelete.add(t);
-			for (LineSegment ls : ds.pendingLineSegments())
+			for (LineSegment ls : Main.main.ds.pendingLineSegments())
 				if (ls.getStart() == osm || ls.getEnd() == osm)
 					lineSegmentsToDelete.add(ls);
@@ -147,5 +144,5 @@
 			LineSegment lineSegment = (LineSegment)osm;
 			lineSegmentsToDelete.add(lineSegment);
-			for (Track t : ds.tracks())
+			for (Track t : Main.main.ds.tracks())
 				for (LineSegment ls : t.segments())
 					if (lineSegment == ls)
@@ -169,16 +166,16 @@
 		// delete tracks and areas
 		for (Track t : tracksToDelete)
-			ds.removeTrack(t);
+			Main.main.ds.removeTrack(t);
 		for (LineSegment ls : lineSegmentsToDelete)
-			ds.destroyPendingLineSegment(ls);
+			Main.main.ds.destroyPendingLineSegment(ls);
 
 		// removing all unreferenced nodes
 		for (Node n : checkUnreferencing) {
-			if (!isReferenced(n, ds))
-				ds.nodes.remove(n);
+			if (!isReferenced(n))
+				Main.main.ds.nodes.remove(n);
 		}
 		// now, all references are killed. Delete the node (if it was a node)
 		if (osm instanceof Node)
-			ds.nodes.remove(osm);
+			Main.main.ds.nodes.remove(osm);
 	}
 
@@ -190,9 +187,9 @@
 	 * @param osm The object to delete.
 	 */
-	private void delete(OsmPrimitive osm, DataSet ds) {
+	private void delete(OsmPrimitive osm) {
 		if (osm instanceof Node) {
 			Node n = (Node)osm;
-			if (isReferenced(n, ds)) {
-				String combined = combine(n, ds);
+			if (isReferenced(n)) {
+				String combined = combine(n);
 				if (combined != null) {
 					JOptionPane.showMessageDialog(Main.main, combined);
@@ -201,8 +198,8 @@
 			}
 			// now, the node isn't referenced anymore, so delete it.
-			ds.nodes.remove(n);
+			Main.main.ds.nodes.remove(n);
 		} else if (osm instanceof LineSegment) {
 			LinkedList<Track> tracksToDelete = new LinkedList<Track>();
-			for (Track t : ds.tracks()) {
+			for (Track t : Main.main.ds.tracks()) {
 				t.remove((LineSegment)osm);
 				if (t.segments().isEmpty())
@@ -210,10 +207,10 @@
 			}
 			for (Track t : tracksToDelete)
-				ds.removeTrack(t);
-			ds.destroyPendingLineSegment((LineSegment)osm);
+				Main.main.ds.removeTrack(t);
+			Main.main.ds.destroyPendingLineSegment((LineSegment)osm);
 		} else if (osm instanceof Track) {
-			ds.removeTrack((Track)osm);
+			Main.main.ds.removeTrack((Track)osm);
 			for (LineSegment ls : ((Track)osm).segments())
-				ds.addPendingLineSegment(ls);
+				Main.main.ds.addPendingLineSegment(ls);
 		}
 	}
@@ -225,10 +222,10 @@
 	 * @return Whether the node is used by a track or area.
 	 */
-	private boolean isReferenced(Node n, DataSet ds) {
-		for (Track t : ds.tracks())
+	private boolean isReferenced(Node n) {
+		for (Track t : Main.main.ds.tracks())
 			for (LineSegment ls : t.segments())
 				if (ls.getStart() == n || ls.getEnd() == n)
 					return true;
-		for (LineSegment ls : ds.pendingLineSegments())
+		for (LineSegment ls : Main.main.ds.pendingLineSegments())
 			if (ls.getStart() == n || ls.getEnd() == n)
 				return true;
@@ -246,7 +243,7 @@
 	 * 		are problems combining the node.
 	 */
-	private String combine(Node n, DataSet ds) {
+	private String combine(Node n) {
 		// first, check for pending line segments
-		for (LineSegment ls : ds.pendingLineSegments())
+		for (LineSegment ls : Main.main.ds.pendingLineSegments())
 			if (n == ls.getStart() || n == ls.getEnd())
 				return "Node used by a line segment which is not part of any track. Remove this first."; 
@@ -261,5 +258,5 @@
 		HashMap<ArrayList<LineSegment>, Track> lineSegments = new HashMap<ArrayList<LineSegment>, Track>();
 		
-		for (Track t : ds.tracks()) {
+		for (Track t : Main.main.ds.tracks()) {
 			ArrayList<LineSegment> current = new ArrayList<LineSegment>();
 			for (LineSegment ls : t.segments())
@@ -284,5 +281,5 @@
 		// try to combine tracks
 		ArrayList<Track> tracks = new ArrayList<Track>();
-		for (Track t : ds.tracks())
+		for (Track t : Main.main.ds.tracks())
 			if (t.getStartingNode() == n || t.getEndingNode() == n)
 				tracks.add(t);
@@ -349,5 +346,5 @@
 			// move the remaining line segments to first track.
 			first.addAll(second.segments());
-			ds.removeTrack(second);
+			Main.main.ds.removeTrack(second);
 		}
 		
Index: /src/org/openstreetmap/josm/actions/mapmode/MapMode.java
===================================================================
--- /src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 21)
+++ /src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 22)
@@ -87,5 +87,5 @@
 		mapFrame.selectMapMode(this);
 	}
-	
+
 	/**
 	 * Does nothing. Only to subclass.
Index: /src/org/openstreetmap/josm/actions/mapmode/MoveAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/mapmode/MoveAction.java	(revision 21)
+++ /src/org/openstreetmap/josm/actions/mapmode/MoveAction.java	(revision 22)
@@ -6,8 +6,9 @@
 import java.awt.event.MouseEvent;
 import java.util.Collection;
-import java.util.HashSet;
 
-import org.openstreetmap.josm.command.DataSet;
-import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.MoveCommand;
+import org.openstreetmap.josm.data.GeoPoint;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.MapFrame;
@@ -75,23 +76,17 @@
 		}
 
-		int dx = e.getX() - mousePos.x;
-		int dy = e.getY() - mousePos.y;
+		GeoPoint mouseGeo = mv.getPoint(e.getX(), e.getY(), false);
+		GeoPoint mouseStartGeo = mv.getPoint(mousePos.x, mousePos.y, false);
+		double dx = mouseGeo.x - mouseStartGeo.x;
+		double dy = mouseGeo.y - mouseStartGeo.y;
 		if (dx == 0 && dy == 0)
 			return;
 
-		Collection<OsmPrimitive> selection = mv.getActiveDataSet().getSelected();
-		// creating a list of all nodes that should be moved.
-		Collection<Node> movingNodes = new HashSet<Node>();
-		for (OsmPrimitive osm : selection)
-			movingNodes.addAll(osm.getAllNodes());
-
-		for (Node n : movingNodes) {
-			Point pos = mv.getScreenPoint(n.coor);
-			pos.x += dx;
-			pos.y += dy;
-			n.coor = mv.getPoint(pos.x, pos.y, true);
-		}
+		Collection<OsmPrimitive> selection = Main.main.ds.getSelected();
+		Command c = new MoveCommand(selection, dx, dy);
+		c.executeCommand();
+		Main.main.commands.add(c);
+		
 		mv.repaint();
-		
 		mousePos = e.getPoint();
 	}
@@ -111,10 +106,8 @@
 			return;
 
-		DataSet ds = mv.getActiveDataSet();
-
-		if (ds.getSelected().size() == 0) {
+		if (Main.main.ds.getSelected().size() == 0) {
 			OsmPrimitive osm = mv.getNearest(e.getPoint(), (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);
 			if (osm != null)
-				osm.setSelected(true, ds);
+				osm.setSelected(true);
 			singleOsmPrimitive = osm;
 			mv.repaint();
@@ -134,5 +127,5 @@
 		mv.setCursor(oldCursor);
 		if (singleOsmPrimitive != null) {
-			singleOsmPrimitive.setSelected(false, mv.getActiveDataSet());
+			singleOsmPrimitive.setSelected(false);
 			mv.repaint();
 		}
Index: /src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java	(revision 21)
+++ /src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java	(revision 22)
@@ -5,5 +5,5 @@
 import java.util.Collection;
 
-import org.openstreetmap.josm.command.DataSet;
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.MapFrame;
@@ -87,12 +87,10 @@
 			return; // not allowed together
 
-		DataSet ds = mv.getActiveDataSet();
-
 		if (!ctrl && !shift)
-			ds.clearSelection(); // new selection will replace the old.
+			Main.main.ds.clearSelection(); // new selection will replace the old.
 
 		Collection<OsmPrimitive> selectionList = selectionManager.getObjectsInRectangle(r,alt);
 		for (OsmPrimitive osm : selectionList)
-			osm.setSelected(!ctrl, ds);
+			osm.setSelected(!ctrl);
 		mv.repaint();
 	}
Index: /src/org/openstreetmap/josm/command/AddCommand.java
===================================================================
--- /src/org/openstreetmap/josm/command/AddCommand.java	(revision 21)
+++ /src/org/openstreetmap/josm/command/AddCommand.java	(revision 22)
@@ -2,8 +2,10 @@
 
 import java.awt.Component;
+import java.util.Collection;
 import java.util.Iterator;
 
 import javax.swing.JLabel;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.Key;
 import org.openstreetmap.josm.data.osm.LineSegment;
@@ -26,15 +28,10 @@
 	 */
 	private final OsmPrimitive osm;
-	/**
-	 * The dataset to add the primitive to.
-	 */
-	private final DataSet ds;
 
 	/**
 	 * Create the command and specify the element to add.
 	 */
-	public AddCommand(OsmPrimitive osm, DataSet dataSet) {
+	public AddCommand(OsmPrimitive osm) {
 		this.osm = osm;
-		this.ds = dataSet;
 	}
 
@@ -42,9 +39,14 @@
 		osm.visit(this);
 	}
-
+	
 	public Component commandDescription() {
 		SelectionComponentVisitor v = new SelectionComponentVisitor();
 		osm.visit(v);
 		return new JLabel(v.name, v.icon, JLabel.LEADING);
+	}
+	
+	public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+		if (!added.contains(osm))
+			added.add(osm);
 	}
 
@@ -54,5 +56,5 @@
 	 */
 	public void visit(Node n) {
-		ds.nodes.add(n);
+		Main.main.ds.nodes.add(n);
 	}
 
@@ -62,5 +64,5 @@
 	 */
 	public void visit(LineSegment ls) {
-		ds.pendingLineSegments.add(ls);
+		Main.main.ds.pendingLineSegments.add(ls);
 	}
 
@@ -70,6 +72,6 @@
 	 */
 	public void visit(Track t) {
-		ds.addTrack(t);
-		for (Iterator<LineSegment> it =  ds.pendingLineSegments.iterator(); it.hasNext();)
+		Main.main.ds.tracks.add(t);
+		for (Iterator<LineSegment> it =  Main.main.ds.pendingLineSegments.iterator(); it.hasNext();)
 			if (t.segments().contains(it.next()))
 				it.remove();
Index: /src/org/openstreetmap/josm/command/CombineCommand.java
===================================================================
--- /src/org/openstreetmap/josm/command/CombineCommand.java	(revision 22)
+++ /src/org/openstreetmap/josm/command/CombineCommand.java	(revision 22)
@@ -0,0 +1,90 @@
+package org.openstreetmap.josm.command;
+
+import java.awt.Component;
+import java.util.Collection;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.openstreetmap.josm.Main;
+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 command combines either a line segment with a track or two tracks together.
+ * @author imi
+ */
+public class CombineCommand implements Command {
+
+	/**
+	 * Both primitives that get combined together. "mod" is modified to be the combined
+	 * object and del is the deleted one.
+	 */
+	private final OsmPrimitive mod, del;
+	
+	/**
+	 * Create a combine command and assign the members
+	 */
+	public CombineCommand(OsmPrimitive first, OsmPrimitive second) {
+		if (first instanceof Track && second instanceof LineSegment) {
+			mod = first;
+			del = second;
+		} else if (first instanceof LineSegment && second instanceof Track) {
+			mod = second;
+			del = first;
+		} else if (((Track)first).getStartingNode() == ((Track)second).getEndingNode()) {
+			mod = first;
+			del = second;
+		} else {
+			mod = second;
+			del = first;
+		}
+	}
+
+	public void executeCommand() {
+		if (del instanceof LineSegment) {
+			LineSegment ls = (LineSegment)mod;
+			Track t = (Track)del;
+			if (!Main.main.ds.pendingLineSegments().contains(ls))
+				throw new IllegalStateException("Should not be able to select non-pending line segments.");
+			
+			Main.main.ds.pendingLineSegments.remove(ls);
+			if (t.getStartingNode() != ls.getEnd())
+				t.add(ls);
+			else
+				t.addStart(ls);
+		} else {
+			Track t1 = (Track)mod;
+			Track t2 = (Track)del;
+			t1.addAll(t2.segments());
+			if (t1.keys == null)
+				t1.keys = t2.keys;
+			else	
+				t1.keys.putAll(t2.keys);
+			t2.destroy();
+			Main.main.ds.tracks.remove(t2);
+		}
+	}
+
+	public Component commandDescription() {
+		JPanel p = new JPanel();
+		p.add(new JLabel("Combine"));
+		SelectionComponentVisitor v = new SelectionComponentVisitor();
+		mod.visit(v);
+		p.add(new JLabel(v.name, v.icon, JLabel.LEADING));
+		p.add(new JLabel("with"));
+		del.visit(v);
+		p.add(new JLabel(v.name, v.icon, JLabel.LEADING));
+		return p;
+	}
+	
+	public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+		if (!modified.contains(mod))
+			modified.add(mod);
+		if (deleted.contains(del))
+			throw new IllegalStateException("Deleted object twice: "+del);
+		deleted.add(del);
+	}
+}
Index: /src/org/openstreetmap/josm/command/Command.java
===================================================================
--- /src/org/openstreetmap/josm/command/Command.java	(revision 21)
+++ /src/org/openstreetmap/josm/command/Command.java	(revision 22)
@@ -2,9 +2,12 @@
 
 import java.awt.Component;
+import java.util.Collection;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 
 
 /**
  * Classes implementing Command modify a dataset in a specific way. A command is
- * one atomic action on a dataset, such as move or delete.
+ * one atomic action on a specific dataset, such as move or delete.
  *
  * @author imi
@@ -16,8 +19,19 @@
 	 */
 	void executeCommand();
-	
+
 	/**
 	 * Give a description of the command as component to draw
 	 */
 	Component commandDescription();
+	
+	/**
+	 * Fill in the changed data this command operates on (for sending to the server).
+	 * Add to the lists, don't clear them.
+	 * @param modified  The modified primitives
+	 * @param deleted   The deleted primitives
+	 * @param added		The added primitives
+	 */
+	void fillModifiedData(Collection<OsmPrimitive> modified,
+			Collection<OsmPrimitive> deleted,
+			Collection<OsmPrimitive> added);
 }
Index: /src/org/openstreetmap/josm/command/DataSet.java
===================================================================
--- /src/org/openstreetmap/josm/command/DataSet.java	(revision 21)
+++ /src/org/openstreetmap/josm/command/DataSet.java	(revision 22)
@@ -205,6 +205,5 @@
 	 */
 	public void mergeFrom(DataSet ds, boolean mergeEqualNodes) {
-		System.out.println(nodes.size()+" "+pendingLineSegments.size()+" "+tracks.size());
-		if (mergeEqualNodes) {
+		if (mergeEqualNodes && !nodes.isEmpty()) {
 			Map<Node, Node> mergeMap = new HashMap<Node, Node>();
 			Set<Node> nodesToAdd = new HashSet<Node>();
@@ -247,5 +246,4 @@
 			pendingLineSegments.addAll(ds.pendingLineSegments);
 		}
-		System.out.println(nodes.size()+" "+pendingLineSegments.size()+" "+tracks.size());
 	}
 
@@ -258,5 +256,5 @@
 			return;
 		for (OsmPrimitive osm : list) {
-			osm.setSelected(false, this);
+			osm.setSelected(false);
 			if (osm.keys != null)
 				clearSelection(osm.keys.keySet());
Index: /src/org/openstreetmap/josm/command/MoveCommand.java
===================================================================
--- /src/org/openstreetmap/josm/command/MoveCommand.java	(revision 21)
+++ /src/org/openstreetmap/josm/command/MoveCommand.java	(revision 22)
@@ -63,3 +63,9 @@
 		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);
+	}
 }
Index: /src/org/openstreetmap/josm/data/SelectionTracker.java
===================================================================
--- /src/org/openstreetmap/josm/data/SelectionTracker.java	(revision 21)
+++ /src/org/openstreetmap/josm/data/SelectionTracker.java	(revision 22)
@@ -59,15 +59,15 @@
 	 * @author imi
 	 */
-	private enum SelectionEventState {WAITING, COLLECTING, PURGING};
+	private enum SelectionEventState {WAITING, COLLECTING, PURGING}
 
 	/**
 	 * The state, regarding to the selection changing that we are in.
 	 */
-	transient private SelectionEventState state = SelectionEventState.WAITING;
+	transient SelectionEventState state = SelectionEventState.WAITING;
 
 	/**
 	 * A list of listeners to selection changed events.
 	 */
-	transient private Collection<SelectionChangedListener> listeners = new LinkedList<SelectionChangedListener>();
+	transient Collection<SelectionChangedListener> listeners = new LinkedList<SelectionChangedListener>();
 
 	
Index: /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 21)
+++ /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 22)
@@ -4,5 +4,5 @@
 import java.util.Map;
 
-import org.openstreetmap.josm.command.DataSet;
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
 
@@ -72,9 +72,8 @@
 	 * changed later, if the value actualy changed.
 	 * @param selected Whether the primitive should be selected or not.
-	 * @param ds The dataSet, this primitive is in.
 	 */
-	public void setSelected(boolean selected, DataSet ds) {
+	public void setSelected(boolean selected) {
 		if (selected != this.selected)
-			ds.fireSelectionChanged();
+			Main.main.ds.fireSelectionChanged();
 		this.selected = selected;
 	}
Index: /src/org/openstreetmap/josm/data/projection/Projection.java
===================================================================
--- /src/org/openstreetmap/josm/data/projection/Projection.java	(revision 21)
+++ /src/org/openstreetmap/josm/data/projection/Projection.java	(revision 22)
@@ -8,5 +8,4 @@
 import javax.swing.event.ChangeListener;
 
-import org.openstreetmap.josm.command.DataSet;
 import org.openstreetmap.josm.data.GeoPoint;
 
@@ -81,14 +80,6 @@
 	 * This implementation does nothing. It is provided only for subclasses
 	 * to initialize their data members.
-	 * 
-	 * @param dataSet
-	 *            The dataset, which will be displayed on screen. Later, all
-	 *            projections should be relative to the given dataset. Any
-	 *            reverse projections (xy2latlon) can be assumed to be in near
-	 *            distance to nodes of this dataset (that means, it is ok, if
-	 *            there is a conversion error, if the requested x/y to xy2latlon
-	 *            is far away from any coordinate in the dataset)
 	 */
-	public void init(DataSet dataSet) {}
+	public void init() {}
 	
 	/**
Index: /src/org/openstreetmap/josm/data/projection/UTM.java
===================================================================
--- /src/org/openstreetmap/josm/data/projection/UTM.java	(revision 21)
+++ /src/org/openstreetmap/josm/data/projection/UTM.java	(revision 22)
@@ -16,5 +16,4 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.DataSet;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.GeoPoint;
@@ -80,5 +79,5 @@
 	};
 
-	private enum Hemisphere {north, south};
+	private enum Hemisphere {north, south}
 
 	/**
@@ -102,9 +101,9 @@
 	 * Spinner with all possible zones for the configuration panel
 	 */
-	private JSpinner zoneSpinner;
+	JSpinner zoneSpinner;
 	/**
 	 * Hemisphere combo for the configuration panel
 	 */
-	private JComboBox hemisphereCombo;
+	JComboBox hemisphereCombo;
 
 	
@@ -193,11 +192,10 @@
 	/**
 	 * Try to autodetect the zone and hemisphere from the dataset.
-	 * @param dataSet The dataset to extrakt zone information from.
 	 * @return The zone data extrakted from the dataset.
 	 */
-	private ZoneData autoDetect(DataSet dataSet) {
+	ZoneData autoDetect() {
 		ZoneData zd = new ZoneData();
 		
-		Bounds b = dataSet.getBoundsLatLon();
+		Bounds b = Main.main.ds.getBoundsLatLon();
 		if (b == null)
 			return zd;
@@ -234,7 +232,7 @@
 	 */
 	@Override
-	public void init(DataSet dataSet) {
+	public void init() {
 		if (zone == 0) {
-			ZoneData zd = autoDetect(dataSet);
+			ZoneData zd = autoDetect();
 			zone = zd.zone;
 			hemisphere = zd.hemisphere;
@@ -274,6 +272,5 @@
 			public void actionPerformed(ActionEvent e) {
 				if (Main.main.getMapFrame() != null) {
-					DataSet ds = Main.main.getMapFrame().mapView.getActiveDataSet();
-					ZoneData zd = autoDetect(ds);
+					ZoneData zd = autoDetect();
 					if (zd.zone == 0)
 						JOptionPane.showMessageDialog(Main.main, "Autodetection failed. Maybe the data set contain too few information.");
Index: /src/org/openstreetmap/josm/gui/ImageProvider.java
===================================================================
--- /src/org/openstreetmap/josm/gui/ImageProvider.java	(revision 21)
+++ /src/org/openstreetmap/josm/gui/ImageProvider.java	(revision 22)
@@ -25,5 +25,5 @@
 	 * @author imi
 	 */
-	public enum OverlayPosition {NORTHWEST, NORTHEAST, SOUTHWEST, SOUTHEAST};
+	public enum OverlayPosition {NORTHWEST, NORTHEAST, SOUTHWEST, SOUTHEAST}
 	
 	/**
Index: /src/org/openstreetmap/josm/gui/MapStatus.java
===================================================================
--- /src/org/openstreetmap/josm/gui/MapStatus.java	(revision 21)
+++ /src/org/openstreetmap/josm/gui/MapStatus.java	(revision 22)
@@ -47,9 +47,9 @@
 	 * The position of the mouse cursor.
 	 */
-	private JTextField positionText = new JTextField("-000.00000000000000 -000.00000000000000".length());
+	JTextField positionText = new JTextField("-000.00000000000000 -000.00000000000000".length());
 	/**
 	 * The field holding the name of the object under the mouse.
 	 */
-	private JTextField nameText = new JTextField(30);
+	JTextField nameText = new JTextField(30);
 
 	/**
@@ -147,5 +147,5 @@
 	 * The last sent mouse movement event.
 	 */
-	private MouseState mouseState = new MouseState();
+	MouseState mouseState = new MouseState();
 	
 	/**
Index: /src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- /src/org/openstreetmap/josm/gui/MapView.java	(revision 21)
+++ /src/org/openstreetmap/josm/gui/MapView.java	(revision 22)
@@ -32,6 +32,4 @@
  * provide the MapMode's enough capabilities to operate. 
  * 
- * MapView holds the map data, organize it, convert it, provide access to it.
- * 
  * MapView hold meta-data about the data set currently displayed, as scale level,
  * center point viewed, what scrolling mode or editing mode is selected or with
@@ -87,7 +85,4 @@
 	 */
 	public MapView(Layer layer) {
-		if (layer.dataSet == null)
-			throw new IllegalArgumentException("Initial layer must have a dataset.");
-
 		addComponentListener(new ComponentAdapter(){
 			@Override
@@ -118,5 +113,5 @@
 			// initialize the projection if it was the first layer
 			if (layers.size() == 1)
-				Main.pref.getProjection().init(layer.dataSet);
+				Main.pref.getProjection().init();
 			
 			// initialize the dataset in the new layer
@@ -231,9 +226,6 @@
 		OsmPrimitive minPrimitive = null;
 
-		// calculate the object based on the current active dataset.
-		DataSet ds = getActiveDataSet();
-		
 		// nodes
-		for (Node n : ds.nodes) {
+		for (Node n : Main.main.ds.nodes) {
 			Point sp = getScreenPoint(n.coor);
 			double dist = p.distanceSq(sp);
@@ -247,5 +239,5 @@
 		
 		// pending line segments
-		for (LineSegment ls : ds.pendingLineSegments()) {
+		for (LineSegment ls : Main.main.ds.pendingLineSegments()) {
 			Point A = getScreenPoint(ls.getStart().coor);
 			Point B = getScreenPoint(ls.getEnd().coor);
@@ -262,5 +254,5 @@
 		// tracks & line segments
 		minDistanceSq = Double.MAX_VALUE;
-		for (Track t : ds.tracks()) {
+		for (Track t : Main.main.ds.tracks()) {
 			for (LineSegment ls : t.segments()) {
 				Point A = getScreenPoint(ls.getStart().coor);
@@ -375,19 +367,4 @@
 	
 	/**
-	 * Return the dataSet for the current selected layer. If the active layer
-	 * does not have a dataset, return the DataSet from the next layer a.s.o.
-	 *  
-	 * @return The DataSet of the current active layer.
-	 */
-	public DataSet getActiveDataSet() {
-		if (activeLayer.dataSet != null)
-			return activeLayer.dataSet;
-		for (Layer l : layers)
-			if (l.dataSet != null)
-				return l.dataSet;
-		throw new IllegalStateException("No dataset found.");
-	}
-
-	/**
 	 * Change to the new projection. Recalculate the dataset and zoom, if autoZoom
 	 * is active.
@@ -422,5 +399,5 @@
 				h = 20;
 			
-			Bounds bounds = getActiveDataSet().getBoundsXY();
+			Bounds bounds = Main.main.ds.getBoundsXY();
 			
 			boolean oldAutoScale = autoScale;
Index: /src/org/openstreetmap/josm/gui/PreferenceDialog.java
===================================================================
--- /src/org/openstreetmap/josm/gui/PreferenceDialog.java	(revision 21)
+++ /src/org/openstreetmap/josm/gui/PreferenceDialog.java	(revision 22)
@@ -91,13 +91,13 @@
 	 * Indicate, that the application has to be restarted for the settings to take effect.
 	 */
-	private boolean requiresRestart = false;
+	boolean requiresRestart = false;
 	/**
 	 * ComboBox with all look and feels.
 	 */
-	private JComboBox lafCombo = new JComboBox(UIManager.getInstalledLookAndFeels());
+	JComboBox lafCombo = new JComboBox(UIManager.getInstalledLookAndFeels());
 	/**
 	 * Combobox with all projections available
 	 */
-	private JComboBox projectionCombo = new JComboBox(Preferences.allProjections.clone());
+	JComboBox projectionCombo = new JComboBox(Preferences.allProjections.clone());
 	/**
 	 * The main tab panel.
@@ -108,25 +108,25 @@
 	 * Editfield for the Base url to the REST API from OSM. 
 	 */
-	private JTextField osmDataServer = new JTextField(20);
+	JTextField osmDataServer = new JTextField(20);
 	/**
 	 * Editfield for the username to the OSM account.
 	 */
-	private JTextField osmDataUsername = new JTextField(20);
+	JTextField osmDataUsername = new JTextField(20);
 	/**
 	 * Passwordfield for the userpassword of the REST API.
 	 */
-	private JPasswordField osmDataPassword = new JPasswordField(20);
+	JPasswordField osmDataPassword = new JPasswordField(20);
 	/**
 	 * The checkbox stating whether nodes should be merged together.
 	 */
-	private JCheckBox drawRawGpsLines = new JCheckBox("Draw lines between raw gps points.");
+	JCheckBox drawRawGpsLines = new JCheckBox("Draw lines between raw gps points.");
 	/**
 	 * The checkbox stating whether raw gps lines should be forced.
 	 */
-	private JCheckBox forceRawGpsLines = new JCheckBox("Force lines if no line segments imported.");
+	JCheckBox forceRawGpsLines = new JCheckBox("Force lines if no line segments imported.");
 	/**
 	 * The checkbox stating whether nodes should be merged together.
 	 */
-	private JCheckBox mergeNodes = new JCheckBox("Merge nodes with equal latitude/longitude.");
+	JCheckBox mergeNodes = new JCheckBox("Merge nodes with equal latitude/longitude.");
 
 	/**
Index: /src/org/openstreetmap/josm/gui/SelectionManager.java
===================================================================
--- /src/org/openstreetmap/josm/gui/SelectionManager.java	(revision 21)
+++ /src/org/openstreetmap/josm/gui/SelectionManager.java	(revision 22)
@@ -15,5 +15,5 @@
 import java.util.LinkedList;
 
-import org.openstreetmap.josm.command.DataSet;
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.LineSegment;
 import org.openstreetmap.josm.data.osm.Node;
@@ -272,6 +272,5 @@
 		} else {
 			// nodes
-			DataSet ds = mv.getActiveDataSet();
-			for (Node n : ds.nodes) {
+			for (Node n : Main.main.ds.nodes) {
 				if (r.contains(mv.getScreenPoint(n.coor)))
 					selection.add(n);
@@ -279,10 +278,10 @@
 			
 			// pending line segments
-			for (LineSegment ls : ds.pendingLineSegments())
+			for (LineSegment ls : Main.main.ds.pendingLineSegments())
 				if (rectangleContainLineSegment(r, alt, ls))
 					selection.add(ls);
 
 			// tracks
-			for (Track t : ds.tracks()) {
+			for (Track t : Main.main.ds.tracks()) {
 				boolean wholeTrackSelected = !t.segments().isEmpty();
 				for (LineSegment ls : t.segments())
Index: /src/org/openstreetmap/josm/gui/dialogs/LayerList.java
===================================================================
--- /src/org/openstreetmap/josm/gui/dialogs/LayerList.java	(revision 21)
+++ /src/org/openstreetmap/josm/gui/dialogs/LayerList.java	(revision 22)
@@ -8,4 +8,5 @@
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
+import java.io.IOException;
 import java.util.Collection;
 
@@ -16,4 +17,5 @@
 import javax.swing.JLabel;
 import javax.swing.JList;
+import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
@@ -30,4 +32,5 @@
 import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
 import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.io.OsmWriter;
 
 /**
@@ -42,13 +45,13 @@
 	 * The data model for the list component.
 	 */
-	private DefaultListModel model = new DefaultListModel();
+	DefaultListModel model = new DefaultListModel();
 	/**
 	 * The list component holding all layers.
 	 */
-	private JList layers = new JList(model);
+	JList layers = new JList(model);
 	/**
 	 * The invisible icon blended over invisible layers.
 	 */
-	private static final Icon invisible = ImageProvider.get("layer", "invisible");
+	static final Icon invisible = ImageProvider.get("layer", "invisible");
 
 	/**
@@ -69,5 +72,9 @@
 	 */
 	private JButton deleteButton = new JButton(ImageProvider.get("dialogs", "delete"));
-	
+	/**
+	 * Button for connecting disconnecting to the server.
+	 */
+	private JButton uploadButton = new JButton(ImageProvider.get("dialogs", "condiscon"));
+
 	/**
 	 * Create an layerlist and attach it to the given mapView.
@@ -89,5 +96,5 @@
 					icon = ImageProvider.overlay(icon, invisible, ImageProvider.OverlayPosition.SOUTHEAST);
 				label.setIcon(icon);
-				
+
 				DataSet ds = layer.dataSet;
 				if (ds != null) {
@@ -100,5 +107,5 @@
 
 		final MapView mapView = mapFrame.mapView;
-		
+
 		Collection<Layer> data = mapView.getAllLayers();
 		for (Layer l : data)
@@ -115,5 +122,5 @@
 		});
 		mapView.addLayerChangeListener(this);
-		
+
 		// Buttons
 		JPanel buttonPanel = new JPanel(new GridLayout(1, 5));
@@ -173,16 +180,30 @@
 		mergeButton.setToolTipText("Merge the selected layer into the layer directly below.");
 		mergeButton.addActionListener(new ActionListener(){
-				public void actionPerformed(ActionEvent e) {
-					Layer lFrom = (Layer)layers.getSelectedValue();
-					DataSet dsFrom = lFrom.dataSet;
-					Layer lTo = (Layer)model.get(layers.getSelectedIndex()+1);
-					DataSet dsTo = lTo.dataSet;
-					dsTo.mergeFrom(dsFrom, Main.pref.mergeNodes);
-					layers.setSelectedValue(lTo, true);
-					mapView.removeLayer(lFrom);
+			public void actionPerformed(ActionEvent e) {
+				Layer lFrom = (Layer)layers.getSelectedValue();
+				DataSet dsFrom = lFrom.dataSet;
+				Layer lTo = (Layer)model.get(layers.getSelectedIndex()+1);
+				DataSet dsTo = lTo.dataSet;
+				dsTo.mergeFrom(dsFrom, Main.pref.mergeNodes);
+				layers.setSelectedValue(lTo, true);
+				mapView.removeLayer(lFrom);
+			}
+		});		
+		buttonPanel.add(mergeButton);
+
+		uploadButton.setToolTipText("Upload changes to the server.");
+		uploadButton.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				OsmWriter con = new OsmWriter(Main.pref.osmDataServer, Main.main.commands);
+				try {
+					con.output();
+				} catch (IOException x) {
+					x.printStackTrace();
+					JOptionPane.showMessageDialog(Main.main, "Not all changes could be uploaded.");
 				}
-			});		
-		buttonPanel.add(mergeButton);
-
+			}
+		});
+		buttonPanel.add(uploadButton);
+		
 		add(buttonPanel, BorderLayout.SOUTH);
 		
@@ -193,5 +214,5 @@
 	 * Updates the state of the Buttons.
 	 */
-	private void updateButtonEnabled() {
+	void updateButtonEnabled() {
 		int sel = layers.getSelectedIndex();
 		Layer l = (Layer)layers.getSelectedValue();
Index: /src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java
===================================================================
--- /src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java	(revision 21)
+++ /src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java	(revision 22)
@@ -17,5 +17,4 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.DataSet;
 import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -23,7 +22,4 @@
 import org.openstreetmap.josm.gui.ImageProvider;
 import org.openstreetmap.josm.gui.MapFrame;
-import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
-import org.openstreetmap.josm.gui.layer.Layer;
 
 /**
@@ -34,5 +30,5 @@
  * @author imi
  */
-public class SelectionListDialog extends ToggleDialog implements SelectionChangedListener, LayerChangeListener {
+public class SelectionListDialog extends ToggleDialog implements SelectionChangedListener {
 
 	/**
@@ -44,8 +40,4 @@
 	 */
 	private JList displaylist = new JList(list);
-	/**
-	 * The dataset, all selections are part of.
-	 */
-	private final MapView mapView;
 	
 	/**
@@ -55,5 +47,4 @@
 	public SelectionListDialog(MapFrame mapFrame) {
 		super(mapFrame, "Current Selection", "Selection List", "selectionlist", KeyEvent.VK_E, "Open a selection list window.");
-		this.mapView = mapFrame.mapView;
 		setLayout(new BorderLayout());
 		setSize(300,400);
@@ -84,5 +75,5 @@
 		getContentPane().add(button, BorderLayout.SOUTH);
 
-		selectionChanged(mapView.getActiveDataSet().getSelected());
+		selectionChanged(Main.main.ds.getSelected());
 	}
 
@@ -90,10 +81,8 @@
 	public void setVisible(boolean b) {
 		if (b) {
-			mapView.addLayerChangeListener(this);
-			mapView.getActiveDataSet().addSelectionChangedListener(this);
-			selectionChanged(mapView.getActiveDataSet().getSelected());
+			Main.main.ds.addSelectionChangedListener(this);
+			selectionChanged(Main.main.ds.getSelected());
 		} else {
-			mapView.removeLayerChangeListener(this);
-			mapView.getActiveDataSet().removeSelectionChangedListener(this);
+			Main.main.ds.removeSelectionChangedListener(this);
 		}
 		super.setVisible(b);
@@ -118,28 +107,9 @@
 	 */
 	public void updateMap() {
-		DataSet ds = mapView.getActiveDataSet();
-		ds.clearSelection();
+		Main.main.ds.clearSelection();
 		for (int i = 0; i < list.getSize(); ++i)
 			if (displaylist.isSelectedIndex(i))
-				((OsmPrimitive)list.get(i)).setSelected(true, ds);
+				((OsmPrimitive)list.get(i)).setSelected(true);
 		Main.main.getMapFrame().repaint();
 	}
-
-	public void activeLayerChange(Layer oldLayer, Layer newLayer) {
-		DataSet ds = oldLayer.dataSet;
-		if (ds != null)
-			ds.removeSelectionChangedListener(this);
-		ds = newLayer.dataSet;
-		if (ds != null)
-			ds.addSelectionChangedListener(this);
-	}
-
-	/**
-	 * Does nothing. Only to satisfy LayerChangeListener
-	 */
-	public void layerAdded(Layer newLayer) {}
-	/**
-	 * Does nothing. Only to satisfy LayerChangeListener
-	 */
-	public void layerRemoved(Layer oldLayer) {}
 }
Index: /src/org/openstreetmap/josm/gui/layer/Layer.java
===================================================================
--- /src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 21)
+++ /src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 22)
@@ -5,10 +5,5 @@
 import javax.swing.Icon;
 
-import org.openstreetmap.josm.command.DataSet;
-import org.openstreetmap.josm.data.osm.LineSegment;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.Track;
 import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.gui.engine.Engine;
 
 /**
@@ -34,27 +29,13 @@
 	public boolean visible = true;
 	/**
-	 * The dataSet this layer operates on, if any. Not all layer may have a
-	 * dataset associated.
-	 */
-	public final DataSet dataSet;
-	/**
 	 * The name of this layer.
 	 */
 	public final String name;
-	/**
-	 * The engine used to draw the data.
-	 */
-	private final Engine engine;
 	
 	/**
 	 * Create the layer and fill in the necessary components.
-	 * @param dataSet The DataSet, this layer operates on. Can be <code>null</code>.
 	 */
-	public Layer(DataSet dataSet, Engine engine, String name) {
-		if (engine == null || name == null)
-			throw new NullPointerException();
-		this.dataSet = dataSet;
+	public Layer(String name) {
 		this.name = name;
-		this.engine = engine;
 	}
 
@@ -63,15 +44,5 @@
 	 * @param mv The object that can translate GeoPoints to screen coordinates.
 	 */
-	public final void paint(Graphics g, MapView mv) {
-		engine.init(g, mv);
-
-		for (Track t : dataSet.tracks())
-			engine.drawTrack(t);
-		for (LineSegment ls : dataSet.pendingLineSegments())
-			engine.drawPendingLineSegment(ls);
-		for (Node n : dataSet.nodes)
-			engine.drawNode(n);
-	}
-
+	abstract public void paint(Graphics g, MapView mv);
 	/**
 	 * Return a representative small image for this layer. The image must not 
Index: /src/org/openstreetmap/josm/gui/layer/LayerFactory.java
===================================================================
--- /src/org/openstreetmap/josm/gui/layer/LayerFactory.java	(revision 21)
+++ /src/org/openstreetmap/josm/gui/layer/LayerFactory.java	(revision 22)
@@ -19,5 +19,5 @@
 	 */
 	public static Layer create(DataSet dataSet, String name, boolean rawGps) {
-		Layer layer = rawGps ? new RawGpsDataLayer(dataSet, name) : new OsmDataLayer(dataSet, name);
+		Layer layer = rawGps ? new RawGpsDataLayer(dataSet, name) : new OsmDataLayer(name);
 		return layer;
 	}
Index: /src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- /src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 21)
+++ /src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 22)
@@ -1,9 +1,21 @@
 package org.openstreetmap.josm.gui.layer;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.util.Collection;
+import java.util.HashSet;
 
 import javax.swing.Icon;
 
-import org.openstreetmap.josm.command.DataSet;
+import org.openstreetmap.josm.Main;
+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.Visitor;
 import org.openstreetmap.josm.gui.ImageProvider;
-import org.openstreetmap.josm.gui.engine.SimpleEngine;
+import org.openstreetmap.josm.gui.MapView;
 
 /**
@@ -14,13 +26,30 @@
  * @author imi
  */
-public class OsmDataLayer extends Layer {
+public class OsmDataLayer extends Layer implements Visitor {
 
 	private static Icon icon;
+	private final static Color darkblue = new Color(0,0,128);
+	private final static Color darkgreen = new Color(0,128,0);
+
+	/**
+	 * The data behind this layer. A list of primitives which are also in Main.main.ds.
+	 */
+	private final Collection<OsmPrimitive> data;
+
+	/**
+	 * The mapview we are currently drawing on.
+	 */
+	private MapView mv;
+	/**
+	 * The graphic environment we are drawing with.
+	 */
+	private Graphics g;
 	
 	/**
 	 * Construct a OsmDataLayer.
 	 */
-	protected OsmDataLayer(DataSet dataSet, String name) {
-		super(dataSet, new SimpleEngine(), name);
+	protected OsmDataLayer(Collection<OsmPrimitive> data, String name) {
+		super(name);
+		this.data = data;
 	}
 
@@ -40,3 +69,88 @@
 		return true;
 	}
+
+	@Override
+	public void paint(Graphics g, MapView mv) {
+		this.mv = mv;
+		this.g = g;
+		for (OsmPrimitive osm : data)
+			osm.visit(this);
+	}
+
+	/**
+	 * Draw a small rectangle. 
+	 * 
+	 * - White if selected (as always)
+	 * - Yellow, if not used by any tracks or areas.
+	 * - Green, if only used by pending line segments.
+	 * - Darkblue, if used in tracks but are only as inbound node. Inbound are
+	 *   all nodes, that have only line segments of the same track and
+	 *   at least two different line segments attached.
+	 * - Red otherwise (means, this is a dead end or is part of more than
+	 *   one track).
+	 * 
+	 * @param n The node to draw.
+	 */
+	public void visit(Node n) {
+		if (n.isSelected()) {
+			drawNode(n, Color.WHITE); // selected
+			return;
+		}
+
+		Collection<LineSegment> lineSegments = n.getParentSegments();
+		if (lineSegments.isEmpty()) {
+			drawNode(n, Color.YELLOW); // single waypoint only
+			return;
+		}
+		
+		HashSet<Track> tracks = new HashSet<Track>();
+		for (LineSegment ls : lineSegments)
+			tracks.addAll(ls.getParents());
+		if (tracks.isEmpty()) {
+			drawNode(n, Color.GREEN); // pending line
+			return;
+		}
+		if (tracks.size() > 1) {
+			drawNode(n, Color.RED); // more than one track
+			return;
+		}
+		int segmentUsed = 0;
+		for (LineSegment ls : tracks.iterator().next().segments())
+			if (n == ls.getStart() || n == ls.getEnd())
+				++segmentUsed;
+		drawNode(n, segmentUsed > 1 ? darkblue : Color.RED);
+	}
+
+	public void visit(LineSegment ls) {
+		g.setColor(ls.isSelected() ? Color.WHITE : darkblue);
+		if (Main.main.ds.pendingLineSegments().contains(ls))
+			g.setColor(darkgreen);
+		Point p1 = mv.getScreenPoint(ls.getStart().coor);
+		Point p2 = mv.getScreenPoint(ls.getEnd().coor);
+		g.drawLine(p1.x, p1.y, p2.x, p2.y);
+	}
+
+	/**
+	 * Draw a darkblue line for all line segments.
+	 * @param t The track to draw.
+	 */
+	public void visit(Track t) {
+		for (LineSegment ls : t.segments())
+			ls.visit(this);
+	}
+
+	public void visit(Key k) {
+	}
+	
+	/**
+	 * Draw the node as small rectangle with the given color.
+	 *
+	 * @param n		The node to draw.
+	 * @param color The color of the node.
+	 */
+	private void drawNode(Node n, Color color) {
+		Point p = mv.getScreenPoint(n.coor);
+		g.setColor(color);
+		g.drawRect(p.x-1, p.y-1, 2, 2);
+	}
 }
Index: /src/org/openstreetmap/josm/gui/layer/RawGpsDataLayer.java
===================================================================
--- /src/org/openstreetmap/josm/gui/layer/RawGpsDataLayer.java	(revision 21)
+++ /src/org/openstreetmap/josm/gui/layer/RawGpsDataLayer.java	(revision 22)
@@ -5,5 +5,4 @@
 import org.openstreetmap.josm.command.DataSet;
 import org.openstreetmap.josm.gui.ImageProvider;
-import org.openstreetmap.josm.gui.engine.RawGpsEngine;
 
 /**
@@ -18,5 +17,5 @@
 
 	protected RawGpsDataLayer(DataSet dataSet, String name) {
-		super(dataSet, new RawGpsEngine(), name);
+		super(name);
 	}
 
Index: /src/org/openstreetmap/josm/io/GpxWriter.java
===================================================================
--- /src/org/openstreetmap/josm/io/GpxWriter.java	(revision 21)
+++ /src/org/openstreetmap/josm/io/GpxWriter.java	(revision 22)
@@ -14,5 +14,5 @@
 import org.jdom.output.Format;
 import org.jdom.output.XMLOutputter;
-import org.openstreetmap.josm.command.DataSet;
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.Key;
 import org.openstreetmap.josm.data.osm.LineSegment;
@@ -47,8 +47,4 @@
 	 */
 	private Writer out;
-	/**
-	 * The DataSet this outputter operates on.
-	 */
-	private final DataSet ds;
 	
 	/**
@@ -57,8 +53,6 @@
 	 *
 	 * @param out The Writer to store the result data in.
-	 * @param ds The dataset to store.
-	 */
-	public GpxWriter(Writer out, DataSet ds) {
-		this.ds = ds;
+	 */
+	public GpxWriter(Writer out) {
 		this.out = out;
 	}
@@ -88,8 +82,8 @@
 		e.setAttribute("creator", "JOSM Beta");
 		// for getting all unreferenced waypoints in the wpt-list
-		LinkedList<Node> nodes = new LinkedList<Node>(ds.nodes);
+		LinkedList<Node> nodes = new LinkedList<Node>(Main.main.ds.nodes);
 
 		// tracks
-		for (Track t : ds.tracks()) {
+		for (Track t : Main.main.ds.tracks()) {
 			Element tElem = new Element("trk", GPX);
 			if (t.keys != null) {
Index: /src/org/openstreetmap/josm/io/OsmConnection.java
===================================================================
--- /src/org/openstreetmap/josm/io/OsmConnection.java	(revision 22)
+++ /src/org/openstreetmap/josm/io/OsmConnection.java	(revision 22)
@@ -0,0 +1,98 @@
+package org.openstreetmap.josm.io;
+
+import java.awt.Font;
+import java.awt.GridBagLayout;
+import java.net.Authenticator;
+import java.net.HttpURLConnection;
+import java.net.PasswordAuthentication;
+
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.GBC;
+
+/**
+ * Base class that handles common things like authentication for the reader and writer
+ * to the osm server.
+ * 
+ * @author imi
+ */
+public class OsmConnection {
+	
+
+
+	/**
+	 * The authentication class handling the login requests.
+	 */
+	private static class OsmAuth extends Authenticator {
+		/**
+		 * Set to true, when the autenticator tried the password once.
+		 */
+		boolean passwordtried = false;
+		/**
+		 * Whether the user cancelled the password dialog
+		 */
+		boolean cancelled = false;
+
+		@Override
+		protected PasswordAuthentication getPasswordAuthentication() {
+			String username = Main.pref.osmDataUsername;
+			String password = Main.pref.osmDataPassword;
+			if (passwordtried || "".equals(username) || password == null || "".equals(password)) {
+				JPanel p = new JPanel(new GridBagLayout());
+				p.add(new JLabel("Username"), GBC.std().insets(0,0,10,0));
+				JTextField usernameField = new JTextField("".equals(username) ? "" : username, 20);
+				p.add(usernameField, GBC.eol());
+				p.add(new JLabel("Password"), GBC.std().insets(0,0,10,0));
+				JPasswordField passwordField = new JPasswordField(password == null ? "" : password, 20);
+				p.add(passwordField, GBC.eol());
+				JLabel warning = new JLabel("Warning: The password is transferred unencrypted.");
+				warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
+				p.add(warning, GBC.eol());
+				int choice = JOptionPane.showConfirmDialog(Main.main, p, "Enter Password", JOptionPane.OK_CANCEL_OPTION);
+				if (choice == JOptionPane.CANCEL_OPTION) {
+					cancelled = true;
+					return null;
+				}
+				username = usernameField.getText();
+				password = String.valueOf(passwordField.getPassword());
+				if ("".equals(username))
+					return null;
+			}
+			passwordtried = true;
+			return new PasswordAuthentication(username, password.toCharArray());
+		}
+	}
+
+	/**
+	 * The authenticator.
+	 */
+	private static OsmAuth authentication;
+	
+	/**
+	 * Initialize the http defaults and the authenticator.
+	 */
+	static {
+		HttpURLConnection.setFollowRedirects(true);
+		Authenticator.setDefault(authentication = new OsmAuth());
+	}
+	
+	/**
+	 * Must be called before each connection attemp to initialize the authentication.
+	 */
+	protected final void initAuthentication() {
+		authentication.cancelled = false;
+		authentication.passwordtried = false;
+	}
+	
+	/**
+	 * @return Whether the connection was cancelled.
+	 */
+	protected final boolean isCancelled() {
+		return authentication.cancelled;
+	}
+}
Index: /src/org/openstreetmap/josm/io/OsmReader.java
===================================================================
--- /src/org/openstreetmap/josm/io/OsmReader.java	(revision 21)
+++ /src/org/openstreetmap/josm/io/OsmReader.java	(revision 22)
@@ -1,23 +1,11 @@
 package org.openstreetmap.josm.io;
 
-import java.awt.Font;
-import java.awt.GridBagLayout;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
-import java.net.Authenticator;
 import java.net.HttpURLConnection;
-import java.net.PasswordAuthentication;
 import java.net.URL;
 
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JPasswordField;
-import javax.swing.JTextField;
-
-import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.command.DataSet;
-import org.openstreetmap.josm.gui.GBC;
 
 /**
@@ -26,5 +14,5 @@
  * @author imi
  */
-public class OsmReader implements DataReader {
+public class OsmReader extends OsmConnection implements DataReader {
 
 	/**
@@ -36,13 +24,5 @@
 	 */
 	private boolean rawGps;
-	/**
-	 * Whether the user cancelled the password dialog
-	 */
-	private boolean cancelled = false;
-	/**
-	 * Set to true, when the autenticator tried the password once.
-	 */
-	private boolean passwordtried = false;
-
+	
 	/**
 	 * Construct the reader and store the information for attaching
@@ -52,40 +32,8 @@
 		this.rawGps = rawGps;
 		urlStr = server.endsWith("/") ? server : server+"/";
-		urlStr += rawGps?"trackpoints" : "map";
-		urlStr += "?bbox="+lon1+","+lat1+","+lon2+","+lat2;
 		if (rawGps)
-			urlStr += "&page=";
-		
-		HttpURLConnection.setFollowRedirects(true);
-		Authenticator.setDefault(new Authenticator(){
-			@Override
-			protected PasswordAuthentication getPasswordAuthentication() {
-				String username = Main.pref.osmDataUsername;
-				String password = Main.pref.osmDataPassword;
-				if (passwordtried || "".equals(username) || password == null || "".equals(password)) {
-					JPanel p = new JPanel(new GridBagLayout());
-					p.add(new JLabel("Username"), GBC.std().insets(0,0,10,0));
-					JTextField usernameField = new JTextField("".equals(username) ? "" : username, 20);
-					p.add(usernameField, GBC.eol());
-					p.add(new JLabel("Password"), GBC.std().insets(0,0,10,0));
-					JPasswordField passwordField = new JPasswordField(password == null ? "" : password, 20);
-					p.add(passwordField, GBC.eol());
-					JLabel warning = new JLabel("Warning: The password is transferred unencrypted.");
-					warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
-					p.add(warning, GBC.eol());
-					int choice = JOptionPane.showConfirmDialog(Main.main, p, "Enter Password", JOptionPane.OK_CANCEL_OPTION);
-					if (choice == JOptionPane.CANCEL_OPTION) {
-						cancelled = true;
-						return null;
-					}
-					username = usernameField.getText();
-					password = String.valueOf(passwordField.getPassword());
-					if ("".equals(username))
-						return null;
-				}
-				passwordtried = true;
-				return new PasswordAuthentication(username, password.toCharArray());
-			}
-		});
+			urlStr += "trackpoints?bbox="+lat1+","+lon1+","+lat2+","+lon2+"&page=";
+		else
+			urlStr += "map?bbox="+lon1+","+lat1+","+lon2+","+lat2;
 	}
 
@@ -93,4 +41,5 @@
 	public DataSet parse() throws ParseException, ConnectionException {
 		Reader in;
+		initAuthentication();
 		try {
 			if (rawGps) {
@@ -98,7 +47,8 @@
 				for (int i = 0;;++i) {
 					URL url = new URL(urlStr+i);
+					System.out.println(url);
 					HttpURLConnection con = (HttpURLConnection)url.openConnection();
 					con.setConnectTimeout(20000);
-					if (con.getResponseCode() == 401 && cancelled)
+					if (con.getResponseCode() == 401 && isCancelled())
 						return null;
 					in = new InputStreamReader(con.getInputStream());
@@ -112,5 +62,5 @@
 			HttpURLConnection con = (HttpURLConnection)url.openConnection();
 			con.setConnectTimeout(20000);
-			if (con.getResponseCode() == 401 && cancelled)
+			if (con.getResponseCode() == 401 && isCancelled())
 				return null;
 			in = new InputStreamReader(con.getInputStream());
Index: /src/org/openstreetmap/josm/io/OsmWriter.java
===================================================================
--- /src/org/openstreetmap/josm/io/OsmWriter.java	(revision 22)
+++ /src/org/openstreetmap/josm/io/OsmWriter.java	(revision 22)
@@ -0,0 +1,49 @@
+package org.openstreetmap.josm.io;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+
+
+/**
+ * Send back the modified data to the osm server.
+ * @author imi
+ */
+public class OsmWriter extends OsmConnection {
+
+	/**
+	 * The server base url to handle the osm requests.
+	 */
+	private final String server;
+	/**
+	 * The commands that should be uploaded on the server.
+	 */
+	private final Collection<Command> commands;
+
+	public OsmWriter(String server, Collection<Command> commands) {
+		this.server = server;
+		this.commands = commands;
+	}
+	
+	/**
+	 * Upload the commands to the server.
+	 * @throws IOException
+	 */
+	public void output() throws IOException {
+		Collection<OsmPrimitive> added = new LinkedList<OsmPrimitive>();
+		Collection<OsmPrimitive> modified = new LinkedList<OsmPrimitive>();
+		Collection<OsmPrimitive> deleted = new LinkedList<OsmPrimitive>();
+		for (Command c : commands)
+			c.fillModifiedData(modified, deleted, added);
+		int answer = JOptionPane.showConfirmDialog(Main.main, "Send "+added.size()+" new, "
+				+modified.size()+" modified and "+deleted.size()+" deleted objects to server?");
+		if (answer != JOptionPane.YES_OPTION)
+			return;
+	}
+}
