Index: /src/org/openstreetmap/josm/Main.java
===================================================================
--- /src/org/openstreetmap/josm/Main.java	(revision 32)
+++ /src/org/openstreetmap/josm/Main.java	(revision 33)
@@ -17,9 +17,10 @@
 import org.openstreetmap.josm.actions.ExitAction;
 import org.openstreetmap.josm.actions.OpenAction;
-import org.openstreetmap.josm.actions.OpenOsmServerAction;
+import org.openstreetmap.josm.actions.DownloadAction;
 import org.openstreetmap.josm.actions.PreferencesAction;
 import org.openstreetmap.josm.actions.RedoAction;
 import org.openstreetmap.josm.actions.SaveAction;
 import org.openstreetmap.josm.actions.UndoAction;
+import org.openstreetmap.josm.actions.UploadAction;
 import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.data.Preferences.PreferencesException;
@@ -79,5 +80,6 @@
 		
 		// creating actions
-		OpenOsmServerAction openServerAction = new OpenOsmServerAction();
+		DownloadAction downloadAction = new DownloadAction();
+		UploadAction uploadAction = new UploadAction();
 		OpenAction openAction = new OpenAction();
 		SaveAction saveAction = new SaveAction();
@@ -103,5 +105,6 @@
 		JMenu connectionMenu = new JMenu("Connection");
 		connectionMenu.setMnemonic('C');
-		connectionMenu.add(openServerAction);
+		connectionMenu.add(downloadAction);
+		connectionMenu.add(uploadAction);
 		mainMenu.add(connectionMenu);
 		
@@ -123,5 +126,6 @@
 		JToolBar toolBar = new JToolBar();
 		toolBar.setFloatable(false);
-		toolBar.add(openServerAction);
+		toolBar.add(downloadAction);
+		toolBar.add(uploadAction);
 		toolBar.add(openAction);
 		toolBar.add(saveAction);
Index: /src/org/openstreetmap/josm/actions/DownloadAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/DownloadAction.java	(revision 33)
+++ /src/org/openstreetmap/josm/actions/DownloadAction.java	(revision 33)
@@ -0,0 +1,199 @@
+package org.openstreetmap.josm.actions;
+
+import java.awt.GridBagLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.io.IOException;
+
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import org.jdom.JDOMException;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.GeoPoint;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.gui.BookmarkList;
+import org.openstreetmap.josm.gui.GBC;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.BookmarkList.Bookmark;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.layer.RawGpsDataLayer;
+import org.openstreetmap.josm.io.OsmServerReader;
+
+/**
+ * Action that opens a connection to the osm server and download map data.
+ * 
+ * An dialog is displayed asking the user to specify a rectangle to grab.
+ * The url and account settings from the preferences are used.
+ *  
+ * @author imi
+ */
+public class DownloadAction extends JosmAction {
+
+	JTextField[] latlon = new JTextField[]{
+			new JTextField(9),
+			new JTextField(9),
+			new JTextField(9),
+			new JTextField(9)};
+	JCheckBox rawGps = new JCheckBox("Open as raw gps data", false);
+
+	public DownloadAction() {
+		super("Download from OSM", "download", "Download map data from the OSM server.", KeyEvent.VK_D, 
+				KeyStroke.getAWTKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		JPanel dlg = new JPanel(new GridBagLayout());
+		dlg.add(new JLabel("Bounding box"), GBC.eol());
+
+		dlg.add(new JLabel("min lat"), GBC.std().insets(10,0,5,0));
+		dlg.add(latlon[0], GBC.std());
+		dlg.add(new JLabel("max lat"), GBC.std().insets(10,0,5,0));
+		dlg.add(latlon[1], GBC.eol());
+		dlg.add(new JLabel("min lon"), GBC.std().insets(10,0,5,0));
+		dlg.add(latlon[2], GBC.std());
+		dlg.add(new JLabel("max lon"), GBC.std().insets(10,0,5,0));
+		dlg.add(latlon[3], GBC.eop());
+
+		if (Main.main.getMapFrame() != null) {
+			MapView mv = Main.main.getMapFrame().mapView;
+			int w = mv.getWidth();
+			int h = mv.getHeight();
+			GeoPoint bottomLeft = mv.getPoint(0, h, true);
+			GeoPoint topRight = mv.getPoint(w, 0, true);
+			latlon[0].setText(""+bottomLeft.lat);
+			latlon[1].setText(""+bottomLeft.lon);
+			latlon[2].setText(""+topRight.lat);
+			latlon[3].setText(""+topRight.lon);
+			for (JTextField f : latlon)
+				f.setCaretPosition(0);
+			rawGps.setSelected(mv.getActiveLayer() instanceof RawGpsDataLayer);
+		}
+
+		dlg.add(rawGps, GBC.eop());
+		
+		// load bookmarks
+		dlg.add(new JLabel("Bookmarks"), GBC.eol());
+		final BookmarkList bookmarks = new BookmarkList();
+		bookmarks.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
+			public void valueChanged(ListSelectionEvent e) {
+				Bookmark b = (Bookmark)bookmarks.getSelectedValue();
+				for (int i = 0; i < 4; ++i) {
+					latlon[i].setText(b == null ? "" : ""+b.latlon[i]);
+					latlon[i].setCaretPosition(0);
+				}
+				rawGps.setSelected(b == null ? false : b.rawgps);
+			}
+		});
+		dlg.add(new JScrollPane(bookmarks), GBC.eol().fill());
+
+		JPanel buttons = new JPanel(new GridLayout(1,2));
+		JButton add = new JButton("Add");
+		add.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				Bookmark b = readBookmark();
+				if (b == null) {
+					JOptionPane.showMessageDialog(Main.main, "Please enter the desired coordinates first.");
+					return;
+				}
+				b.name = JOptionPane.showInputDialog(Main.main, "Please enter a name for the location.");
+				if (!b.name.equals("")) {
+					((DefaultListModel)bookmarks.getModel()).addElement(b);
+					bookmarks.save();
+				}
+			}
+		});
+		buttons.add(add);
+		JButton remove = new JButton("Remove");
+		remove.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				Object sel = bookmarks.getSelectedValue();
+				if (sel == null) {
+					JOptionPane.showMessageDialog(Main.main, "Select a bookmark first.");
+					return;
+				}
+				((DefaultListModel)bookmarks.getModel()).removeElement(sel);
+				bookmarks.save();
+			}
+		});
+		buttons.add(remove);
+		dlg.add(buttons, GBC.eop().fill(GBC.HORIZONTAL));
+		
+		int r = JOptionPane.showConfirmDialog(Main.main, dlg, "Choose an area", 
+				JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
+		if (r != JOptionPane.OK_OPTION)
+			return;
+
+		Bookmark b = readBookmark();
+		if (b == null) {
+			JOptionPane.showMessageDialog(Main.main, "Please enter the desired coordinates or click on a bookmark.");
+			return;
+		}
+		OsmServerReader osmReader = new OsmServerReader(Main.pref.osmDataServer,
+				b.latlon[0], b.latlon[1], b.latlon[2], b.latlon[3]);
+		try {
+			String name = latlon[0].getText()+" "+latlon[1].getText()+" x "+
+					latlon[2].getText()+" "+latlon[3].getText();
+			
+			Layer layer;
+			if (rawGps.isSelected()) {
+				layer = new RawGpsDataLayer(osmReader.parseRawGps(), name);
+			} else {
+				DataSet dataSet = osmReader.parseOsm();
+				if (dataSet == null)
+					return; // user cancelled download
+				if (dataSet.nodes.isEmpty())
+					JOptionPane.showMessageDialog(Main.main, "No data imported.");
+				
+				layer = new OsmDataLayer(dataSet, name);
+			}
+
+			if (Main.main.getMapFrame() == null)
+				Main.main.setMapFrame(name, new MapFrame(layer));
+			else
+				Main.main.getMapFrame().mapView.addLayer(layer);
+		} catch (JDOMException x) {
+			x.printStackTrace();
+			JOptionPane.showMessageDialog(Main.main, x.getMessage());
+		} catch (IOException x) {
+			x.printStackTrace();
+			JOptionPane.showMessageDialog(Main.main, x.getMessage());
+		}
+	}
+	
+	/**
+	 * Read a bookmark from the current set edit fields. If one of the fields is
+	 * empty or contain illegal chars, <code>null</code> is returned.
+	 * The name of the bookmark is <code>null</code>.
+	 * @return A bookmark containing information from the edit fields and rawgps
+	 * 		checkbox.
+	 */
+	Bookmark readBookmark() {
+		try {
+			Bookmark b = new Bookmark();
+			for (int i = 0; i < 4; ++i) {
+				if (latlon[i].getText().equals(""))
+					return null;
+				b.latlon[i] = Double.parseDouble(latlon[i].getText());
+			}
+			b.rawgps = rawGps.isSelected();
+			return b;
+		} catch (NumberFormatException x) {
+			return null;
+		}
+	}
+}
Index: /src/org/openstreetmap/josm/actions/ExtensionFileFilter.java
===================================================================
--- /src/org/openstreetmap/josm/actions/ExtensionFileFilter.java	(revision 32)
+++ /src/org/openstreetmap/josm/actions/ExtensionFileFilter.java	(revision 33)
@@ -21,5 +21,5 @@
 		//new ExtensionFileFilter(".josm", "JOSM Savefiles (.josm)")
 	};
