Index: src/org/openstreetmap/josm/actions/OpenGpxAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/OpenGpxAction.java	(revision 6)
+++ src/org/openstreetmap/josm/actions/OpenGpxAction.java	(revision 7)
@@ -56,5 +56,4 @@
 			MapFrame map = new MapFrame(dataSet);
 			Main.main.setMapFrame(gpxFile.getName(), map);
-			map.setVisible(true);
 		} catch (JDOMException x) {
 			x.printStackTrace();
Index: src/org/openstreetmap/josm/actions/mapmode/AddLineSegmentAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/AddLineSegmentAction.java	(revision 7)
+++ src/org/openstreetmap/josm/actions/mapmode/AddLineSegmentAction.java	(revision 7)
@@ -0,0 +1,185 @@
+package org.openstreetmap.josm.actions.mapmode;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.JOptionPane;
+
+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.gui.Main;
+import org.openstreetmap.josm.gui.MapFrame;
+
+/**
+ * The user can add a new line segment between two nodes by pressing on the 
+ * starting node and dragging to the ending node. 
+ * 
+ * If the Alt key was pressed when releasing the mouse, this action tries to
+ * add the line segment to a track. The new line segment gets added to all tracks
+ * of the first node that end in the first node. If no tracks are found, the
+ * line segment gets added to all tracks in the second node that start with
+ * the second node.
+ * 
+ * No line segment can be created if there is already a line segment containing
+ * both nodes in the same order.
+ * 
+ * @author imi
+ */
+public class AddLineSegmentAction extends MapMode implements MouseListener {
+
+	/**
+	 * The first node the user pressed the button onto.
+	 */
+	private Node first;
+	/**
+	 * The second node used if the user releases the button.
+	 */
+	private Node second;
+
+	/**
+	 * Whether the hint is currently drawn on screen.
+	 */
+	private boolean hintDrawn = false;
+	
+	/**
+	 * Create a new AddLineSegmentAction.
+	 * @param mapFrame The MapFrame this action belongs to.
+	 */
+	public AddLineSegmentAction(MapFrame mapFrame) {
+		super("Add Line Segment", "addlinesegment", "Add a line segment between two nodes.", KeyEvent.VK_L, mapFrame);
+	}
+
+	@Override
+	public void registerListener() {
+		super.registerListener();
+		mv.addMouseListener(this);
+		mv.addMouseMotionListener(this);
+	}
+
+	@Override
+	public void unregisterListener() {
+		super.unregisterListener();
+		mv.removeMouseListener(this);
+		mv.removeMouseMotionListener(this);
+		drawHint(false);
+	}
+
+	/**
+	 * If user clicked on a node, start the dragging with that node. 
+	 */
+	@Override
+	public void mousePressed(MouseEvent e) {
+		if (e.getButton() != MouseEvent.BUTTON1)
+			return;
+
+		OsmPrimitive clicked = mv.getNearest(e.getPoint(), false);
+		if (clicked == null || !(clicked instanceof Node))
+			return;
+
+		drawHint(false);
+		first = second = (Node)clicked;
+	}
+
+	/**
+	 * Draw a hint which nodes will get connected if the user release
+	 * the mouse button now.
+	 */
+	@Override
+	public void mouseDragged(MouseEvent e) {
+		if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0)
+			return;
+
+		OsmPrimitive clicked = mv.getNearest(e.getPoint(), (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);
+		if (clicked == null || clicked == second || !(clicked instanceof Node))
+			return;
+
+		drawHint(false);
+
+		second = (Node)clicked;
+		drawHint(true);
+	}
+
+	/**
+	 * Create the line segment if first and second are different and there is
+	 * not already a line segment.
+	 */
+	@Override
+	public void mouseReleased(MouseEvent e) {
+		if (e.getButton() != MouseEvent.BUTTON1)
+			return;
+
+		if (first == null || second == null) {
+			first = null;
+			second = null;
+			return;
+		}
+
+		drawHint(false);
+		
+		Node start = first;
+		Node end = second;
+		first = null;
+		second = null;
+		
+		if (start != end) {
+			// try to find a line segment
+			for (Track t : 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;
+					}
+
+			LineSegment ls = new LineSegment(start, end);
+			boolean foundTrack = false;
+
+			if (((e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0)) {
+				// find a track for the new line segment
+				for (Track t : ds.tracks) {
+					if (t.getEndingNode() == start) {
+						t.segments.add(ls);
+						foundTrack = true;
+					}
+				}
+				if (!foundTrack) {
+					for (Track t : ds.tracks) {
+						if (t.getStartingNode() == end) {
+							t.segments.add(0,ls);
+							foundTrack = true;
+						}
+					}
+				}
+			}
+			if (!foundTrack)
+				ds.pendingLineSegments.add(ls);
+		}
+		
+		mv.repaint();
+	}
+
+	/**
+	 * Draw or remove the hint line, depending on the parameter.
+	 */
+	private void drawHint(boolean draw) {
+		if (draw == hintDrawn)
+			return;
+		if (first == null || second == null)
+			return;
+		if (second == first)
+			return;
+
+		Graphics g = mv.getGraphics();
+		g.setColor(Color.BLACK);
+		g.setXORMode(Color.WHITE);
+		Point firstDrawn = mv.getScreenPoint(first.coor);
+		Point secondDrawn = mv.getScreenPoint(second.coor);
+		g.drawLine(firstDrawn.x, firstDrawn.y, secondDrawn.x, secondDrawn.y);
+		hintDrawn = !hintDrawn;
+	}
+}
Index: src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java	(revision 7)
+++ src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java	(revision 7)
@@ -0,0 +1,54 @@
+package org.openstreetmap.josm.actions.mapmode;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.gui.MapFrame;
+
+/**
+ * This mode adds a new node to the dataset. The user clicks on a place to add
+ * and there is it. Nothing more, nothing less.
+ * 
+ * Newly created nodes are selected. Shift modifier does not cancel the old 
+ * selection as usual.
+ * 
+ * @author imi
+ *
+ */
+public class AddNodeAction extends MapMode {
+
+	/**
+	 * Create an AddNodeAction. Mnemonic is 'a'
+	 * @param mapFrame
+	 */
+	public AddNodeAction(MapFrame mapFrame) {
+		super("Add nodes", "addnode", "Add new nodes to the map.", KeyEvent.VK_A, mapFrame);
+	}
+
+	@Override
+	public void registerListener() {
+		super.registerListener();
+		mv.addMouseListener(this);
+	}
+
+	@Override
+	public void unregisterListener() {
+		super.unregisterListener();
+		mv.removeMouseListener(this);
+	}
+
+	/**
+	 * If user clicked with the left button, add a node at the current mouse
+	 * position.
+	 */
+	@Override
+	public void mouseClicked(MouseEvent e) {
+		if (e.getButton() == MouseEvent.BUTTON1) {
+			Node node = new Node();
+			node.coor = mv.getPoint(e.getX(), e.getY(), true);
+			ds.nodes.add(node);
+			mv.repaint();
+		}
+	}
+}
Index: src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java	(revision 7)
+++ src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java	(revision 7)
@@ -0,0 +1,107 @@
+package org.openstreetmap.josm.actions.mapmode;
+
+import java.awt.Rectangle;
+import java.awt.event.KeyEvent;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.openstreetmap.josm.data.osm.LineSegment;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Track;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.SelectionManager;
+import org.openstreetmap.josm.gui.SelectionManager.SelectionEnded;
+
+/**
+ * Add a new track from all selected line segments.
+ *
+ * If there is a selection when the mode is entered, all line segments in this
+ * selection form a new track, except the user holds down Shift.
+ *
+ * The user can click on a line segment. If he holds down Shift, no track is 
+ * created yet. If he holds down Alt, the whole track is considered instead of 
+ * the clicked line segment. If the user holds down Ctrl, no track is created 
+ * and the clicked line segment get removed from the list.
+ *
+ * Also, the user may select a rectangle as in selection mode. No node, area or
+ * track can be selected this way.
+ *
+ * @author imi
+ *
+ */
+public class AddTrackAction extends MapMode implements SelectionEnded {
+
+	/**
+	 * The selection manager for this action, keeping track of all selections.
+	 */
+	SelectionManager selectionManager;
+	
+	/**
+	 * Create a new AddTrackAction.
+	 * @param mapFrame The MapFrame this action belongs to.
+	 */
+	public AddTrackAction(MapFrame mapFrame) {
+		super("Add Track", "addtrack", "Combine line segments to a new track.", KeyEvent.VK_T, mapFrame);
+		this.selectionManager = new SelectionManager(this, false, mv);
+	}
+
+	@Override
+	public void registerListener() {
+		super.registerListener();
+		selectionManager.register(mv);
+	}
+
+	@Override
+	public void unregisterListener() {
+		super.unregisterListener();
+		selectionManager.unregister(mv);
+	}
+
+	/**
+	 * If Shift is pressed, only add the selected line segments to the selection.
+	 * If Ctrl is pressed, only remove the selected line segments from the selection.
+	 * If both, Shift and Ctrl is pressed, do nothing.
+	 * 
+	 * Else, form a new track out of all line segments in the selection and
+	 * clear the selection afterwards.
+	 * 
+	 * If Alt is pressed, consider all linesegments of all tracks a selected
+	 * line segment is part of. Also consider all line segments that cross the
+	 * selecting rectangle, instead only those that are fully within.
+	 * 
+	 */
+	public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) {
+		if (shift && ctrl)
+			return; // not allowed together
+
+		if (!ctrl && !shift)
+			ds.clearSelection(); // new selection will replace the old.
+
+		Collection<OsmPrimitive> selectionList = selectionManager.getObjectsInRectangle(r,alt);
+		for (OsmPrimitive osm : selectionList)
+			osm.selected = !ctrl;
+
+		mv.repaint(); // from now on, the map has to be repainted.
+
+		if (ctrl || shift)
+			return; // no new track yet.
+		
+		Collection<OsmPrimitive> selection = ds.getSelected();
+		if (selection.isEmpty())
+			return;
+
+		// form a new track
+		LinkedList<LineSegment> lineSegments = new LinkedList<LineSegment>();
+		for (OsmPrimitive osm : selection) {
+			if (osm instanceof Track)
+				lineSegments.addAll(((Track)osm).segments);
+			else if (osm instanceof LineSegment)
+				lineSegments.add((LineSegment)osm);
+		}
+		Track t = new Track();
+		t.segments.addAll(lineSegments);
+		ds.tracks.add(t);
+		ds.pendingLineSegments.removeAll(lineSegments);
+		ds.clearSelection();
+	}
+}
Index: src/org/openstreetmap/josm/actions/mapmode/CombineAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/CombineAction.java	(revision 7)
+++ src/org/openstreetmap/josm/actions/mapmode/CombineAction.java	(revision 7)
@@ -0,0 +1,233 @@
+package org.openstreetmap.josm.actions.mapmode;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+
+import javax.swing.JOptionPane;
+
+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.gui.Main;
+import org.openstreetmap.josm.gui.MapFrame;
+
+/**
+ * A MapMode that allows the user to combine two objects to a new one.
+ * 
+ * When entering CombineAction, all selection is cleared.
+ * 
+ * The user can select objects by dragging them to another object, so the object 
+ * he pressed and the one he released the button are combined. No selection 
+ * rectangle is supported. 
+ * 
+ * Even if the user don't press Alt, tracks instead of line segments are selected. 
+ * This means, it is impossible to select non-pending line segments.
+ * 
+ * Pressing Ctrl or Shift has no effect too.
+ *
+ * No object can be combined with an object it is already part of. E.g. line
+ * segment cannot be combined with a track it is part of. In case of such a 
+ * constillation, the user is informed.
+ *
+ * When combining, the object the user pressed on is called <i>source</i> and 
+ * the object the button was released on is called <i>target</i>.
+ *
+ * The following objects can be combined:
+ *
+ * - A line segment and a track can be combined if one of them is a pending line
+ *   segment. This get integrated into the track.
+ * - Two tracks can be combined. The latter track get removed and all its 
+ *   segments are moved to the first track. This is only possible, if both 
+ *   tracks have no different value in any key.
+ * - Two areas can be combined, if they share at least one node, in which case
+ *   the combined area span both areas. If the areas share more than one node,
+ *   all lines between the areas get removed. This is only possible if both areas
+ *   have no different value in any key.
+ *
+ * All other object combinations cannot be combined.
+ * 
+ * TODO: This and AddLineSegmentAction are similar. Refactor both.
+ * 
+ * @author imi
+ */
+public class CombineAction extends MapMode {
+
+	/**
+	 * The object that was first selected as combine source. 
+	 */
+	private OsmPrimitive first;
+	/**
+	 * The object that was last selected as combine target. 
+	 */
+	private OsmPrimitive second;
+	/**
+	 * Whether a hint is drawn on screen or not.
+	 */
+	private boolean combineHintDrawn = false;
+
+	/**
+	 * Constructs a CombineAction. Mnemonic is "c".
+	 */
+	public CombineAction(MapFrame mapFrame) {
+		super("Combine", "combine", "Combine objects together.", KeyEvent.VK_C, mapFrame);
+	}
+
+	@Override
+	public void registerListener() {
+		super.registerListener();
+		mv.addMouseListener(this);
+		mv.addMouseMotionListener(this);
+		ds.clearSelection();
+	}
+
+	@Override
+	public void unregisterListener() {
+		super.unregisterListener();
+		mv.removeMouseListener(this);
+		mv.removeMouseMotionListener(this);
+		drawCombineHint(false);
+	}
+
+	/**
+	 * If nothing is selected, select the object nearest to the mouse. Else
+	 * start the "display possible combining" phase and draw a hint what would
+	 * be combined if user releases the button. 
+	 */
+	@Override
+	public void mousePressed(MouseEvent e) {
+		if (e.getButton() != MouseEvent.BUTTON1)
+			return;
+
+		OsmPrimitive clicked = mv.getNearest(e.getPoint(), true);
+		if (clicked == null || clicked instanceof Node)
+			return;
+
+		drawCombineHint(false);
+		first = second = clicked;
+	}
+
+	/**
+	 * Updates the drawn combine hint if necessary.
+	 */
+	@Override
+	public void mouseDragged(MouseEvent e) {
+		if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0)
+			return;
+		
+		OsmPrimitive clicked = mv.getNearest(e.getPoint(), true);
+		if (clicked == null || clicked == second || clicked instanceof Node)
+			return;
+
+		drawCombineHint(false);
+		second = clicked;
+		drawCombineHint(true);
+	}
+	
+	/**
+	 * Start combining (if there is something to combine).
+	 */
+	@Override
+	public void mouseReleased(MouseEvent e) {
+		if (e.getButton() != MouseEvent.BUTTON1)
+			return;
+
+		if (first == null || second == null) {
+			first = null;
+			second = null;
+			return;
+		}
+
+		drawCombineHint(false);
+		
+		if (first instanceof LineSegment && second instanceof LineSegment)
+			JOptionPane.showMessageDialog(Main.main, "Cannot combine two line segments. To create tracks use 'Add Track'.");
+		else if (first instanceof LineSegment && second instanceof Track)
+			combine((LineSegment)first, (Track)second);
+		else if (first instanceof Track && second instanceof LineSegment)
+			combine((LineSegment)second, (Track)first);
+		else if (first instanceof Track && second instanceof Track) {
+			if (!first.keyPropertiesMergable(second))
+				JOptionPane.showMessageDialog(Main.main, "Cannot combine because of different properties.");
+			else {
+				Track t1 = (Track)first;
+				Track t2 = (Track)second;
+				if (t1.getStartingNode() == t2.getEndingNode()) {
+					t1 = t2;
+					t2 = (Track)first;
+				}
+				t1.segments.addAll(t2.segments);
+				if (t1.keys == null)
+					t1.keys = t2.keys;
+				else	
+					t1.keys.putAll(t2.keys);
+				ds.tracks.remove(t2);
+			}
+		}
+		mv.repaint();
+	}
+
+
+	/**
+	 * Add the line segment to the track and remove it from the pending segments.
+	 * @param ls The line segment to add
+	 * @param t The track to add the line segment to
+	 */
+	private void combine(LineSegment ls, Track t) {
+		if (!ds.pendingLineSegments.contains(first))
+			throw new IllegalStateException("Should not be able to select non-pending line segments.");
+		
+		if (t.getStartingNode() == ls.end)
+			t.segments.add(0, ls);
+		else
+			t.segments.add(ls);
+		ds.pendingLineSegments.remove(ls);
+	}
+
+	/**
+	 * Draws or removes the combine hint using the combineHint structure.
+	 *
+	 * @param draw 	<code>true</code> to draw the hint or 
+	 * 				<code>false</code> to remove it.
+	 */
+	private void drawCombineHint(boolean draw) {
+		if (draw == combineHintDrawn)
+			return;
+		if (first == null || second == null)
+			return;
+		if (second == first)
+			return;
+
+		Graphics g = mv.getGraphics();
+		g.setColor(draw ? Color.WHITE : Color.GRAY); // HACK
+		draw(g, first);
+		draw(g, second);
+		combineHintDrawn = !combineHintDrawn;
+	}
+
+	/**
+	 * Draw a hint for the specified primitive
+	 * @param g The graphic to draw into
+	 * @param osm The primitive to draw a hint for.
+	 */
+	private void draw(Graphics g, OsmPrimitive osm) {
+		if (osm instanceof LineSegment) {
+			LineSegment ls = (LineSegment)osm;
+			Point start = mv.getScreenPoint(ls.start.coor);
+			Point end = mv.getScreenPoint(ls.end.coor);
+			if (mv.dataSet.pendingLineSegments.contains(osm) && g.getColor() == Color.GRAY) {
+				// HACK
+				g.setColor(Color.LIGHT_GRAY);
+				g.drawLine(start.x, start.y, end.x, end.y);
+				g.setColor(Color.GRAY);
+			} else
+				g.drawLine(start.x, start.y, end.x, end.y);
+		} else if (osm instanceof Track) {
+			for (LineSegment ls : ((Track)osm).segments)
+				draw(g, ls);
+		}
+	}
+}
Index: src/org/openstreetmap/josm/actions/mapmode/DebugAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/DebugAction.java	(revision 6)
+++ src/org/openstreetmap/josm/actions/mapmode/DebugAction.java	(revision 7)
@@ -8,6 +8,4 @@
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.awt.event.MouseMotionListener;
 
 import javax.swing.JLabel;
