Index: src/org/openstreetmap/josm/Main.java
===================================================================
--- src/org/openstreetmap/josm/Main.java	(revision 22)
+++ src/org/openstreetmap/josm/Main.java	(revision 23)
@@ -4,6 +4,4 @@
 import java.awt.BorderLayout;
 import java.awt.Container;
-import java.util.Collection;
-import java.util.LinkedList;
 
 import javax.swing.JFrame;
@@ -22,8 +20,7 @@
 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;
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.ImageProvider;
 import org.openstreetmap.josm.gui.MapFrame;
@@ -45,11 +42,4 @@
 	 */
 	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>();
 
 	/**
@@ -121,5 +111,5 @@
 		// creating toolbar
 		JToolBar toolBar = new JToolBar();
-		toolBar.setFloatable(true);
+		toolBar.setFloatable(false);
 		toolBar.add(openServerAction);
 		toolBar.add(openGpxAction);
Index: src/org/openstreetmap/josm/actions/OpenGpxAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/OpenGpxAction.java	(revision 22)
+++ src/org/openstreetmap/josm/actions/OpenGpxAction.java	(revision 23)
@@ -7,4 +7,5 @@
 import java.io.FileReader;
 import java.io.IOException;
+import java.util.Collection;
 
 import javax.swing.AbstractAction;
@@ -17,14 +18,17 @@
 import javax.swing.filechooser.FileFilter;
 
+import org.jdom.JDOMException;
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.DataSet;
+import org.openstreetmap.josm.data.GeoPoint;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.GBC;
 import org.openstreetmap.josm.gui.ImageProvider;
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.LayerFactory;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.layer.RawGpsDataLayer;
 import org.openstreetmap.josm.io.GpxReader;
-import org.openstreetmap.josm.io.DataReader.ConnectionException;
-import org.openstreetmap.josm.io.DataReader.ParseException;
+import org.openstreetmap.josm.io.RawGpsReader;
 
 /**
@@ -83,7 +87,13 @@
 		
 		try {
-			DataSet dataSet = new GpxReader(new FileReader(gpxFile), rawGps.isSelected()).parse();
-
-			Layer layer = LayerFactory.create(dataSet, gpxFile.getName(), rawGps.isSelected());
+			Layer layer;
+			if (rawGps.isSelected()) {
+				Collection<Collection<GeoPoint>> data = new RawGpsReader(new FileReader(gpxFile)).parse();
+				layer = new RawGpsDataLayer(data, gpxFile.getName());
+			} else {
+				DataSet dataSet = new GpxReader(new FileReader(gpxFile)).parse();
+				Collection<OsmPrimitive> l = Main.main.ds.mergeFrom(dataSet);
+				layer = new OsmDataLayer(l, gpxFile.getName());
+			}
 			
 			if (Main.main.getMapFrame() == null || !newLayer.isSelected())
@@ -92,5 +102,5 @@
 				Main.main.getMapFrame().mapView.addLayer(layer);
 			
-		} catch (ParseException x) {
+		} catch (JDOMException x) {
 			x.printStackTrace();
 			JOptionPane.showMessageDialog(Main.main, x.getMessage());
@@ -98,7 +108,4 @@
 			x.printStackTrace();
 			JOptionPane.showMessageDialog(Main.main, "Could not read '"+gpxFile.getName()+"'\n"+x.getMessage());
-		} catch (ConnectionException x) {
-			x.printStackTrace();
-			JOptionPane.showMessageDialog(Main.main, x.getMessage());
 		}
 	}
Index: src/org/openstreetmap/josm/actions/OpenOsmServerAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/OpenOsmServerAction.java	(revision 22)
+++ src/org/openstreetmap/josm/actions/OpenOsmServerAction.java	(revision 23)
@@ -6,4 +6,6 @@
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
+import java.io.IOException;
+import java.util.Collection;
 
 import javax.swing.AbstractAction;
@@ -19,7 +21,9 @@
 import javax.swing.event.ListSelectionListener;
 
+import org.jdom.JDOMException;
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.DataSet;
 import org.openstreetmap.josm.data.GeoPoint;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.BookmarkList;
 import org.openstreetmap.josm.gui.GBC;
@@ -29,8 +33,7 @@
 import org.openstreetmap.josm.gui.BookmarkList.Bookmark;
 import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.LayerFactory;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.layer.RawGpsDataLayer;
 import org.openstreetmap.josm.io.OsmReader;
-import org.openstreetmap.josm.io.DataReader.ConnectionException;
-import org.openstreetmap.josm.io.DataReader.ParseException;
 
 /**
@@ -82,5 +85,5 @@
 			for (JTextField f : latlon)
 				f.setCaretPosition(0);
-			rawGps.setSelected(!mv.getActiveLayer().isEditable());
+			rawGps.setSelected(mv.getActiveLayer() instanceof RawGpsDataLayer);
 		}
 
@@ -145,16 +148,22 @@
 		}
 		OsmReader osmReader = new OsmReader(Main.pref.osmDataServer,
-				rawGps.isSelected(), b.latlon[0], b.latlon[1], b.latlon[2], b.latlon[3]);
+				b.latlon[0], b.latlon[1], b.latlon[2], b.latlon[3]);
 		try {
-			DataSet dataSet = osmReader.parse();
-			if (dataSet == null)
-				return; // user cancelled download
-			if (dataSet.nodes.isEmpty())
-				JOptionPane.showMessageDialog(Main.main, "No data imported.");
-
 			String name = latlon[0].getText()+" "+latlon[1].getText()+" x "+
 					latlon[2].getText()+" "+latlon[3].getText();
 			
-			Layer layer = LayerFactory.create(dataSet, name, rawGps.isSelected());
+			Layer layer;
+			if (rawGps.isSelected()) {
+				layer = new RawGpsDataLayer(osmReader.parseRawGps(), name);
+			} else {
+				DataSet dataSet = osmReader.parseOsm();
+				if (dataSet == null)
+					return; // user cancelled download
+				if (dataSet.nodes.isEmpty())
+					JOptionPane.showMessageDialog(Main.main, "No data imported.");
+				
+				Collection<OsmPrimitive> data = Main.main.ds.mergeFrom(dataSet);
+				layer = new OsmDataLayer(data, name);
+			}
 
 			if (Main.main.getMapFrame() == null)
@@ -162,8 +171,8 @@
 			else
 				Main.main.getMapFrame().mapView.addLayer(layer);
-		} catch (ParseException x) {
+		} catch (JDOMException x) {
 			x.printStackTrace();
 			JOptionPane.showMessageDialog(Main.main, x.getMessage());
-		} catch (ConnectionException x) {
+		} catch (IOException x) {
 			x.printStackTrace();
 			JOptionPane.showMessageDialog(Main.main, x.getMessage());
Index: src/org/openstreetmap/josm/actions/mapmode/AddLineSegmentAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/AddLineSegmentAction.java	(revision 22)
+++ src/org/openstreetmap/josm/actions/mapmode/AddLineSegmentAction.java	(revision 23)
@@ -12,5 +12,4 @@
 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.Node;
@@ -132,7 +131,7 @@
 		if (start != end) {
 			// try to find a line segment
-			for (Track t : Main.main.ds.tracks())
-				for (LineSegment ls : t.segments())
-					if (start == ls.getStart() && end == ls.getEnd()) {
+			for (Track t : Main.main.ds.tracks)
+				for (LineSegment ls : t.segments)
+					if (start == ls.start && end == ls.end) {
 						JOptionPane.showMessageDialog(Main.main, "There is already an line segment with the same direction between the selected nodes.");
 						return;
@@ -140,7 +139,5 @@
 
 			LineSegment ls = new LineSegment(start, end);
-			Command c = new AddCommand(ls);
-			c.executeCommand();
-			Main.main.commands.add(c);
+			mv.editLayer().add(new AddCommand(ls));
 		}
 		
@@ -167,8 +164,3 @@
 		hintDrawn = !hintDrawn;
 	}
-
-	@Override
-	protected boolean isEditMode() {
-		return true;
-	}
 }
Index: src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java	(revision 22)
+++ src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java	(revision 23)
@@ -4,7 +4,5 @@
 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;
@@ -51,14 +49,7 @@
 			Node node = new Node();
 			node.coor = mv.getPoint(e.getX(), e.getY(), true);
-			Command c = new AddCommand(node);
-			c.executeCommand();
-			Main.main.commands.add(c);
+			mv.editLayer().add(new AddCommand(node));
 			mv.repaint();
 		}
 	}
-
-	@Override
-	protected boolean isEditMode() {
-		return true;
-	}
 }
Index: src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java	(revision 22)
+++ src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java	(revision 23)
@@ -4,9 +4,9 @@
 import java.awt.event.KeyEvent;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.LinkedList;
 
 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;
@@ -98,20 +98,43 @@
 		for (OsmPrimitive osm : selection) {
 			if (osm instanceof Track)
-				lineSegments.addAll(((Track)osm).segments());
+				lineSegments.addAll(((Track)osm).segments);
 			else if (osm instanceof LineSegment)
 				lineSegments.add((LineSegment)osm);
 		}
+		
+		// sort the line segments in best possible order. This is done by:
+		// 0  if no elements in list, quit
+		// 1  taking the first ls as pivot, remove it from list
+		// 2  searching for a connection at start or end of pivot
+		// 3  if found, attach it, remove it from list, goto 2
+		// 4  if not found, save the pivot-string and goto 0
+		LinkedList<LineSegment> sortedLineSegments = new LinkedList<LineSegment>();
+		while (!lineSegments.isEmpty()) {
+			LinkedList<LineSegment> pivotList = new LinkedList<LineSegment>();
+			pivotList.add(lineSegments.getFirst());
+			lineSegments.removeFirst();
+			for (boolean found = true; found;) {
+				found = false;
+				for (Iterator<LineSegment> it = lineSegments.iterator(); it.hasNext();) {
+					LineSegment ls = it.next();
+					if (ls.start == pivotList.getLast().end) {
+						pivotList.addLast(ls);
+						it.remove();
+						found = true;
+					} else if (ls.end == pivotList.getFirst().start) {
+						pivotList.addFirst(ls);
+						it.remove();
+						found = true;
+					}
+				}
+			}
+			sortedLineSegments.addAll(pivotList);
+		}
+		
 		Track t = new Track();
-		for (LineSegment ls : lineSegments)
+		for (LineSegment ls : sortedLineSegments)
 			t.add(ls);
-		Command c = new AddCommand(t);
-		c.executeCommand();
-		Main.main.commands.add(c);
+		mv.editLayer().add(new AddCommand(t));
 		Main.main.ds.clearSelection();
 	}
-
-	@Override
-	protected boolean isEditMode() {
-		return true;
-	}
 }
Index: src/org/openstreetmap/josm/actions/mapmode/CombineAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/CombineAction.java	(revision 22)
+++ src/org/openstreetmap/josm/actions/mapmode/CombineAction.java	(revision 23)
@@ -11,5 +11,4 @@
 import org.openstreetmap.josm.Main;
 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;
@@ -150,9 +149,6 @@
 		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);
-		}
+		else
+			mv.editLayer().add(new CombineCommand(first, second));
 		mv.repaint();
 	}
@@ -188,19 +184,14 @@
 		if (osm instanceof LineSegment) {
 			LineSegment ls = (LineSegment)osm;
-			Point start = mv.getScreenPoint(ls.getStart().coor);
-			Point end = mv.getScreenPoint(ls.getEnd().coor);
-			if (Main.main.ds.pendingLineSegments().contains(osm) && g.getColor() == Color.GRAY)
+			Point start = mv.getScreenPoint(ls.start.coor);
+			Point end = mv.getScreenPoint(ls.end.coor);
+			if (Main.main.ds.pendingLineSegments.contains(osm) && g.getColor() == Color.GRAY)
 				g.drawLine(start.x, start.y, end.x, end.y);
 			else
 				g.drawLine(start.x, start.y, end.x, end.y);
 		} else if (osm instanceof Track) {
-			for (LineSegment ls : ((Track)osm).segments())
+			for (LineSegment ls : ((Track)osm).segments)
 				draw(g, ls);
 		}
 	}
-
-	@Override
-	protected boolean isEditMode() {
-		return true;
-	}
 }
Index: src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 22)
+++ src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 23)
@@ -4,12 +4,13 @@
 import java.awt.event.MouseEvent;
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collection;
 import java.util.LinkedList;
-import java.util.Map;
 
 import javax.swing.JOptionPane;
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.osm.Key;
+import org.openstreetmap.josm.command.CombineAndDeleteCommand;
+import org.openstreetmap.josm.command.DeleteCommand;
+import org.openstreetmap.josm.command.CombineAndDeleteCommand.LineSegmentCombineEntry;
 import org.openstreetmap.josm.data.osm.LineSegment;
 import org.openstreetmap.josm.data.osm.Node;
@@ -133,10 +134,10 @@
 		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.getStart() == osm || ls.getEnd() == osm)
+			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.pendingLineSegments())
-				if (ls.getStart() == osm || ls.getEnd() == osm)
+			for (LineSegment ls : Main.main.ds.pendingLineSegments)
+				if (ls.start == osm || ls.end == osm)
 					lineSegmentsToDelete.add(ls);
 				
@@ -144,6 +145,6 @@
 			LineSegment lineSegment = (LineSegment)osm;
 			lineSegmentsToDelete.add(lineSegment);
-			for (Track t : Main.main.ds.tracks())
-				for (LineSegment ls : t.segments())
+			for (Track t : Main.main.ds.tracks)
+				for (LineSegment ls : t.segments)
 					if (lineSegment == ls)
 						tracksToDelete.add(t);
@@ -154,28 +155,26 @@
 		ArrayList<Node> checkUnreferencing = new ArrayList<Node>();
 		for (Track t : tracksToDelete) {
-			for (LineSegment ls : t.segments()) {
-				checkUnreferencing.add(ls.getStart());
-				checkUnreferencing.add(ls.getEnd());
+			for (LineSegment ls : t.segments) {
+				checkUnreferencing.add(ls.start);
+				checkUnreferencing.add(ls.end);
 			}
 		}
 		for (LineSegment ls : lineSegmentsToDelete) {
-			checkUnreferencing.add(ls.getStart());
-			checkUnreferencing.add(ls.getEnd());
-		}
-		
-		// delete tracks and areas
-		for (Track t : tracksToDelete)
-			Main.main.ds.removeTrack(t);
-		for (LineSegment ls : lineSegmentsToDelete)
-			Main.main.ds.destroyPendingLineSegment(ls);
-
+			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) {
+		for (Node n : checkUnreferencing)
 			if (!isReferenced(n))
-				Main.main.ds.nodes.remove(n);
-		}
+				deleteData.add(n);
 		// now, all references are killed. Delete the node (if it was a node)
 		if (osm instanceof Node)
-			Main.main.ds.nodes.remove(osm);
+			deleteData.add(osm);
+		
+		mv.editLayer().add(new DeleteCommand(deleteData));
 	}
 
@@ -188,30 +187,11 @@
 	 */
 	private void delete(OsmPrimitive osm) {
-		if (osm instanceof Node) {
-			Node n = (Node)osm;
-			if (isReferenced(n)) {
-				String combined = combine(n);
-				if (combined != null) {
-					JOptionPane.showMessageDialog(Main.main, combined);
-					return;
-				}
-			}
-			// now, the node isn't referenced anymore, so delete it.
-			Main.main.ds.nodes.remove(n);
-		} else if (osm instanceof LineSegment) {
-			LinkedList<Track> tracksToDelete = new LinkedList<Track>();
-			for (Track t : Main.main.ds.tracks()) {
-				t.remove((LineSegment)osm);
-				if (t.segments().isEmpty())
-					tracksToDelete.add(t);
-			}
-			for (Track t : tracksToDelete)
-				Main.main.ds.removeTrack(t);
-			Main.main.ds.destroyPendingLineSegment((LineSegment)osm);
-		} else if (osm instanceof Track) {
-			Main.main.ds.removeTrack((Track)osm);
-			for (LineSegment ls : ((Track)osm).segments())
-				Main.main.ds.addPendingLineSegment(ls);
-		}
+		if (osm instanceof Node && isReferenced((Node)osm)) {
+			combineAndDelete((Node)osm);
+			return;
+		}
+		Collection<OsmPrimitive> c = new LinkedList<OsmPrimitive>();
+		c.add(osm);
+		mv.editLayer().add(new DeleteCommand(c));
 	}
 