-	
+
 	/**
 	 * Construct an extension file filter by giving the extension to check after.
Index: c/org/openstreetmap/josm/actions/OpenOsmServerAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/OpenOsmServerAction.java	(revision 32)
+++ 	(revision )
@@ -1,199 +1,0 @@
-package org.openstreetmap.josm.actions;
-
-import java.awt.GridBagLayout;
-import java.awt.GridLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.InputEvent;
-import java.awt.event.KeyEvent;
-import java.io.IOException;
-
-import javax.swing.DefaultListModel;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-import javax.swing.KeyStroke;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-
-import org.jdom.JDOMException;
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.GeoPoint;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.gui.BookmarkList;
-import org.openstreetmap.josm.gui.GBC;
-import org.openstreetmap.josm.gui.MapFrame;
-import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.gui.BookmarkList.Bookmark;
-import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.OsmDataLayer;
-import org.openstreetmap.josm.gui.layer.RawGpsDataLayer;
-import org.openstreetmap.josm.io.OsmServerReader;
-
-/**
- * Action that opens a connection to the osm server.
- * 
- * An dialog is displayed asking the user to specify a rectangle to grab.
- * The url and account settings from the preferences are used.
- *  
- * @author imi
- */
-public class OpenOsmServerAction extends JosmAction {
-
-	JTextField[] latlon = new JTextField[]{
-			new JTextField(9),
-			new JTextField(9),
-			new JTextField(9),
-			new JTextField(9)};
-	JCheckBox rawGps = new JCheckBox("Open as raw gps data", false);
-
-	public OpenOsmServerAction() {
-		super("Connect to OSM", "connectosm", "Open a connection to the OSM server.", KeyEvent.VK_C, 
-				KeyStroke.getAWTKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
-	}
-
-	public void actionPerformed(ActionEvent e) {
-		JPanel dlg = new JPanel(new GridBagLayout());
-		dlg.add(new JLabel("Bounding box"), GBC.eol());
-
-		dlg.add(new JLabel("min lat"), GBC.std().insets(10,0,5,0));
-		dlg.add(latlon[0], GBC.std());
-		dlg.add(new JLabel("max lat"), GBC.std().insets(10,0,5,0));
-		dlg.add(latlon[1], GBC.eol());
-		dlg.add(new JLabel("min lon"), GBC.std().insets(10,0,5,0));
-		dlg.add(latlon[2], GBC.std());
-		dlg.add(new JLabel("max lon"), GBC.std().insets(10,0,5,0));
-		dlg.add(latlon[3], GBC.eop());
-
-		if (Main.main.getMapFrame() != null) {
-			MapView mv = Main.main.getMapFrame().mapView;
-			int w = mv.getWidth();
-			int h = mv.getHeight();
-			GeoPoint bottomLeft = mv.getPoint(0, h, true);
-			GeoPoint topRight = mv.getPoint(w, 0, true);
-			latlon[0].setText(""+bottomLeft.lat);
-			latlon[1].setText(""+bottomLeft.lon);
-			latlon[2].setText(""+topRight.lat);
-			latlon[3].setText(""+topRight.lon);
-			for (JTextField f : latlon)
-				f.setCaretPosition(0);
-			rawGps.setSelected(mv.getActiveLayer() instanceof RawGpsDataLayer);
-		}
-
-		dlg.add(rawGps, GBC.eop());
-		
-		// load bookmarks
-		dlg.add(new JLabel("Bookmarks"), GBC.eol());
-		final BookmarkList bookmarks = new BookmarkList();
-		bookmarks.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
-			public void valueChanged(ListSelectionEvent e) {
-				Bookmark b = (Bookmark)bookmarks.getSelectedValue();
-				for (int i = 0; i < 4; ++i) {
-					latlon[i].setText(b == null ? "" : ""+b.latlon[i]);
-					latlon[i].setCaretPosition(0);
-				}
-				rawGps.setSelected(b == null ? false : b.rawgps);
-			}
-		});
-		dlg.add(new JScrollPane(bookmarks), GBC.eol().fill());
-
-		JPanel buttons = new JPanel(new GridLayout(1,2));
-		JButton add = new JButton("Add");
-		add.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				Bookmark b = readBookmark();
-				if (b == null) {
-					JOptionPane.showMessageDialog(Main.main, "Please enter the desired coordinates first.");
-					return;
-				}
-				b.name = JOptionPane.showInputDialog(Main.main, "Please enter a name for the location.");
-				if (!b.name.equals("")) {
-					((DefaultListModel)bookmarks.getModel()).addElement(b);
-					bookmarks.save();
-				}
-			}
-		});
-		buttons.add(add);
-		JButton remove = new JButton("Remove");
-		remove.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				Object sel = bookmarks.getSelectedValue();
-				if (sel == null) {
-					JOptionPane.showMessageDialog(Main.main, "Select a bookmark first.");
-					return;
-				}
-				((DefaultListModel)bookmarks.getModel()).removeElement(sel);
-				bookmarks.save();
-			}
-		});
-		buttons.add(remove);
-		dlg.add(buttons, GBC.eop().fill(GBC.HORIZONTAL));
-		
-		int r = JOptionPane.showConfirmDialog(Main.main, dlg, "Choose an area", 
-				JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
-		if (r != JOptionPane.OK_OPTION)
-			return;
-
-		Bookmark b = readBookmark();
-		if (b == null) {
-			JOptionPane.showMessageDialog(Main.main, "Please enter the desired coordinates or click on a bookmark.");
-			return;
-		}
-		OsmServerReader osmReader = new OsmServerReader(Main.pref.osmDataServer,
-				b.latlon[0], b.latlon[1], b.latlon[2], b.latlon[3]);
-		try {
-			String name = latlon[0].getText()+" "+latlon[1].getText()+" x "+
-					latlon[2].getText()+" "+latlon[3].getText();
-			
-			Layer layer;
-			if (rawGps.isSelected()) {
-				layer = new RawGpsDataLayer(osmReader.parseRawGps(), name);
-			} else {
-				DataSet dataSet = osmReader.parseOsm();
-				if (dataSet == null)
-					return; // user cancelled download
-				if (dataSet.nodes.isEmpty())
-					JOptionPane.showMessageDialog(Main.main, "No data imported.");
-				
-				layer = new OsmDataLayer(dataSet, name);
-			}
-
-			if (Main.main.getMapFrame() == null)
-				Main.main.setMapFrame(name, new MapFrame(layer));
-			else
-				Main.main.getMapFrame().mapView.addLayer(layer);
-		} catch (JDOMException x) {
-			x.printStackTrace();
-			JOptionPane.showMessageDialog(Main.main, x.getMessage());
-		} catch (IOException x) {
-			x.printStackTrace();
-			JOptionPane.showMessageDialog(Main.main, x.getMessage());
-		}
-	}
-	
-	/**
-	 * Read a bookmark from the current set edit fields. If one of the fields is
-	 * empty or contain illegal chars, <code>null</code> is returned.
-	 * The name of the bookmark is <code>null</code>.
-	 * @return A bookmark containing information from the edit fields and rawgps
-	 * 		checkbox.
-	 */
-	Bookmark readBookmark() {
-		try {
-			Bookmark b = new Bookmark();
-			for (int i = 0; i < 4; ++i) {
-				if (latlon[i].getText().equals(""))
-					return null;
-				b.latlon[i] = Double.parseDouble(latlon[i].getText());
-			}
-			b.rawgps = rawGps.isSelected();
-			return b;
-		} catch (NumberFormatException x) {
-			return null;
-		}
-	}
-}
Index: /src/org/openstreetmap/josm/actions/UploadAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/UploadAction.java	(revision 33)
+++ /src/org/openstreetmap/josm/actions/UploadAction.java	(revision 33)
@@ -0,0 +1,109 @@
+package org.openstreetmap.josm.actions;
+
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.KeyStroke;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.GBC;
+import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
+
+/**
+ * Action that opens a connection to the osm server and upload all changes.
+ * 
+ * An dialog is displayed asking the user to specify a rectangle to grab.
+ * The url and account settings from the preferences are used.
+ *  
+ * @author imi
+ */
+public class UploadAction extends JosmAction {
+
+	public UploadAction() {
+		super("Upload to OSM", "upload", "Upload all changes to the OSM server.", KeyEvent.VK_U, 
+				KeyStroke.getAWTKeyStroke(KeyEvent.VK_U, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		Collection<OsmPrimitive> add = new LinkedList<OsmPrimitive>();
+		Collection<OsmPrimitive> update = new LinkedList<OsmPrimitive>();
+		Collection<OsmPrimitive> delete = new LinkedList<OsmPrimitive>();
+		for (OsmPrimitive osm : Main.main.ds.nodes)
+			if (osm.id == 0)
+				add.add(osm);
+			else if (osm.modified)
+				update.add(osm);
+		for (OsmPrimitive osm : Main.main.ds.lineSegments)
+			if (osm.id == 0)
+				add.add(osm);
+			else if (osm.modified)
+				update.add(osm);
+		for (OsmPrimitive osm : Main.main.ds.tracks)
+			if (osm.id == 0)
+				add.add(osm);
+			else if (osm.modified)
+				update.add(osm);
+		for (OsmPrimitive osm : Main.main.ds.deleted)
+			if (osm.id != 0)
+				delete.add(osm);
+
+		if (!displayUploadScreen(add, update, delete))
+			return;
+		
+		JOptionPane.showMessageDialog(Main.main, "not implemented yet.");
+	}
+	
+	/**
+	 * Displays a screen where the actions that would be taken are displayed and
+	 * give the user the possibility to cancel the upload.
+	 * @return <code>true</code>, if the upload should continue. <code>false</code>
+	 * 			if the user requested cancel.
+	 */
+	private boolean displayUploadScreen(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete) {
+		if (add.isEmpty() && update.isEmpty() && delete.isEmpty()) {
+			JOptionPane.showMessageDialog(Main.main, "No changes to upload.");
+			return false;
+		}
+		
+		JPanel p = new JPanel(new GridBagLayout());
+
+		OsmPrimitivRenderer renderer = new OsmPrimitivRenderer();
+
+		if (!add.isEmpty()) {
+			p.add(new JLabel("Objects to add:"), GBC.eol());
+			JList l = new JList(add.toArray());
+			l.setCellRenderer(renderer);
+			l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
+			p.add(new JScrollPane(l), GBC.eol().fill());
+		}
+
+		if (!update.isEmpty()) {
+			p.add(new JLabel("Objects to modify:"), GBC.eol());
+			JList l = new JList(update.toArray());
+			l.setCellRenderer(renderer);
+			l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
+			p.add(new JScrollPane(l), GBC.eol().fill());
+		}
+
+		if (!delete.isEmpty()) {
+			p.add(new JLabel("Objects to delete:"), GBC.eol());
+			JList l = new JList(delete.toArray());
+			l.setCellRenderer(renderer);
+			l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
+			p.add(new JScrollPane(l), GBC.eol().fill());
+		}
+
+		return JOptionPane.showConfirmDialog(Main.main, p, "Upload this changes?", 
+				JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
+	}
+}
Index: /src/org/openstreetmap/josm/command/ChangeKeyValueCommand.java
===================================================================
--- /src/org/openstreetmap/josm/command/ChangeKeyValueCommand.java	(revision 32)
+++ /src/org/openstreetmap/josm/command/ChangeKeyValueCommand.java	(revision 33)
@@ -56,6 +56,7 @@
 			oldProperties.add(osm.keys == null ? null : new HashMap<Key, String>(osm.keys));
 			oldModified.add(osm.modified);
+			osm.modified = true;
 		}
-			
+
 		if (value == null) {
 			for (OsmPrimitive osm : objects) {
Index: /src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- /src/org/openstreetmap/josm/data/Preferences.java	(revision 32)
+++ /src/org/openstreetmap/josm/data/Preferences.java	(revision 33)
@@ -50,8 +50,4 @@
 	 */
 	private boolean forceRawGpsLines = false;
-	/**
-	 * Whether nodes on the same place should be considered identical.
-	 */
-	public boolean mergeNodes = true;
 
 	/**
@@ -132,5 +128,4 @@
 				osmDataPassword = osmServer.getChildText("password");
 			}
-			mergeNodes = root.getChild("mergeNodes") != null;
 			drawRawGpsLines = root.getChild("drawRawGpsLines") != null;
 			forceRawGpsLines = root.getChild("forceRawGpsLines") != null;
@@ -153,6 +148,4 @@
 		children.add(new Element("laf").setText(laf.getClassName()));
 		children.add(new Element("projection").setText(getProjection().getClass().getName()));
-		if (mergeNodes)
-			children.add(new Element("mergeNodes"));
 		if (drawRawGpsLines)
 			children.add(new Element("drawRawGpsLines"));
Index: /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 32)
+++ /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 33)
@@ -15,9 +15,4 @@
 abstract public class OsmPrimitive {
 
-	private static int idcount = 0;
-	public OsmPrimitive() {
-		id = ++idcount;
-	}
-	
 	/**
 	 * The key/value list for this primitive.
@@ -43,5 +38,5 @@
 	 * If set to true, this object is currently selected.
 	 */
-	transient private boolean selected = false;
+	private boolean selected = false;
 
 	/**
@@ -60,5 +55,5 @@
 	 * @return	True, if the keysets are mergable
 	 */
-	public boolean keyPropertiesMergable(OsmPrimitive other) {
+	final public boolean keyPropertiesMergable(OsmPrimitive other) {
 		if ((keys == null) != (other.keys == null))
 			return false;
@@ -80,5 +75,5 @@
 	 * @param selected Whether the primitive should be selected or not.
 	 */
-	public void setSelected(boolean selected) {
+	final public void setSelected(boolean selected) {
 		if (selected != this.selected)
 			Main.main.ds.fireSelectionChanged();
@@ -89,5 +84,5 @@
 	 * @return Return whether the primitive is selected on screen.
 	 */
-	public boolean isSelected() {
+	final public boolean isSelected() {
 		return selected;
 	}
Index: /src/org/openstreetmap/josm/gui/OsmPrimitivRenderer.java
===================================================================
--- /src/org/openstreetmap/josm/gui/OsmPrimitivRenderer.java	(revision 33)
+++ /src/org/openstreetmap/josm/gui/OsmPrimitivRenderer.java	(revision 33)
@@ -0,0 +1,30 @@
+package org.openstreetmap.josm.gui;
+
+import java.awt.Component;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JLabel;
+import javax.swing.JList;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.visitor.SelectionComponentVisitor;
+
+/**
+ * Renderer that renders the objects from an OsmPrimitive as data.
+ * @author imi
+ */
+public class OsmPrimitivRenderer extends DefaultListCellRenderer {
+
+	private SelectionComponentVisitor visitor = new SelectionComponentVisitor();
+
+	@Override
+	public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+		Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+		if (c instanceof JLabel && value != null) {
+			((OsmPrimitive)value).visit(visitor);
+			((JLabel)c).setText(visitor.name);
+			((JLabel)c).setIcon(visitor.icon);
+		}
+		return c;
+	}
+}
Index: /src/org/openstreetmap/josm/gui/PreferenceDialog.java
===================================================================
--- /src/org/openstreetmap/josm/gui/PreferenceDialog.java	(revision 32)
+++ /src/org/openstreetmap/josm/gui/PreferenceDialog.java	(revision 33)
@@ -54,5 +54,4 @@
 			projection.commitConfigurationPanel();
 			Main.pref.setProjection(projection);
-			Main.pref.mergeNodes = mergeNodes.isSelected();
 			Main.pref.osmDataServer = osmDataServer.getText();
 			Main.pref.osmDataUsername = osmDataUsername.getText();
@@ -125,8 +124,4 @@
 	 */
 	JCheckBox forceRawGpsLines = new JCheckBox("Force lines if no line segments imported.");
-	/**
-	 * The checkbox stating whether nodes should be merged together.
-	 */
-	JCheckBox mergeNodes = new JCheckBox("Merge nodes with equal latitude/longitude.");
 
 	/**
@@ -198,6 +193,4 @@
 		forceRawGpsLines.setSelected(Main.pref.isForceRawGpsLines());
 		forceRawGpsLines.setEnabled(drawRawGpsLines.isSelected());
-		mergeNodes.setToolTipText("When importing GPX data, all nodes with exact the same lat/lon are merged.");
-		mergeNodes.setSelected(Main.pref.mergeNodes);
 
 		osmDataServer.setText(Main.pref.osmDataServer);
@@ -238,7 +231,4 @@
 		map.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
 		map.add(projectionDetail, GBC.eop());
-		
-		map.add(new JLabel("GPX import / export"), GBC.eol());
-		map.add(mergeNodes, GBC.eol().insets(20,0,0,0));
 		map.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
 
Index: /src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java
===================================================================
--- /src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java	(revision 32)
+++ /src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java	(revision 33)
@@ -2,5 +2,4 @@
 
 import java.awt.BorderLayout;
-import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.event.ActionEvent;
@@ -9,8 +8,6 @@
 import java.util.Collection;
 
-import javax.swing.DefaultListCellRenderer;
 import javax.swing.DefaultListModel;
 import javax.swing.JButton;
-import javax.swing.JLabel;
 import javax.swing.JList;
 import javax.swing.JScrollPane;
@@ -20,7 +17,7 @@
 import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.visitor.SelectionComponentVisitor;
 import org.openstreetmap.josm.gui.ImageProvider;
 import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
 
 /**
@@ -49,17 +46,5 @@
 		super("Current Selection", "Selection List", "selectionlist", KeyEvent.VK_E, "Open a selection list window.");
 		setPreferredSize(new Dimension(320,150));
-		displaylist.setCellRenderer(new DefaultListCellRenderer(){
-			private SelectionComponentVisitor visitor = new SelectionComponentVisitor();
-			@Override
-			public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-				Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
-				if (c instanceof JLabel && value != null) {
-					((OsmPrimitive)value).visit(visitor);
-					((JLabel)c).setText(visitor.name);
-					((JLabel)c).setIcon(visitor.icon);
-				}
-				return c;
-			}
-		});
+		displaylist.setCellRenderer(new OsmPrimitivRenderer());
 		displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
 
Index: /src/org/openstreetmap/josm/io/GpxReader.java
===================================================================
--- /src/org/openstreetmap/josm/io/GpxReader.java	(revision 32)
+++ /src/org/openstreetmap/josm/io/GpxReader.java	(revision 33)
@@ -1,3 +1,7 @@
 package org.openstreetmap.josm.io;
+
+import static org.openstreetmap.josm.io.GpxWriter.GPX;
+import static org.openstreetmap.josm.io.GpxWriter.OSM;
+import static org.openstreetmap.josm.io.GpxWriter.JOSM;
 
 import java.io.IOException;
@@ -7,7 +11,5 @@
 import org.jdom.Element;
 import org.jdom.JDOMException;
-import org.jdom.Namespace;
 import org.jdom.input.SAXBuilder;
-import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.GeoPoint;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -26,13 +28,4 @@
  */
 public class GpxReader {
-
-	/**
-	 * The GPX namespace used.
-	 */
-	public static final Namespace GPX = Namespace.getNamespace("http://www.topografix.com/GPX/1/0");
-	/**
-	 * The OSM namespace used (for extensions).
-	 */
-	private static final Namespace OSM = Namespace.getNamespace("osm", "http://www.openstreetmap.org");
 
 	/**
@@ -136,5 +129,5 @@
 			} else if (child.getName().equals("extensions")) {
 				parseKeyValueExtensions(track, child);
-				if (child.getChild("segment", OSM) != null)
+				if (child.getChild("segment", JOSM) != null)
 					realLineSegment = true;
 			} else if (child.getName().equals("link"))
@@ -162,8 +155,7 @@
 	 */
 	private Node addNode(DataSet data, Node node) {
-		if (Main.pref.mergeNodes)
-			for (Node n : data.nodes)
-				if (node.coor.equalsLatLon(n.coor))
-					return n;
+		for (Node n : data.nodes)
+			if (node.coor.equalsLatLon(n.coor))
+				return n;
 		data.nodes.add(node);
 		return node;
@@ -194,4 +186,8 @@
 				}
 			}
+			Element idElement = e.getChild("uid", JOSM);
+			if (idElement != null)
+				osm.id = Long.parseLong(idElement.getText());
+			osm.modified = e.getChild("modified", JOSM) != null;
 		}
 	}
Index: /src/org/openstreetmap/josm/io/GpxWriter.java
===================================================================
--- /src/org/openstreetmap/josm/io/GpxWriter.java	(revision 32)
+++ /src/org/openstreetmap/josm/io/GpxWriter.java	(revision 33)
@@ -18,4 +18,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;
 
@@ -34,12 +35,14 @@
 	/**
 	 * The GPX namespace used.
-	 * TODO unify with GpxReader
-	 */
-	private static final Namespace GPX = Namespace.getNamespace("http://www.topografix.com/GPX/1/0");
+	 */
+	public static final Namespace GPX = Namespace.getNamespace("http://www.topografix.com/GPX/1/0");
 	/**
 	 * The OSM namespace used (for extensions).
-	 * TODO unify with GpxReader
-	 */
-	private static final Namespace OSM = Namespace.getNamespace("osm", "http://www.openstreetmap.org");
+	 */
+	public static final Namespace OSM = Namespace.getNamespace("osm", "http://www.openstreetmap.org");
+	/**
+	 * The JOSM namespace (for JOSM-extensions).
+	 */
+	public static final Namespace JOSM = Namespace.getNamespace("josm", "http://wiki.eigenheimstrasse.de/wiki/JOSM");
 
 	/**
@@ -66,4 +69,5 @@
 		Element root = parseDataSet();
 		root.addNamespaceDeclaration(OSM);
+		root.addNamespaceDeclaration(JOSM);
 		Document d = new Document(root);
 		XMLOutputter xmlOut = new XMLOutputter(Format.getPrettyFormat());
@@ -89,6 +93,7 @@
 		for (Track t : Main.main.ds.tracks) {
 			Element tElem = new Element("trk", GPX);
+			HashMap<Key, String> keys = null;
 			if (t.keys != null) {
-				HashMap<Key, String> keys = new HashMap<Key, String>(t.keys);
+				keys = new HashMap<Key, String>(t.keys);
 				addAndRemovePropertyTag("name", tElem, keys);
 				addAndRemovePropertyTag("cmt", tElem, keys);
@@ -98,6 +103,7 @@
 				addAndRemovePropertyTag("number", tElem, keys);
 				addAndRemovePropertyTag("type", tElem, keys);
-				addPropertyExtensions(tElem, keys);
 			}
+			addPropertyExtensions(tElem, keys, t);
+
 			// line segments
 			for (LineSegment ls : t.segments) {
@@ -118,5 +124,5 @@
 			unrefNodes.remove(ls.end);
 			Element ext = new Element("extensions", GPX);
-			ext.getChildren().add(new Element("segment", OSM));
+			ext.getChildren().add(new Element("segment", JOSM));
 			t.getChildren().add(ext);
 			e.getChildren().add(t);
@@ -137,6 +143,5 @@
 	private Element parseLineSegment(LineSegment ls) {
 		Element lsElem = new Element("trkseg", GPX);
-		if (ls.keys != null)
-		addPropertyExtensions(lsElem, ls.keys);
+		addPropertyExtensions(lsElem, ls.keys, ls);
 		lsElem.getChildren().add(parseWaypoint(ls.start, "trkpt"));
 		lsElem.getChildren().add(parseWaypoint(ls.end, "trkpt"));
@@ -156,6 +161,7 @@
 		e.setAttribute("lat", Double.toString(n.coor.lat));
 		e.setAttribute("lon", Double.toString(n.coor.lon));
+		HashMap<Key, String> keys = null;
 		if (n.keys != null) {
-			HashMap<Key, String> keys = new HashMap<Key, String>(n.keys);
+			keys = new HashMap<Key, String>(n.keys);
 			addAndRemovePropertyTag("ele", e, keys);
 			addAndRemovePropertyTag("time", e, keys);
@@ -176,6 +182,6 @@
 			addAndRemovePropertyTag("ageofdgpsdata", e, keys);
 			addAndRemovePropertyTag("dgpsid", e, keys);
-			addPropertyExtensions(e, keys);
-		}
+		}
+		addPropertyExtensions(e, keys, n);
 		return e;
 	}
@@ -235,16 +241,29 @@
 	 */
 	@SuppressWarnings("unchecked")
-	private void addPropertyExtensions(Element e, Map<Key, String> keys) {
-		if (keys.isEmpty())
+	private void addPropertyExtensions(Element e, Map<Key, String> keys, OsmPrimitive osm) {
+		if ((keys == null || keys.isEmpty()) && osm.id == 0 && !osm.modified)
 			return;
 		Element extensions = e.getChild("extensions", GPX);
 		if (extensions == null)
 			e.getChildren().add(extensions = new Element("extensions", GPX));
-		for (Entry<Key, String> prop : keys.entrySet()) {
-			Element propElement = new Element("property", OSM);
-			propElement.setAttribute("key", prop.getKey().name);
-			propElement.setAttribute("value", prop.getValue());
+		if (keys != null && !keys.isEmpty()) {
+			for (Entry<Key, String> prop : keys.entrySet()) {
+				Element propElement = new Element("property", OSM);
+				propElement.setAttribute("key", prop.getKey().name);
+				propElement.setAttribute("value", prop.getValue());
+				extensions.getChildren().add(propElement);
+			}
+		}
+		// id
+		if (osm.id != 0) {
+			Element propElement = new Element("uid", JOSM);
+			propElement.setText(""+osm.id);
 			extensions.getChildren().add(propElement);
 		}
+		// modified
+		if (osm.modified) {
+			Element modElement = new Element("modified", JOSM);
+			extensions.getChildren().add(modElement);
+		}
 	}
 }
Index: /src/org/openstreetmap/josm/io/OsmReader.java
===================================================================
--- /src/org/openstreetmap/josm/io/OsmReader.java	(revision 32)
+++ /src/org/openstreetmap/josm/io/OsmReader.java	(revision 33)
@@ -10,5 +10,4 @@
 import org.jdom.JDOMException;
 import org.jdom.input.SAXBuilder;
-import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.GeoPoint;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -18,4 +17,5 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Track;
+import org.openstreetmap.josm.data.osm.visitor.AddVisitor;
 
 /**
@@ -77,4 +77,91 @@
 
 	/**
+	 * Parse any (yet unknown) object and return it.
+	 */
+	private OsmPrimitive parseObject(Element e, DataSet data) throws JDOMException {
+		if (e.getName().equals("node"))
+			return parseNode(e);
+		else if (e.getName().equals("segment"))
+			return parseLineSegment(e, data);
+		else if (e.getName().equals("track"))
+			return parseTrack(e, data);
+		else if (e.getName().equals("property")) {
+			parseProperty(e, data);
+			return null;
+		}
+		throw new JDOMException("unknown tag: "+e.getName());
+	}
+	
+	/**
+	 * Read a data set from the element.
+	 * @param e 	The element to parse
+	 * @return		The DataSet read from the element
+	 * @throws JDOMException In case of a parsing error.
+	 */
+	private DataSet parseDataSet(Element e) throws JDOMException {
+		DataSet data = new DataSet();
+		AddVisitor visitor = new AddVisitor(data);
+		for (Object o : e.getChildren()) {
+			Element child = (Element)o;
+			if (child.getName().equals("deleted"))
+				for (Object delObj : child.getChildren())
+					data.deleted.add(parseObject((Element)delObj, data));
+			else {
+				OsmPrimitive osm = parseObject(child, data);
+				if (osm != null)
+					osm.visit(visitor);
+			}
+		}
+
+		return data;
+	}
+
+	/**
+	 * Parse and return an line segment. The node information of the "from" and
+	 * "to" attributes must already be in the dataset.
+	 * @param e		The line segment element to parse.
+	 * @param data	The dataset to obtain the node information from.
+	 * @return The parsed line segment.
+	 * @throws JDOMException In case of parsing errors.
+	 */
+	private LineSegment parseLineSegment(Element e, DataSet data) throws JDOMException {
+		long startId = Long.parseLong(e.getAttributeValue("from"));
+		long endId = Long.parseLong(e.getAttributeValue("to"));
+		
+		Node start = null, end = null;
+		for (Node n : data.nodes) {
+			if (n.id == startId)
+				start = n;
+			if (n.id == endId)
+				end = n;
+		}
+		if (start == null || end == null)
+			throw new JDOMException("The 'from' or 'to' object has not been transfered before.");
+		LineSegment ls = new LineSegment(start, end);
+		parseCommon(ls, e);
+		return ls;
+	}
+
+	/**
+	 * Parse and read a track from the element.
+	 *
+	 * @param e		The element that contain the track.
+	 * @param data	The DataSet to get segment information from.
+	 * @return 		The parsed track.
+	 * @throws JDOMException In case of a parsing error.
+	 */
+	private Track parseTrack(Element e, DataSet data) throws JDOMException {
+		Track track = new Track();
+		parseCommon(track, e);
+		for (Object o : e.getChildren("segment")) {
+			Element child = (Element)o;
+			long id = Long.parseLong(child.getAttributeValue("uid"));
+			LineSegment ls = findLineSegment(data.lineSegments, id);
+			track.segments.add(ls);
+		}
+		return track;
+	}
+	
+	/**
 	 * Parse the common part (properties and uid) of the element.
 	 * @param data	To store the data in. 
@@ -82,8 +169,10 @@
 	 * @throws JDOMException In case of a parsing error
 	 */
-	private void parseCommon(OsmPrimitive data, Element e) throws JDOMException {
-		data.id = Long.parseLong(e.getAttributeValue("uid"));
-		if (data.id == 0)
-			throw new JDOMException("Object has illegal or no id.");
+	private void parseCommon(OsmPrimitive data, Element e) {
+		String suid = e.getAttributeValue("uid");
+		if (suid != null)
+			data.id = Long.parseLong(suid);
+		if (data.id < 0)
+			data.id = 0;
 		
 		String propStr = e.getAttributeValue("tags");
@@ -105,77 +194,37 @@
 
 	/**
-	 * Read a data set from the element.
-	 * @param e 	The element to parse
-	 * @return		The DataSet read from the element
-	 * @throws JDOMException In case of a parsing error.
-	 */
-	private DataSet parseDataSet(Element e) throws JDOMException {
-		DataSet data = new DataSet();
-		for (Object o : e.getChildren()) {
-			Element child = (Element)o;
-			if (child.getName().equals("node"))
-				addNode(data, parseNode(child));
-			else if (child.getName().equals("segment")) {
-				LineSegment ls = parseLineSegment(child, data);
-				if (data.lineSegments.contains(ls))
-					throw new JDOMException("Double segment definition "+ls.id);
-				data.lineSegments.add(ls);
-			} else if (child.getName().equals("track")) {
-				Track track = parseTrack(child, data);
-				if (data.tracks.contains(track))
-					throw new JDOMException("Double track definition "+track.id);
-				data.tracks.add(track);
-			}
-		}
-
-		return data;
-	}
-
-	/**
-	 * Parse and return an line segment. The node information of the "from" and
-	 * "to" attributes must already be in the dataset.
-	 * @param e		The line segment element to parse.
-	 * @param data	The dataset to obtain the node information from.
-	 * @return The parsed line segment.
-	 * @throws JDOMException In case of parsing errors.
-	 */
-	private LineSegment parseLineSegment(Element e, DataSet data) throws JDOMException {
-		long startId = Long.parseLong(e.getAttributeValue("from"));
-		long endId = Long.parseLong(e.getAttributeValue("to"));
-		
-		Node start = null, end = null;
-		for (Node n : data.nodes) {
-			if (n.id == startId)
-				start = n;
-			if (n.id == endId)
-				end = n;
-		}
-		if (start == null || end == null)
-			throw new JDOMException("The 'from' or 'to' object has not been transfered before.");
-		LineSegment ls = new LineSegment(start, end);
-		parseCommon(ls, e);
-		return ls;
-	}
-
-	/**
-	 * Parse and read a track from the element.
-	 *
-	 * @param e		The element that contain the track.
-	 * @param data	The DataSet to get segment information from.
-	 * @return 		The parsed track.
-	 * @throws JDOMException In case of a parsing error.
-	 */
-	private Track parseTrack(Element e, DataSet data) throws JDOMException {
-		Track track = new Track();
-		parseCommon(track, e);
-		for (Object o : e.getChildren("segment")) {
-			Element child = (Element)o;
-			long id = Long.parseLong(child.getAttributeValue("uid"));
-			LineSegment ls = findLineSegment(data.lineSegments, id);
-			track.segments.add(ls);
-		}
-		return track;
-	}
-	
+	 * Parse a property tag and assign the property to a previous found object.
+	 */
+	private void parseProperty(Element e, DataSet data) throws JDOMException {
+		long id = Long.parseLong(e.getAttributeValue("uid"));
+		OsmPrimitive osm = findObject(data, id);
+		Key key = Key.get(e.getAttributeValue("key"));
+		String value =e.getAttributeValue("value");
+		if (value != null) {
+			if (osm.keys == null)
+				osm.keys = new HashMap<Key, String>();
+			osm.keys.put(key, value);
+		}
+	}
+
+	/**
+	 * Search for an object in the dataset by comparing the id.
+	 */
+	private OsmPrimitive findObject(DataSet data, long id) throws JDOMException {
+		for (OsmPrimitive osm : data.nodes)
+			if (osm.id == id)
+				return osm;
+		for (OsmPrimitive osm : data.lineSegments)
+			if (osm.id == id)
+				return osm;
+		for (OsmPrimitive osm : data.tracks)
+			if (osm.id == id)
+				return osm;
+		for (OsmPrimitive osm : data.deleted)
+			if (osm.id == id)
+				return osm;
+		throw new JDOMException("Unknown object reference: "+id);
+	}
+
 	/**
 	 * Search for a segment in a collection by comparing the id.
@@ -187,24 +236,3 @@
 		throw new JDOMException("Unknown line segment reference: "+id);
 	}
-	
-	/**
-	 * Adds the node to allNodes if it is not already listed. Does respect the
-	 * preference setting "mergeNodes". Return the node in the list that correspond
-	 * to the node in the list (either the new added or the old found).
-	 * 
-	 * If reading raw gps data, mergeNodes are always on (To save memory. You
-	 * can't edit raw gps nodes anyway.)
-	 * 
-	 * @param data The DataSet to add the node to.
-	 * @param node The node that should be added.
-	 * @return Either the parameter node or the old node found in the dataset. 
-	 */
-	private Node addNode(DataSet data, Node node) {
-		if (Main.pref.mergeNodes)
-			for (Node n : data.nodes)
-				if (node.coor.equalsLatLon(n.coor))
-					return n;
-		data.nodes.add(node);
-		return node;
-	}
 }
Index: /src/org/openstreetmap/josm/io/OsmServerWriter.java
===================================================================
--- /src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 33)
+++ /src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 33)
@@ -0,0 +1,29 @@
+package org.openstreetmap.josm.io;
+
+import java.io.IOException;
+
+import org.jdom.JDOMException;
+import org.openstreetmap.josm.data.osm.DataSet;
+
+/**
+ * Class that uploades all changes to the osm server.
+ * 
+ * This is done like this:
+ * - All objects with id = 0 are uploaded as new, except those in deleted, 
+ *   which are ignored
+ * - All objects in deleted list are deleted.
+ * - All remaining objects with modified flag set are updated.
+ * 
+ * @author imi
+ */
+public class OsmServerWriter extends OsmConnection {
+
+	
+	/**
+	 * Send the dataset to the server. Ask the user first and does nothing if
+	 * he does not want to send the data.
+	 */
+	public void uploadOsm(DataSet dataSet) throws IOException, JDOMException {
+		initAuthentication();
+	}
+}
Index: /src/org/openstreetmap/josm/io/OsmWriter.java
===================================================================
--- /src/org/openstreetmap/josm/io/OsmWriter.java	(revision 32)
+++ /src/org/openstreetmap/josm/io/OsmWriter.java	(revision 33)
@@ -4,8 +4,6 @@
 import java.io.Writer;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Set;
 import java.util.Map.Entry;
 
@@ -20,4 +18,5 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Track;
+import org.openstreetmap.josm.data.osm.visitor.Visitor;
 
 
@@ -26,5 +25,5 @@
  * @author imi
  */
-public class OsmWriter extends OsmConnection {
+public class OsmWriter implements Visitor {
 
 	/**
@@ -37,11 +36,16 @@
 	private DataSet ds;
 	/**
-	 * ID generator start for all nodes with id==0
+	 * The counter for new created objects. Starting at -1 and goes down.
 	 */
-	private long id = 0;
+	private long newIdCounter = -1;
+
 	/**
-	 * A collection of all ids used so far to look up and jump over used ids.
+	 * Set from the visitor functions as result.
 	 */
-	private Set<Long> ids;
+	private Element element;
+	/**
+	 * Filled with all generated properties tags.
+	 */
+	private Collection<Element> properties;
 	
 	public OsmWriter(Writer out, DataSet dataSet) {
@@ -56,15 +60,30 @@
 	@SuppressWarnings("unchecked")
 	public void output() throws IOException {
-		ids = allUsedIds();
 		Element root = new Element("osm");
 		List<Element> list = root.getChildren();
-		Collection<Element> properties = new LinkedList<Element>();
-		for (Node n : ds.nodes)
-			list.add(parseNode(n, properties));
-		for (LineSegment ls : ds.lineSegments)
-			list.add(parseLineSegment(ls, properties));
-		for (Track t : ds.tracks)
-			list.add(parseTrack(t, properties));
+		properties = new LinkedList<Element>();
+		for (Node n : ds.nodes) {
+			visit(n);
+			list.add(element);
+		}
+		for (LineSegment ls : ds.lineSegments) {
+			visit(ls);
+			list.add(element);
+		}
+		for (Track t : ds.tracks) {
+			visit(t);
+			list.add(element);
+		}
 		list.addAll(properties);
+		properties = new LinkedList<Element>();
+		Element deleted = new Element("deleted");
+		Collection<Element> allDeleted = deleted.getChildren();
+		for (OsmPrimitive osm : ds.deleted) {
+			osm.visit(this);
+			allDeleted.add(element);
+		}
+		allDeleted.addAll(properties);
+		if (!allDeleted.isEmpty())
+			list.add(deleted);
 
 		Document d = new Document(root);
@@ -74,40 +93,4 @@
 
 	/**
-	 * Create an track element. Add all properties of the node to the properties-list.
-	 */
-	@SuppressWarnings("unchecked")
-	private Element parseTrack(Track t, Collection<Element> properties) {
-		Element e = new Element("track");
-		addProperties(e, t, properties);
-		for (LineSegment ls : t.segments)
-			e.getChildren().add(new Element("segment").setAttribute("uid", ""+ls.id));
-		return e;
-	}
-
-	/**
-	 * Create an node element. Add all properties of the node to the properties-list.
-	 */
-	private Element parseNode(Node n, Collection<Element> properties) {
-		Element e = new Element("node");
-		addProperties(e, n, properties);
-		e.setAttribute("lat", ""+n.coor.lat);
-		e.setAttribute("lon", ""+n.coor.lon);
-		return e;
-	}
-
-	
-
-	/**
-	 * Create an line segment element. Add all properties of the node to the properties-list.
-	 */
-	private Element parseLineSegment(LineSegment ls, Collection<Element> properties) {
-		Element e = new Element("segment");
-		addProperties(e, ls, properties);
-		e.setAttribute("from", ""+ls.start.id);
-		e.setAttribute("to", ""+ls.end.id);
-		return e;
-	}
-	
-	/**
 	 * Create a properties element.
 	 */
@@ -115,8 +98,5 @@
 		Element e = new Element("property");
 		Key key = entry.getKey();
-		if (key.id == 0)
-			key.id = generateId();
-		e.setAttribute("uid", ""+key.id);
-		e.setAttribute("object", ""+osm.id);
+		e.setAttribute("uid", ""+osm.id);
 		e.setAttribute("key", key.name);
 		e.setAttribute("value", entry.getValue());
@@ -127,7 +107,7 @@
 	 * Add the id attribute to the element and the properties to the collection.
 	 */
-	private void addProperties(Element e, OsmPrimitive osm, Collection<Element> properties) {
+	private void addProperties(Element e, OsmPrimitive osm) {
 		if (osm.id == 0)
-			osm.id = generateId();
+			osm.id = newIdCounter--;
 		e.setAttribute("uid", ""+osm.id);
 		if (osm.keys != null)
@@ -137,41 +117,37 @@
 
 	/**
-	 * Generate an new unused id.
+	 * Create an node element. Add all properties of the node to the properties-list.
 	 */
-	private long generateId() {
-		while (ids.contains(Long.valueOf(id)))
-			id++;
-		ids.add(id);
-		return id;
+	public void visit(Node n) {
+		element = new Element("node");
+		addProperties(element, n);
+		element.setAttribute("lat", ""+n.coor.lat);
+		element.setAttribute("lon", ""+n.coor.lon);
 	}
 
 	/**
-	 * Return all used ids in a set. 
+	 * Create an line segment element. Add all properties of the node to the properties-list.
 	 */
-	private Set<Long> allUsedIds() {
-		HashSet<Long> ids = new HashSet<Long>();
-		for (OsmPrimitive osm : ds.nodes)
-			addIdAndKeyIds(osm, ids);
-		for (OsmPrimitive osm : ds.lineSegments)
-			addIdAndKeyIds(osm, ids);
-		for (Track t : ds.tracks) {
-			addIdAndKeyIds(t, ids);
-			for (LineSegment ls : t.segments) {
-				addIdAndKeyIds(ls, ids);
-				addIdAndKeyIds(ls.start, ids);
-				addIdAndKeyIds(ls.end, ids);
-			}
-		}
-		return ids;
+	public void visit(LineSegment ls) {
+		element = new Element("segment");
+		addProperties(element, ls);
+		element.setAttribute("from", ""+ls.start.id);
+		element.setAttribute("to", ""+ls.end.id);
 	}
 
 	/**
-	 * Return all used ids in the given osm primitive.
+	 * Create an track element. Add all properties of the node to the properties-list.
 	 */
-	private void addIdAndKeyIds(OsmPrimitive osm, Collection<Long> ids) {
-		ids.add(osm.id);
-		if (osm.keys != null)
-			for (Key key : osm.keys.keySet())
-				ids.add(key.id);
+	@SuppressWarnings("unchecked")
+	public void visit(Track t) {
+		Element e = new Element("track");
+		addProperties(e, t);
+		for (LineSegment ls : t.segments)
+			e.getChildren().add(new Element("segment").setAttribute("uid", ""+ls.id));
+	}
+
+	public void visit(Key k) {
+		element = new Element("property");
+		addProperties(element, k);
 	}
 }