@@ -16,5 +14,4 @@
 import org.openstreetmap.josm.data.osm.Track;
 import org.openstreetmap.josm.gui.MapFrame;
-import org.openstreetmap.josm.gui.MapView;
 
 /**
@@ -23,5 +20,5 @@
  * @author imi
  */
-public class DebugAction extends MapMode implements MouseMotionListener, MouseListener {
+public class DebugAction extends MapMode {
 
 	private JLabel label = new JLabel();
@@ -32,23 +29,20 @@
 	
 	@Override
-	public void registerListener(MapView mapView) {
-		mapView.addMouseMotionListener(this);
-		mapView.addMouseListener(this);
+	public void registerListener() {
+		super.registerListener();
+		mv.addMouseMotionListener(this);
+		mv.addMouseListener(this);
 		mapFrame.add(label, BorderLayout.SOUTH);
 	}
 
 	@Override
-	public void unregisterListener(MapView mapView) {
-		mapView.removeMouseMotionListener(this);
-		mapView.removeMouseListener(this);
+	public void unregisterListener() {
+		super.unregisterListener();
+		mv.removeMouseMotionListener(this);
+		mv.removeMouseListener(this);
 		mapFrame.remove(label);
 	}
 
-	public void mouseDragged(MouseEvent e) {
-	}
-
-	public void mouseMoved(MouseEvent e) {
-	}
-
+	@Override
 	public void mouseClicked(MouseEvent e) {
 		Graphics g = mapFrame.mapView.getGraphics();
@@ -66,20 +60,5 @@
 
 	private double perpendicularDistSq(double a, double b, double c) {
-		// I did this on paper by myself, so I am surprised too, that it is that 
-		// performant ;-) 
 		return a-(a-b+c)*(a-b+c)/4/c;
 	}
-
-	public void mousePressed(MouseEvent e) {
-	}
-
-	public void mouseReleased(MouseEvent e) {
-	}
-
-	public void mouseEntered(MouseEvent e) {
-	}
-
-	public void mouseExited(MouseEvent e) {
-	}
-
 }
Index: src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 7)
+++ src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 7)
@@ -0,0 +1,362 @@
+package org.openstreetmap.josm.actions.mapmode;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.swing.JOptionPane;
+
+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.gui.Main;
+import org.openstreetmap.josm.gui.MapFrame;
+
+/**
+ * An action that enables the user to delete nodes and other objects.
+ * 
+ * The user can click on an object, which get deleted if possible. When Ctrl is 
+ * pressed when releasing the button, the objects and all its references are 
+ * deleted as well. The exact definition of "all its references" are in 
+ * @see #deleteWithReferences(OsmPrimitive)
+ *
+ * Pressing Alt will select the track instead of a line segment, as usual.
+ *
+ * If the user presses Ctrl, no combining is possible. Otherwise, DeleteAction 
+ * tries to combine the referencing objects as follows:
+ *
+ * If a node is part of exactly two line segments from a track, the two line 
+ * segments are combined into one. The first line segment spans now to the end 
+ * of the second and the second line segment gets deleted. This is checked for
+ * every track.
+ * 
+ * If a node is the end of the ending line segment of one track and the start of
+ * exactly one other tracks start segment, the tracks are combined into one track,
+ * deleting the second track and keeping the first one. The ending line segment 
+ * of the fist track is combined with the starting line segment of the second 
+ * track.
+ * 
+ * Combining is only possible, if both objects that should be combined have no
+ * key with a different property value. The remaining keys are merged together.
+ * 
+ * If a node is part of an area with more than 3 nodes, the node is removed from 
+ * the area and the area has now one fewer node.
+ * 
+ * If combining fails, the node has still references and the user did not hold
+ * Ctrl down, the deleting fails, the action informs the user and nothing is
+ * deleted.
+ * 
+ * 
+ * If the user enters the mapmode and any object is selected, all selected
+ * objects get deleted. Combining applies to the selected objects.
+ * 
+ * @author imi
+ */
+public class DeleteAction extends MapMode {
+
+	/**
+	 * Construct a new DeleteAction. Mnemonic is the delete - key.
+	 * @param mapFrame The frame this action belongs to.
+	 */
+	public DeleteAction(MapFrame mapFrame) {
+		super("Delete", "delete", "Delete nodes, streets or areas.", KeyEvent.VK_DELETE, mapFrame);
+	}
+
+	@Override
+	public void registerListener() {
+		super.registerListener();
+		mv.addMouseListener(this);
+	}
+
+	@Override
+	public void unregisterListener() {
+		super.unregisterListener();
+		mv.removeMouseListener(this);
+	}
+
+	/**
+	 * If user clicked with the left button, delete the nearest object.
+	 * position.
+	 */
+	@Override
+	public void mouseClicked(MouseEvent e) {
+		if (e.getButton() != MouseEvent.BUTTON1)
+			return;
+		
+		OsmPrimitive sel = mv.getNearest(e.getPoint(), (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);
+		if (sel == null)
+			return;
+
+		if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0)
+			deleteWithReferences(sel);
+		else
+			delete(sel);
+
+		mv.repaint();
+	}
+
+	/**
+	 * Delete the primitive and everything it references or beeing directly 
+	 * referenced by, except of nodes which are deleted only if passed 
+	 * directly or become unreferenced while deleting other objects.
+	 *
+	 * Nothing is combined as in @see #delete(OsmPrimitive).
+	 * 
+	 * Example (A is a track of line segment a and b. z is a node):
+	 *
+	 *              A
+	 *   B   x        z
+	 *  -----*--------+-----
+	 *       |     a      b
+	 *       |C
+	 *       |
+	 *       *y
+	 *       
+	 * If you delete C, C and y (since now unreferenced) gets deleted.
+	 * If you delete A, then A, a, b and z (since now unreferenced) gets deleted.
+	 * If you delete y, then y and C gets deleted.
+	 * TODO If you delete x, then a,B,C and x gets deleted. A now consist of b only.
+	 * If you delete a or b, then A, a, b and z gets deleted.
+	 *
+	 * @param osm The object to delete.
+	 */
+	private void deleteWithReferences(OsmPrimitive osm) {
+		// collect all tracks, areas and pending line segments that should be deleted
+		ArrayList<Track> tracksToDelete = new ArrayList<Track>();
+		ArrayList<LineSegment> lineSegmentsToDelete = new ArrayList<LineSegment>();
+
+		if (osm instanceof Node) {
+			// delete any track and line segment the node is in.
+			for (Track t : ds.tracks)
+				for (LineSegment ls : t.segments)
+					if (ls.start == osm || ls.end == osm)
+						tracksToDelete.add(t);
+			for (LineSegment ls : ds.pendingLineSegments)
+				if (ls.start == osm || ls.end == osm)
+					lineSegmentsToDelete.add(ls);
+				
+		} else if (osm instanceof LineSegment) {
+			LineSegment lineSegment = (LineSegment)osm;
+			lineSegmentsToDelete.add(lineSegment);
+			for (Track t : ds.tracks)
+				for (LineSegment ls : t.segments)
+					if (lineSegment == ls)
+						tracksToDelete.add(t);
+		} else if (osm instanceof Track) {
+			tracksToDelete.add((Track)osm);
+		}
+		// collect all nodes, that could be unreferenced after deletion
+		ArrayList<Node> checkUnreferencing = new ArrayList<Node>();
+		for (Track t : tracksToDelete) {
+			for (LineSegment ls : t.segments) {
+				checkUnreferencing.add(ls.start);
+				checkUnreferencing.add(ls.end);
+			}
+		}
+		for (LineSegment ls : lineSegmentsToDelete) {
+			checkUnreferencing.add(ls.start);
+			checkUnreferencing.add(ls.end);
+		}
+		
+		// delete tracks and areas
+		ds.tracks.removeAll(tracksToDelete);
+		ds.pendingLineSegments.removeAll(lineSegmentsToDelete);
+
+		// removing all unreferenced nodes
+		for (Node n : checkUnreferencing) {
+			if (!isReferenced(n))
+				ds.nodes.remove(n);
+		}
+		// now, all references are killed. Delete the node (if it was a node)
+		if (osm instanceof Node)
+			ds.nodes.remove(osm);
+	}
+
+	/**
+	 * Try to delete the given primitive. If the primitive is a node and
+	 * used somewhere, try to combine the references to make the node unused.
+	 * If this fails, inform the user and do not delete.
+	 * 
+	 * @param osm The object to delete.
+	 */
+	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.
+			ds.nodes.remove(n);
+		} else if (osm instanceof LineSegment) {
+			for (Iterator<Track> it = ds.tracks.iterator(); it.hasNext();) {
+				Track t = it.next();
+				t.segments.remove(osm);
+				if (t.segments.isEmpty())
+					it.remove();
+			}
+			ds.pendingLineSegments.remove(osm);
+		} else if (osm instanceof Track) {
+			ds.tracks.remove(osm);
+			ds.pendingLineSegments.addAll(((Track)osm).segments);
+		}
+	}
+
+	
+	/**
+	 * Return <code>true</code>, if the node is used by anything in the map.
+	 * @param n The node to check.
+	 * @return Whether the node is used by a track or area.
+	 */
+	private boolean isReferenced(Node n) {
+		for (Track t : ds.tracks)
+			for (LineSegment ls : t.segments)
+				if (ls.start == n || ls.end == n)
+					return true;
+		for (LineSegment ls : ds.pendingLineSegments)
+			if (ls.start == n || ls.end == n)
+				return true;
+		// TODO areas
+		return false;
+	}
+
+	/**
+	 * Try to combine all objects when deleting the node n. If combining is not
+	 * possible, return an error string why. Otherwise, combine it and return 
+	 * <code>null</code>.
+	 *
+	 * @param n The node that is going to be deleted.
+	 * @return <code>null</code> if combining suceded or an error string if there
+	 * 		are problems combining the node.
+	 */
+	private String combine(Node n) {
+		// first, check for pending line segments
+		for (LineSegment ls : ds.pendingLineSegments)
+			if (n == ls.start || n == ls.end)
+				return "Node used by a line segment which is not part of any track. Remove this first."; 
+		
+		// These line segments must be combined within the track combining
+		ArrayList<LineSegment> pendingLineSegmentsForTrack = new ArrayList<LineSegment>();
+
+		// try to combine line segments
+		
+		// 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 : ds.tracks) {
+			ArrayList<LineSegment> current = new ArrayList<LineSegment>();
+			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() == 1 && 
+						(current.get(0) == t.segments.get(0) || current.get(0) == t.segments.get(t.segments.size()-1)))
+					pendingLineSegmentsForTrack.add(current.get(0));
+				else if (current.get(0).end != current.get(1).start &&
+						current.get(1).end != current.get(0).start)
+					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);
+			}
+		}
+		
+		// try to combine tracks
+		ArrayList<Track> tracks = new ArrayList<Track>();
+		for (Track t : ds.tracks)
+			if (!t.segments.isEmpty() && (t.segments.get(0).start == n || t.segments.get(t.segments.size()-1).end == 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.";
+			Track t1 = tracks.get(0);
+			Track t2 = tracks.get(1);
+			if (t1.segments.get(0).start != t2.segments.get(t2.segments.size()-1).end &&
+					t2.segments.get(0).start != t1.segments.get(t1.segments.size()-1).end) {
+				if (t1.segments.get(0).start == t2.segments.get(t2.segments.size()-1).start ||
+						t1.segments.get(0).end == t2.segments.get(t2.segments.size()-1).end)
+					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.";
+		}
+		
+		// try to match the pending line segments
+		if (pendingLineSegmentsForTrack.size() == 2) {
+			LineSegment l1 = pendingLineSegmentsForTrack.get(0);
+			LineSegment l2 = pendingLineSegmentsForTrack.get(1);
+			if (l1.start == l2.start || l1.end == l2.end)
+				return "Node used by line segments that points together.";
+			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.";
+
+		// 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.start == second.end) {
+				first = second;
+				second = list.get(0);
+			}
+			first.end = second.end;
+			first.keys = mergeKeys(first.keys, second.keys);
+			lineSegments.get(list).segments.remove(second);
+		}
+		
+		// tracks
+		if (!tracks.isEmpty()) {
+			Track first = tracks.get(0);
+			Track second = tracks.get(1);
+			if (first.segments.get(0).start == second.segments.get(second.segments.size()-1).end) {
+				first = second;
+				second = tracks.get(0);
+			}
+			// concatenate the line segments.
+			LineSegment lastOfFirst = first.segments.get(first.segments.size()-1);
+			LineSegment firstOfSecond = second.segments.get(0);
+			lastOfFirst.end = firstOfSecond.end;
+			lastOfFirst.keys = mergeKeys(lastOfFirst.keys, firstOfSecond.keys);
+			second.segments.remove(firstOfSecond);
+			// move the remaining line segments to first track.
+			first.segments.addAll(second.segments);
+			ds.tracks.remove(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;
+	}
+}
Index: src/org/openstreetmap/josm/actions/mapmode/MapMode.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 6)
+++ src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 7)
@@ -2,8 +2,14 @@
 
 import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
 
 import javax.swing.AbstractAction;
 import javax.swing.ImageIcon;