@@ -223,10 +203,10 @@
 	 */
 	private boolean isReferenced(Node n) {
-		for (Track t : Main.main.ds.tracks())
-			for (LineSegment ls : t.segments())
-				if (ls.getStart() == n || ls.getEnd() == n)
+		for (Track t : Main.main.ds.tracks)
+			for (LineSegment ls : t.segments)
+				if (ls.start == n || ls.end == n)
 					return true;
-		for (LineSegment ls : Main.main.ds.pendingLineSegments())
-			if (ls.getStart() == n || ls.getEnd() == n)
+		for (LineSegment ls : Main.main.ds.pendingLineSegments)
+			if (ls.start == n || ls.end == n)
 				return true;
 		// TODO areas
@@ -243,9 +223,11 @@
 	 * 		are problems combining the node.
 	 */
-	private String combine(Node n) {
+	private void combineAndDelete(Node n) {
 		// first, check for pending line segments
-		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."; 
+		for (LineSegment ls : Main.main.ds.pendingLineSegments)
+			if (n == ls.start || n == ls.end) {
+				JOptionPane.showMessageDialog(Main.main, "Node used by a line segment which is not part of any track. Remove this first.");
+				return;
+			}
 		
 		// These line segments must be combined within the track combining
@@ -256,24 +238,33 @@
 		// These line segments are combinable. The inner arraylist has always 
 		// two elements. The keys maps to the track, the line segments are in.
-		HashMap<ArrayList<LineSegment>, Track> lineSegments = new HashMap<ArrayList<LineSegment>, Track>();
-		
-		for (Track t : Main.main.ds.tracks()) {
+		Collection<LineSegmentCombineEntry> lineSegments = new ArrayList<LineSegmentCombineEntry>();
+		
+		for (Track t : Main.main.ds.tracks) {
 			ArrayList<LineSegment> current = new ArrayList<LineSegment>();
-			for (LineSegment ls : t.segments())
-				if (ls.getStart() == n || ls.getEnd() == n)
+			for (LineSegment ls : t.segments)
+				if (ls.start == n || ls.end == n)
 					current.add(ls);
 			if (!current.isEmpty()) {
-				if (current.size() > 2)
-					return "Node used by more than two line segments.";
+				if (current.size() > 2) {
+					JOptionPane.showMessageDialog(Main.main, "Node used by more than two line segments.");
+					return;
+				}
 				if (current.size() == 1 && 
 						(current.get(0) == t.getStartingSegment() || current.get(0) == t.getEndingSegment()))
 					pendingLineSegmentsForTrack.add(current.get(0));
-				else if (current.get(0).getEnd() != current.get(1).getStart() &&
-						current.get(1).getEnd() != current.get(0).getStart())
-					return "Node used by line segments that points together.";
-				else if (!current.get(0).keyPropertiesMergable(current.get(1)))
-					return "Node used by line segments with different properties.";
-				else
-					lineSegments.put(current, t);
+				else if (current.get(0).end != current.get(1).start &&
+						current.get(1).end != current.get(0).start) {
+					JOptionPane.showMessageDialog(Main.main, "Node used by line segments that points together.");
+					return;
+				} else if (!current.get(0).keyPropertiesMergable(current.get(1))) {
+					JOptionPane.showMessageDialog(Main.main, "Node used by line segments with different properties.");
+					return;
+				} else {
+					LineSegmentCombineEntry e = new LineSegmentCombineEntry();
+					e.first = current.get(0);
+					e.second = current.get(1);
+					e.track = t;
+					lineSegments.add(e);
+				}
 			}
 		}
@@ -281,12 +272,16 @@
 		// try to combine tracks
 		ArrayList<Track> tracks = new ArrayList<Track>();
-		for (Track t : Main.main.ds.tracks())
+		for (Track t : Main.main.ds.tracks)
 			if (t.getStartingNode() == n || t.getEndingNode() == n)
 				tracks.add(t);
 		if (!tracks.isEmpty()) {
-			if (tracks.size() > 2)
-				return "Node used by more than two tracks.";
-			if (tracks.size() == 1)
-				return "Node used by a track.";
+			if (tracks.size() > 2) {
+				JOptionPane.showMessageDialog(Main.main, "Node used by more than two tracks.");
+				return;
+			}
+			if (tracks.size() == 1) {
+				JOptionPane.showMessageDialog(Main.main, "Node used by a track.");
+				return;
+			}
 			Track t1 = tracks.get(0);
 			Track t2 = tracks.get(1);
@@ -294,10 +289,15 @@
 					t2.getStartingNode() != t1.getEndingNode()) {
 				if (t1.getStartingNode() == t2.getStartingNode() ||
-						t1.getEndingNode() == t2.getEndingNode())
-					return "Node used by tracks that point together.";
-				return "Node used by tracks that cannot be combined.";
-			}
-			if (!t1.keyPropertiesMergable(t2))
-				return "Node used by tracks with different properties.";
+						t1.getEndingNode() == t2.getEndingNode()) {
+					JOptionPane.showMessageDialog(Main.main, "Node used by tracks that point together.");
+					return;
+				}
+				JOptionPane.showMessageDialog(Main.main, "Node used by tracks that cannot be combined.");
+				return;
+			}
+			if (!t1.keyPropertiesMergable(t2)) {
+				JOptionPane.showMessageDialog(Main.main, "Node used by tracks with different properties.");
+				return;
+			}
 		}
 		
@@ -306,67 +306,22 @@
 			LineSegment l1 = pendingLineSegmentsForTrack.get(0);
 			LineSegment l2 = pendingLineSegmentsForTrack.get(1);
-			if (l1.getStart() == l2.getStart() || l1.getEnd() == l2.getEnd())
-				return "Node used by line segments that points together.";
-			if (l1.getStart() == l2.getEnd() || l2.getStart() == l1.getEnd())
+			if (l1.start == l2.start || l1.end == l2.end) {
+				JOptionPane.showMessageDialog(Main.main, "Node used by line segments that points together.");
+				return;
+			}
+			if (l1.start == l2.end || l2.start == l1.end)
 				pendingLineSegmentsForTrack.clear(); // resolved.
 		}
 		
 		// still pending line segments?
-		if (!pendingLineSegmentsForTrack.isEmpty())
-			return "Node used by tracks that cannot be combined.";
+		if (!pendingLineSegmentsForTrack.isEmpty()) {
+			JOptionPane.showMessageDialog(Main.main, "Node used by tracks that cannot be combined.");
+			return;
+		}
 
 		// Ok, we can combine. Do it.
