Index: /src/org/openstreetmap/josm/Main.java
===================================================================
--- /src/org/openstreetmap/josm/Main.java	(revision 202)
+++ /src/org/openstreetmap/josm/Main.java	(revision 203)
@@ -160,6 +160,9 @@
 	public final void removeLayer(final Layer layer) {
 		map.mapView.removeLayer(layer);
-		if (layer instanceof OsmDataLayer)
-			ds = new DataSet();
+		if (layer instanceof OsmDataLayer) {
+			DataSet newDs = new DataSet();
+			newDs.listeners.addAll(ds.listeners);
+			ds = newDs;
+		}
 		if (map.mapView.getAllLayers().isEmpty())
 			setMapFrame(null);
Index: /src/org/openstreetmap/josm/actions/AutoScaleAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/AutoScaleAction.java	(revision 202)
+++ /src/org/openstreetmap/josm/actions/AutoScaleAction.java	(revision 203)
@@ -60,5 +60,5 @@
 		setCurrent(0);
 		this.mapFrame = mapFrame;
-		Main.ds.addSelectionChangedListener(new SelectionChangedListener(){
+		Main.ds.listeners.add(new SelectionChangedListener(){
 			public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
 				if (mode.equals("selection"))
Index: /src/org/openstreetmap/josm/actions/SplitWayAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/SplitWayAction.java	(revision 202)
+++ /src/org/openstreetmap/josm/actions/SplitWayAction.java	(revision 203)
@@ -98,5 +98,5 @@
 	public SplitWayAction() {
 		super(tr("Split Way"), "splitway", tr("Split a way at the selected node."), KeyEvent.VK_P, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK, true);
-		Main.ds.addSelectionChangedListener(this);
+		Main.ds.listeners.add(this);
 	}
 
@@ -230,9 +230,7 @@
 
 		// finally check if the selected way is complete.
-		for (Segment s : selectedWay.segments) {
-			if (s.incomplete) {
-				JOptionPane.showMessageDialog(Main.parent, tr("Warning: This way is incomplete. Try to download it before splitting."));
-				return;
-			}
+		if (selectedWay.isIncomplete()) {
+			JOptionPane.showMessageDialog(Main.parent, tr("Warning: This way is incomplete. Try to download it before splitting."));
+			return;
 		}
 
@@ -311,5 +309,5 @@
 				// the moveSegments method.
 				if (split) {
-					ArrayList<Segment> subSegments = new ArrayList<Segment>();
+					LinkedList<Segment> subSegments = new LinkedList<Segment>();
 					moveSegments(allSegments, subSegments, splitSeg, selectedNodes);
 					segmentSets.add(subSegments);
@@ -356,5 +354,5 @@
 			partThatContainsSegments.removeAll(selectedSegments);
 			if (!partThatContainsSegments.isEmpty()) {
-				ArrayList<Segment> contiguousSubpart = new ArrayList<Segment>();
+				LinkedList<Segment> contiguousSubpart = new LinkedList<Segment>();
 				moveSegments(partThatContainsSegments, contiguousSubpart, partThatContainsSegments.get(0), null);
 				// if partThatContainsSegments was contiguous before, it will now be empty as all segments
@@ -380,5 +378,5 @@
 
 			while (!allSegments.isEmpty()) {
-				List<Segment> subSegments = new LinkedList<Segment>();
+				LinkedList<Segment> subSegments = new LinkedList<Segment>();
 				moveSegments(allSegments, subSegments, allSegments.get(0), null);
 				segmentSets.add(subSegments);
@@ -465,7 +463,10 @@
 	 * @param stopNodes collection of nodes which should be considered end points for moving (may be null).
 	 */
-	private void moveSegments(Collection<Segment> source, Collection<Segment> destination, Segment start, Collection<Node> stopNodes) {
+	private void moveSegments(Collection<Segment> source, LinkedList<Segment> destination, Segment start, Collection<Node> stopNodes) {
 		source.remove(start);
-		destination.add(start);
+		if (destination.isEmpty() || destination.iterator().next().from.equals(start.to))
+			destination.addFirst(start);
+		else
+			destination.addLast(start);
 		Segment moveSeg = start;
 		while(moveSeg != null) {
@@ -473,5 +474,6 @@
 
 			for (Node node : new Node[] { start.from, start.to }) {
-				if (stopNodes != null && stopNodes.contains(node)) continue;
+				if (stopNodes != null && stopNodes.contains(node))
+					continue;
 				for (Segment sourceSeg : source) {
 					if (sourceSeg.from.equals(node) || sourceSeg.to.equals(node)) {
Index: /src/org/openstreetmap/josm/actions/mapmode/AddWayAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/mapmode/AddWayAction.java	(revision 202)
+++ /src/org/openstreetmap/josm/actions/mapmode/AddWayAction.java	(revision 203)
@@ -60,6 +60,5 @@
 	public AddWayAction(MapFrame mapFrame) {
 		super(tr("Add Way"), "addway", tr("Add a new way to the data."), KeyEvent.VK_W, mapFrame, ImageProvider.getCursor("normal", "way"));
-		
-		Main.ds.addSelectionChangedListener(this);
+		Main.ds.listeners.add(this);
 	}
 
Index: c/org/openstreetmap/josm/data/conflict/Merger.java
===================================================================
--- /src/org/openstreetmap/josm/data/conflict/Merger.java	(revision 202)
+++ 	(revision )
@@ -1,247 +1,0 @@
-package org.openstreetmap.josm.data.conflict;
-
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Segment;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.data.osm.visitor.AddVisitor;
-import org.openstreetmap.josm.data.osm.visitor.Visitor;
-
-/**
- * Merger provides an operation, that merges one dataset into an other, creating a list
- * of merged conflicts on the way.
- * 
- * @author Immanuel.Scholz
- */
-public class Merger {
-
-	/**
-	 * The map of all conflicting primitives. Keys are elements from our dataset (given at
-	 * constructor) and values are the associated primitives from the other dataset.
-	 * 
-	 * All references of the conflicting primitives point always to objects from our dataset.
-	 * This ensures, that later one you can just call osm.copyFrom(conflicts.get(osm)) to
-	 * "resolve" the conflict.
-	 */
-	public final Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>();
-
-	private final DataSet ds;
-
-	/**
-	 * Maps all resolved objects that were transferred to the own dataset. The key is 
-	 * the object from the other dataset given to merge(). The value is the object that
-	 * is the resolved one in the internal dataset. Both objects are from the same class.
-	 */
-	private Map<OsmPrimitive, OsmPrimitive> resolved = new HashMap<OsmPrimitive, OsmPrimitive>();
-
-
-	private AddVisitor adder;
-
-	/**
-	 * Hold the result of a decission between two elements. <code>MY</code> is keep my own,
-	 * THEIR<code>THEIR</code> means copy the other object over here and <code>CONFLICT</code>
-	 * means that both objects have to be looked closer at to decide it finally (there are
-	 * possible conflicts).
-	 */
-	private enum Solution {MY, THEIR, CONFLICT}
-
-	/**
-	 * @param ds The dataset that is the base to merge the other into.
-	 */
-	public Merger(DataSet ds) {
-		this.ds = ds;
-		adder = new AddVisitor(ds);
-	}
-
-	/**
-	 * This function merges the given dataset into the one given at constructor. The output
-	 * is dataset obtained at the constructor. Additional to that, a list of conflicts that
-	 * need to be resolved is created as member variable <code>conflicts</code>.
-	 * 
-	 * @param other The dataset that should be merged into the one given at construction time.
-	 */
-	public void merge(DataSet other) {
-		for (Node n : other.nodes)
-			merge(n);
-		for (Segment s : other.segments)
-			merge(s);
-		for (Way w : other.ways)
-			merge(w);
-	}
-
-
-	/**
-	 * Merge the object into the own dataset or add it as conflict.
-	 */
-	public void merge(OsmPrimitive their) {
-		// find the matching partner in my dataset
-		OsmPrimitive my;
-		if (their.id == 0)
-			my = findSimilar(their);
-		else {
-			my = find(their);
-			if (my == null)
-				my = findSimilar(their); // give it a second chance.
-		}
-		
-		// partner are found, solve both primitives
-		
-		if (my == null) {
-			// their is new? -> import their to my
-			their.visit(adder);
-			resolved.put(their, their);
-			copyReferences(their);
-			return;
-		}
-		Solution solution = solve(my, their);
-
-		switch(solution) {
-		case MY:
-			resolved.put(my, my);
-			return;
-		case THEIR:
-			resolved.put(their, my);
-			copyReferences(their);
-			my.cloneFrom(their);
-			return;
-		case CONFLICT:
-			resolved.put(their, my); // thats correct. Put all references from the own in case of conflicts
-			conflicts.put(my, their);
-			copyReferences(their);
-			return;
-		}
-
-	}
-
-	/**
-	 * Replace all references in the given primitive with those from resolved map
-	 */
-	private void copyReferences(OsmPrimitive osm) {
-		osm.visit(new Visitor() {
-			public void visit(Node n) {}
-			public void visit(Segment s) {
-				s.from = (Node)resolved.get(s.from);
-				s.to = (Node)resolved.get(s.to);
-				if (s.from == null || s.to == null)
-					throw new NullPointerException();
-            }
-			public void visit(Way w) {
-				Collection<Segment> segments = new LinkedList<Segment>(w.segments);
-				w.segments.clear();
-				for (Segment s : segments) {
-					if (!resolved.containsKey(s))
-						throw new NullPointerException();
-					w.segments.add((Segment)resolved.get(s));
-				}
-            }
-		});
-    }
-
-	/**
-	 * Decide what solution is necessary for my and their object to be solved. If both
-	 * objects are as good as each other, use my object (since it is cheaper to keep it than
-	 * change everything).
-	 *
-	 * @return Which object should be used or conflict in case of problems.
-	 */
-	private Solution solve(OsmPrimitive my, OsmPrimitive their) {
-		Date myDate = my.timestamp == null ? new Date(0) : my.timestamp;
-		Date theirDate = their.timestamp == null ? new Date(0) : their.timestamp;
-		Date baseDate = theirDate.before(myDate) ? theirDate : myDate;
-
-		if (my.id == 0 && their.id != 0)
-			return Solution.THEIR;
-		if (my.id != 0 && their.id == 0)
-			return Solution.MY;
-		if (my.id == 0 && their.id == 0)
-			return my.realEqual(their) ? Solution.MY : Solution.CONFLICT;
-
-		// from here on, none primitives is new
-
-		boolean myChanged = my.modified  || myDate.after(baseDate);
-		boolean theirChanged = their.modified  || theirDate.after(baseDate);
-		if (myChanged && theirChanged)
-			return my.realEqual(their) ? Solution.MY : Solution.CONFLICT;
-		if (theirChanged)
-			return Solution.THEIR;
-		if (my instanceof Segment && ((Segment)my).incomplete && !((Segment)their).incomplete)
-			return Solution.THEIR;
-		return Solution.MY;
-	}
-
-	/**
-	 * Try to find the object in the own dataset.
-	 * @return Either the object from the own dataset or <code>null</code> if not there.
-	 */
-	private OsmPrimitive find(OsmPrimitive osm) {
-		for (OsmPrimitive own : ds.allPrimitives())
-			if (own.equals(osm))
-				return own;
-		return null;
-	}
-
-	/**
-     * Find an primitive from our dataset that matches the given primitive by having the 
-     * same location. Do not look for the id for this.
-     * 
-     * @return For nodes, return the first node with the same location (in tolerance to the
-     * servers imprecision epsilon). For segments return for same starting/ending nodes.
-     * For ways, return if consist of exact the same segments.
-     */
-    private OsmPrimitive findSimilar(OsmPrimitive their) {
-    	final OsmPrimitive[] ret = new OsmPrimitive[1];
-    	Visitor v = new Visitor(){
-			public void visit(Node n) {
-				// go for an exact match first
-				for (Node my : ds.nodes) {
-					if (my.coor.equals(n.coor)) {
-						ret[0] = my;
-						return;
-					}
-				}
-				// second chance with epsilon
-				for (Node my : ds.nodes) {
-					if (my.coor.equalsEpsilon(n.coor)) {
-						ret[0] = my;
-						return;
-					}
-				}
-            }
-			public void visit(Segment s) {
-				for (Segment my : ds.segments) {
-					if (my.from == s.from && my.to == s.to) {
-						ret[0] = my;
-						return;
-					}
-				}
-            }
-			public void visit(Way w) {
-				for (Way my : ds.ways) {
-					boolean eq = true;
-					Iterator<Segment> myIt = my.segments.iterator();
-					Iterator<Segment> theirIt = w.segments.iterator();
-					while (myIt.hasNext() && theirIt.hasNext()) {
-						if (myIt.next() != theirIt.next()) {
-							eq = false;
-							break;
-						}
-					}
-					if (eq && !myIt.hasNext() && !theirIt.hasNext()) {
-						ret[0] = my;
-						return;
-					}
-				}
-            }
-    	};
-    	their.visit(v);
-    	return ret[0];
-    }
-}
Index: /src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 202)
+++ /src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 203)
@@ -5,5 +5,4 @@
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -47,5 +46,5 @@
 	 * A list of listeners to selection changed events.
 	 */
-	transient Collection<SelectionChangedListener> listeners = new LinkedList<SelectionChangedListener>();
+	transient public Collection<SelectionChangedListener> listeners = new LinkedList<SelectionChangedListener>();
 
 	/**
@@ -143,45 +142,3 @@
 			l.selectionChanged(sel);
 	}
-
-	/**
-	 * Add a listener to the selection changed listener list. If <code>null</code>
-	 * is passed, nothing happens.
-	 * @param listener The listener to add to the list.
-	 */
-	public void addSelectionChangedListener(SelectionChangedListener listener) {
-		if (listener != null)
-			listeners.add(listener);
-	}
-
-	/**
-	 * Remove a listener from the selection changed listener list.
-	 * If <code>null</code> is passed, nothing happens.
-	 * @param listener The listener to remove from the list.
-	 */
-	public void removeSelectionChangedListener(SelectionChangedListener listener) {
-		if (listener != null)
-			listeners.remove(listener);
-	}
-
-	public void addAllSelectionListener(DataSet ds) {
-		listeners.addAll(ds.listeners);
-	}
-
-	/**
-	 * Compares this and the parameter dataset and return <code>true</code> if both
-	 * contain the same data primitives (ignoring the selection)
-	 */
-	public boolean realEqual(Collection<OsmPrimitive> other) {
-		Collection<OsmPrimitive> my = allPrimitives();
-
-		if (my.size() != other.size())
-			return false;
-
-		Iterator<OsmPrimitive> it = other.iterator();
-		for (OsmPrimitive osm : my)
-			if (!osm.realEqual(it.next()))
-				return false;
-
-		return true;
-	}
 }
Index: /src/org/openstreetmap/josm/data/osm/Node.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/Node.java	(revision 202)
+++ /src/org/openstreetmap/josm/data/osm/Node.java	(revision 203)
@@ -43,6 +43,6 @@
 	}
 
-	@Override public boolean realEqual(OsmPrimitive osm) {
-		return osm instanceof Node ? super.realEqual(osm) && coor.equals(((Node)osm).coor) : false;
+	@Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
+		return osm instanceof Node ? super.realEqual(osm, semanticOnly) && coor.equals(((Node)osm).coor) : false;
     }
 
Index: /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 202)
+++ /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 203)
@@ -166,13 +166,14 @@
 	/**
 	 * Perform an equality compare for all non-volatile fields not only for the id 
-	 * but for the whole object (for conflict resolving etc)
+	 * but for the whole object (for conflict resolving)
+	 * @param semanticOnly if <code>true</code>, modified flag and timestamp are not compared
 	 */
-	public boolean realEqual(OsmPrimitive osm) {
+	public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
 		return
-		id == osm.id && 
-		modified == osm.modified && 
-		deleted == osm.deleted &&
-		(timestamp == null ? osm.timestamp==null : timestamp.equals(osm.timestamp)) &&
-		(keys == null ? osm.keys==null : keys.equals(osm.keys));
+			id == osm.id && 
+			(semanticOnly || (modified == osm.modified)) && 
+			deleted == osm.deleted &&
+			(semanticOnly || (timestamp == null ? osm.timestamp==null : timestamp.equals(osm.timestamp))) &&
+			(keys == null ? osm.keys==null : keys.equals(osm.keys));
 	}
 	
Index: /src/org/openstreetmap/josm/data/osm/Segment.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/Segment.java	(revision 202)
+++ /src/org/openstreetmap/josm/data/osm/Segment.java	(revision 203)
@@ -79,10 +79,10 @@
 	}
 
-	@Override public boolean realEqual(OsmPrimitive osm) {
+	@Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
 		if (!(osm instanceof Segment))
-			return super.realEqual(osm); 
+			return super.realEqual(osm, semanticOnly); 
 		if (incomplete)
 			return ((Segment)osm).incomplete;
-		return super.realEqual(osm) && from.equals(((Segment)osm).from) && to.equals(((Segment)osm).to);
+		return super.realEqual(osm, semanticOnly) && from.equals(((Segment)osm).from) && to.equals(((Segment)osm).to);
 	}
 
Index: /src/org/openstreetmap/josm/data/osm/Way.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/Way.java	(revision 202)
+++ /src/org/openstreetmap/josm/data/osm/Way.java	(revision 203)
@@ -43,6 +43,6 @@
     }
 
-	@Override public boolean realEqual(OsmPrimitive osm) {
-		return osm instanceof Way ? super.realEqual(osm) && segments.equals(((Way)osm).segments) : false;
+	@Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
+		return osm instanceof Way ? super.realEqual(osm, semanticOnly) && segments.equals(((Way)osm).segments) : false;
     }
 
Index: /src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java	(revision 202)
+++ /src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java	(revision 203)
@@ -295,15 +295,25 @@
 
 	/**
-	 * @return <code>true</code>, if no merge is needed.
+	 * @return <code>true</code>, if no merge is needed or merge is performed already.
 	 */
 	private <P extends OsmPrimitive> boolean mergeAfterId(Map<P,P> merged, Collection<P> primitives, P other) {
 		for (P my : primitives) {
-			if (my.realEqual(other))
+			Date d1 = my.timestamp == null ? new Date(0) : my.timestamp;
+			Date d2 = other.timestamp == null ? new Date(0) : other.timestamp;
+			if (my.realEqual(other, false))
 				return true; // no merge needed.
+			if (my.realEqual(other, true)) {
+				// they differ in modified/timestamp combination only. Auto-resolve it.
+				if (merged != null)
+					merged.put(other, my);
+				if (d1.before(d2)) {
+					my.modified = other.modified;
+					my.timestamp = other.timestamp;
+				}
+				return true; // merge done.
+			}
 			if (my.id == other.id && my.id != 0) {
 				if (my instanceof Segment && ((Segment)my).incomplete)
 					return false; // merge always over an incomplete
-				Date d1 = my.timestamp == null ? new Date(0) : my.timestamp;
-				Date d2 = other.timestamp == null ? new Date(0) : other.timestamp;
 				if (my.modified && other.modified) {
 					conflicts.put(my, other);
Index: /src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- /src/org/openstreetmap/josm/gui/MapView.java	(revision 202)
+++ /src/org/openstreetmap/josm/gui/MapView.java	(revision 203)
@@ -89,5 +89,5 @@
 
 		// listend to selection changes to redraw the map
-		Main.ds.addSelectionChangedListener(new SelectionChangedListener(){
+		Main.ds.listeners.add(new SelectionChangedListener(){
 			public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
 				repaint();
@@ -119,5 +119,5 @@
 			}
 			editLayer = dataLayer;
-			dataLayer.data.addAllSelectionListener(Main.ds);
+			dataLayer.data.listeners.addAll(Main.ds.listeners);
 			Main.ds = dataLayer.data;
 			dataLayer.listenerModified.add(new ModifiedChangedListener(){
Index: /src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java
===================================================================
--- /src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java	(revision 202)
+++ /src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java	(revision 203)
@@ -86,5 +86,5 @@
 		add(buttonPanel, BorderLayout.SOUTH);
 
-		Main.ds.addSelectionChangedListener(new SelectionChangedListener(){
+		Main.ds.listeners.add(new SelectionChangedListener(){
 			public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
 				displaylist.clearSelection();
Index: /src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java
===================================================================
--- /src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java	(revision 202)
+++ /src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java	(revision 203)
@@ -143,8 +143,8 @@
 	@Override public void setVisible(boolean b) {
 		if (b) {
-			Main.ds.addSelectionChangedListener(this);
+			Main.ds.listeners.add(this);
 			selectionChanged(Main.ds.getSelected());
 		} else {
-			Main.ds.removeSelectionChangedListener(this);
+			Main.ds.listeners.remove(this);
 		}
 		super.setVisible(b);
Index: /src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java
===================================================================
--- /src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java	(revision 202)
+++ /src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java	(revision 203)
@@ -328,8 +328,8 @@
 	@Override public void setVisible(boolean b) {
 		if (b) {
-			Main.ds.addSelectionChangedListener(this);
+			Main.ds.listeners.add(this);
 			selectionChanged(Main.ds.getSelected());
 		} else {
-			Main.ds.removeSelectionChangedListener(this);
+			Main.ds.listeners.remove(this);
 		}
 		super.setVisible(b);
Index: /src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java
===================================================================
--- /src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java	(revision 202)
+++ /src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java	(revision 203)
@@ -89,8 +89,8 @@
 	@Override public void setVisible(boolean b) {
 		if (b) {
-			Main.ds.addSelectionChangedListener(this);
+			Main.ds.listeners.add(this);
 			selectionChanged(Main.ds.getSelected());
 		} else {
-			Main.ds.removeSelectionChangedListener(this);
+			Main.ds.listeners.remove(this);
 		}
 		super.setVisible(b);
Index: /src/org/openstreetmap/josm/io/OsmServerWriter.java
===================================================================
--- /src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 202)
+++ /src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 203)
@@ -74,4 +74,5 @@
 			}
 		} catch (RuntimeException e) {
+			e.printStackTrace();
 			throw new SAXException("An error occoured: "+e.getMessage());
 		}
Index: st/org/openstreetmap/josm/data/conflict/MergerTest.java
===================================================================
--- /test/org/openstreetmap/josm/data/conflict/MergerTest.java	(revision 202)
+++ 	(revision )
@@ -1,334 +1,0 @@
-package org.openstreetmap.josm.data.conflict;
-
-import java.util.Date;
-
-import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.Segment;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.testframework.Bug;
-import org.openstreetmap.josm.testframework.DataSetTestCaseHelper;
-import org.openstreetmap.josm.testframework.MotherObject;
-
-public class MergerTest extends MotherObject {
-
-	private DataSet ds;
-	private Node my;
-	private Node their;
-	private Merger merger;
-
-	private Segment createSegment(DataSet ds, boolean incomplete, boolean deleted, int id) {
-    	Node n1 = DataSetTestCaseHelper.createNode(ds);
-    	Node n2 = DataSetTestCaseHelper.createNode(ds);
-    	Segment s = DataSetTestCaseHelper.createSegment(ds, n1, n2);
-    	s.incomplete = incomplete;
-    	s.id = id;
-    	s.deleted = deleted;
-    	s.timestamp = new Date();
-    	return s;
-    }
-
-
-	/**
-     * Create that amount of nodes and add them to the dataset. The id will be 1,2,3,4...
-     * @param amount Number of nodes to create.
-     * @return The created nodes.
-     */
-    private Node[] createNodes(DataSet ds, int amount) {
-    	Node[] nodes = new Node[amount];
-    	for (int i = 0; i < amount; ++i) {
-    		nodes[i] = DataSetTestCaseHelper.createNode(ds);
-    		nodes[i].id = i+1;
-    	}
-    	return nodes;
-    }
-
-
-	@Override protected void setUp() throws Exception {
-		ds = new DataSet();
-		my = DataSetTestCaseHelper.createNode(ds);
-		merger = new Merger(ds);
-		their = DataSetTestCaseHelper.createNode(null);
-	}
-
-
-	public void testNodesMergeUpdate() {
-		my.id = 1;
-		their.id = 1;
-		their.timestamp = new Date();
-		merger.merge(their);
-		assertEquals(my, their);
-	}
-	public void testNodesMergeModified() {
-		my.id = 1;
-		their.id = 1;
-		their.modified = true;
-		merger.merge(their);
-		assertEquals(my, their);
-	}
-	public void testNodesConflictBothModified() {
-		their.modified = true;
-		my.modified = true;
-		their.id = 1;
-		my.id = 1;
-		merger.merge(their);
-		assertEquals(1, merger.conflicts.size());
-	}
-	public void testNodesConflict() {
-		my.id = 1;
-		my.timestamp = new Date();
-		their.id = 1;
-		their.modified = true;
-		their.timestamp = new Date(my.timestamp.getTime()-1);
-		merger.merge(their);
-		assertEquals(1, merger.conflicts.size());
-		assertSame(my, merger.conflicts.keySet().iterator().next());
-		assertSame(their, merger.conflicts.values().iterator().next());
-	}
-
-	public void testConflictWhenMergingUnmodifiedNewerPrimitiveOverModified() {
-		my.id = their.id = 1;
-		my.modified = true;
-
-		my.timestamp = new Date();
-		their.timestamp = new Date(my.timestamp.getTime()+1);
-		
-		merger.merge(their);
-		
-		assertEquals(1, merger.conflicts.size());
-	}
-
-	public void testNodesConflictModifyDelete() {
-		my.id = 1;
-		my.modified = true;
-		their.id = 1;
-		their.delete(true);
-		merger.merge(their);
-		assertEquals(1, merger.conflicts.size());
-	}
-
-	public void testNodesMergeSamePosition() {
-		their.id = 1; // new node comes from server
-		my.modified = true; // our node is modified
-		my.coor = new LatLon(their.coor.lat(), their.coor.lon());
-		merger.merge(their);
-		assertEquals(0, merger.conflicts.size());
-		assertEquals(1, my.id);
-		assertFalse("updating a new node clear the modified state", my.modified);
-	}
-
-	public void testNoConflictNewNodesMerged() {
-		assertEquals(0, their.id);
-		assertEquals(0, my.id);
-		merger.merge(their);
-		assertEquals(0,merger.conflicts.size());
-		assertTrue(ds.nodes.contains(their));
-		assertEquals(2, ds.nodes.size());
-	}
-
-	/**
-	 * Test that two new segments that have different from/to are not merged
-	 */
-	@Bug(101)
-	public void testNewSegmentsWithDifferentNodesNotMerged() {
-		Node my2 = createNode();
-		Segment mySeg = new Segment(my, my2);
-		my.id = 1;
-		my2.id = 2;
-		ds.nodes.add(my2);
-		ds.segments.add(mySeg);
-		
-		DataSet ds2 = new DataSet();
-		their = new Node(my);
-		Node their2 = new Node(my2);
-		Segment theirSeg = new Segment(their2, their);
-		ds2.nodes.add(their);
-		ds2.nodes.add(their2);
-		ds2.segments.add(theirSeg);
-
-		merger.merge(ds2);
-		
-		assertEquals(2, ds.segments.size());
-	}
-	
-	public void testReferencesOfConflictingSegmentsPointToMyDataset() {
-		// make two nodes mergable
-		my.id = their.id = 1;
-		their.timestamp = new Date();
-		// have an old segment with the old node
-		Segment sold = new Segment(my, my);
-		ds.segments.add(sold);
-		// have a conflicting segment point to the new node
-		Segment s = new Segment(their,DataSetTestCaseHelper.createNode(null));
-		sold.id = s.id = 23;
-		sold.modified = s.modified = true;
-
-		DataSet ds2 = new DataSet();
-		ds2.nodes.add(s.from);
-		ds2.nodes.add(s.to);
-		ds2.segments.add(s);
-
-		merger.merge(ds2);
-
-		assertEquals(their.timestamp, my.timestamp);
-		assertEquals(1, merger.conflicts.size());
-		assertSame(s.from, my);
-	}
-
-	public void testNoConflictForSame() {
-		my.id = 1;
-		my.modified = true;
-		their.cloneFrom(my);
-		merger.merge(their);
-		assertEquals(0, merger.conflicts.size());
-	}
-
-	/**
-	 * Merge of an old segment with a new one. This should
-	 * be mergable (if the nodes matches).
-	 */
-	public void testMergeOldSegmentsWithNew() {
-		ds = new DataSet();
-		Node n1 = createNode();
-		Node n2 = createNode();
-		Segment ls = new Segment(n1, n2);
-		ls.id = 3;
-		ds.nodes.add(n1);
-		ds.nodes.add(n2);
-		ds.segments.add(ls);
-		merger = new Merger(ds);
-		
-		DataSet ds2 = new DataSet();
-		Node newN1 = new Node(n1);
-		Node newN2 = new Node(n2);
-		Segment newLs = new Segment(newN1, newN2);
-		ds2.nodes.add(newN1);
-		ds2.nodes.add(newN2);
-		ds2.segments.add(newLs);
-
-		merger.merge(ds2);
-
-		assertEquals("segment should have been merged.", 1, ds.segments.size());
-	}
-
-	/**
-	 * Incomplete segments should always loose.
-	 */
-	public void testImportIncomplete() throws Exception {
-		Segment s1 = DataSetTestCaseHelper.createSegment(ds, my, my);
-		s1.id = 1;
-		Segment s2 = new Segment(s1);
-		s1.incomplete = true;
-		s2.timestamp = new Date();
-		merger.merge(s2);
-		assertTrue(s1.realEqual(s2));
-	}
-	/**
-	 * Incomplete segments should extend existing ways.
-	 */
-	public void testImportIncompleteExtendWays() throws Exception {
-		Segment s1 = DataSetTestCaseHelper.createSegment(ds, my, my);
-		Way w = DataSetTestCaseHelper.createWay(ds, new Segment[]{s1});
-		s1.id = 1;
-		Segment s2 = new Segment(s1);
-		s1.incomplete = true;
-		merger.merge(s2);
-		assertEquals(1, w.segments.size());
-		assertEquals(s2, w.segments.get(0));
-		assertFalse(s2.incomplete);
-	}
-
-
-	/**
-	 * Nodes beeing merged are equal but should be the same.
-	 */
-	@Bug(54)
-	public void testEqualNotSame() {
-		ds = new DataSet();
-		// create a dataset with segment a-b
-		Node n[] = createNodes(ds, 2);
-		Segment ls1 = DataSetTestCaseHelper.createSegment(ds, n[0], n[1]);
-		ls1.id = 1;
-
-		// create an other dataset with segment a'-c (a' is equal, but not same to a)
-		DataSet ds2 = new DataSet();
-		Node n2[] = createNodes(ds2, 2);
-		n2[0].coor = new LatLon(n[0].coor.lat(), n[0].coor.lon());
-		n2[0].id = 0;
-		n2[1].id = 42;
-
-		Segment ls2 = DataSetTestCaseHelper.createSegment(ds, n2[0], n2[1]);
-		merger = new Merger(ds);
-		merger.merge(ds2);
-
-		assertSame(ls1.from, ls2.from);
-	}
-
-
-	public void testCloneWayNotIncomplete() {
-		ds = new DataSet();
-		Node[] n = createNodes(ds, 2);
-		Segment s = DataSetTestCaseHelper.createSegment(ds, n[0], n[1]);
-		Way w = DataSetTestCaseHelper.createWay(ds, s);
-		
-		merger = new Merger(ds);
-		DataSet ds2 = new DataSet();
-		ds2.nodes.add(n[0]);
-		ds2.nodes.add(n[1]);
-		ds2.segments.add(s);
-		ds2.ways.add(w);
-		merger.merge(ds2);
-
-		Way w2 = new Way(w);
-		w2.timestamp = new Date();
-		Segment s2 = new Segment(s);
-		s2.incomplete = true;
-		w2.segments.clear();
-		w2.segments.add(s2);
-		merger.merge(w2);
-
-		assertSame("Do not import incomplete segments when merging ways.", s, w.segments.iterator().next());
-	}
-
-	/**
-	 * When merging an incomplete way over a dataset that contain already all
-	 * necessary segments, the way must be completed.
-	 */
-	@Bug(117)
-	public void testMergeIncompleteOnExistingDoesNotComplete() {
-		// create a dataset with an segment (as base for the later incomplete way)
-		ds = new DataSet();
-		Node[] n = createNodes(ds, 2);
-		Segment s = DataSetTestCaseHelper.createSegment(ds, n[0], n[1]);
-		s.id = 23;
-		// create an incomplete way which references the former segment
-		Way w = new Way();
-		Segment incompleteSegment = new Segment(s.id);
-		w.segments.add(incompleteSegment);
-		w.id = 42;
-
-		// merge both
-		merger = new Merger(ds);
-		merger.merge(w);
-		
-		assertTrue(ds.ways.contains(w));
-		assertEquals(1, w.segments.size());
-		assertFalse(w.segments.get(0).incomplete);
-	}
-	
-	/**
-	 * Deleted segments should raise an conflict when merged over changed segments. 
-	 */
-	public void testMergeDeletedOverChangedConflict() {
-		ds = new DataSet();
-		createSegment(ds, false, false, 23).modified = true;
-		Segment s = createSegment(null, false, true, 23);
-		s.timestamp = new Date(new Date().getTime()+1);
-		
-		merger = new Merger(ds);
-		merger.merge(s);
-		
-		assertEquals(1, merger.conflicts.size());
-	}
-}
Index: /test/org/openstreetmap/josm/data/osm/DataSetTest.java
===================================================================
--- /test/org/openstreetmap/josm/data/osm/DataSetTest.java	(revision 202)
+++ /test/org/openstreetmap/josm/data/osm/DataSetTest.java	(revision 203)
@@ -77,5 +77,5 @@
 	public void testFireSelectionChanged() {
 		TestSelectionChangeListener l = new TestSelectionChangeListener();
-		ds.addSelectionChangedListener(l);
+		ds.listeners.add(l);
 		ds.setSelected(segment);
 		assertNotNull(l.called);
@@ -84,33 +84,15 @@
 	}
 
-	public void testAddRemoveSelectionChangedListener() {
-		TestSelectionChangeListener l = new TestSelectionChangeListener();
-		ds.addSelectionChangedListener(l);
-		ds.removeSelectionChangedListener(l);
-		ds.setSelected(way);
-		assertNull(l.called);
-	}
-
 	public void testAddAllSelectionListener() {
 		DataSet ds2 = new DataSet();
 		TestSelectionChangeListener l1 = new TestSelectionChangeListener();
 		TestSelectionChangeListener l2 = new TestSelectionChangeListener();
-		ds2.addSelectionChangedListener(l1);
-		ds2.addSelectionChangedListener(l2);
-		ds.addAllSelectionListener(ds2);
-		ds2.removeSelectionChangedListener(l1);
+		ds2.listeners.add(l1);
+		ds2.listeners.add(l2);
+		ds.listeners.addAll(ds2.listeners);
+		ds2.listeners.remove(l1);
 		ds.setSelected(node2);
 		assertNotNull(l1.called);
 		assertNotNull(l2.called);
 	}
-
-	public void testRealEqual() {
-		Collection<OsmPrimitive> all = new LinkedList<OsmPrimitive>();
-		all.add(new Node(node1));
-		all.add(new Node(node2));
-		all.add(new Node(node3));
-		all.add(createSegment(segment.id, node1, node2));
-		all.add(createWay(way.id, way.segments.iterator().next()));
-		assertTrue(ds.realEqual(all));
-	}
 }
Index: /test/org/openstreetmap/josm/data/osm/NodeTest.java
===================================================================
--- /test/org/openstreetmap/josm/data/osm/NodeTest.java	(revision 202)
+++ /test/org/openstreetmap/josm/data/osm/NodeTest.java	(revision 203)
@@ -21,14 +21,14 @@
 	public void testCloneFromRealEqual() {
 		Node node2 = createNode(23,3,4);
-		assertFalse(node2.realEqual(node));
-		assertFalse(node.realEqual(node2));
+		assertFalse(node2.realEqual(node, false));
+		assertFalse(node.realEqual(node2, false));
 		node.cloneFrom(node2);
-		assertTrue(node2.realEqual(node));
-		assertTrue(node.realEqual(node2));
+		assertTrue(node2.realEqual(node, false));
+		assertTrue(node.realEqual(node2, false));
 	}
 
 	public void testNodeNode() {
 		Node node2 = new Node(node);
-		assertTrue(node2.realEqual(node));
+		assertTrue(node2.realEqual(node, false));
 	}
 
Index: /test/org/openstreetmap/josm/data/osm/SegmentTest.java
===================================================================
--- /test/org/openstreetmap/josm/data/osm/SegmentTest.java	(revision 202)
+++ /test/org/openstreetmap/josm/data/osm/SegmentTest.java	(revision 203)
@@ -21,6 +21,6 @@
 		Segment s2 = createSegment(23, createNode(1,2,3), createNode(2,3,4));
 		segment.cloneFrom(s2);
-		assertTrue(segment.realEqual(s2));
-		assertTrue(s2.realEqual(segment));
+		assertTrue(segment.realEqual(s2, false));
+		assertTrue(s2.realEqual(segment, false));
 		assertSame(segment.from, s2.from);
 		assertSame(segment.to, s2.to);
@@ -29,5 +29,5 @@
 	public void testSegmentSegment() {
 		Segment s = new Segment(segment);
-		assertTrue(s.realEqual(segment));
+		assertTrue(s.realEqual(segment, false));
 	}
 
Index: /test/org/openstreetmap/josm/data/osm/WayTest.java
===================================================================
--- /test/org/openstreetmap/josm/data/osm/WayTest.java	(revision 202)
+++ /test/org/openstreetmap/josm/data/osm/WayTest.java	(revision 203)
@@ -21,5 +21,5 @@
 		Way w2 = createWay(42);
 		way.cloneFrom(w2);
-		assertTrue(way.realEqual(w2));
+		assertTrue(way.realEqual(w2, false));
 		assertEquals(w2.segments.size(), way.segments.size());
 	}
@@ -28,5 +28,5 @@
 		Way w = new Way(way);
 		assertEquals(way.id, w.id);
-		assertTrue(way.realEqual(w));
+		assertTrue(way.realEqual(w, false));
 	}
 
Index: /test/org/openstreetmap/josm/data/osm/visitor/MergeVisitorTest.java
===================================================================
--- /test/org/openstreetmap/josm/data/osm/visitor/MergeVisitorTest.java	(revision 202)
+++ /test/org/openstreetmap/josm/data/osm/visitor/MergeVisitorTest.java	(revision 203)
@@ -197,5 +197,5 @@
 		s2.timestamp = new Date();
 		v.visit(s2);
-		assertTrue(s1.realEqual(s2));
+		assertTrue(s1.realEqual(s2, false));
 	}
 	/**
@@ -312,4 +312,28 @@
 		assertEquals(1, ds.segments.size());
     }
-	
+
+	/**
+	 * The merger should auto-resolve items, that have not changed but are marked as
+	 * changed. In the case where an unmodified newer item is merged over an modified
+	 * older, the modified-flag should be removed and the newer timestamp is used.
+	 */
+	public void testMergeModifiedWithOlderTimestampOverUnmodifiedNewerDoesNotConflict() throws Exception {
+		DataSet ds = new DataSet();
+
+		Node oldNode = createNodes(ds, 1)[0];
+		oldNode.modified = true;
+		oldNode.timestamp = new Date();
+		
+		Node newNode = new Node(oldNode);
+		Date date = new Date(oldNode.timestamp.getTime()+10000);
+		newNode.modified = false;
+		newNode.timestamp = new Date(date.getTime());
+		
+		MergeVisitor v = new MergeVisitor(ds);
+		v.visit(newNode);
+
+		assertEquals(0, v.conflicts.size());
+		assertEquals(date, ds.nodes.iterator().next().timestamp);
+		assertFalse(ds.nodes.iterator().next().modified);
+	}
 }