+import javax.swing.JComponent;
+import javax.swing.KeyStroke;
 
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.MapView;
@@ -17,5 +23,5 @@
  * control. 
  */
-abstract public class MapMode extends AbstractAction {
+abstract public class MapMode extends AbstractAction implements MouseListener, MouseMotionListener {
 
 	/**
@@ -23,4 +29,12 @@
 	 */
 	protected final MapFrame mapFrame;
+	/**
+	 * Shortcut to the MapView.
+	 */
+	protected final MapView mv;
+	/**
+	 * Shortcut to the DataSet.
+	 */
+	protected final DataSet ds;
 
 	/**
@@ -31,8 +45,13 @@
 	 */
 	public MapMode(String name, String iconName, String tooltip, int mnemonic, MapFrame mapFrame) {
-		super(name, new ImageIcon("images/"+iconName+".png"));
+		super(name, new ImageIcon("images/mapmode/"+iconName+".png"));
 		putValue(MNEMONIC_KEY, mnemonic);
+		putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(mnemonic,0));
 		putValue(LONG_DESCRIPTION, tooltip);
+		mapFrame.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(mnemonic,0), this);
+		mapFrame.getActionMap().put(this, this);
 		this.mapFrame = mapFrame;
+		mv = mapFrame.mapView;
+		ds = mv.dataSet;
 	}
 	