-		// line segments
-		for (ArrayList<LineSegment> list : lineSegments.keySet()) {
-			LineSegment first = list.get(0);
-			LineSegment second = list.get(1);
-			if (first.getStart() == second.getEnd()) {
-				first = second;
-				second = list.get(0);
-			}
-			first.setEnd(second.getEnd());
-			first.keys = mergeKeys(first.keys, second.keys);
-			lineSegments.get(list).remove(second);
-		}
-		
-		// tracks
-		if (!tracks.isEmpty()) {
-			Track first = tracks.get(0);
-			Track second = tracks.get(1);
-			if (first.getStartingNode() == second.getEndingNode()) {
-				first = second;
-				second = tracks.get(0);
-			}
-			// concatenate the line segments.
-			LineSegment lastOfFirst = first.getEndingSegment();
-			LineSegment firstOfSecond = second.getStartingSegment();
-			lastOfFirst.setEnd(firstOfSecond.getEnd());
-			lastOfFirst.keys = mergeKeys(lastOfFirst.keys, firstOfSecond.keys);
-			second.remove(firstOfSecond);
-			// move the remaining line segments to first track.
-			first.addAll(second.segments());
-			Main.main.ds.removeTrack(second);
-		}
-		
-		return null;
-	}
-
-	/**
-	 * 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;
-	}
-
-	@Override
-	protected boolean isEditMode() {
-		return true;
+		Track firstTrack = tracks.isEmpty() ? null : tracks.get(0);
+		Track secondTrack = tracks.isEmpty() ? null : tracks.get(1);
+		mv.editLayer().add(new CombineAndDeleteCommand(n, lineSegments, firstTrack, secondTrack));
 	}
 }
Index: src/org/openstreetmap/josm/actions/mapmode/MapMode.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 22)
+++ src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 23)
@@ -13,6 +13,4 @@
 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;
 
 /**
@@ -50,18 +48,5 @@
 		this.mapFrame = mapFrame;
 		mv = mapFrame.mapView;
-		mv.addLayerChangeListener(new LayerChangeListener(){
-			public void activeLayerChange(Layer oldLayer, Layer newLayer) {
-				setEnabled(!isEditMode() || newLayer.isEditable());
-			}
-			public void layerAdded(Layer newLayer) {}
-			public void layerRemoved(Layer oldLayer) {}
-		});
 	}
-
-	/**
-	 * Subclasses should return whether they want to edit the map data or
-	 * whether they are read-only.
-	 */
-	abstract protected boolean isEditMode();
 
 	/**
Index: src/org/openstreetmap/josm/actions/mapmode/MoveAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/MoveAction.java	(revision 22)
+++ src/org/openstreetmap/josm/actions/mapmode/MoveAction.java	(revision 23)
@@ -8,5 +8,4 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.command.MoveCommand;
 import org.openstreetmap.josm.data.GeoPoint;
@@ -84,7 +83,5 @@
 
 		Collection<OsmPrimitive> selection = Main.main.ds.getSelected();
-		Command c = new MoveCommand(selection, dx, dy);
-		c.executeCommand();
-		Main.main.commands.add(c);
+		mv.editLayer().add(new MoveCommand(selection, dx, dy));
 		
 		mv.repaint();
@@ -131,8 +128,3 @@
 		}
 	}
-
-	@Override
-	protected boolean isEditMode() {
-		return true;
-	}
 }
Index: src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java	(revision 22)
+++ src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java	(revision 23)
@@ -95,8 +95,3 @@
 		mv.repaint();
 	}
-
-	@Override
-	protected boolean isEditMode() {
-		return false;
-	}
 }
Index: src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java	(revision 22)
+++ src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java	(revision 23)
@@ -68,8 +68,3 @@
 		selectionManager.unregister(mv);
 	}
-
-	@Override
-	protected boolean isEditMode() {
-		return false;
-	}
 }
Index: src/org/openstreetmap/josm/command/AddCommand.java
===================================================================
--- src/org/openstreetmap/josm/command/AddCommand.java	(revision 22)
+++ src/org/openstreetmap/josm/command/AddCommand.java	(revision 23)
@@ -43,9 +43,9 @@
 		SelectionComponentVisitor v = new SelectionComponentVisitor();
 		osm.visit(v);
-		return new JLabel(v.name, v.icon, JLabel.LEADING);
+		return new JLabel("Add "+v.name, v.icon, JLabel.LEADING);
 	}
 	
 	public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
-		if (!added.contains(osm))
+		if (added != null && !added.contains(osm))
 			added.add(osm);
 	}
@@ -65,4 +65,6 @@
 	public void visit(LineSegment ls) {
 		Main.main.ds.pendingLineSegments.add(ls);
+		Main.main.ds.addBackReference(ls.start, ls);
+		Main.main.ds.addBackReference(ls.end, ls);
 	}
 
@@ -74,6 +76,11 @@
 		Main.main.ds.tracks.add(t);
 		for (Iterator<LineSegment> it =  Main.main.ds.pendingLineSegments.iterator(); it.hasNext();)
-			if (t.segments().contains(it.next()))
+			if (t.segments.contains(it.next()))
 				it.remove();
+		for (LineSegment ls : t.segments) {
+			Main.main.ds.addBackReference(ls, t);
+			Main.main.ds.addBackReference(ls.start, t);
+			Main.main.ds.addBackReference(ls.end, t);
+		}
 	}
 
Index: src/org/openstreetmap/josm/command/CombineAndDeleteCommand.java
===================================================================
--- src/org/openstreetmap/josm/command/CombineAndDeleteCommand.java	(revision 23)
+++ src/org/openstreetmap/josm/command/CombineAndDeleteCommand.java	(revision 23)
@@ -0,0 +1,136 @@
+package org.openstreetmap.josm.command;
+
+import java.awt.Component;
+import java.util.Collection;
+import java.util.Map;
+
+import javax.swing.JLabel;
+
+import org.openstreetmap.josm.Main;
+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;
+
+/**
+ * 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.
+ * @author imi
+ */
+public class CombineAndDeleteCommand implements Command {
+
+	/**
+	 * This class is used as one line segment pair that needs to get combined
+	 * for the node to be deleted.
+	 * @author imi
+	 */
+	public static class LineSegmentCombineEntry {
+		public LineSegment first, second;
+		public Track track;
+	}
+	
+	/**
+	 * The node that get deleted
+	 */
+	private Node node;
+	/**
+	 * These line segments are 
+	 */
+	private Collection<LineSegmentCombineEntry> combineLineSegments;
+	/**
+	 * These tracks are combined
+	 */
+	private Track firstTrack, secondTrack;
+	/**
+	 * This line segment is deleted together with the second track. It was the
+	 * first segment of the second track (the other line segments were integrated
+	 * into the first track).
+	 */
+	private LineSegment firstOfSecond;
+
+	/**
+	 * Create the command and assign the data entries.
+	 */
+	public CombineAndDeleteCommand(Node nodeToDelete, 
+			Collection<LineSegmentCombineEntry> combineLineSegments,
+			Track firstTrack, Track secondTrack) {
+		node = nodeToDelete;
+		this.combineLineSegments = combineLineSegments;
+		this.firstTrack = firstTrack;
+		this.secondTrack = secondTrack;
+	}
+	
+	public void executeCommand() {
+		// line segments
+		DataSet ds = Main.main.ds;
+		for (LineSegmentCombineEntry e : combineLineSegments) {
+			if (e.first.start == e.second.end) {
+				LineSegment tmp = e.first;
+				e.first = e.second;
+				e.second = tmp;
+			}
+			e.first.end = e.second.end;
+			e.first.keys = mergeKeys(e.first.keys, e.second.keys);
+			e.track.segments.remove(e.second);
+		}
+		
+		// tracks
+		if (firstTrack != null && secondTrack != null) {
+			if (firstTrack.getStartingNode() == secondTrack.getEndingNode()) {
+				Track t = firstTrack;
+				firstTrack = secondTrack;
+				secondTrack = t;
+			}
+			// concatenate the line segments.
+			LineSegment lastOfFirst = firstTrack.getEndingSegment();
+			firstOfSecond = secondTrack.getStartingSegment();
+			lastOfFirst.end = firstOfSecond.end;
+			lastOfFirst.keys = mergeKeys(lastOfFirst.keys, firstOfSecond.keys);
+			secondTrack.segments.remove(firstOfSecond);
+			// move the remaining line segments to first track.
+			firstTrack.segments.addAll(secondTrack.segments);
+			ds.tracks.remove(secondTrack);
+		}
+		ds.nodes.remove(node);
+		ds.rebuildBackReferences();
+	}
+
+	/**
+	 * 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(node);
+		return new JLabel("Remove "+v.name, v.icon, JLabel.LEADING);
+	}
+
+	public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+		deleted.add(node);
+		if (firstTrack != null)
+			modified.add(firstTrack);
+		if (secondTrack != null)
+			deleted.add(secondTrack);
+		if (firstOfSecond != null)
+			deleted.add(firstOfSecond);
+		for (LineSegmentCombineEntry e : combineLineSegments) {
+			modified.add(e.first);
+			deleted.add(e.second);
+			modified.add(e.track);
+		}
+	}
+
+}
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 23)
@@ -46,25 +46,25 @@
 	public void executeCommand() {
 		if (del instanceof LineSegment) {
-			LineSegment ls = (LineSegment)mod;
-			Track t = (Track)del;
-			if (!Main.main.ds.pendingLineSegments().contains(ls))
+			LineSegment ls = (LineSegment)del;
+			Track t = (Track)mod;
+			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())
+			if (t.getStartingNode() != ls.end)
 				t.add(ls);
 			else
-				t.addStart(ls);
+				t.segments.add(0,ls);
 		} else {
 			Track t1 = (Track)mod;
 			Track t2 = (Track)del;
-			t1.addAll(t2.segments());
+			t1.segments.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);
 		}
+		Main.main.ds.rebuildBackReferences();
 	}
 
@@ -82,7 +82,7 @@
 	
 	public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
-		if (!modified.contains(mod))
+		if (modified != null && !modified.contains(mod))
 			modified.add(mod);
-		if (deleted.contains(del))
+		if (deleted != null && 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 22)
+++ src/org/openstreetmap/josm/command/Command.java	(revision 23)
@@ -27,8 +27,10 @@
 	/**
 	 * 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
+	 * Add to the lists, don't clear them. The lists can be <code>null</code>
+	 * in which case they are ignored.
+	 * 
+	 * @param modified  The modified primitives or <code>null</code>
+	 * @param deleted   The deleted primitives or <code>null</code>
+	 * @param added		The added primitives or <code>null</code>
 	 */
 	void fillModifiedData(Collection<OsmPrimitive> modified,
Index: src/org/openstreetmap/josm/command/DataSet.java
===================================================================
--- src/org/openstreetmap/josm/command/DataSet.java	(revision 22)
+++ 	(revision )
@@ -1,287 +1,0 @@
-package org.openstreetmap.josm.command;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Set;
-
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.SelectionTracker;
-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;
-
-/**
- * DataSet is the data behind one window in the application. It can consist of only a few
- * points up to the whole osm database. DataSet's can be merged together, split up into
- * several different ones, saved, (up/down/disk)loaded etc.
- *
- * Note, that DataSet is not an osm-primitive, it is not within 
- * org.openstreetmap.josm.data.osm and has no key association but a few
- * members to store some information.
- * 
- * @author imi
- */
-public class DataSet extends SelectionTracker implements Cloneable {
-
-	/**
-	 * All nodes goes here, even when included in other data (tracks etc).
-	 * This enables the instant conversion of the whole DataSet by iterating over
-	 * this data structure.
-	 */
-	public Collection<Node> nodes = new LinkedList<Node>();
-
-	/**
-	 * All pending line segments goes here. Pending line segments are those, that 
-	 * are in this list but are in no track.
-	 */
-	Collection<LineSegment> pendingLineSegments = new LinkedList<LineSegment>();
-
-	/**
-	 * All tracks (Streets etc.) in the DataSet. 
-	 * 
-	 * The nodes of the track segments of this track must be objects from 
-	 * the nodes list, however the track segments are stored only in the 
-	 * track list.
-	 */
-	Collection<Track> tracks = new LinkedList<Track>();
-
-	/**
-	 * Add the track to the tracklist.
-	 */
-	public void addTrack(Track t) {
-		tracks.add(t);
-	}
-	/**
-	 * Remove the track from the tracklist.
-	 */
-	public void removeTrack(Track t) {
-		t.destroy();
-		tracks.remove(t);
-	}
-	/**
-	 * Return a read-only collection of all tracks
-	 */
-	public Collection<Track> tracks() {
-		return Collections.unmodifiableCollection(tracks);
-	}
-
-	/**
-	 * Add a newly created line segment to the pending lines list.
-	 */
-	public void addPendingLineSegment(LineSegment ls) {
-		pendingLineSegments.add(ls);
-	}
-	/**
-	 * Remove a line segment from the pending lines list, because it has been
-	 * assigned to the track.
-	 * @param ls The line segment from the pending list
-	 * @param t The track, that will hold the line segment
-	 * @param end <code>true</code> to attach on the end. <code>false</code>
-	 * 		to attach on the beginning.
-	 */
-	public void assignPendingLineSegment(LineSegment ls, Track t, boolean end) {
-		pendingLineSegments.remove(ls);
-		if (end)
-			t.add(ls);
-		else
-			t.addStart(ls);
-	}
-	/**
-	 * Delete the pending line segment without moving it anywhere.
-	 */
-	public void destroyPendingLineSegment(LineSegment ls) {
-		pendingLineSegments.remove(ls);
-		ls.destroy();
-	}
-	/**
-	 * Return an read-only iterator over all pending line segments.
-	 */
-	public Collection<LineSegment> pendingLineSegments() {
-		return Collections.unmodifiableCollection(pendingLineSegments);
-	}
-
-	/**
-	 * Return the bounds of this DataSet, depending on X/Y values.
-	 * The min of the return value is the upper left GeoPoint, the max the lower
-	 * down GeoPoint, regarding to the X/Y values.
-	 * 
-	 * Return null, if any point not converted yet or if there are no points at all.
-	 * 
-	 * @return Bounding coordinate structure.
-	 */
-	public Bounds getBoundsXY() {
-		if (nodes.isEmpty())
-			return null;
-
-		Node first = nodes.iterator().next();
-		Bounds b = new Bounds(first.coor.clone(), first.coor.clone());
-		for (Node w : nodes)
-		{
-			if (Double.isNaN(w.coor.x) || Double.isNaN(w.coor.y))
-				return null;
-			if (w.coor.x < b.min.x)
-				b.min.x = w.coor.x;
-			if (w.coor.y < b.min.y)
-				b.min.y = w.coor.y;
-			if (w.coor.x > b.max.x)
-				b.max.x = w.coor.x;
-			if (w.coor.y > b.max.y)
-				b.max.y = w.coor.y;
-		}
-		return b;
-	}
-
-	/**
-	 * Return the bounds of this DataSet, depending on lat/lon values.
-	 * The min of the return value is the upper left GeoPoint, the max the lower
-	 * down GeoPoint.
-	 * 
-	 * Return null, if any point does not have lat/lon or if there are no 
-	 * points at all.
-	 * 
-	 * @return Bounding coordinate structure.
-	 */
-	public Bounds getBoundsLatLon() {
-		if (nodes.isEmpty())
-			return null;
-
-		Node first = nodes.iterator().next();
-		Bounds b = new Bounds(first.coor.clone(), first.coor.clone());
-		for (Node w : nodes)
-		{
-			if (Double.isNaN(w.coor.lat) || Double.isNaN(w.coor.lon))
-				return null;
-			if (w.coor.lat < b.min.lat)
-				b.min.lat = w.coor.lat;
-			if (w.coor.lon < b.min.lon)
-				b.min.lon = w.coor.lon;
-			if (w.coor.lat > b.max.lat)
-				b.max.lat = w.coor.lat;
-			if (w.coor.lon > b.max.lon)
-				b.max.lon = w.coor.lon;
-		}
-		return b;
-	}
-
-	/**
-	 * Remove the selection of the whole dataset.
-	 */
-	public void clearSelection() {
-		clearSelection(nodes);
-		clearSelection(tracks);
-		for (Track t : tracks)
-			clearSelection(t.segments());
-	}
-
-	/**
-	 * Return a list of all selected objects. Even keys are returned.
-	 * @return List of all selected objects.
-	 */
-	@Override
-	public Collection<OsmPrimitive> getSelected() {
-		Collection<OsmPrimitive> sel = getSelected(nodes);
-		sel.addAll(getSelected(pendingLineSegments));
-		sel.addAll(getSelected(tracks));
-		for (Track t : tracks)
-			sel.addAll(getSelected(t.segments()));
-		return sel;
-	}
-
-	/**
-	 * Import the given dataset by merging all data with this dataset.
-	 * The objects imported are not cloned, so from now on, these data belong
-	 * to both datasets. So use mergeFrom only if you are about to abandon the
-	 * other dataset or this dataset.
-	 * 
-	 * @param ds	The DataSet to merge into this one.
-	 * @param mergeEqualNodes If <code>true</code>, nodes with the same lat/lon
-	 * 		are merged together.
-	 */
-	public void mergeFrom(DataSet ds, boolean mergeEqualNodes) {
-		if (mergeEqualNodes && !nodes.isEmpty()) {
-			Map<Node, Node> mergeMap = new HashMap<Node, Node>();
-			Set<Node> nodesToAdd = new HashSet<Node>();
-			for (Node n : nodes) {
-				for (Iterator<Node> it = ds.nodes.iterator(); it.hasNext();) {
-					Node dsn = it.next();
-					if (n.coor.equalsLatLon(dsn.coor)) {
-						mergeMap.put(dsn, n);
-						n.mergeFrom(dsn);
-						it.remove();
-					} else {
-						nodesToAdd.add(dsn);
-					}
-				}
-			}
-			nodes.addAll(nodesToAdd);
-			for (Track t : ds.tracks) {
-				for (LineSegment ls : t.segments()) {
-					Node n = mergeMap.get(ls.getStart());
-					if (n != null)
-						ls.start = n;
-					n = mergeMap.get(ls.getEnd());
-					if (n != null)
-						ls.end = n;
-				}
-			}
-			tracks.addAll(ds.tracks);
-			for (LineSegment ls : ds.pendingLineSegments) {
-				Node n = mergeMap.get(ls.getStart());
-				if (n != null)
-					ls.start = n;
-				n = mergeMap.get(ls.getEnd());
-				if (n != null)
-					ls.end = n;
-			}
-			pendingLineSegments.addAll(ds.pendingLineSegments);
-		} else {
-			nodes.addAll(ds.nodes);
-			tracks.addAll(ds.tracks);
-			pendingLineSegments.addAll(ds.pendingLineSegments);
-		}
-	}
-
-	/**
-	 * Remove the selection from every value in the collection.
-	 * @param list The collection to remove the selection from.
-	 */
-	private void clearSelection(Collection<? extends OsmPrimitive> list) {
-		if (list == null)
-			return;
-		for (OsmPrimitive osm : list) {
-			osm.setSelected(false);
-			if (osm.keys != null)
-				clearSelection(osm.keys.keySet());
-		}
-	}
-
-	/**
-	 * Return all selected items in the collection.
-	 * @param list The collection from which the selected items are returned.
-	 */
-	private Collection<OsmPrimitive> getSelected(Collection<? extends OsmPrimitive> list) {
-		Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>();
-		if (list == null)
-			return sel;
-		for (OsmPrimitive osm : list) {
-			if (osm.isSelected())
-				sel.add(osm);
-			if (osm.keys != null)
-				sel.addAll(getSelected(osm.keys.keySet()));
-		}
-		return sel;
-	}
-
-
-	@Override
-	public DataSet clone() {
-		try {return (DataSet)super.clone();} catch (CloneNotSupportedException e) {}
-		return null;
-	}
-}
Index: src/org/openstreetmap/josm/command/DeleteCommand.java
===================================================================
--- src/org/openstreetmap/josm/command/DeleteCommand.java	(revision 23)
+++ src/org/openstreetmap/josm/command/DeleteCommand.java	(revision 23)
@@ -0,0 +1,79 @@
+package org.openstreetmap.josm.command;
+
+import java.awt.Component;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import javax.swing.JLabel;
+
+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;
+
+/**
+ * A command to delete a number of primitives from the dataset.
+ * @author imi
+ */
+public class DeleteCommand implements Command, Visitor {
+
+	/**
+	 * The primitives that are going to deleted.
+	 */
+	private final Collection<OsmPrimitive> data;
+	
+	public DeleteCommand(Collection<OsmPrimitive> data) {
+		this.data = data;
+	}
+	
+	public void executeCommand() {
+		for (OsmPrimitive osm : data)
+			osm.visit(this);
+	}
+
+	public Component commandDescription() {
+		return new JLabel("Delete "+data.size()+" primitives");
+	}
+
+	public void fillModifiedData(Collection<OsmPrimitive> modified,
+			Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+		if (deleted != null)
+			deleted.addAll(data);
+	}
+
+
+	public void visit(Node n) {
+		Main.main.ds.nodes.remove(n);
+		Main.main.ds.removeBackReference(n);
+	}
+
+	public void visit(LineSegment ls) {
+		Main.main.ds.pendingLineSegments.remove(ls);
+		LinkedList<Track> tracksToDelete = new LinkedList<Track>();
+		for (Track t : Main.main.ds.tracks) {
+			t.segments.remove(ls);
+			if (t.segments.isEmpty())
+				tracksToDelete.add(t);
+		}
+		for (Track t : tracksToDelete) {
+			Main.main.ds.tracks.remove(t);
+			Main.main.ds.removeBackReference(t);
+		}
+		Main.main.ds.removeBackReference(ls);
+	}
+
+	public void visit(Track t) {
+		Main.main.ds.tracks.remove(t);
+		for (LineSegment ls : t.segments)
+			Main.main.ds.pendingLineSegments.add(ls);
+		Main.main.ds.removeBackReference(t);
+	}
+
+	public void visit(Key k) {
+		// TODO
+	}
+
+}
Index: src/org/openstreetmap/josm/command/MoveCommand.java
===================================================================
--- src/org/openstreetmap/josm/command/MoveCommand.java	(revision 22)
+++ src/org/openstreetmap/josm/command/MoveCommand.java	(revision 23)
@@ -3,5 +3,4 @@
 import java.awt.Component;
 import java.util.Collection;
-import java.util.HashSet;
 
 import javax.swing.JLabel;
@@ -9,4 +8,5 @@
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
 
 /**
@@ -49,8 +49,8 @@
 
 	public void executeCommand() {
-		Collection<Node> movingNodes = new HashSet<Node>();
+		AllNodesVisitor visitor = new AllNodesVisitor();
 		for (OsmPrimitive osm : objects)
-			movingNodes.addAll(osm.getAllNodes());
-		for (Node n : movingNodes) {
+			osm.visit(visitor);
+		for (Node n : visitor.nodes) {
 			n.coor.x += x;
 			n.coor.y += y;
@@ -65,7 +65,8 @@
 
 	public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
-		for (OsmPrimitive osm : objects)
-			if (!modified.contains(osm))
-				modified.add(osm);
+		if (modified != null)
+			for (OsmPrimitive osm : objects)
+				if (!modified.contains(osm))
+					modified.add(osm);
 	}
 }
Index: src/org/openstreetmap/josm/data/Bounds.java
===================================================================
--- src/org/openstreetmap/josm/data/Bounds.java	(revision 22)
+++ src/org/openstreetmap/josm/data/Bounds.java	(revision 23)
@@ -45,3 +45,31 @@
 		this.max = max;
 	}
+	
+	/**
+	 * @return The bounding rectangle that covers <code>this</code> and 
+	 * 		the <code>other</code> bounds, regarding the x/y values.
+	 */
+	public Bounds mergeXY(Bounds other) {
+		GeoPoint nmin = new GeoPoint();
+		nmin.x = Math.min(min.x, other.min.x);
+		nmin.y = Math.min(min.y, other.min.y);
+		GeoPoint nmax = new GeoPoint();
+		nmax.x = Math.max(max.x, other.max.x);
+		nmax.y = Math.max(max.y, other.max.y);
+		return new Bounds(nmin, nmax);
+	}
+	
+	/**
+	 * @return The bounding rectangle that covers <code>this</code> and 
+	 * 		the <code>other</code> bounds, regarding the lat/lon values.
+	 */
+	public Bounds mergeLatLon(Bounds other) {
+		GeoPoint nmin = new GeoPoint(
+				Math.min(min.lat, other.min.lat),
+				Math.min(min.lon, other.min.lon));
+		GeoPoint nmax = new GeoPoint(
+				Math.max(max.lat, other.max.lat),
+				Math.max(max.lon, other.max.lon));
+		return new Bounds(nmin, nmax);
+	}
 }
Index: src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- src/org/openstreetmap/josm/data/Preferences.java	(revision 22)
+++ src/org/openstreetmap/josm/data/Preferences.java	(revision 23)
@@ -45,4 +45,8 @@
 	 */
 	private boolean drawRawGpsLines = false;
+	/**
+	 * Whether deleted objects should be drawn in a dark color.
+	 */
+	private boolean drawDeleted = false;
 	/**
 	 * Force the drawing of lines between raw gps points if there are no
@@ -134,4 +138,6 @@
 			mergeNodes = root.getChild("mergeNodes") != null;
 			drawRawGpsLines = root.getChild("drawRawGpsLines") != null;
+			forceRawGpsLines = root.getChild("forceRawGpsLines") != null;
+			drawDeleted = root.getChild("drawDeleted") != null;
 		} catch (Exception e) {
 			if (e instanceof PreferencesException)
@@ -156,4 +162,8 @@
 		if (drawRawGpsLines)
 			children.add(new Element("drawRawGpsLines"));
+		if (drawDeleted)
+			children.add(new Element("drawDeleted"));
+		if (forceRawGpsLines)
+			children.add(new Element("forceRawGpsLines"));
 		Element osmServer = new Element("osm-server");
 		osmServer.getChildren().add(new Element("url").setText(osmDataServer));
@@ -177,5 +187,4 @@
 	}
 
-	
 	// projection change listener stuff
 	
@@ -184,4 +193,5 @@
 	 */
 	private Collection<PropertyChangeListener> listener = new LinkedList<PropertyChangeListener>();
+
 	/**
 	 * Add a listener of projection changes to the list of listeners.
@@ -246,3 +256,11 @@
 		return forceRawGpsLines;
 	}
+	public boolean isDrawDeleted() {
+		return drawDeleted;
+	}
+	public void setDrawDeleted(boolean drawDeleted) {
+		boolean old = this.drawDeleted;
+		this.drawDeleted = drawDeleted;
+		firePropertyChanged("drawDeleted", old, drawDeleted);
+	}
 }
Index: src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 23)
+++ src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 23)
@@ -0,0 +1,380 @@
+package org.openstreetmap.josm.data.osm;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.SelectionTracker;
+import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
+
+/**
+ * DataSet is the data behind one window in the application. It can consist of only a few
+ * points up to the whole osm database. DataSet's can be merged together, split up into
+ * several different ones, saved, (up/down/disk)loaded etc.
+ *
+ * Note, that DataSet is not an osm-primitive, it is not within 
+ * org.openstreetmap.josm.data.osm and has no key association but a few
+ * members to store some information.
+ * 
+ * @author imi
+ */
+public class DataSet extends SelectionTracker implements Cloneable {
+
+	/**
+	 * All nodes goes here, even when included in other data (tracks etc).
+	 * This enables the instant conversion of the whole DataSet by iterating over
+	 * this data structure.
+	 */
+	public Collection<Node> nodes = new LinkedList<Node>();
+
+	/**
+	 * All pending line segments goes here. Pending line segments are those, that 
+	 * are in this list but are in no track.
+	 */
+	public Collection<LineSegment> pendingLineSegments = new LinkedList<LineSegment>();
+
+	/**
+	 * All tracks (Streets etc.) in the DataSet. 
+	 * 
+	 * The nodes of the track segments of this track must be objects from 
+	 * the nodes list, however the track segments are stored only in the 
+	 * track list.
+	 */
+	public Collection<Track> tracks = new LinkedList<Track>();
+
+	
+	/**
+	 * This is a list of all back references of nodes to their track usage.
+	 */
+	public Map<Node, Set<Track>> nodeTrackRef = new HashMap<Node, Set<Track>>();
+	/**
+	 * This is a list of all back references of nodes to their line segments.
+	 */
+	public Map<Node, Set<LineSegment>> nodeLsRef = new HashMap<Node, Set<LineSegment>>();
+	/**
+	 * This is a list of all back references of lines to their tracks.
+	 */
+	public Map<LineSegment, Set<Track>> lsTrackRef = new HashMap<LineSegment, Set<Track>>();
+
+	/**
+	 * Add a back reference from the node to the line segment.
+	 */
+	public void addBackReference(Node from, LineSegment to) {
+		Set<LineSegment> references = nodeLsRef.get(from);
+		if (references == null)
+			references = new HashSet<LineSegment>();
+		references.add(to);
+		nodeLsRef.put(from, references);
+	}
+	/**
+	 * Add a back reference from the node to the track.
+	 */
+	public void addBackReference(Node from, Track to) {
+		Set<Track> references = nodeTrackRef.get(from);
+		if (references == null)
+			references = new HashSet<Track>();
+		references.add(to);
+		nodeTrackRef.put(from, references);
+	}
+	/**
+	 * Add a back reference from the line segment to the track.
+	 */
+	public void addBackReference(LineSegment from, Track to) {
+		Set<Track> references = lsTrackRef.get(from);
+		if (references == null)
+			references = new HashSet<Track>();
+		references.add(to);
+		lsTrackRef.put(from, references);
+	}
+
+	/**
+	 * Removes all references to and from this line segment.
+	 */
+	public void removeBackReference(LineSegment ls) {
+		Set<LineSegment> s = nodeLsRef.get(ls.start);
+		if (s != null)
+			s.remove(ls);
+		s = nodeLsRef.get(ls.end);
+		if (s != null)
+			s.remove(ls);
+		lsTrackRef.remove(ls);
+	}
+	/**
+	 * Removes all references to and from the node.
+	 */
+	public void removeBackReference(Node n) {
+		nodeLsRef.remove(n);
+		nodeTrackRef.remove(n);
+	}
+	/**
+	 * Removes all references to and from the track.
+	 */
+	public void removeBackReference(Track t) {
+		Collection<Node> nodes = AllNodesVisitor.getAllNodes(t);
+		for (Node n : nodes) {
+			Set<Track> s = nodeTrackRef.get(n);
+			if (s != null)
+				s.remove(t);
+		}
+		for (LineSegment ls : t.segments) {
+			Set<Track> s = lsTrackRef.get(ls);
+			if (s != null)
+				s.remove(t);
+		}
+	}
+	
+	/**
+	 * Rebuild the caches of back references.
+	 */
+	public void rebuildBackReferences() {
+		nodeTrackRef.clear();
+		nodeLsRef.clear();
+		lsTrackRef.clear();
+		for (Track t : tracks) {
+			for (LineSegment ls : t.segments) {
+				addBackReference(ls.start, ls);
+				addBackReference(ls.end, ls);
+				addBackReference(ls.start, t);
+				addBackReference(ls.end, t);
+				addBackReference(ls, t);
+			}
+		}
+		for (LineSegment ls : pendingLineSegments) {
+			addBackReference(ls.start, ls);
+			addBackReference(ls.end, ls);
+		}
+	}
+	
+	/**
+	 * Return the bounds of this DataSet, depending on X/Y values.
+	 * The min of the return value is the upper left GeoPoint, the max the lower
+	 * down GeoPoint, regarding to the X/Y values.
+	 * 
+	 * Return null, if any point not converted yet or if there are no points at all.
+	 * 
+	 * @return Bounding coordinate structure.
+	 */
+	public Bounds getBoundsXY() {
+		if (nodes.isEmpty())
+			return null;
+
+		Node first = nodes.iterator().next();
+		Bounds b = new Bounds(first.coor.clone(), first.coor.clone());
+		for (Node w : nodes)
+		{
+			if (Double.isNaN(w.coor.x) || Double.isNaN(w.coor.y))
+				return null;
+			if (w.coor.x < b.min.x)
+				b.min.x = w.coor.x;
+			if (w.coor.y < b.min.y)
+				b.min.y = w.coor.y;
+			if (w.coor.x > b.max.x)
+				b.max.x = w.coor.x;
+			if (w.coor.y > b.max.y)
+				b.max.y = w.coor.y;
+		}
+		return b;
+	}
+
+	/**
+	 * Return the bounds of this DataSet, depending on lat/lon values.
+	 * The min of the return value is the upper left GeoPoint, the max the lower
+	 * down GeoPoint.
+	 * 
+	 * Return null, if any point does not have lat/lon or if there are no 
+	 * points at all.
+	 * 
+	 * @return Bounding coordinate structure.
+	 */
+	public Bounds getBoundsLatLon() {
+		if (nodes.isEmpty())
+			return null;
+
+		Node first = nodes.iterator().next();
+		Bounds b = new Bounds(first.coor.clone(), first.coor.clone());
+		for (Node w : nodes)
+		{
+			if (Double.isNaN(w.coor.lat) || Double.isNaN(w.coor.lon))
+				return null;
+			if (w.coor.lat < b.min.lat)
+				b.min.lat = w.coor.lat;
+			if (w.coor.lon < b.min.lon)
+				b.min.lon = w.coor.lon;
+			if (w.coor.lat > b.max.lat)
+				b.max.lat = w.coor.lat;
+			if (w.coor.lon > b.max.lon)
+				b.max.lon = w.coor.lon;
+		}
+		return b;
+	}
+
+	/**
+	 * Remove the selection of the whole dataset.
+	 */
+	public void clearSelection() {
+		clearSelection(nodes);
+		clearSelection(tracks);
+		for (Track t : tracks)
+			clearSelection(t.segments);
+	}
+
+	/**
+	 * Return a list of all selected objects. Even keys are returned.
+	 * @return List of all selected objects.
+	 */
+	@Override
+	public Collection<OsmPrimitive> getSelected() {
+		Collection<OsmPrimitive> sel = getSelected(nodes);
+		sel.addAll(getSelected(pendingLineSegments));
+		sel.addAll(getSelected(tracks));
+		for (Track t : tracks)
+			sel.addAll(getSelected(t.segments));
+		return sel;
+	}
+
+	/**
+	 * Import the given dataset by merging all data with this dataset.
+	 * The objects imported are not cloned, so from now on, these data belong
+	 * to both datasets. So use mergeFrom only if you are about to abandon the
+	 * other dataset.
+	 * 
+	 * Elements are tried to merged. 
+	 * Nodes are merged first, if their lat/lon are equal.
+	 * Line segments are merged, if they have the same nodes.
+	 * Tracs are merged, if they consist of the same line segments.
+	 * 
+	 * Additional to that, every two objects with the same id are merged.
+	 * 
+	 * @param ds	The DataSet to merge into this one.
+	 * @return A list of all primitives that were used in the conjunction. That
+	 * 		is all used primitives (the merged primitives and all added ones).
+	 */
+	public Collection<OsmPrimitive> mergeFrom(DataSet ds) {
+		Collection<OsmPrimitive> data = new LinkedList<OsmPrimitive>();
+
+		Set<LineSegment> myLineSegments = new HashSet<LineSegment>();
+		myLineSegments.addAll(pendingLineSegments);
+		for (Track t : tracks)
+			myLineSegments.addAll(t.segments);
+		
+		Set<LineSegment> otherLineSegments = new HashSet<LineSegment>();
+		otherLineSegments.addAll(ds.pendingLineSegments);
+		for (Track t : ds.tracks)
+			otherLineSegments.addAll(t.segments);
+		
+		
+		// merge nodes
+
+		Map<Node, Node> nodeMap = new HashMap<Node, Node>();
+		// find mergable
+		for (Node otherNode : ds.nodes)
+			for (Node myNode : nodes)
+				if (otherNode.coor.equalsLatLon(myNode.coor))
+					nodeMap.put(otherNode, myNode);
+		// add
+		data.addAll(new HashSet<Node>(nodeMap.values()));
+		for (Node n : ds.nodes) {
+			if (!nodeMap.containsKey(n)) {
+				nodes.add(n);
+				data.add(n);
+			}
+		}
+		// reassign
+		for (LineSegment ls : otherLineSegments) {
+			Node n = nodeMap.get(ls.start);
+			if (n != null)
+				ls.start = n;
+			n = nodeMap.get(ls.end);
+			if (n != null)
+				ls.end = n;
+		}
+
+
+		// merge line segments
+
+		Map<LineSegment, LineSegment> lsMap = new HashMap<LineSegment, LineSegment>();
+		// find mergable
+		for (LineSegment otherLS : otherLineSegments)
+			for (LineSegment myLS : myLineSegments)
+				if (otherLS.start == myLS.start && otherLS.end == myLS.end)
+					lsMap.put(otherLS, myLS);
+		// add pendings (ls from track are added later
+		for (LineSegment ls : ds.pendingLineSegments) {
+			if (!lsMap.containsKey(ls)) {
+				pendingLineSegments.add(ls);
+				data.add(ls);
+			}
+		}
+		// reassign
+		for (Track t : ds.tracks) {
+			for (int i = 0; i < t.segments.size(); ++i) {
+				LineSegment newLS = lsMap.get(t.segments.get(i));
+				if (newLS != null)
+					t.segments.set(i, newLS);
+			}
+		}
+		
+		
+		// merge tracks
+		LinkedList<Track> trackToAdd = new LinkedList<Track>();
+		for (Track otherTrack : ds.tracks) {
+			boolean found = false;
+			for (Track myTrack : tracks) {
+				if (myTrack.segments.equals(otherTrack.segments)) {
+					found = true;
+					data.add(myTrack);
+					break;
+				}
+			}
+			if (!found)
+				trackToAdd.add(otherTrack);
+		}
+		data.addAll(trackToAdd);
+		tracks.addAll(trackToAdd);
+
+		rebuildBackReferences();
+		return data;
+	}
+
+	/**
+	 * Remove the selection from every value in the collection.
+	 * @param list The collection to remove the selection from.
+	 */
+	private void clearSelection(Collection<? extends OsmPrimitive> list) {
+		if (list == null)
+			return;
+		for (OsmPrimitive osm : list) {
+			osm.setSelected(false);
+			if (osm.keys != null)
+				clearSelection(osm.keys.keySet());
+		}
+	}
+
+	/**
+	 * Return all selected items in the collection.
+	 * @param list The collection from which the selected items are returned.
+	 */
+	private Collection<OsmPrimitive> getSelected(Collection<? extends OsmPrimitive> list) {
+		Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>();
+		if (list == null)
+			return sel;
+		for (OsmPrimitive osm : list) {
+			if (osm.isSelected())
+				sel.add(osm);
+			if (osm.keys != null)
+				sel.addAll(getSelected(osm.keys.keySet()));
+		}
+		return sel;
+	}
+
+
+	@Override
+	public DataSet clone() {
+		try {return (DataSet)super.clone();} catch (CloneNotSupportedException e) {}
+		return null;
+	}
+}
Index: src/org/openstreetmap/josm/data/osm/Key.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Key.java	(revision 22)
+++ src/org/openstreetmap/josm/data/osm/Key.java	(revision 23)
@@ -1,7 +1,5 @@
 package org.openstreetmap.josm.data.osm;
 
-import java.util.Collection;
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.Map;
 
@@ -49,12 +47,4 @@
 	}
 	