@@ -41,5 +60,7 @@
 	 * @param mapView	The view, where the listener should be registered.
 	 */
-	abstract public void registerListener(MapView mapView);
+	public void registerListener() {
+		firePropertyChange("active", false, true);
+	}
 	
 	/**
@@ -47,5 +68,7 @@
 	 * @param mapView	The view from which the listener should be deregistered.
 	 */
-	abstract public void unregisterListener(MapView mapView);
+	public void unregisterListener() {
+		firePropertyChange("active", true, false);
+	}
 
 	/**
@@ -55,3 +78,32 @@
 		mapFrame.selectMapMode(this);
 	}
+	
+	/**
+	 * Does nothing. Only to subclass.
+	 */
+	public void mouseClicked(MouseEvent e) {}
+	/**
+	 * Does nothing. Only to subclass.
+	 */
+	public void mousePressed(MouseEvent e) {}
+	/**
+	 * Does nothing. Only to subclass.
+	 */
+	public void mouseReleased(MouseEvent e) {}
+	/**
+	 * Does nothing. Only to subclass.
+	 */
+	public void mouseEntered(MouseEvent e) {}
+	/**
+	 * Does nothing. Only to subclass.
+	 */
+	public void mouseExited(MouseEvent e) {}
+	/**
+	 * Does nothing. Only to subclass.
+	 */
+	public void mouseMoved(MouseEvent e) {}
+	/**
+	 * Does nothing. Only to subclass.
+	 */
+	public void mouseDragged(MouseEvent e) {}
 }
Index: src/org/openstreetmap/josm/actions/mapmode/MoveAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/MoveAction.java	(revision 6)
+++ src/org/openstreetmap/josm/actions/mapmode/MoveAction.java	(revision 7)
@@ -1,8 +1,14 @@
 package org.openstreetmap.josm.actions.mapmode;
 
+import java.awt.Cursor;
+import java.awt.Point;
 import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.util.Collection;
+import java.util.HashSet;
 
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.MapFrame;
-import org.openstreetmap.josm.gui.MapView;
 
 /**
@@ -10,7 +16,6 @@
  * 
  * If any object is selected, all selected objects are moved. If no object is 
- * selected, only nodes can be moved. In this case, the Node which is nearest to
- * the mouse cursor when the left mouse button is pressed get selected and moved.
- * (Of course, all primitives, which use this node are moved somewhat too).
+ * selected, the nearest object will be selected and moved. In this case, the
+ * object will be unselected as soon as movement stopped.
  * 
  * @author imi
@@ -18,4 +23,22 @@
 public class MoveAction extends MapMode {
 
+	/**
+	 * The old cursor before the user pressed the mouse button.
+	 */
+	private Cursor oldCursor;
+	/**
+	 * The position of the mouse before the user moves a node.
+	 */
+	private Point mousePos;
+	/**
+	 * Non-<code>null</code>, if no object was selected before movement 
+	 * (and so the object get unselected after mouse release).
+	 */
+	private OsmPrimitive singleOsmPrimitive;
+
+	/**
+	 * Create a new MoveAction
+	 * @param mapFrame The MapFrame, this action belongs to.
+	 */
 	public MoveAction(MapFrame mapFrame) {
 		super("Move", "move", "Move selected objects around", KeyEvent.VK_M, mapFrame);
@@ -23,10 +46,92 @@
 
 	@Override
-	public void registerListener(MapView mapView) {
+	public void registerListener() {
+		super.registerListener();
+		mv.addMouseListener(this);
+		mv.addMouseMotionListener(this);
 	}
 
 	@Override
-	public void unregisterListener(MapView mapView) {
+	public void unregisterListener() {
+		super.unregisterListener();
+		mv.removeMouseListener(this);
+		mv.removeMouseMotionListener(this);
 	}
 
+	
+	/**
+	 * If the left mouse button is pressed, move all currently selected
+	 * objects.
+	 */
+	@Override
+	public void mouseDragged(MouseEvent e) {
+		if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0)
+			return;
+		
+		if (mousePos == null) {
+			mousePos = e.getPoint();
+			singleOsmPrimitive = null;
+		}
+
+		int dx = e.getX() - mousePos.x;
+		int dy = e.getY() - mousePos.y;
+		if (dx == 0 && dy == 0)
+			return;
+
+		Collection<OsmPrimitive> selection = ds.getSelected();
+		// creating a list of all nodes that should be moved.
+		Collection<Node> movingNodes = new HashSet<Node>();
+		for (OsmPrimitive osm : selection)
+			movingNodes.addAll(osm.getAllNodes());
+
+		for (Node n : movingNodes) {
+			Point pos = mv.getScreenPoint(n.coor);
+			pos.x += dx;
+			pos.y += dy;
+			n.coor = mv.getPoint(pos.x, pos.y, true);
+		}
+		mv.repaint();
+		
+		mousePos = e.getPoint();
+	}
+
+	/**
+	 * Look, whether any object is selected. If not, select the nearest node.
+	 * If there are no nodes in the dataset, do nothing.
+	 * 
+	 * If the user did not press the left mouse button, do nothing.
+	 * 
+	 * Also remember the starting position of the movement and change the mouse 
+	 * cursor to movement.
+	 */
+	@Override
+	public void mousePressed(MouseEvent e) {
+		if (e.getButton() != MouseEvent.BUTTON1)
+			return;
+
+		if (ds.getSelected().size() == 0) {
+			OsmPrimitive osm = mv.getNearest(e.getPoint(), (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);
+			if (osm != null)
+				osm.selected = true;
+			singleOsmPrimitive = osm;
+			mv.repaint();
+		} else
+			singleOsmPrimitive = null;
+		
+		mousePos = e.getPoint();
+		oldCursor = mv.getCursor();
+		mv.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+	}
+	
+	/**
+	 * Restore the old mouse cursor.
+	 */
+	@Override
+	public void mouseReleased(MouseEvent e) {
+		mv.setCursor(oldCursor);
+		if (singleOsmPrimitive != null) {
+			singleOsmPrimitive.selected = false;
+			mv.repaint();
+		}
+	}
 }
Index: src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java	(revision 6)
+++ src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java	(revision 7)
@@ -1,16 +1,10 @@
 package org.openstreetmap.josm.actions.mapmode;
 
-import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.event.KeyEvent;
-import java.awt.event.MouseEvent;
-import java.awt.geom.Point2D;
+import java.util.Collection;
 
-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.gui.MapFrame;
-import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.gui.SelectionManager;
 import org.openstreetmap.josm.gui.SelectionManager.SelectionEnded;
@@ -52,5 +46,5 @@
  * and the user clicked in or 10 pixel away from an area, this area is selected. 
  * If there is even no area, nothing is selected. Shift and Ctrl key applies to 
- * this as usual.
+ * this as usual. For more, @see MapView#getNearest(Point, boolean)
  *
  * @author imi
@@ -58,8 +52,4 @@
 public class SelectionAction extends MapMode implements SelectionEnded {
 
-	/**
-	 * Shortcut for the MapView.
-	 */
-	private MapView mv;
 	/**
 	 * The SelectionManager that manages the selection rectangle.
@@ -69,20 +59,21 @@
 	/**
 	 * Create a new SelectionAction in the given frame.
-	 * @param mapFrame
+	 * @param mapFrame The frame this action belongs to
 	 */
 	public SelectionAction(MapFrame mapFrame) {
 		super("Selection", "selection", "Select objects by dragging or clicking", KeyEvent.VK_S, mapFrame);
-		this.mv = mapFrame.mapView;
 		this.selectionManager = new SelectionManager(this, false, mv);
 	}
 
 	@Override
-	public void registerListener(MapView mapView) {
-		selectionManager.register(mapView);
+	public void registerListener() {
+		super.registerListener();
+		selectionManager.register(mv);
 	}
 
 	@Override
-	public void unregisterListener(MapView mapView) {
-		selectionManager.unregister(mapView);
+	public void unregisterListener() {
+		super.unregisterListener();
+		selectionManager.unregister(mv);
 	}
 
@@ -91,109 +82,15 @@
 	 * Check the state of the keys and buttons and set the selection accordingly.
 	 */
-	public void selectionEnded(Rectangle r, int modifiers) {
-		boolean shift = (modifiers & MouseEvent.SHIFT_DOWN_MASK) != 0;
-		boolean alt = (modifiers & MouseEvent.ALT_DOWN_MASK) != 0;
-		boolean ctrl = (modifiers & MouseEvent.CTRL_DOWN_MASK) != 0;
+	public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) {
 		if (shift && ctrl)
 			return; // not allowed together
 
-		if (!ctrl && !shift) {
-			// remove the old selection. The new selection will replace the old.
-			mv.dataSet.clearSelection();
-		}
+		if (!ctrl && !shift)
+			ds.clearSelection(); // new selection will replace the old.
 
-		// now set the selection to this value
-		boolean selection = !ctrl;
-
-		// whether user only clicked, not dragged.
-		boolean clicked = r.width <= 2 && r.height <= 2;
-		Point2D.Double center = new Point2D.Double(r.getCenterX(), r.getCenterY());
-
-		try {
-			// nodes
-			double minDistanceSq = Double.MAX_VALUE;
-			OsmPrimitive minPrimitive = null;
-			for (Node n : mv.dataSet.allNodes) {
-				Point sp = mv.getScreenPoint(n.coor);
-				double dist = center.distanceSq(sp);
-				if (clicked && minDistanceSq > dist && dist < 100) {
-					minDistanceSq = center.distanceSq(sp);
-					minPrimitive = n;
-				} else if (r.contains(sp))
-					n.selected = selection;
-			}
-			if (minPrimitive != null) {
-				minPrimitive.selected = selection;
-				return;
-			}
-
-			// tracks
-			minDistanceSq = Double.MAX_VALUE;
-			for (Track t : mv.dataSet.tracks) {
-				boolean wholeTrackSelected = t.segments.size() > 0;
-				for (LineSegment ls : t.segments) {
-					if (clicked) {
-						Point A = mv.getScreenPoint(ls.start.coor);
-						Point B = mv.getScreenPoint(ls.end.coor);
-						double c = A.distanceSq(B);
-						double a = center.distanceSq(B);
-						double b = center.distanceSq(A);
-						double perDist = perpendicularDistSq(a,b,c);
-						if (perDist < 100 && minDistanceSq > perDist && a < c+100 && b < c+100) {
-							minDistanceSq = perDist;
-							if (alt)
-								minPrimitive = t;
-							else
-								minPrimitive = ls;
-						}
-					} else {
-						if (alt) {
-							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))
-								ls.selected = selection;
-							else
-								wholeTrackSelected = false;
-						} else {
-							if (r.contains(mv.getScreenPoint(ls.start.coor))
-									&& r.contains(mv.getScreenPoint(ls.end.coor)))
-								ls.selected = selection;
-							else
-								wholeTrackSelected = false;
-						}
-					}
-				}
-				if (wholeTrackSelected && !clicked)
-					t.selected = true;
-			}
-			if (minPrimitive != null) {
-				minPrimitive.selected = selection;
-				return;
-			}
-			
-			// TODO arrays
-		} finally {
-			mv.repaint();
-		}
-	}
-
-	/**
-	 * Calculates the squared perpendicular distance named "h" from a point C to the
-	 * straight line going to the points A and B, where the distance to B is 
-	 * sqrt(a) and the distance to A is sqrt(b).
-	 * 
-	 * Think of a, b and c as the squared line lengths of any ordinary triangle 
-	 * A,B,C. a = BC, b = AC and c = AB. The straight line goes through A and B 
-	 * and the desired return value is the perpendicular distance from C to c.
-	 *
-	 * @param a Squared distance from B to C.
-	 * @param b Squared distance from A to C.
-	 * @param c Squared distance from A to B.
-	 * @return The perpendicular distance from C to c.
-	 */
-	private double perpendicularDistSq(double a, double b, double c) {
-		// I did this on paper by myself, so I am surprised too, that it is that 
-		// performant ;-) 
-		return a-(a-b+c)*(a-b+c)/4/c;
+		Collection<OsmPrimitive> selectionList = selectionManager.getObjectsInRectangle(r,alt);
+		for (OsmPrimitive osm : selectionList)
+			osm.selected = !ctrl;
+		mv.repaint();
 	}
 }
Index: src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java	(revision 6)
+++ src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java	(revision 7)
@@ -34,6 +34,6 @@
 	 */
 	private final SelectionManager selectionManager;
-	
-	
+
+
 	/**
 	 * Construct a ZoomAction without a label.
@@ -49,5 +49,5 @@
 	 * Zoom to the rectangle on the map.
 	 */
-	public void selectionEnded(Rectangle r, int modifier) {
+	public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) {
 		if (r.width >= 3 && r.height >= 3) {
 			double scale = mv.getScale() * r.getWidth()/mv.getWidth();
@@ -58,11 +58,13 @@
 
 	@Override
-	public void registerListener(MapView mapView) {
-		selectionManager.register(mapView);
+	public void registerListener() {
+		super.registerListener();
+		selectionManager.register(mv);
 	}
 
 	@Override
-	public void unregisterListener(MapView mapView) {
-		selectionManager.unregister(mapView);
+	public void unregisterListener() {
+		super.unregisterListener();
+		selectionManager.unregister(mv);
 	}
 }
Index: src/org/openstreetmap/josm/data/GeoPoint.java
===================================================================
--- src/org/openstreetmap/josm/data/GeoPoint.java	(revision 6)
+++ src/org/openstreetmap/josm/data/GeoPoint.java	(revision 7)
@@ -1,3 +1,4 @@
 package org.openstreetmap.josm.data;
+
 
 
@@ -65,4 +66,16 @@
 		return super.hashCode();
 	}
+
+	/**
+	 * Return the squared distance of the northing/easting values between 
+	 * this and the argument.
+	 *
+	 * @param other The other point to calculate the distance to.
+	 * @return The square of the distance between this and the other point,
+	 * 		regarding to the x/y values.
+	 */
+	public double distanceXY(GeoPoint other) {
+		return (x-other.x)*(x-other.x)+(y-other.y)*(y-other.y);
+	}
 	
 	
Index: src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 6)
+++ src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 7)
@@ -2,5 +2,6 @@
 
 import java.util.Collection;
-import java.util.List;
+import java.util.HashSet;
+import java.util.LinkedList;
 
 import org.openstreetmap.josm.data.Bounds;
@@ -19,9 +20,15 @@
 
 	/**
-	 * All nodes goes here, even when included in other data (tracks etc) listed.
+	 * 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 List<Node> allNodes;
+	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>();
 
 	/**
@@ -32,5 +39,5 @@
 	 * track list.
 	 */
-	public List<Track> tracks;
+	public Collection<Track> tracks;
 
 	/**
@@ -44,9 +51,10 @@
 	 */
 	public Bounds getBoundsXY() {
-		if (allNodes.size() == 0)
+		if (nodes.isEmpty())
 			return null;
 
-		Bounds b = new Bounds(allNodes.get(0).coor.clone(), allNodes.get(0).coor.clone());
-		for (Node w : allNodes)
+		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))
@@ -65,4 +73,24 @@
 
 	/**
+	 * Return all tracks that contain the node. If nothing found, an empty array
+	 * is returned.
+	 * 
+	 * @param node This node is searched.
+	 * @return All tracks, that reference the node in one of its line segments.
+	 */
+	public Collection<Track> getReferencedTracks(Node n) {
+		Collection<Track> all = new LinkedList<Track>();
+		for (Track t : tracks) {
+			for (LineSegment ls : t.segments) {
+				if (ls.start == n || ls.end == n) {
+					all.add(t);
+					break;
+				}
+			}
+		}
+		return all;
+	}
+	
+	/**
 	 * 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
@@ -75,9 +103,10 @@
 	 */
 	public Bounds getBoundsLatLon() {
-		if (allNodes.size() == 0)
+		if (nodes.isEmpty())
 			return null;
 
-		Bounds b = new Bounds(allNodes.get(0).coor.clone(), allNodes.get(0).coor.clone());
-		for (Node w : allNodes)
+		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))
@@ -99,8 +128,21 @@
 	 */
 	public void clearSelection() {
-		clearSelection(allNodes);
+		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.
+	 */
+	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;
 	}
 	