-	/**
-	 * Return an empty list, since keys cannot have nodes. 
-	 */
-	@Override
-	public Collection<Node> getAllNodes() {
-		return new LinkedList<Node>();
-	}
-
 	@Override
 	public void visit(Visitor visitor) {
Index: src/org/openstreetmap/josm/data/osm/LineSegment.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/LineSegment.java	(revision 22)
+++ src/org/openstreetmap/josm/data/osm/LineSegment.java	(revision 23)
@@ -1,7 +1,3 @@
 package org.openstreetmap.josm.data.osm;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
 
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
@@ -26,9 +22,4 @@
 
 	/**
-	 * The tracks, this line segment is part of.
-	 */
-	transient Collection<Track> parent = new LinkedList<Track>();
-
-	/**
 	 * Create an line segment from the given starting and ending node
 	 * @param start	Starting node of the line segment.
@@ -38,49 +29,4 @@
 		this.start = start;
 		this.end = end;
-		start.parentSegment.add(this);
-		end.parentSegment.add(this);
-	}
-
-	/**
-	 * Return all parent tracks this line segment is part of. The list is readonly.
-	 */
-	public Collection<Track> getParents() {
-		return Collections.unmodifiableCollection(parent);
-	}
-
-	public void setStart(Node start) {
-		this.start.parentSegment.remove(this);
-		this.start = start;
-		start.parentSegment.add(this);
-	}
-	public Node getStart() {
-		return start;
-	}
-	public void setEnd(Node end) {
-		this.end.parentSegment.remove(this);
-		this.end = end;
-		end.parentSegment.add(this);
-	}
-	public Node getEnd() {
-		return end;
-	}
-
-	/**
-	 * The LineSegment is going to be destroyed. Unlink all back references.
-	 */
-	public void destroy() {
-		start.parentSegment.remove(this);
-		end.parentSegment.remove(this);
-	}
-
-	/**
-	 * Return start and end in a list.
-	 */
-	@Override
-	public Collection<Node> getAllNodes() {
-		LinkedList<Node> nodes = new LinkedList<Node>();
-		nodes.add(getStart());
-		nodes.add(getEnd());
-		return nodes;
 	}
 
Index: src/org/openstreetmap/josm/data/osm/Node.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Node.java	(revision 22)
+++ src/org/openstreetmap/josm/data/osm/Node.java	(revision 23)
@@ -1,7 +1,3 @@
 package org.openstreetmap.josm.data.osm;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
 
 import org.openstreetmap.josm.data.GeoPoint;
@@ -21,43 +17,4 @@
 	public GeoPoint coor;
 
-	/**
-	 * The list of line segments, this node is part of.
-	 */
-	transient Collection<LineSegment> parentSegment = new LinkedList<LineSegment>();
-
-	/**
-	 * Returns a read-only list of all segments this node is in.
-	 * @return A list of all segments. Readonly.
-	 */
-	public Collection<LineSegment> getParentSegments() {
-		return Collections.unmodifiableCollection(parentSegment);
-	}
-
-	/**
-	 * Merge the node given at parameter with this node.
-	 * All parents of the parameter-node become parents of this node.
-	 * 
-	 * The argument node is not changed.
-	 * 
-	 * @param node Merge the node to this.
-	 */
-	public void mergeFrom(Node node) {
-		parentSegment.addAll(node.parentSegment);
-		if (keys == null)
-			keys = node.keys;
-		else if (node.keys != null)
-			keys.putAll(node.keys);
-	}
-	
-	/**
-	 * Return a list only this added.
-	 */
-	@Override
-	public Collection<Node> getAllNodes() {
-		LinkedList<Node> nodes = new LinkedList<Node>();
-		nodes.add(this);
-		return nodes;
-	}
-
 	@Override
 	public void visit(Visitor visitor) {
Index: src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 22)
+++ src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 23)
@@ -1,5 +1,4 @@
 package org.openstreetmap.josm.data.osm;
 