@@ -118,5 +160,23 @@
 		}
 	}
-	
+
+	/**
+	 * 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.selected)
+				sel.add(osm);
+			if (osm.keys != null)
+				sel.addAll(getSelected(osm.keys.keySet()));
+		}
+		return sel;
+	}
+
+
 	@Override
 	public DataSet clone() {
Index: src/org/openstreetmap/josm/data/osm/Key.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Key.java	(revision 6)
+++ src/org/openstreetmap/josm/data/osm/Key.java	(revision 7)
@@ -1,3 +1,6 @@
 package org.openstreetmap.josm.data.osm;
+
+import java.util.Collection;
+import java.util.LinkedList;
 
 
@@ -13,3 +16,26 @@
 	 */
 	public String name;
+
+	/**
+	 * Return an empty list, since keys cannot have nodes. 
+	 */
+	@Override
+	public Collection<Node> getAllNodes() {
+		return new LinkedList<Node>();
+	}
+
+	/**
+	 * Keys are equal, when their name is equal, regardless of their other keys.
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if (!(obj instanceof Key))
+			return false;
+		return name.equals(((Key)obj).name);
+	}
+
+	@Override
+	public int hashCode() {
+		return name.hashCode();
+	}
 }
Index: src/org/openstreetmap/josm/data/osm/LineSegment.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/LineSegment.java	(revision 6)
+++ src/org/openstreetmap/josm/data/osm/LineSegment.java	(revision 7)
@@ -1,3 +1,6 @@
 package org.openstreetmap.josm.data.osm;
+
+import java.util.Collection;
+import java.util.LinkedList;
 
 
@@ -28,3 +31,32 @@
 	 */
 	public Node end;
+
+	/**
+	 * Return start and end in a list.
+	 */
+	@Override
+	public Collection<Node> getAllNodes() {
+		LinkedList<Node> nodes = new LinkedList<Node>();
+		nodes.add(start);
+		nodes.add(end);
+		return nodes;
+	}
+
+	/**
+	 * Line segments are equal, if their starting and ending node and their
+	 * keys are equal.
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if (!(obj instanceof LineSegment))
+			return false;
+		return super.equals(obj) && 
+			start.equals(((LineSegment)obj).start) &&
+			end.equals(((LineSegment)obj).end);
+	}
+
+	@Override
+	public int hashCode() {
+		return super.hashCode() + start.hashCode() + end.hashCode();
+	}
 }	
Index: src/org/openstreetmap/josm/data/osm/Node.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Node.java	(revision 6)
+++ src/org/openstreetmap/josm/data/osm/Node.java	(revision 7)
@@ -1,3 +1,6 @@
 package org.openstreetmap.josm.data.osm;
+
+import java.util.Collection;
+import java.util.LinkedList;
 
 import org.openstreetmap.josm.data.GeoPoint;
@@ -36,4 +39,14 @@
 		return (coor == null ? 0 : coor.hashCode()) + super.hashCode();
 	}
+
+	/**
+	 * Return a list only this added.
+	 */
+	@Override
+	public Collection<Node> getAllNodes() {
+		LinkedList<Node> nodes = new LinkedList<Node>();
+		nodes.add(this);
+		return nodes;
+	}
 	
 	
Index: src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 6)
+++ src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 7)
@@ -1,4 +1,5 @@
 package org.openstreetmap.josm.data.osm;
 
+import java.util.Collection;
 import java.util.Map;
 
@@ -10,5 +11,5 @@
  * @author imi
  */
-public class OsmPrimitive {
+abstract public class OsmPrimitive {
 
 	/**
@@ -27,4 +28,33 @@
 	transient public 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)
+	 */
+	abstract public Collection<Node> getAllNodes();
+
+	/**
+	 * Return <code>true</code>, if either <code>this.keys</code> and 
+	 * <code>other.keys</code> is <code>null</code> or if they do not share Keys
+	 * with different values.
+	 *  
+	 * @param other		The second key-set to compare with.
+	 * @return	True, if the keysets are mergable
+	 */
+	public boolean keyPropertiesMergable(OsmPrimitive other) {
+		if ((keys == null) != (other.keys == null))
+			return false;
+
+		if (keys != null) {
+			for (Key k : keys.keySet())
+				if (other.keys.containsKey(k) && !keys.get(k).equals(other.keys.get(k)))
+					return false;
+			for (Key k : other.keys.keySet())
+				if (keys.containsKey(k) && !other.keys.get(k).equals(keys.get(k)))
+					return false;
+		}
+		return true;
+	}
+	
 	/**
 	 * Osm primitives are equal, when their keys are equal. 
@@ -49,5 +79,3 @@
 		return keys == null ? 0 : keys.hashCode();
 	}
-	
-	
 }
Index: src/org/openstreetmap/josm/data/osm/Track.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Track.java	(revision 6)
+++ src/org/openstreetmap/josm/data/osm/Track.java	(revision 7)
@@ -2,4 +2,5 @@
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 
@@ -14,4 +15,72 @@
 	 * All track segments in this track
 	 */
-	public List<LineSegment> segments = new ArrayList<LineSegment>();
+	public final List<LineSegment> segments = new ArrayList<LineSegment>();
+
+	/**
+	 * 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;
+	}
+
+	/**
+	 * Tracks are equal, when all segments and the keys are equal
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if (!(obj instanceof Track))
+			return false;
+		if (!super.equals(obj))
+			return false;
+		Track t = (Track)obj;
+		int size = segments.size();
+		if (size != t.segments.size())
+			return false;
+		for (int i = 0; i < size; ++i)
+			if (!segments.get(i).equals(t.segments.get(i)))
+				return false;
+		return true;
+	}
+
+	@Override
+	public int hashCode() {
+		int hash = super.hashCode();
+		for (LineSegment ls : segments)
+			hash += ls.hashCode();
+		return hash;
+	}
+
+	/**
+	 * Return the last node in the track. This is the node, which no line segment
+	 * has as start, but at least one has it as end. If there are not exact one
+	 * such nodes found, <code>null</code> is returned.
+	 *
+	 * TODO Currently does return just the end node in the list.
+	 *
+	 * @return The ending node, if there is one.
+	 */
+	public Node getEndingNode() {
+		if (segments.isEmpty())
+			return null;
+		return segments.get(segments.size()-1).end;
+	}
+
+	/**
+	 * Return the first node in the track. This is the node, which no line segment
+	 * has as end, but at least one as starting node. If there are not exact one
+	 * such nodes found, <code>null</code> is returned.
+	 * 
+	 * TODO Currently does return just the first node in the list.
+	 * 
+	 * @return The starting node, if there is one.
+	 */
+	public Node getStartingNode() {
+		if (segments.isEmpty())
+			return null;
+		return segments.get(0).start;
+	}
 }
Index: src/org/openstreetmap/josm/data/projection/Projection.java
===================================================================
--- src/org/openstreetmap/josm/data/projection/Projection.java	(revision 6)
+++ src/org/openstreetmap/josm/data/projection/Projection.java	(revision 7)
@@ -89,5 +89,5 @@
 	 */
 	public void init(DataSet dataSet) {
-		for (Node w : dataSet.allNodes)
+		for (Node w : dataSet.nodes)
 			latlon2xy(w.coor);
 	}
Index: src/org/openstreetmap/josm/gui/IconToggleButton.java
===================================================================
--- src/org/openstreetmap/josm/gui/IconToggleButton.java	(revision 6)
+++ src/org/openstreetmap/josm/gui/IconToggleButton.java	(revision 7)
@@ -1,3 +1,6 @@
 package org.openstreetmap.josm.gui;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 
 import javax.swing.Action;
@@ -11,5 +14,5 @@
  * @author imi
  */
-public class IconToggleButton extends JToggleButton {
+public class IconToggleButton extends JToggleButton implements PropertyChangeListener {
 
 	/**
@@ -19,7 +22,27 @@
 		super(action);
 		setText(null);
+		
+		// Tooltip
+		String toolTipText = "";
 		Object o = action.getValue(Action.LONG_DESCRIPTION);
 		if (o != null)
-			setToolTipText(o.toString());
+			toolTipText += o.toString();
+		o = action.getValue(Action.ACCELERATOR_KEY);
+		if (o != null) {
+			String ksName = o.toString();
+			if (ksName.startsWith("pressed "))
+				ksName = ksName.substring("pressed ".length());
+			else if (ksName.startsWith("released "))
+				ksName = ksName.substring("released ".length());
+			toolTipText += " Shortcut: "+ksName;
+		}
+		setToolTipText(toolTipText);
+		
+		action.addPropertyChangeListener(this);
+	}
+
+	public void propertyChange(PropertyChangeEvent evt) {
+		if (evt.getPropertyName() == "active")
+			setSelected((Boolean)evt.getNewValue());
 	}
 }
Index: src/org/openstreetmap/josm/gui/Main.java
===================================================================
--- src/org/openstreetmap/josm/gui/Main.java	(revision 6)
+++ src/org/openstreetmap/josm/gui/Main.java	(revision 7)
@@ -62,4 +62,10 @@
 		setExtendedState(MAXIMIZED_BOTH); // some platform are able to maximize
 		
+		// creating actions
+		OpenGpxAction openGpxAction = new OpenGpxAction();
+		SaveGpxAction saveGpxAction = new SaveGpxAction();
+		ExitAction exitAction = new ExitAction();
+		PreferencesAction preferencesAction = new PreferencesAction();
+
 		// creating menu
 		JMenuBar mainMenu = new JMenuBar();
@@ -68,13 +74,13 @@
 		JMenu fileMenu = new JMenu("Files");
 		fileMenu.setMnemonic('F');
-		fileMenu.add(new OpenGpxAction());
-		fileMenu.add(new SaveGpxAction());
+		fileMenu.add(openGpxAction);
+		fileMenu.add(saveGpxAction);
 		fileMenu.addSeparator();
-		fileMenu.add(new ExitAction());
+		fileMenu.add(exitAction);
 		mainMenu.add(fileMenu);
 		
 		JMenu editMenu = new JMenu("Edit");
 		editMenu.setMnemonic('E');
-		editMenu.add(new PreferencesAction());
+		editMenu.add(preferencesAction);
 		mainMenu.add(editMenu);
 
@@ -82,8 +88,8 @@
 		JToolBar toolBar = new JToolBar();
 		toolBar.setFloatable(false);
-		toolBar.add(new OpenGpxAction());
-		toolBar.add(new SaveGpxAction());
+		toolBar.add(openGpxAction);
+		toolBar.add(saveGpxAction);
 		toolBar.addSeparator();
-		toolBar.add(new PreferencesAction());
+		toolBar.add(preferencesAction);
 		
 		getContentPane().add(toolBar, BorderLayout.NORTH);
@@ -133,7 +139,9 @@
 		this.name = name;
 		this.mapFrame = mapFrame;
+		panel.setVisible(false);
 		panel.removeAll();
 		panel.add(mapFrame, BorderLayout.CENTER);
 		panel.add(mapFrame.getToolBarActions(), BorderLayout.WEST);
+		panel.setVisible(true);
 	}
 	/**
Index: src/org/openstreetmap/josm/gui/MapFrame.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapFrame.java	(revision 6)
+++ src/org/openstreetmap/josm/gui/MapFrame.java	(revision 7)
@@ -25,6 +25,12 @@
 import javax.swing.event.ChangeListener;
 
+import org.openstreetmap.josm.actions.mapmode.AddLineSegmentAction;
+import org.openstreetmap.josm.actions.mapmode.AddNodeAction;
+import org.openstreetmap.josm.actions.mapmode.AddTrackAction;
+import org.openstreetmap.josm.actions.mapmode.CombineAction;
 import org.openstreetmap.josm.actions.mapmode.DebugAction;
+import org.openstreetmap.josm.actions.mapmode.DeleteAction;
 import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.actions.mapmode.MoveAction;
 import org.openstreetmap.josm.actions.mapmode.SelectionAction;
 import org.openstreetmap.josm.actions.mapmode.ZoomAction;
@@ -39,5 +45,5 @@
  * @author imi
  */
-public class MapFrame extends JComponent {
+public class MapFrame extends JPanel {
 
 	/**
@@ -123,8 +129,15 @@
 
 		add(mapView = new MapView(dataSet), BorderLayout.CENTER);
-		
+
+		// toolbar
 		toolBarActions.setFloatable(false);
 		toolBarActions.add(new IconToggleButton(this, new ZoomAction(this)));
 		toolBarActions.add(new IconToggleButton(this, new SelectionAction(this)));
+		toolBarActions.add(new IconToggleButton(this, new MoveAction(this)));
+		toolBarActions.add(new IconToggleButton(this, new AddNodeAction(this)));
+		toolBarActions.add(new IconToggleButton(this, new AddLineSegmentAction(this)));
+		toolBarActions.add(new IconToggleButton(this, new AddTrackAction(this)));
+		toolBarActions.add(new IconToggleButton(this, new CombineAction(this)));
+		toolBarActions.add(new IconToggleButton(this, new DeleteAction(this)));
 		toolBarActions.add(new IconToggleButton(this, new DebugAction(this)));
 
@@ -159,7 +172,7 @@
 	public void selectMapMode(MapMode mapMode) {
 		if (this.mapMode != null)
-			this.mapMode.unregisterListener(mapView);
+			this.mapMode.unregisterListener();
 		this.mapMode = mapMode;
-		mapMode.registerListener(mapView);
+		mapMode.registerListener();
 	}
 
Index: src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapView.java	(revision 6)
+++ src/org/openstreetmap/josm/gui/MapView.java	(revision 7)
@@ -24,4 +24,5 @@
 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.projection.Projection;
@@ -81,45 +82,4 @@
 
 	
-	// Event handling functions and data
-	
-	/**
-	 * The event list with all state chaned listener
-	 */
-	List<ChangeListener> listener = new LinkedList<ChangeListener>();
-	/**
-	 * Add an event listener to the state changed event queue. If passed 
-	 * <code>null</code>, nothing happens.
-	 */
-	public final void addChangeListener(ChangeListener l) {
-		if (l != null)
-			listener.add(l);
-	}
-	/**
-	 * Remove an event listener from the event queue. If passed 
-	 * <code>null</code>, nothing happens.
-	 */
-	public final void removeChangeListener(ChangeListener l) {
-		listener.remove(l);
-	}
-	/**
-	 * Fires an ChangeEvent. Occours, when an non-data value changed, as example
-	 * the autoScale - state or the center. Is not fired, dataSet internal things
-	 * changes.
-	 */
-	public final void fireStateChanged() {
-		ChangeEvent e = null;
-		for(ChangeListener l : listener) {
-			if (e == null)
-				e = new ChangeEvent(this);
-			l.stateChanged(e);
-		}
-	}
-	
-	
-	
-	
-	
-	// other functions
-	
 	/**
 	 * Construct a MapView and attach it to a frame.
@@ -178,5 +138,83 @@
 		return new Point(toScreenX(p.x), toScreenY(p.y));
 	}
-	
+
+	/**
+	 * Return the object, that is nearest to the given screen point.
+	 * 
+	 * First, a node will be searched. If a node within 10 pixel is found, the
+	 * nearest node is returned.
+	 * 
+	 * If no node is found, search for pending line segments.
+	 * 
+	 * If no such line segment is found, and a non-pending line segment is 
+	 * within 10 pixel to p, this segment is returned, except when 
+	 * <code>wholeTrack</code> is <code>true</code>, in which case the 
+	 * corresponding Track is returned.
+	 * 
+	 * If no line segment is found and the point is within an area, return that
+	 * area.
+	 * 
+	 * If no area is found, return <code>null</code>.
+	 * 
+	 * @param p				The point on screen.
+	 * @param wholeTrack	Whether the whole track or only the line segment
+	 * 					 	should be returned.
+	 * @return	The primitive, that is nearest to the point p.
+	 */
+	public OsmPrimitive getNearest(Point p, boolean wholeTrack) {
+		double minDistanceSq = Double.MAX_VALUE;
+		OsmPrimitive minPrimitive = null;
+		
+		// nodes
+		for (Node n : dataSet.nodes) {
+			Point sp = getScreenPoint(n.coor);
+			double dist = p.distanceSq(sp);
+			if (minDistanceSq > dist && dist < 100) {
+				minDistanceSq = p.distanceSq(sp);
+				minPrimitive = n;
+			}
+		}
+		if (minPrimitive != null)
+			return minPrimitive;
+		
+		// pending line segments
+		for (LineSegment ls : dataSet.pendingLineSegments) {
+			Point A = getScreenPoint(ls.start.coor);
+			Point B = getScreenPoint(ls.end.coor);
+			double c = A.distanceSq(B);
+			double a = p.distanceSq(B);
+			double b = p.distanceSq(A);
+			double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
+			if (perDist < 100 && minDistanceSq > perDist && a < c+100 && b < c+100) {
+				minDistanceSq = perDist;
+				minPrimitive = ls;
+			}
+		}
+
+		// tracks & line segments
+		minDistanceSq = Double.MAX_VALUE;
+		for (Track t : dataSet.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);
+				double b = p.distanceSq(A);
+				double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
+				if (perDist < 100 && minDistanceSq > perDist && a < c+100 && b < c+100) {
+					minDistanceSq = perDist;
+					minPrimitive = wholeTrack ? t : ls;
+				}
+			}			
+		}
+		if (minPrimitive != null)
+			return minPrimitive;
+		
+		// TODO areas
+		
+		
+		return null; // nothing found
+	}
+
 	/**
 	 * Zoom to the given coordinate.
@@ -220,5 +258,5 @@
 				center = new GeoPoint(51.526447, -0.14746371);
 				getProjection().latlon2xy(center);
-				scale = 10000; // nice view from 1:10000, eh?
+				scale = 10;
 			} else {
 				center = bounds.centerXY();
@@ -258,8 +296,15 @@
 				}
 
+		// draw pending line segments
+		for (LineSegment ls : dataSet.pendingLineSegments) {
+			g.setColor(ls.selected ? Color.WHITE : Color.LIGHT_GRAY);
+			g.drawLine(toScreenX(ls.start.coor.x), toScreenY(ls.start.coor.y),
+					toScreenX(ls.end.coor.x), toScreenY(ls.end.coor.y));
+		}
+
 		// draw nodes
 		Set<Integer> alreadyDrawn = new HashSet<Integer>();
 		int width = getWidth();
-		for (Node w : dataSet.allNodes) {
+		for (Node w : dataSet.nodes) {
 			g.setColor(w.selected ? Color.WHITE : Color.RED);
 			int x = toScreenX(w.coor.x);
@@ -294,17 +339,40 @@
 	}
 
-	/**
-	 * Does nothing. Just to satisfy ComponentListener.
-	 */
-	public void componentMoved(ComponentEvent e) {}
-	/**
-	 * Does nothing. Just to satisfy ComponentListener.
-	 */
-	public void componentShown(ComponentEvent e) {}
-	/**
-	 * Does nothing. Just to satisfy ComponentListener.
-	 */
-	public void componentHidden(ComponentEvent e) {}
-
+
+	// Event handling functions and data
+	
+	/**
+	 * The event list with all state chaned listener
+	 */
+	List<ChangeListener> listener = new LinkedList<ChangeListener>();
+	/**
+	 * Add an event listener to the state changed event queue. If passed 
+	 * <code>null</code>, nothing happens.
+	 */
+	public final void addChangeListener(ChangeListener l) {
+		if (l != null)
+			listener.add(l);
+	}
+	/**
+	 * Remove an event listener from the event queue. If passed 
+	 * <code>null</code>, nothing happens.
+	 */
+	public final void removeChangeListener(ChangeListener l) {
+		listener.remove(l);
+	}
+	/**
+	 * Fires an ChangeEvent. Occours, when an non-data value changed, as example
+	 * the autoScale - state or the center. Is not fired, dataSet internal things
+	 * changes.
+	 */
+	public final void fireStateChanged() {
+		ChangeEvent e = null;
+		for(ChangeListener l : listener) {
+			if (e == null)
+				e = new ChangeEvent(this);
+			l.stateChanged(e);
+		}
+	}
+	
 	/**
 	 * Notify from the projection, that something has changed.
@@ -363,3 +431,16 @@
 		return center.clone();
 	}
+
+	/**
+	 * Does nothing. Just to satisfy ComponentListener.
+	 */
+	public void componentMoved(ComponentEvent e) {}
+	/**
+	 * Does nothing. Just to satisfy ComponentListener.
+	 */
+	public void componentShown(ComponentEvent e) {}
+	/**
+	 * Does nothing. Just to satisfy ComponentListener.
+	 */
+	public void componentHidden(ComponentEvent e) {}
 }
Index: src/org/openstreetmap/josm/gui/SelectionManager.java
===================================================================
--- src/org/openstreetmap/josm/gui/SelectionManager.java	(revision 6)
+++ src/org/openstreetmap/josm/gui/SelectionManager.java	(revision 7)
@@ -10,4 +10,13 @@
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Collection;
+import java.util.LinkedList;
+
+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;
 
 /**
@@ -36,5 +45,5 @@
  * @author imi
  */
-public class SelectionManager implements MouseListener, MouseMotionListener {
+public class SelectionManager implements MouseListener, MouseMotionListener, PropertyChangeListener {
 
 	/**
@@ -47,9 +56,21 @@
 		 * Called, when the left mouse button was released.
 		 * @param r The rectangle, that is currently the selection.
-		 * @param modifiers The modifiers returned from the MouseEvent when
-		 * 		the left mouse button was released. 
+		 * @param alt Whether the alt key was pressed
+		 * @param shift Whether the shift key was pressed
+		 * @param ctrl Whether the ctrl key was pressed 
 		 * @see InputEvent#getModifiersEx()
 		 */
-		public void selectionEnded(Rectangle r, int modifiers);
+		public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl);
+		/**
+		 * Called to register the selection manager for "active" property.
+		 * @param listener The listener to register
+		 */
+		public void addPropertyChangeListener(PropertyChangeListener listener);
+		/**
+		 * Called to remove the selection manager from the listener list 
+		 * for "active" property.
+		 * @param listener The listener to register
+		 */
+		public void removePropertyChangeListener(PropertyChangeListener listener);
 	}
 	/**
@@ -67,7 +88,7 @@
 	private Point mousePos;
 	/**
-	 * The component, the selection rectangle is drawn onto.
-	 */
-	private final Component drawComponent;
+	 * The MapView, the selection rectangle is drawn onto.
+	 */
+	private final MapView mv;
 	/**
 	 * Whether the selection rectangle must obtain the aspect ratio of the 
@@ -83,10 +104,10 @@
 	 * @param aspectRatio If true, the selection window must obtain the aspect
 	 * 		ratio of the drawComponent.
-	 * @param drawComponent The component, the rectangle is drawn onto.
-	 */
-	public SelectionManager(SelectionEnded selectionEndedListener, boolean aspectRatio, Component drawComponent) {
+	 * @param mapView The view, the rectangle is drawn onto.
+	 */
+	public SelectionManager(SelectionEnded selectionEndedListener, boolean aspectRatio, MapView mapView) {
 		this.selectionEndedListener = selectionEndedListener;
 		this.aspectRatio = aspectRatio;
-		this.drawComponent = drawComponent;
+		this.mv = mapView;
 	}
 	
@@ -98,4 +119,5 @@
 		eventSource.addMouseListener(this);
 		eventSource.addMouseMotionListener(this);
+		selectionEndedListener.addPropertyChangeListener(this);
 	}
 	/**
@@ -108,4 +130,5 @@
 		eventSource.removeMouseListener(this);
 		eventSource.removeMouseMotionListener(this);
+		selectionEndedListener.removePropertyChangeListener(this);
 	}
 
@@ -158,6 +181,10 @@
 		mousePosStart = null;
 		mousePos = null;
+
+		boolean shift = (e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0;
+		boolean alt = (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0;
+		boolean ctrl = (e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0;
 		if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) == 0)
-			selectionEndedListener.selectionEnded(r, e.getModifiersEx());
+			selectionEndedListener.selectionEnded(r, alt, shift, ctrl);
 	}
 
@@ -168,5 +195,5 @@
 	 */
 	private void paintRect() {
-		Graphics g = drawComponent.getGraphics();
+		Graphics g = mv.getGraphics();
 		g.setColor(Color.BLACK);
 		g.setXORMode(Color.WHITE);
@@ -196,5 +223,5 @@
 		if (aspectRatio) {
 			// keep the aspect ration by shrinking the rectangle
-			double aspectRatio = (double)drawComponent.getWidth()/drawComponent.getHeight();
+			double aspectRatio = (double)mv.getWidth()/mv.getHeight();
 			if ((double)w/h > aspectRatio) {
 				int neww = (int)(h*aspectRatio);
@@ -212,5 +239,87 @@
 		return new Rectangle(x,y,w,h);
 	}
+
+	/**
+	 * If the action goes inactive, remove the selection rectangle from screen
+	 */
+	public void propertyChange(PropertyChangeEvent evt) {
+		if (evt.getPropertyName() == "active" && !(Boolean)evt.getNewValue() && mousePosStart != null) {
+			paintRect();
+			mousePosStart = null;
+			mousePos = null;
+		}
+	}
+
+	/**
+	 * Return a list of all objects in the rectangle, respecting the different
+	 * modifier.
+	 * @param alt Whether the alt key was pressed, which means select all objects
+	 * 		that are touched, instead those which are completly covered. Also 
+	 * 		select whole tracks instead of line segments.
+	 */
+	public Collection<OsmPrimitive> getObjectsInRectangle(Rectangle r, boolean alt) {
+		Collection<OsmPrimitive> selection = new LinkedList<OsmPrimitive>();
+
+		// whether user only clicked, not dragged.
+		boolean clicked = r.width <= 2 && r.height <= 2;
+		Point center = new Point(r.x+r.width/2, r.y+r.height/2);
+
+		if (clicked) {
+			OsmPrimitive osm = mv.getNearest(center, alt);
+			if (osm != null)
+				selection.add(osm);
+		} else {
+			// nodes
+			for (Node n : mv.dataSet.nodes) {
+				if (r.contains(mv.getScreenPoint(n.coor)))
+					selection.add(n);
+			}
+			
+			// pending line segments
+			for (LineSegment ls : mv.dataSet.pendingLineSegments)
+				if (rectangleContainLineSegment(r, alt, ls))
+					selection.add(ls);
+
+			// tracks
+			for (Track t : mv.dataSet.tracks) {
+				boolean wholeTrackSelected = t.segments.size() > 0;
+				for (LineSegment ls : t.segments)
+					if (rectangleContainLineSegment(r, alt, ls))
+						selection.add(ls);
+					else
+						wholeTrackSelected = false;
+				if (wholeTrackSelected)
+					selection.add(t);
+			}
+			
+			// TODO areas
+		}
+		return selection;
+	}
+
+	/**
+	 * Decide whether the line segment is in the rectangle Return 
+	 * <code>true</code>, if it is in or false if not.
+	 * 
+	 * @param r			The rectangle, in which the line segment has to be.
+	 * @param alt		Whether user pressed the Alt key
+	 * @param ls		The line segment.
+	 * @return <code>true</code>, if the LineSegment was added to the selection.
+	 */
+	private boolean rectangleContainLineSegment(Rectangle r, boolean alt, LineSegment ls) {
+		if (alt) {
+			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.start.coor))
+					&& r.contains(mv.getScreenPoint(ls.end.coor)))
+				return true;
+		}
+		return false;
+	}
 	
+	
 	/**
 	 * Does nothing. Only to satisfy MouseListener
@@ -229,3 +338,4 @@
 	 */
 	public void mouseMoved(MouseEvent e) {}
+
 }