-import java.util.Collection;
 import java.util.Map;
 
@@ -20,5 +19,12 @@
 	 */
 	public Map<Key, String> keys;
-	
+
+	/**
+	 * Unique identifier in OSM. This is used to reidentify objects in the server.
+	 * An id of 0 means an unknown id. The object has not been uploaded yet to 
+	 * know what id it will get.
+	 */
+	public long id = 0;
+
 	/**
 	 * If set to true, this object has been modified in the current session.
@@ -30,11 +36,4 @@
 	 */
 	transient private boolean selected = false;
-
-	/**
-	 * Return a list of all nodes, this osmPrimitive consists of. Does return
-	 * an empty list, if it is an primitive that cannot have nodes (e.g. Key)
-	 * TODO replace with visitor
-	 */
-	abstract public Collection<Node> getAllNodes();
 
 	/**
Index: src/org/openstreetmap/josm/data/osm/Track.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Track.java	(revision 22)
+++ src/org/openstreetmap/josm/data/osm/Track.java	(revision 23)
@@ -2,6 +2,4 @@
 
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 
@@ -18,5 +16,5 @@
 	 * All track segments in this track
 	 */
-	private final List<LineSegment> segments = new ArrayList<LineSegment>();
+	public final List<LineSegment> segments = new ArrayList<LineSegment>();
 
 	
@@ -26,65 +24,4 @@
 	public void add(LineSegment ls) {
 		segments.add(ls);
-		ls.parent.add(this);
-	}
-
-	/**
-	 * Add the line segment at first position to the track. First position means,
-	 * the line segment's start becomes the starting node.
-	 * @param ls The line segment to add at starting position.
-	 * @see #getStartingNode()
-	 */
-	public void addStart(LineSegment ls) {
-		segments.add(ls);
-		ls.parent.add(this);
-	}
-
-	/**
-	 * Add all LineSegment's to the list of segments. 
-	 * @param lineSegments The line segments to add.
-	 */
-	public void addAll(Collection<? extends LineSegment> lineSegments) {
-		segments.addAll(lineSegments);
-		for (LineSegment ls : lineSegments)
-			ls.parent.add(this);
-	}
-	
-	/**
-	 * Remove the line segment from the track.
-	 */
-	public void remove(LineSegment ls) {
-		if (segments.remove(ls))
-			if (!ls.parent.remove(this))
-				throw new IllegalStateException("Parent violation detected.");
-	}
-
-	/**
-	 * Return an read-only collection. Do not alter the object returned.
-	 * @return The read-only Collection of all segments.
-	 */
-	public Collection<LineSegment> segments() {
-		return Collections.unmodifiableCollection(segments);
-	}
-
-	/**
-	 * Return a merge of getAllNodes - calls to the line segments.
-	 */
-	@Override
-	public Collection<Node> getAllNodes() {
-		ArrayList<Node> nodes = new ArrayList<Node>();
-		for (LineSegment ls : segments)
-			nodes.addAll(ls.getAllNodes());
-		return nodes;
-	}
-	/**
-	 * The track is going to be destroyed. Unlink all back references.
-	 */
-	public void destroy() {
-		for (LineSegment ls : segments) {
-			ls.parent.remove(this);
-			if (ls.parent.isEmpty())
-				ls.destroy();
-		}
-		segments.clear();
 	}
 
@@ -101,5 +38,5 @@
 		if (segments.isEmpty())
 			return null;
-		return segments.get(segments.size()-1).getEnd();
+		return segments.get(segments.size()-1).end;
 	}
 	
@@ -126,5 +63,5 @@
 		if (segments.isEmpty())
 			return null;
-		return segments.get(0).getStart();
+		return segments.get(0).start;
 	}
 	
Index: src/org/openstreetmap/josm/data/osm/visitor/AllNodesVisitor.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/visitor/AllNodesVisitor.java	(revision 23)
+++ src/org/openstreetmap/josm/data/osm/visitor/AllNodesVisitor.java	(revision 23)
@@ -0,0 +1,63 @@
+package org.openstreetmap.josm.data.osm.visitor;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+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;
+
+/**
+ * Collect all nodes a specific osm primitive has.
+ * 
+ * @author imi
+ */
+public class AllNodesVisitor implements Visitor {
+
+	/**
+	 * The resulting nodes collected so far.
+	 */
+	public Collection<Node> nodes = new HashSet<Node>();
+
+	/**
+	 * Nodes have only itself as nodes.
+	 */
+	public void visit(Node n) {
+		nodes.add(n);
+	}
+
+	/**
+	 * Line segments have exactly two nodes: start and end.
+	 */
+	public void visit(LineSegment ls) {
+		nodes.add(ls.start);
+		nodes.add(ls.end);
+	}
+
+	/**
+	 * Tracks have all nodes from their line segments.
+	 */
+	public void visit(Track t) {
+		for (LineSegment ls : t.segments) {
+			nodes.add(ls.start);
+			nodes.add(ls.end);
+		}
+	}
+
+	/**
+	 * Keys have no nodes.
+	 */
+	public void visit(Key k) {
+	}
+
+	/**
+	 * @return All nodes the given primitive has.
+	 */
+	public static Collection<Node> getAllNodes(OsmPrimitive osm) {
+		AllNodesVisitor v = new AllNodesVisitor();
+		osm.visit(v);
+		return v.nodes;
+	}
+}
Index: src/org/openstreetmap/josm/data/osm/visitor/BoundingVisitor.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/visitor/BoundingVisitor.java	(revision 23)
+++ src/org/openstreetmap/josm/data/osm/visitor/BoundingVisitor.java	(revision 23)
@@ -0,0 +1,64 @@
+package org.openstreetmap.josm.data.osm.visitor;
+
+import org.openstreetmap.josm.data.Bounds;
+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;
+
+/**
+ * Calculates the total bounding rectangle of a serie of OsmPrimitives.
+ * @author imi
+ */
+public class BoundingVisitor implements Visitor {
+
+	/**
+	 * The bounding rectangle of all primitives visited so far.
+	 */
+	public Bounds bounds;
+
+	/**
+	 * Calculate regarding lat/lon or x/y?
+	 */
+	public static enum Type {LATLON, XY};
+	private Type type;
+	
+	
+	public BoundingVisitor(Type type) {
+		this.type = type;
+	}
+	
+
+	public void visit(Node n) {
+		if (bounds == null)
+			bounds = new Bounds(n.coor.clone(), n.coor.clone());
+		else {
+			if (type == Type.LATLON) {
+				bounds.min.lat = Math.min(bounds.min.lat, n.coor.lat);
+				bounds.min.lon = Math.min(bounds.min.lon, n.coor.lon);
+				bounds.max.lat = Math.max(bounds.max.lat, n.coor.lat);
+				bounds.max.lon = Math.max(bounds.max.lon, n.coor.lon);
+			} else {
+				bounds.min.x = Math.min(bounds.min.x, n.coor.x);
+				bounds.min.y = Math.min(bounds.min.y, n.coor.y);
+				bounds.max.x = Math.max(bounds.max.x, n.coor.x);
+				bounds.max.y = Math.max(bounds.max.y, n.coor.y);
+			}
+		}
+	}
+
+	public void visit(LineSegment ls) {
+		visit(ls.start);
+		visit(ls.end);
+	}
+
+	public void visit(Track t) {
+		for (LineSegment ls : t.segments)
+			visit(ls);
+	}
+
+	public void visit(Key k) {
+		// do nothing
+	}
+}
+
Index: src/org/openstreetmap/josm/data/osm/visitor/SelectionComponentVisitor.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/visitor/SelectionComponentVisitor.java	(revision 22)
+++ src/org/openstreetmap/josm/data/osm/visitor/SelectionComponentVisitor.java	(revision 23)
@@ -47,5 +47,5 @@
 		String name = getName(ls.keys);
 		if (name == null)
-			name = "("+ls.getStart().coor.lat+","+ls.getStart().coor.lon+") -> ("+ls.getEnd().coor.lat+","+ls.getEnd().coor.lon+")";
+			name = "("+ls.start.coor.lat+","+ls.start.coor.lon+") -> ("+ls.end.coor.lat+","+ls.end.coor.lon+")";
 			
 		this.name = name;