Index: src/org/openstreetmap/josm/io/GpxReader.java
===================================================================
--- src/org/openstreetmap/josm/io/GpxReader.java	(revision 6)
+++ src/org/openstreetmap/josm/io/GpxReader.java	(revision 7)
@@ -4,5 +4,4 @@
 import java.io.Reader;
 import java.util.ArrayList;
-import java.util.LinkedList;
 
 import org.jdom.Element;
@@ -12,7 +11,7 @@
 import org.openstreetmap.josm.data.GeoPoint;
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.LineSegment;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.Track;
-import org.openstreetmap.josm.data.osm.LineSegment;
 import org.openstreetmap.josm.gui.Main;
 
@@ -69,5 +68,4 @@
 		DataSet data = new DataSet();
 		// read waypoints not contained in tracks or areas
-		data.allNodes = new LinkedList<Node>(); 
 		for (Object o : e.getChildren("wpt", GPX))
 			addNode(data, parseWaypoint((Element)o));
@@ -109,8 +107,8 @@
 	private Node addNode (DataSet data, Node node) {
 		if (Main.pref.mergeNodes)
-			for (Node n : data.allNodes)
+			for (Node n : data.nodes)
 				if (node.equals(n))
 					return n;
-		data.allNodes.add(node);
+		data.nodes.add(node);
 		return node;
 	}