@@ -74,7 +74,7 @@
 		if (name == null) {
 			Set<Node> nodes = new HashSet<Node>();
-			for (LineSegment ls : t.segments()) {
-				nodes.add(ls.getStart());
-				nodes.add(ls.getEnd());
+			for (LineSegment ls : t.segments) {
+				nodes.add(ls.start);
+				nodes.add(ls.end);
 			}
 			name = "("+nodes.size()+" nodes)";
Index: src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java	(revision 23)
+++ src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java	(revision 23)
@@ -0,0 +1,130 @@
+package org.openstreetmap.josm.data.osm.visitor;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.util.Collection;
+
+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.Track;
+import org.openstreetmap.josm.gui.MapView;
+
+/**
+ * A visitor that paint a simple scheme of every primitive it visits to a 
+ * previous set graphic environment.
+ * 
+ * @author imi
+ */
+public class SimplePaintVisitor implements Visitor {
+
+	private final static Color darkblue = new Color(0,0,128);
+	private final static Color darkgreen = new Color(0,128,0);
+
+	/**
+	 * The environment to paint to.
+	 */
+	private final Graphics g;
+	/**
+	 * MapView to get screen coordinates.
+	 */
+	private final MapView mv;
+	/**
+	 * Can be set to non-<code>null</code> and then replace every other color.
+	 */
+	private final Color forceColor;
+	
+	/**
+	 * Construct the painter visitor.
+	 * @param g   The graphics to draw to.
+	 * @param mv  The view to get screen coordinates from.
+	 * @param forceColor If non-<code>null</code>, always draw with this color.
+	 */
+	public SimplePaintVisitor(Graphics g, MapView mv, Color forceColor) {
+		this.g = g;
+		this.mv = mv;
+		this.forceColor = forceColor;
+	}
+	
+	/**
+	 * 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 = Main.main.ds.nodeLsRef.get(n);
+		if (lineSegments == null || lineSegments.isEmpty()) {
+			drawNode(n, Color.YELLOW); // single waypoint only
+			return;
+		}
+
+		Collection<Track> tracks = Main.main.ds.nodeTrackRef.get(n);
+		if (tracks == null || 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.start || n == ls.end)
+				++segmentUsed;
+		drawNode(n, segmentUsed > 1 ? darkblue : Color.RED);
+	}
+
+	public void visit(LineSegment ls) {
+		if (forceColor != null)
+			g.setColor(forceColor);
+		else if (ls.isSelected())
+			g.setColor(Color.WHITE);
+		else if (Main.main.ds.pendingLineSegments.contains(ls))
+			g.setColor(darkgreen);
+		else
+			g.setColor(darkblue);
+		Point p1 = mv.getScreenPoint(ls.start.coor);
+		Point p2 = mv.getScreenPoint(ls.end.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)
+			visit(ls);
+	}
+
+	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(forceColor != null ? forceColor : color);
+		g.drawRect(p.x-1, p.y-1, 2, 2);
+	}
+}
Index: src/org/openstreetmap/josm/data/projection/Projection.java
===================================================================
--- src/org/openstreetmap/josm/data/projection/Projection.java	(revision 22)
+++ src/org/openstreetmap/josm/data/projection/Projection.java	(revision 23)
@@ -8,4 +8,5 @@
 import javax.swing.event.ChangeListener;
 
+import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.GeoPoint;
 
@@ -70,5 +71,5 @@
 
 	/**
-	 * Initialize itself with the given dataSet.
+	 * Initialize itself with the given bounding rectangle (regarding lat/lon).
 	 * 
 	 * This function should initialize own parameters needed to do the
@@ -81,5 +82,5 @@
 	 * to initialize their data members.
 	 */
-	public void init() {}
+	public void init(Bounds b) {}
 	
 	/**
Index: src/org/openstreetmap/josm/data/projection/UTM.java
===================================================================
--- src/org/openstreetmap/josm/data/projection/UTM.java	(revision 22)
+++ src/org/openstreetmap/josm/data/projection/UTM.java	(revision 23)
@@ -186,5 +186,5 @@
 	 * @author imi
 	 */
-	private class ZoneData {
+	private static class ZoneData {
 		int zone = 0;
 		Hemisphere hemisphere = Hemisphere.north;
@@ -194,8 +194,6 @@
 	 * @return The zone data extrakted from the dataset.
 	 */
-	ZoneData autoDetect() {
+	ZoneData autoDetect(Bounds b) {
 		ZoneData zd = new ZoneData();
-		
-		Bounds b = Main.main.ds.getBoundsLatLon();
 		if (b == null)
 			return zd;
@@ -232,7 +230,7 @@
 	 */
 	@Override
-	public void init() {
+	public void init(Bounds b) {
 		if (zone == 0) {
-			ZoneData zd = autoDetect();
+			ZoneData zd = autoDetect(b);
 			zone = zd.zone;
 			hemisphere = zd.hemisphere;
@@ -272,5 +270,5 @@
 			public void actionPerformed(ActionEvent e) {
 				if (Main.main.getMapFrame() != null) {
-					ZoneData zd = autoDetect();
+					ZoneData zd = autoDetect(Main.main.ds.getBoundsLatLon());
 					if (zd.zone == 0)
 						JOptionPane.showMessageDialog(Main.main, "Autodetection failed. Maybe the data set contain too few information.");
Index: src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapView.java	(revision 22)
+++ src/org/openstreetmap/josm/gui/MapView.java	(revision 23)
@@ -18,5 +18,4 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.DataSet;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.GeoPoint;
@@ -26,4 +25,5 @@
 import org.openstreetmap.josm.data.osm.Track;
 import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.gui.layer.EditLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
 
@@ -72,4 +72,8 @@
 	private ArrayList<Layer> layers = new ArrayList<Layer>();
 	/**
+	 * Direct link to the edit layer (if any) in the layers list.
+	 */
+	private EditLayer editLayer;
+	/**
 	 * The layer from the layers list that is currently active.
 	 */
@@ -98,7 +102,4 @@
 		addLayer(layer);
 		Main.pref.addPropertyChangeListener(this);
-
-		// init screen
-		recalculateCenterScale();
 	}
 
@@ -108,15 +109,21 @@
 	 */
 	public void addLayer(Layer layer) {
+		if (layer instanceof EditLayer) {
+			if (editLayer != null) {
+				// there can only be one EditLayer
+				editLayer.mergeFrom(layer);
+				return;
+			}
+			editLayer = (EditLayer)layer;
+		}
+		
 		layers.add(0,layer);
 
-		if (layer.dataSet != null) {
-			// initialize the projection if it was the first layer
-			if (layers.size() == 1)
-				Main.pref.getProjection().init();
-			
-			// initialize the dataset in the new layer
-			for (Node n : layer.dataSet.nodes)
-				Main.pref.getProjection().latlon2xy(n.coor);
-		}
+		// initialize the projection if it is the first layer
+		if (layers.size() == 1)
+			Main.pref.getProjection().init(layer.getBoundsLatLon());
+
+		// reinitialize layer's data
+		layer.init(Main.pref.getProjection());
 
 		for (LayerChangeListener l : listeners)
@@ -125,5 +132,5 @@
 		setActiveLayer(layer);
 	}
-	
+
 	/**
 	 * Remove the layer from the mapview. If the layer was in the list before,
@@ -239,7 +246,7 @@
 		
 		// pending line segments
-		for (LineSegment ls : Main.main.ds.pendingLineSegments()) {
-			Point A = getScreenPoint(ls.getStart().coor);
-			Point B = getScreenPoint(ls.getEnd().coor);
+		for (LineSegment ls : Main.main.ds.pendingLineSegments) {
+			Point A = getScreenPoint(ls.start.coor);
+			Point B = getScreenPoint(ls.end.coor);
 			double c = A.distanceSq(B);
 			double a = p.distanceSq(B);
@@ -254,8 +261,8 @@
 		// tracks & line segments
 		minDistanceSq = Double.MAX_VALUE;
-		for (Track t : Main.main.ds.tracks()) {
-			for (LineSegment ls : t.segments()) {
-				Point A = getScreenPoint(ls.getStart().coor);
-				Point B = getScreenPoint(ls.getEnd().coor);
+		for (Track t : Main.main.ds.tracks) {
+			for (LineSegment ls : t.segments) {
+				Point A = getScreenPoint(ls.start.coor);
+				Point B = getScreenPoint(ls.end.coor);
 				double c = A.distanceSq(B);
 				double a = p.distanceSq(B);
@@ -323,10 +330,6 @@
 		// reset all datasets.
 		Projection p = Main.pref.getProjection();
-		for (Layer l : layers) {
-			DataSet ds = l.dataSet;
-			if (ds != null)
-				for (Node n : ds.nodes)
-					p.latlon2xy(n.coor);
-		}
+		for (Node n : Main.main.ds.nodes)
+			p.latlon2xy(n.coor);
 		recalculateCenterScale();
 	}
@@ -399,6 +402,12 @@
 				h = 20;
 			
-			Bounds bounds = Main.main.ds.getBoundsXY();
-			
+			Bounds bounds = null;
+			for (Layer l : layers) {
+				if (bounds == null)
+					bounds = l.getBoundsXY();
+				else
+					bounds = bounds.mergeXY(l.getBoundsXY());
+			}
+
 			boolean oldAutoScale = autoScale;
 			GeoPoint oldCenter = center;
@@ -460,6 +469,4 @@
 		activeLayer = layer;
 		if (old != layer) {
-			if (old != null && old.dataSet != null)
-				old.dataSet.clearSelection();
 			for (LayerChangeListener l : listeners)
 				l.activeLayerChange(old, layer);
@@ -474,3 +481,13 @@
 		return activeLayer;
 	}
+
+	/**
+	 * @return The current edit layer. If no edit layer exist, one is created.
+	 * 		So editLayer does never return <code>null</code>.
+	 */
+	public EditLayer editLayer() {
+		if (editLayer == null)
+			addLayer(new EditLayer(this));
+		return editLayer;
+	}
 }
Index: src/org/openstreetmap/josm/gui/PreferenceDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/PreferenceDialog.java	(revision 22)
+++ src/org/openstreetmap/josm/gui/PreferenceDialog.java	(revision 23)
@@ -62,4 +62,5 @@
 			Main.pref.setDrawRawGpsLines(drawRawGpsLines.isSelected());
 			Main.pref.setForceRawGpsLines(forceRawGpsLines.isSelected());
+			Main.pref.setDrawDeleted(drawDeleted.isSelected());
 			try {
 				Main.pref.save();
@@ -125,4 +126,8 @@
 	 */
 	JCheckBox forceRawGpsLines = new JCheckBox("Force lines if no line segments imported.");
+	/**
+	 * The checkbox stating whether deleted nodes should be drawn.
+	 */
+	JCheckBox drawDeleted = new JCheckBox("Draw deleted lines.");
 	/**
 	 * The checkbox stating whether nodes should be merged together.
@@ -198,4 +203,6 @@
 		forceRawGpsLines.setSelected(Main.pref.isForceRawGpsLines());
 		forceRawGpsLines.setEnabled(drawRawGpsLines.isSelected());
+		drawDeleted.setToolTipText("Draw dark hints where objects were deleted.");
+		drawDeleted.setSelected(Main.pref.isDrawDeleted());
 		mergeNodes.setToolTipText("When importing GPX data, all nodes with exact the same lat/lon are merged.");
 		mergeNodes.setSelected(Main.pref.mergeNodes);
@@ -212,4 +219,5 @@
 		display.add(drawRawGpsLines, GBC.eol().insets(20,0,0,0));
 		display.add(forceRawGpsLines, GBC.eol().insets(40,0,0,0));
+		display.add(drawDeleted, GBC.eol().insets(20,0,0,0));
 		display.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
 
Index: src/org/openstreetmap/josm/gui/SelectionManager.java
===================================================================
--- src/org/openstreetmap/josm/gui/SelectionManager.java	(revision 22)
+++ src/org/openstreetmap/josm/gui/SelectionManager.java	(revision 23)
@@ -278,12 +278,12 @@
 			
 			// pending line segments
-			for (LineSegment ls : Main.main.ds.pendingLineSegments())
+			for (LineSegment ls : Main.main.ds.pendingLineSegments)
 				if (rectangleContainLineSegment(r, alt, ls))
 					selection.add(ls);
 
 			// tracks
-			for (Track t : Main.main.ds.tracks()) {
-				boolean wholeTrackSelected = !t.segments().isEmpty();
-				for (LineSegment ls : t.segments())
+			for (Track t : Main.main.ds.tracks) {
+				boolean wholeTrackSelected = !t.segments.isEmpty();
+				for (LineSegment ls : t.segments)
 					if (rectangleContainLineSegment(r, alt, ls))
 						selection.add(ls);
@@ -310,11 +310,11 @@
 	private boolean rectangleContainLineSegment(Rectangle r, boolean alt, LineSegment ls) {
 		if (alt) {
-			Point p1 = mv.getScreenPoint(ls.getStart().coor);
-			Point p2 = mv.getScreenPoint(ls.getEnd().coor);
+			Point p1 = mv.getScreenPoint(ls.start.coor);
+			Point p2 = mv.getScreenPoint(ls.end.coor);
 			if (r.intersectsLine(p1.x, p1.y, p2.x, p2.y))
 				return true;
 		} else {
-			if (r.contains(mv.getScreenPoint(ls.getStart().coor))
-					&& r.contains(mv.getScreenPoint(ls.getEnd().coor)))
+			if (r.contains(mv.getScreenPoint(ls.start.coor))
+					&& r.contains(mv.getScreenPoint(ls.end.coor)))
 				return true;
 		}
Index: src/org/openstreetmap/josm/gui/dialogs/LayerList.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/LayerList.java	(revision 22)
+++ src/org/openstreetmap/josm/gui/dialogs/LayerList.java	(revision 23)
@@ -8,5 +8,4 @@
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
-import java.io.IOException;
 import java.util.Collection;
 
@@ -17,5 +16,4 @@
 import javax.swing.JLabel;
 import javax.swing.JList;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
@@ -26,5 +24,4 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.DataSet;
 import org.openstreetmap.josm.gui.ImageProvider;
 import org.openstreetmap.josm.gui.MapFrame;
@@ -32,5 +29,4 @@
 import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
 import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.io.OsmWriter;
 
 /**
@@ -72,8 +68,4 @@
 	 */
 	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"));
 
 	/**
@@ -96,10 +88,5 @@
 					icon = ImageProvider.overlay(icon, invisible, ImageProvider.OverlayPosition.SOUTHEAST);
 				label.setIcon(icon);
-
-				DataSet ds = layer.dataSet;
-				if (ds != null) {
-					label.setToolTipText(ds.nodes.size()+" nodes, "+
-							ds.tracks().size()+" tracks");
-				}
+				label.setToolTipText(layer.getToolTipText());
 				return label;
 			}
@@ -182,8 +169,6 @@
 			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);
+				lTo.mergeFrom(lFrom);
 				layers.setSelectedValue(lTo, true);
 				mapView.removeLayer(lFrom);
@@ -192,18 +177,4 @@
 		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(uploadButton);
-		
 		add(buttonPanel, BorderLayout.SOUTH);
 		
@@ -219,7 +190,5 @@
 		boolean enable = model.getSize() > 1;
 		enable = enable && sel < model.getSize()-1;
-		enable = enable && l.dataSet != null;
-		enable = enable && ((Layer)model.get(sel+1)).dataSet != null;
-		enable = enable && l.isEditable() == ((Layer)model.get(sel+1)).isEditable();
+		enable = enable && l.isMergable((Layer)model.get(sel+1));
 		mergeButton.setEnabled(enable);
 		upButton.setEnabled(sel > 0);
Index: src/org/openstreetmap/josm/gui/layer/EditLayer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/EditLayer.java	(revision 23)
+++ src/org/openstreetmap/josm/gui/layer/EditLayer.java	(revision 23)
@@ -0,0 +1,197 @@
+package org.openstreetmap.josm.gui.layer;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+
+import javax.swing.Icon;
+import javax.swing.SwingUtilities;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
+import org.openstreetmap.josm.data.osm.visitor.BoundingVisitor;
+import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor;
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.gui.ImageProvider;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
+
+/**
+ * The layer that contain all editing commands in the current session. All commands
+ * are saved here. The command actions "move" data from the data layer to this 
+ * layer (by just removing them from the data layer) for all edited data, so 
+ * invisible this layer will actually invisible all changes made to the data set.
+ * 
+ * There may only be one EditLayer per MapView.
+ * 
+ * Only EditLayers can be uploaded to the server.
+ */
+public class EditLayer extends Layer implements LayerChangeListener, PropertyChangeListener {
+
+	private static Icon icon;
+
+	/**
+	 * All commands that were made on the dataset.
+	 */
+	public Collection<Command> commands = new LinkedList<Command>();
+
+	/**
+	 * The map view this layer belongs to.
+	 */
+	private final MapView mv;
+
+	/**
+	 * Create an initial empty edit layer.
+	 * @param mv The mapview that emits layer change events.
+	 */
+	public EditLayer(final MapView mv) {
+		super("not uploaded changes");
+		this.mv = mv;
+		mv.addLayerChangeListener(this);
+		Main.pref.addPropertyChangeListener(this);
+	}
+
+
+	/**
+	 * Paint all changes in the changes list.
+	 * @param g
+	 * @param mv
+	 */
+	@Override
+	public void paint(Graphics g, MapView mv) {
+		LinkedList<OsmPrimitive> changes = new LinkedList<OsmPrimitive>();
+		LinkedList<OsmPrimitive> deleted = new LinkedList<OsmPrimitive>();
+		for (Command c : commands)
+			c.fillModifiedData(changes, deleted, changes);
+
+		SimplePaintVisitor visitor = new SimplePaintVisitor(g, mv, null);
+		SimplePaintVisitor deletedvisitor = new SimplePaintVisitor(g, mv, Color.DARK_GRAY);
+
+		changes.removeAll(deleted);
+
+		// first draw deleted objects in dark gray
+		if (Main.pref.isDrawDeleted())
+			for (OsmPrimitive osm : deleted)
+				osm.visit(deletedvisitor);
+		// next draw the tracks (and line segments)
+		for (OsmPrimitive osm : changes)
+			if (!(osm instanceof Node))
+				osm.visit(visitor);
+		// now draw the remaining objects
+		for (OsmPrimitive osm : changes)
+			if (osm instanceof Node)
+				osm.visit(visitor);
+		
+	}
+
+	@Override
+	public Icon getIcon() {
+		if (icon == null)
+			icon = ImageProvider.get("layer", "edit");
+		return icon;
+	}
+
+	@Override
+	public String getToolTipText() {
+		return commands.size()+" changes";
+	}
+
+	@Override
+	public void mergeFrom(Layer from) {
+		EditLayer edit = (EditLayer)from;
+		commands.addAll(edit.commands);
+	}
+
+	@Override
+	public boolean isMergable(Layer other) {
+		return other instanceof EditLayer;
+	}
+
+	@Override
+	public Bounds getBoundsLatLon() {
+		LinkedList<OsmPrimitive> data = new LinkedList<OsmPrimitive>();
+		for (Command c : commands)
+			c.fillModifiedData(data, null, data); // all in one list
+		BoundingVisitor b = new BoundingVisitor(BoundingVisitor.Type.LATLON);
+		for (OsmPrimitive osm : data)
+			osm.visit(b);
+		return b.bounds;
+	}
+
+	@Override
+	public Bounds getBoundsXY() {
+		LinkedList<OsmPrimitive> data = new LinkedList<OsmPrimitive>();
+		for (Command c : commands)
+			c.fillModifiedData(data, null, data); // all in one list
+		BoundingVisitor b = new BoundingVisitor(BoundingVisitor.Type.XY);
+		for (OsmPrimitive osm : data)
+			osm.visit(b);
+		return b.bounds;
+	}
+
+	@Override
+	public void init(Projection projection) {
+		LinkedList<OsmPrimitive> data = new LinkedList<OsmPrimitive>();
+		for (Command c : commands)
+			c.fillModifiedData(data, data, data); // all in one list
+		for (OsmPrimitive osm : data)
+			for (Node n : AllNodesVisitor.getAllNodes(osm))
+				projection.latlon2xy(n.coor);
+	}
+	
+	/**
+	 * 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) {
+		c.executeCommand();
+		Collection<OsmPrimitive> data = new HashSet<OsmPrimitive>();
+		c.fillModifiedData(data, data, data);
+		for (OsmPrimitive osm : data)
+			osm.modified = true;
+		commands.add(c);
+	}
+
+	/**
+	 * Clean up the data and remove itself from the map view after
+	 * the notifications ended.
+	 */
+	public void layerRemoved(Layer oldLayer) {
+		if (oldLayer == EditLayer.this) {
+			Collection<OsmPrimitive> data = new HashSet<OsmPrimitive>();
+			for (Command c : commands)
+				c.fillModifiedData(data, data, data);
+			for (OsmPrimitive osm : data)
+				osm.modified = false;
+			commands.clear();
+			SwingUtilities.invokeLater(new Runnable(){
+				public void run() {
+					mv.removeLayerChangeListener(EditLayer.this);
+				}
+			});
+		}
+	}
+	
+	/**
+	 * Does nothing. Only to satisfy LayerChangeListener
+	 */
+	public void activeLayerChange(Layer oldLayer, Layer newLayer) {}
+	/**
+	 * Does nothing. Only to satisfy LayerChangeListener
+	 */
+	public void layerAdded(Layer newLayer) {}
+
+
+	public void propertyChange(PropertyChangeEvent evt) {
+		if (evt.getPropertyName().equals("drawDeleted"))
+			mv.repaint();
+	}
+}
Index: src/org/openstreetmap/josm/gui/layer/Layer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 22)
+++ src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 23)
@@ -5,4 +5,6 @@
 import javax.swing.Icon;
 
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.gui.MapView;
 
@@ -32,5 +34,5 @@
 	 */
 	public final String name;
-	
+
 	/**
 	 * Create the layer and fill in the necessary components.
@@ -52,8 +54,40 @@
 
 	/**
-	 * @return <code>true</code>, if the map data can be edited.
+	 * @return A small tooltip hint about some statistics for this layer.
 	 */
-	public boolean isEditable() {
-		return false;
-	}
+	abstract public String getToolTipText();
+
+	/**
+	 * Merges the given layer into this layer. Throws if the layer types are
+	 * incompatible.
+	 * @param from The layer that get merged into this one. After the merge,
+	 * 		the other layer is not usable anymore and passing to one others
+	 * 		mergeFrom should be one of the last things to do with a layer.
+	 */
+	abstract public void mergeFrom(Layer from);
+	
+	/**
+	 * @param other The other layer that is tested to be mergable with this.
+	 * @return Whether the other layer can be merged into this layer.
+	 */
+	abstract public boolean isMergable(Layer other);
+	
+	/**
+	 * @return The bounding rectangle this layer occupies on screen when looking
+	 * 		at lat/lon values or <code>null</code>, if infinite area or unknown
+	 * 		area is occupied.
+	 */
+	abstract public Bounds getBoundsLatLon();
+	
+	/**
+	 * @return The bounding rectangle this layer occupies on screen when looking
+	 * 		at x/y values or <code>null</code>, if infinite area or unknown
+	 * 		area is occupied.
+	 */
+	abstract public Bounds getBoundsXY();
+
+	/**
+	 * Initialize the internal dataset with the given projection.
+	 */
+	abstract public void init(Projection projection);
 }
Index: src/org/openstreetmap/josm/gui/layer/LayerFactory.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/LayerFactory.java	(revision 22)
+++ 	(revision )
@@ -1,24 +1,0 @@
-package org.openstreetmap.josm.gui.layer;
-
-import org.openstreetmap.josm.command.DataSet;
-
-/**
- * A factory class that create Layers.
- *
- * @author imi
- */
-public class LayerFactory {
-
-	/**
-	 * Create a layer from a given DataSet. The DataSet cannot change over the
-	 * layers lifetime (but the data in the dataset may change)
-	 * 
-	 * @param dataSet The dataSet this layer displays.
-	 * @param rawGps  <code>true</code>, if the dataSet contain raw gps data.
-	 * @return The created layer instance. 
-	 */
-	public static Layer create(DataSet dataSet, String name, boolean rawGps) {
-		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 22)
+++ src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 23)
@@ -1,19 +1,16 @@
 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.Main;
-import org.openstreetmap.josm.data.osm.Key;
-import org.openstreetmap.josm.data.osm.LineSegment;
+import org.openstreetmap.josm.data.Bounds;
 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.data.osm.visitor.AllNodesVisitor;
+import org.openstreetmap.josm.data.osm.visitor.BoundingVisitor;
+import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor;
+import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.gui.ImageProvider;
 import org.openstreetmap.josm.gui.MapView;
@@ -26,9 +23,7 @@
  * @author imi
  */
-public class OsmDataLayer extends Layer implements Visitor {
+public class OsmDataLayer extends Layer {
 
 	private static Icon icon;
-	private final static Color darkblue = new Color(0,0,128);
-	private final static Color darkgreen = new Color(0,128,0);
 
 	/**
@@ -38,16 +33,7 @@
 
 	/**
-	 * 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(Collection<OsmPrimitive> data, String name) {
+	public OsmDataLayer(Collection<OsmPrimitive> data, String name) {
 		super(name);
 		this.data = data;
@@ -65,92 +51,58 @@
 	}
 
+	/**
+	 * Draw all primitives in this layer but do not draw modified ones (they
+	 * are drawn by the edit layer).
+	 * Draw nodes last to overlap the line segments they belong to.
+	 */
 	@Override
-	public boolean isEditable() {
-		return true;
+	public void paint(Graphics g, MapView mv) {
+		SimplePaintVisitor visitor = new SimplePaintVisitor(g, mv, null);
+		// first draw the tracks (and line segments)
+		for (OsmPrimitive osm : data)
+			if (!osm.modified && !(osm instanceof Node))
+				osm.visit(visitor);
+		for (OsmPrimitive osm : data)
+			if (!osm.modified && osm instanceof Node)
+				osm.visit(visitor);
 	}
 
 	@Override
-	public void paint(Graphics g, MapView mv) {
-		this.mv = mv;
-		this.g = g;
-		for (OsmPrimitive osm : data)
-			osm.visit(this);
+	public String getToolTipText() {
+		return data.size()+" primitives.";
 	}
 
-	/**
-	 * 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);
+	@Override
+	public void mergeFrom(Layer from) {
+		OsmDataLayer layer = (OsmDataLayer)from;
+		data.addAll(layer.data);
 	}
 
-	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);
+	@Override
+	public boolean isMergable(Layer other) {
+		return other instanceof OsmDataLayer;
 	}
 
-	/**
-	 * 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);
+	@Override
+	public Bounds getBoundsLatLon() {
+		BoundingVisitor b = new BoundingVisitor(BoundingVisitor.Type.LATLON);
+		for (OsmPrimitive osm : data)
+			osm.visit(b);
+		return b.bounds;
 	}
 
-	public void visit(Key k) {
+	@Override
+	public Bounds getBoundsXY() {
+		BoundingVisitor b = new BoundingVisitor(BoundingVisitor.Type.XY);
+		for (OsmPrimitive osm : data)
+			osm.visit(b);
+		return b.bounds;
 	}
-	
-	/**
-	 * 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);
+
+	@Override
+	public void init(Projection projection) {
+		for (OsmPrimitive osm : data)
+			for (Node n : AllNodesVisitor.getAllNodes(osm))
+				projection.latlon2xy(n.coor);
 	}
 }
Index: src/org/openstreetmap/josm/gui/layer/RawGpsDataLayer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/RawGpsDataLayer.java	(revision 22)
+++ src/org/openstreetmap/josm/gui/layer/RawGpsDataLayer.java	(revision 23)
@@ -1,8 +1,19 @@
 package org.openstreetmap.josm.gui.layer;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Collection;
 
 import javax.swing.Icon;
 
-import org.openstreetmap.josm.command.DataSet;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.GeoPoint;
+import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.gui.ImageProvider;
+import org.openstreetmap.josm.gui.MapView;
 
 /**
@@ -16,6 +27,23 @@
 	private static Icon icon;
 
-	protected RawGpsDataLayer(DataSet dataSet, String name) {
+	/**
+	 * A list of tracks which containing a list of points.
+	 */
+	private final Collection<Collection<GeoPoint>> data;
+
+	public RawGpsDataLayer(Collection<Collection<GeoPoint>> data, String name) {
 		super(name);
+		this.data = data;
+		Main.pref.addPropertyChangeListener(new PropertyChangeListener(){
+			public void propertyChange(PropertyChangeEvent evt) {
+				if (Main.main.getMapFrame() == null) {
+					Main.pref.removePropertyChangeListener(this);
+					return;
+				}
+				if (evt.getPropertyName().equals("drawRawGpsLines") ||
+						evt.getPropertyName().equals("drawRawGpsLines"))
+					Main.main.getMapFrame().repaint();
+			}
+		});
 	}
 
@@ -29,3 +57,89 @@
 		return icon;
 	}
+
+	@Override
+	public void paint(Graphics g, MapView mv) {
+		g.setColor(Color.GRAY);
+		Point old = null;
+		for (Collection<GeoPoint> c : data) {
+			if (!Main.pref.isForceRawGpsLines())
+				old = null;
+			for (GeoPoint p : c) {
+				Point screen = mv.getScreenPoint(p);
+				if (Main.pref.isDrawRawGpsLines() && old != null) {
+					g.drawLine(old.x, old.y, screen.x, screen.y);
+				} else {
+					g.drawRect(screen.x, screen.y, 0, 0);
+					old = screen;
+				}
+			}
+		}
+	}
+
+	@Override
+	public String getToolTipText() {
+		return data.size()+" tracks.";
+	}
+
+	@Override
+	public void mergeFrom(Layer from) {
+		RawGpsDataLayer layer = (RawGpsDataLayer)from;
+		data.addAll(layer.data);
+	}
+
+	@Override
+	public boolean isMergable(Layer other) {
+		return other instanceof RawGpsDataLayer;
+	}
+
+	@Override
+	public Bounds getBoundsLatLon() {
+		GeoPoint min = null;
+		GeoPoint max = null;
+		for (Collection<GeoPoint> c : data) {
+			for (GeoPoint p : c) {
+				if (min == null) {
+					min = p.clone();
+					max = p.clone();
+				} else {
+					min.lat = Math.min(min.lat, p.lat);
+					min.lon = Math.min(min.lon, p.lon);
+					max.lat = Math.max(max.lat, p.lat);
+					max.lon = Math.max(max.lon, p.lon);
+				}
+			}
+		}
+		if (min == null)
+			return null;
+		return new Bounds(min, max);
+	}
+
+	@Override
+	public Bounds getBoundsXY() {
+		GeoPoint min = null;
+		GeoPoint max = null;
+		for (Collection<GeoPoint> c : data) {
+			for (GeoPoint p : c) {
+				if (min == null) {
+					min = p.clone();
+					max = p.clone();
+				} else {
+					min.x = Math.min(min.x, p.x);
+					min.y = Math.min(min.y, p.y);
+					max.x = Math.max(max.x, p.x);
+					max.y = Math.max(max.y, p.y);
+				}
+			}
+		}
+		if (min == null)
+			return null;
+		return new Bounds(min, max);
+	}
+
+	@Override
+	public void init(Projection projection) {
+		for (Collection<GeoPoint> c : data)
+			for (GeoPoint p : c)
+				projection.latlon2xy(p);
+	}
 }
Index: src/org/openstreetmap/josm/io/DataReader.java
===================================================================
--- src/org/openstreetmap/josm/io/DataReader.java	(revision 22)
+++ 	(revision )
@@ -1,49 +1,0 @@
-package org.openstreetmap.josm.io;
-
-import org.openstreetmap.josm.command.DataSet;
-
-/**
- * All Classes that subclass DataReader are capable of importing data from a source
- * to a DataSet.
- *
- * @author imi
- */
-public interface DataReader {
-	
-	/**
-	 * Thrown from the parse command in case of parsing problems.
-	 * @author imi
-	 */
-	public class ParseException extends Exception {
-		public ParseException(String message, Throwable cause) {
-			super(message, cause);
-		}
-		public ParseException(String message) {
-			super(message);
-		}
-	}
-	/**
-	 * Thrown from the parse command in case of other problems like connection
-	 * failed or a file could not be read.
-	 * @author imi
-	 */
-	public class ConnectionException extends Exception {
-		public ConnectionException(String message, Throwable cause) {
-			super(message, cause);
-		}
-		public ConnectionException(String message) {
-			super(message);
-		}
-	}
-
-	/**
-	 * Called to parse the source and return the dataset.
-	 * @return The dataSet parsed.
-	 * @throws DataParseException The data is ill-formated. The data could be
-	 * 		retrieved but it contain errors that could not be handled.
-	 * @throws ConnectionException A problem with the connection to the data source
-	 * 		occoured. As example, the file could not be read or the server
-	 * 		does not repsonse
-	 */
-	public DataSet parse() throws ParseException, ConnectionException; 
-}
Index: src/org/openstreetmap/josm/io/GpxReader.java
===================================================================
--- src/org/openstreetmap/josm/io/GpxReader.java	(revision 22)
+++ src/org/openstreetmap/josm/io/GpxReader.java	(revision 23)
@@ -10,6 +10,6 @@
 import org.jdom.input.SAXBuilder;
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.DataSet;
 import org.openstreetmap.josm.data.GeoPoint;
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Key;
 import org.openstreetmap.josm.data.osm.LineSegment;
@@ -25,10 +25,10 @@
  * @author imi
  */
-public class GpxReader implements DataReader {
+public class GpxReader {
 
 	/**
 	 * The GPX namespace used.
 	 */
-	private static Namespace GPX = Namespace.getNamespace("http://www.topografix.com/GPX/1/0");
+	public static final Namespace GPX = Namespace.getNamespace("http://www.topografix.com/GPX/1/0");
 	/**
 	 * The OSM namespace used (for extensions).
@@ -40,21 +40,11 @@
 	 */
 	public Reader source;
-	/**
-	 * If <code>true</code>, only nodes and tracks are imported (but no key/value
-	 * pairs). That is to support background gps information as an hint for 
-	 * real OSM data.
-	 */
-	private final boolean rawGps;
 	
 	/**
 	 * Construct a parser from a specific data source.
 	 * @param source The data source, as example a FileReader to read from a file.
-	 * @param rawGps Whether the gpx file describes raw gps data. Only very few
-	 * 		information (only nodes and line segments) imported for raw gps to 
-	 * 		save memory.
-	 */
-	public GpxReader(Reader source, boolean rawGps) {
+	 */
+	public GpxReader(Reader source) {
 		this.source = source;
-		this.rawGps = rawGps;
 	}
 	
@@ -62,22 +52,13 @@
 	 * Read the input stream and return a DataSet from the stream.
 	 */
-	public DataSet parse() throws ParseException, ConnectionException {
+	public DataSet parse() throws JDOMException, IOException {
 		try {
 			final SAXBuilder builder = new SAXBuilder();
 			Element root = builder.build(source).getRootElement();
-			
-			// HACK, since the osm server seem to not provide a namespace.
-			if (root.getNamespacePrefix().equals(""))
-				GPX = null;
-			
 			return parseDataSet(root);
 		} catch (NullPointerException npe) {
-			throw new ParseException("NullPointerException. Probably a tag name mismatch.", npe);
+			throw new JDOMException("NullPointerException. Probably a tag name mismatch.", npe);
 		} catch (ClassCastException cce) {
-			throw new ParseException("ClassCastException. Probably a tag does not contain the correct type.", cce);
-		} catch (JDOMException e) {
-			throw new ParseException("The data could not be parsed. Reason: "+e.getMessage(), e);
-		} catch (IOException e) {
-			throw new ConnectionException("The data could not be retrieved. Reason: "+e.getMessage(), e);
+			throw new JDOMException("ClassCastException. Probably a tag does not contain the correct type.", cce);
 		}
 	}
@@ -94,7 +75,4 @@
 			Float.parseFloat(e.getAttributeValue("lat")),
 			Float.parseFloat(e.getAttributeValue("lon")));
-		
-		if (rawGps)
-			return data;
 		
 		for (Object o : e.getChildren()) {
@@ -149,6 +127,5 @@
 					else {
 						LineSegment lineSegment = new LineSegment(start, node);
-						if (!rawGps)
-							parseKeyValueExtensions(lineSegment, ((Element)w).getChild("extensions", GPX));
+						parseKeyValueExtensions(lineSegment, ((Element)w).getChild("extensions", GPX));
 						track.add(lineSegment);
 						start = null;
@@ -156,7 +133,4 @@
 				}
 			}
-			
-			if (rawGps)
-				continue;
 			
 			if (child.getName().equals("extensions"))
@@ -167,5 +141,5 @@
 				parseKeyValueTag(track, child);
 		}
-		ds.addTrack(track);
+		ds.tracks.add(track);
 	}
 	
@@ -184,5 +158,5 @@
 	 */
 	private Node addNode (DataSet data, Node node) {
-		if (Main.pref.mergeNodes || rawGps)
+		if (Main.pref.mergeNodes)
 			for (Node n : data.nodes)
 				if (node.coor.equalsLatLon(n.coor))
Index: src/org/openstreetmap/josm/io/GpxWriter.java
===================================================================
--- src/org/openstreetmap/josm/io/GpxWriter.java	(revision 22)
+++ src/org/openstreetmap/josm/io/GpxWriter.java	(revision 23)
@@ -85,5 +85,5 @@
 
 		// tracks
-		for (Track t : Main.main.ds.tracks()) {
+		for (Track t : Main.main.ds.tracks) {
 			Element tElem = new Element("trk", GPX);
 			if (t.keys != null) {
@@ -99,12 +99,12 @@
 			}
 			// line segments
-			for (LineSegment ls : t.segments()) {
+			for (LineSegment ls : t.segments) {
 				Element lsElem = new Element("trkseg", GPX);
 				if (ls.keys != null)
 				addPropertyExtensions(lsElem, ls.keys);
-				lsElem.getChildren().add(parseWaypoint(ls.getStart(), "trkpt"));
-				lsElem.getChildren().add(parseWaypoint(ls.getEnd(), "trkpt"));
-				nodes.remove(ls.getStart());
-				nodes.remove(ls.getEnd());
+				lsElem.getChildren().add(parseWaypoint(ls.start, "trkpt"));
+				lsElem.getChildren().add(parseWaypoint(ls.end, "trkpt"));
+				nodes.remove(ls.start);
+				nodes.remove(ls.end);
 				tElem.getChildren().add(lsElem);
 			}
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 23)
@@ -23,6 +23,4 @@
  */
 public class OsmConnection {
-	
-
 
 	/**
Index: src/org/openstreetmap/josm/io/OsmReader.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmReader.java	(revision 22)
+++ src/org/openstreetmap/josm/io/OsmReader.java	(revision 23)
@@ -6,6 +6,10 @@
 import java.net.HttpURLConnection;
 import java.net.URL;
+import java.util.Collection;
+import java.util.LinkedList;
 
-import org.openstreetmap.josm.command.DataSet;
+import org.jdom.JDOMException;
+import org.openstreetmap.josm.data.GeoPoint;
+import org.openstreetmap.josm.data.osm.DataSet;
 
 /**
@@ -14,5 +18,5 @@
  * @author imi
  */
-public class OsmReader extends OsmConnection implements DataReader {
+public class OsmReader extends OsmConnection {
 
 	/**
@@ -20,53 +24,82 @@
 	 */
 	private String urlStr;
-	/**
-	 * Whether importing the raw trackpoints or the regular osm map information
-	 */
-	private boolean rawGps;
+	private final double lat1;
+	private final double lon1;
+	private final double lat2;
+	private final double lon2;
 	
 	/**
 	 * Construct the reader and store the information for attaching
 	 */
-	public OsmReader(String server, boolean rawGps, 
+	public OsmReader(String server, 
 			double lat1, double lon1, double lat2, double lon2) {
-		this.rawGps = rawGps;
+		this.lon2 = lon2;
+		this.lat2 = lat2;
+		this.lon1 = lon1;
+		this.lat1 = lat1;
 		urlStr = server.endsWith("/") ? server : server+"/";
-		if (rawGps)
-			urlStr += "trackpoints?bbox="+lat1+","+lon1+","+lat2+","+lon2+"&page=";
-		else
-			urlStr += "map?bbox="+lon1+","+lat1+","+lon2+","+lat2;
 	}
 
 
-	public DataSet parse() throws ParseException, ConnectionException {
-		Reader in;
-		initAuthentication();
-		try {
-			if (rawGps) {
-				DataSet ds = new DataSet();
-				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 && isCancelled())
-						return null;
-					in = new InputStreamReader(con.getInputStream());
-					DataSet currentData = new GpxReader(in, true).parse();
-					if (currentData.nodes.isEmpty())
-						return ds;
-					ds.mergeFrom(currentData, true);
+	/**
+	 * Retrieve raw gps trackpoints from the server API.
+	 * @return A list of all primitives retrieved. Currently, the list of lists
+	 * 		contain only one list, since the server cannot distinguish between
+	 * 		tracks.
+	 */
+	public Collection<Collection<GeoPoint>> parseRawGps() throws IOException, JDOMException {
+		String url = urlStr+"trackpoints?bbox="+lat1+","+lon1+","+lat2+","+lon2+"&page=";
+		Collection<Collection<GeoPoint>> data = new LinkedList<Collection<GeoPoint>>();
+		Collection<GeoPoint> list = new LinkedList<GeoPoint>();
+		
+		for (int i = 0;;++i) {
+			Reader r = getReader(url+i);
+			if (r == null)
+				break;
+			RawGpsReader gpsReader = new RawGpsReader(r);
+			Collection<Collection<GeoPoint>> allTracks = gpsReader.parse();
+			boolean foundSomething = false;
+			for (Collection<GeoPoint> t : allTracks) {
+				if (!t.isEmpty()) {
+					foundSomething = true;
+					list.addAll(t);
 				}
 			}
-			URL url = new URL(urlStr);
-			HttpURLConnection con = (HttpURLConnection)url.openConnection();
-			con.setConnectTimeout(20000);
-			if (con.getResponseCode() == 401 && isCancelled())
-				return null;
-			in = new InputStreamReader(con.getInputStream());
-			return new GpxReader(in, false).parse();
-		} catch (IOException e) {
-			throw new ConnectionException("Failed to open server connection\n"+e.getMessage(), e);
+			if (!foundSomething)
+				break;
 		}
+
+		data.add(list);
+		return data;
+	}
+
+
+	/**
+	 * Read the data from the osm server address.
+	 * @return A data set containing all data retrieved from that url
+	 */
+	public DataSet parseOsm() throws JDOMException, IOException {
+		Reader r = getReader(urlStr+"map?bbox="+lon1+","+lat1+","+lon2+","+lat2);
+		if (r == null)
+			return null;
+		return new GpxReader(r).parse();
+	}
+
+
+	/**
+	 * Open a connection to the given url and return a reader on the input stream
+	 * from that connection. In case of user cancel, return <code>null</code>.
+	 * @param url The exact url to connect to.
+	 * @return An reader reading the input stream (servers answer) or <code>null</code>.
+	 */
+	private Reader getReader(String urlStr) throws IOException {
+		System.out.println(urlStr);
+		initAuthentication();
+		URL url = new URL(urlStr);
+		HttpURLConnection con = (HttpURLConnection)url.openConnection();
+		con.setConnectTimeout(20000);
+		if (con.getResponseCode() == 401 && isCancelled())
+			return null;
+		return new InputStreamReader(con.getInputStream());
 	}
 }
Index: src/org/openstreetmap/josm/io/RawGpsReader.java
===================================================================
--- src/org/openstreetmap/josm/io/RawGpsReader.java	(revision 23)
+++ src/org/openstreetmap/josm/io/RawGpsReader.java	(revision 23)
@@ -0,0 +1,88 @@
+package org.openstreetmap.josm.io;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+import org.openstreetmap.josm.data.GeoPoint;
+
+/**
+ * Read raw gps data from a gpx file. Only track points with their tracks segments
+ * and waypoints are imported.
+ * @author imi
+ */
+public class RawGpsReader {
+
+	/**
+	 * The data source from this reader.
+	 */
+	public Reader source;
+	
+	/**
+	 * Construct a gps reader from an input reader source.
+	 * @param source The source to read the raw gps data from. The data must be
+	 * 		in GPX format.
+	 */
+	public RawGpsReader(Reader source) {
+		this.source = source;
+	}
+
+	/**
+	 * Parse and return the read data
+	 */
+	public Collection<Collection<GeoPoint>> parse() throws JDOMException, IOException {
+		final SAXBuilder builder = new SAXBuilder();
+		builder.setValidation(false);
+		Element root = builder.build(source).getRootElement();
+		return parseData(root);
+	}
+
+	/**
+	 * Parse and return the whole data thing.
+	 * @param root
+	 * @return
+	 */
+	@SuppressWarnings("unchecked")
+	private Collection<Collection<GeoPoint>> parseData(Element root) {
+		Collection<Collection<GeoPoint>> data = new LinkedList<Collection<GeoPoint>>();
+
+		for (Object o : root.getChildren("wpt", GpxReader.GPX)) {
+			Collection<GeoPoint> line = new LinkedList<GeoPoint>();
+			line.add(new GeoPoint(
+					Float.parseFloat(((Element)o).getAttributeValue("lat")),
+					Float.parseFloat(((Element)o).getAttributeValue("lon"))));
+			data.add(line);
+		}
+		for (Object o : root.getChildren("rte", GpxReader.GPX)) {
+			Collection<GeoPoint> line = parseLine(((Element)o).getChildren("rtept", GpxReader.GPX));
+			if (!line.isEmpty())
+				data.add(line);
+		}
+		for (Object o : root.getChildren("trk", GpxReader.GPX)) {
+			for (Object seg : ((Element)o).getChildren("trkseg", GpxReader.GPX)) {
+				Collection<GeoPoint> line = parseLine(((Element)seg).getChildren("trkpt", GpxReader.GPX));
+				if (!line.isEmpty())
+					data.add(line);
+			}
+		}
+		return data;
+	}
+
+	/**
+	 * Parse the list of trackpoint - elements and return a collection with the
+	 * points read.
+	 */
+	private Collection<GeoPoint> parseLine(List<Element> wpt) {
+		Collection<GeoPoint> data = new LinkedList<GeoPoint>();
+		for (Element e : wpt)
+			data.add(new GeoPoint(
+					Float.parseFloat(e.getAttributeValue("lat")),
+					Float.parseFloat(e.getAttributeValue("lon"))));
+		return data;
+	}
+}
