Index: src/org/openstreetmap/josm/Main.java
===================================================================
--- src/org/openstreetmap/josm/Main.java	(revision 77)
+++ src/org/openstreetmap/josm/Main.java	(revision 78)
@@ -15,4 +15,5 @@
 import java.util.StringTokenizer;
 
+import javax.swing.Action;
 import javax.swing.JFrame;
 import javax.swing.JMenu;
@@ -27,4 +28,5 @@
 import org.openstreetmap.josm.actions.DownloadAction;
 import org.openstreetmap.josm.actions.ExitAction;
+import org.openstreetmap.josm.actions.GpxExportAction;
 import org.openstreetmap.josm.actions.OpenAction;
 import org.openstreetmap.josm.actions.PreferencesAction;
@@ -80,10 +82,4 @@
 	public final RedoAction redoAction;
 
-	/**
-	 * This directory is used for all disc IO access as starting directory. Should
-	 * be set accordingly after the IO action.
-	 */
-	public File currentDirectory = new File(".");
-
 	private OpenAction openAction;
 
@@ -104,12 +100,13 @@
 		
 		downloadAction = new DownloadAction();
-		UploadAction uploadAction = new UploadAction();
+		Action uploadAction = new UploadAction();
 		openAction = new OpenAction();
-		SaveAction saveAction = new SaveAction();
-		ExitAction exitAction = new ExitAction();
+		Action saveAction = new SaveAction();
+		Action gpxExportAction = new GpxExportAction(null);
+		Action exitAction = new ExitAction();
 		undoAction = new UndoAction();
 		redoAction = new RedoAction();
-		PreferencesAction preferencesAction = new PreferencesAction();
-		AboutAction aboutAction = new AboutAction();
+		Action preferencesAction = new PreferencesAction();
+		Action aboutAction = new AboutAction();
 
 		// creating menu
@@ -121,4 +118,5 @@
 		fileMenu.add(openAction);
 		fileMenu.add(saveAction);
+		fileMenu.add(gpxExportAction);
 		fileMenu.addSeparator();
 		fileMenu.add(exitAction);
@@ -151,6 +149,8 @@
 		toolBar.add(downloadAction);
 		toolBar.add(uploadAction);
+		toolBar.addSeparator();
 		toolBar.add(openAction);
 		toolBar.add(saveAction);
+		toolBar.add(gpxExportAction);
 		toolBar.addSeparator();
 		toolBar.add(undoAction);
Index: src/org/openstreetmap/josm/actions/DiskAccessAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/DiskAccessAction.java	(revision 78)
+++ src/org/openstreetmap/josm/actions/DiskAccessAction.java	(revision 78)
@@ -0,0 +1,61 @@
+package org.openstreetmap.josm.actions;
+
+import java.io.File;
+
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+import javax.swing.KeyStroke;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+
+/**
+ * Helper class for all actions, that access the disk
+ */
+abstract public class DiskAccessAction extends JosmAction {
+
+	public DiskAccessAction(String name, String iconName, String tooltip, String shortCutName, KeyStroke shortCut) {
+		super(name, iconName, tooltip, shortCutName, shortCut);
+	}
+	
+	
+	/**
+	 * Check the data set if it would be empty on save. It is empty, if it contains
+	 * no objects (after all objects that are created and deleted without beeing 
+	 * transfered to the server have been removed).
+	 *  
+	 * @return <code>true</code>, if a save result in an empty data set.
+	 */
+	protected boolean isDataSetEmpty() {
+		for (OsmPrimitive osm : Main.main.ds.allNonDeletedPrimitives())
+			if (osm.id > 0)
+				return false;
+		return true;
+	}
+	
+	protected JFileChooser createAndOpenFileChooser(boolean open, boolean multiple) {
+		String curDir = Main.pref.get("lastDirectory");
+		if (curDir.equals(""))
+			curDir = ".";
+		JFileChooser fc = new JFileChooser(new File(curDir));
+		fc.setMultiSelectionEnabled(multiple);
+		for (int i = 0; i < ExtensionFileFilter.filters.length; ++i)
+			fc.addChoosableFileFilter(ExtensionFileFilter.filters[i]);
+		fc.setAcceptAllFileFilterUsed(true);
+	
+		int answer = open ? fc.showOpenDialog(Main.main) : fc.showSaveDialog(Main.main);
+		if (answer != JFileChooser.APPROVE_OPTION)
+			return null;
+		
+		if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir))
+			Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath());
+
+		if (!open) {
+			File file = fc.getSelectedFile();
+			if (file == null || (file.exists() && JOptionPane.YES_OPTION != 
+					JOptionPane.showConfirmDialog(Main.main, "File exists. Overwrite?", "Overwrite", JOptionPane.YES_NO_OPTION)))
+				return null;
+		}
+		
+		return fc;
+	}}
Index: src/org/openstreetmap/josm/actions/GpxExportAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/GpxExportAction.java	(revision 78)
+++ src/org/openstreetmap/josm/actions/GpxExportAction.java	(revision 78)
@@ -0,0 +1,225 @@
+package org.openstreetmap.josm.actions;
+
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Calendar;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.ListSelectionModel;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.RawGpsDataLayer;
+import org.openstreetmap.josm.io.GpxWriter;
+import org.openstreetmap.josm.tools.GBC;
+
+/**
+ * Exports data to gpx.
+ */
+public class GpxExportAction extends DiskAccessAction {
+
+	private final static String warningGpl = "<html><font color='red' size='-2'>Note: GPL is not compatible to the OSM license. Do not upload GPL licensed tracks</html>";
+
+	private final Layer layer;
+
+	public GpxExportAction(Layer layer) {
+		super("Export to GPX", "exportgpx", "Export the data to GPX file.", "Ctrl-E", KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_DOWN_MASK));
+		this.layer = layer;
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		if (layer == null && Main.main.getMapFrame() == null) {
+			JOptionPane.showMessageDialog(Main.main, "Nothing to export. Get some data first.");
+			return;
+		}
+
+		JFileChooser fc = createAndOpenFileChooser(false, false);
+		if (fc == null)
+			return;
+		File file = fc.getSelectedFile();
+		if (file == null)
+			return;
+
+		String fn = file.getPath();
+		if (fn.indexOf('.') == -1) {
+			fn += ".gpx";
+			file = new File(fn);
+		}
+		
+		// open the dialog asking for options
+		JPanel p = new JPanel(new GridBagLayout());
+
+		p.add(new JLabel("gps track description"), GBC.eol());
+		JTextArea desc = new JTextArea(3,40);
+		desc.setWrapStyleWord(true);
+		desc.setLineWrap(true);
+		p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH));
+		
+		JCheckBox author = new JCheckBox("Add author information", Main.pref.getBoolean("lastAddAuthor", true));
+		author.setSelected(true);
+		p.add(author, GBC.eol());
+		JLabel nameLabel = new JLabel("Real name");
+		p.add(nameLabel, GBC.std().insets(10,0,5,0));
+		JTextField authorName = new JTextField(Main.pref.get("lastAuthorName"));
+		p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL));
+		JLabel emailLabel = new JLabel("Email");
+		p.add(emailLabel, GBC.std().insets(10,0,5,0));
+		JTextField email = new JTextField(Main.pref.get("osm-server.username"));
+		p.add(email, GBC.eol().fill(GBC.HORIZONTAL));
+		JLabel copyrightLabel = new JLabel("Copyright (URL)");
+		p.add(copyrightLabel, GBC.std().insets(10,0,5,0));
+		JTextField copyright = new JTextField();
+		p.add(copyright, GBC.std().fill(GBC.HORIZONTAL));
+		JButton predefined = new JButton("Predefined");
+		p.add(predefined, GBC.eol().insets(5,0,0,0));
+		JLabel copyrightYearLabel = new JLabel("Copyright year");
+		p.add(copyrightYearLabel, GBC.std().insets(10,0,5,5));
+		JTextField copyrightYear = new JTextField("");
+		p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL));
+		JLabel warning = new JLabel("<html><font size='-2'>&nbsp;</html");
+		p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15,0,0,0));
+		addDependencies(author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel, copyrightLabel, copyrightYearLabel, warning);
+		
+		p.add(new JLabel("Keywords"), GBC.eol());
+		JTextField keywords = new JTextField();
+		p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL));
+
+		int answer = JOptionPane.showConfirmDialog(Main.main, p, "Export options", JOptionPane.OK_CANCEL_OPTION);
+		if (answer != JOptionPane.OK_OPTION)
+			return;
+		
+		Main.pref.put("lastAddAuthor", author.isSelected());
+		if (!authorName.getText().isEmpty())
+			Main.pref.put("lastAuthorName", authorName.getText());
+		if (!copyright.getText().isEmpty())
+			Main.pref.put("lastCopyright", copyright.getText());
+		
+		try {
+			Layer layer = this.layer == null ? Main.main.getMapFrame().mapView.editLayer() : this.layer;
+			FileWriter out = new FileWriter(file);
+			GpxWriter w = new GpxWriter(out, layer.name, desc.getText(),
+					authorName.getText(), email.getText(), copyright.getText(),
+					copyrightYear.getText(), keywords.getText());
+			if (layer instanceof RawGpsDataLayer)
+				w.output(((RawGpsDataLayer)layer).data);
+			else
+				w.output(Main.main.ds);
+			out.close();
+		} catch (IOException x) {
+			x.printStackTrace();
+			JOptionPane.showMessageDialog(Main.main, "Error while exporting "+fn+":\n"+x.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
+		}		
+	}
+
+	/**
+	 * Add all those listeners to handle the enable state of the fields.
+	 * @param copyrightYearLabel 
+	 * @param copyrightLabel 
+	 * @param emailLabel 
+	 * @param nameLabel 
+	 * @param warning 
+	 */
+	private void addDependencies(
+			final JCheckBox author, 
+			final JTextField authorName,
+			final JTextField email,
+			final JTextField copyright,
+			final JButton predefined,
+			final JTextField copyrightYear,
+			final JLabel nameLabel,
+			final JLabel emailLabel,
+			final JLabel copyrightLabel,
+			final JLabel copyrightYearLabel,
+			final JLabel warning) {
+		
+		ActionListener authorActionListener = new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				boolean b = author.isSelected();
+				authorName.setEnabled(b);
+				email.setEnabled(b);
+				nameLabel.setEnabled(b);
+				emailLabel.setEnabled(b);
+				authorName.setText(b ? Main.pref.get("lastAuthorName") : "");
+				email.setText(b ? Main.pref.get("osm-server.username") : "");
+
+				boolean authorSet = !authorName.getText().isEmpty();
+				enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b && authorSet);
+			}
+		};
+		author.addActionListener(authorActionListener);
+
+		KeyAdapter authorNameListener = new KeyAdapter(){
+					@Override public void keyReleased(KeyEvent e) {
+						boolean b = !authorName.getText().isEmpty() && author.isSelected();
+						enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b);
+					}
+				};
+		authorName.addKeyListener(authorNameListener);
+		
+		predefined.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				JList l = new JList(new String[]{"Creative Commons By-SA", "public domain", "GNU Lesser Public License (LGPL)", "BSD License (same as MIT/X11)"});
+				l.setVisibleRowCount(4);
+				l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+				int answer = JOptionPane.showConfirmDialog(Main.main, new JScrollPane(l), "Choose a predefined license", JOptionPane.OK_CANCEL_OPTION);
+				if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1)
+					return;
+				final String[] urls = {
+						"http://creativecommons.org/licenses/by-sa/2.5",
+						"public domain",
+						"http://www.gnu.org/copyleft/lesser.html",
+						"http://www.opensource.org/licenses/bsd-license.php"};
+				String license = "";
+				for (int i : l.getSelectedIndices()) {
+					if (i == 1) {
+						license = "public domain";
+						break;
+					}
+					license += license.isEmpty() ? urls[i] : ", "+urls[i];
+				}
+				copyright.setText(license);
+				copyright.setCaretPosition(0);
+			}
+		});
+
+		authorActionListener.actionPerformed(null);
+		authorNameListener.keyReleased(null);
+	}
+
+	private void enableCopyright(final JTextField copyright, final JButton predefined, final JTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel, final JLabel warning, boolean enable) {
+		copyright.setEnabled(enable);
+		predefined.setEnabled(enable);
+		copyrightYear.setEnabled(enable);
+		copyrightLabel.setEnabled(enable);
+		copyrightYearLabel.setEnabled(enable);
+		warning.setText(enable ? warningGpl : "<html><font size='-2'>&nbsp;</html");
+
+		if (enable && copyrightYear.getText().isEmpty()) {
+			copyrightYear.setText(enable ? Integer.toString(Calendar.getInstance().get(Calendar.YEAR)) : "");
+		} else if (!enable)
+			copyrightYear.setText("");
+
+		if (enable && copyright.getText().isEmpty()) {
+			copyright.setText(enable ? Main.pref.get("lastCopyright", "http://creativecommons.org/licenses/by-sa/2.5") : "");
+			copyright.setCaretPosition(0);
+		} else if (!enable)
+			copyright.setText("");
+	}
+}
Index: src/org/openstreetmap/josm/actions/OpenAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/OpenAction.java	(revision 77)
+++ src/org/openstreetmap/josm/actions/OpenAction.java	(revision 78)
@@ -16,5 +16,4 @@
 import org.jdom.JDOMException;
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.MapFrame;
@@ -22,4 +21,5 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.RawGpsDataLayer;
+import org.openstreetmap.josm.gui.layer.RawGpsDataLayer.GpsPoint;
 import org.openstreetmap.josm.io.GpxReader;
 import org.openstreetmap.josm.io.OsmReader;
@@ -35,5 +35,5 @@
  * @author imi
  */
-public class OpenAction extends JosmAction {
+public class OpenAction extends DiskAccessAction {
 
 	/**
@@ -45,19 +45,10 @@
 
 	public void actionPerformed(ActionEvent e) {
-		JFileChooser fc = new JFileChooser(Main.main.currentDirectory);
-		for (int i = 0; i < ExtensionFileFilter.filters.length; ++i)
-			fc.addChoosableFileFilter(ExtensionFileFilter.filters[i]);
-		fc.setAcceptAllFileFilterUsed(true);
-
-		if (fc.showOpenDialog(Main.main) != JFileChooser.APPROVE_OPTION)
+		JFileChooser fc = createAndOpenFileChooser(true, true);
+		if (fc == null)
 			return;
-		
-		Main.main.currentDirectory = fc.getCurrentDirectory();
-
-		File filename = fc.getSelectedFile();
-		if (filename == null)
-			return;
-
-		openFile(filename);
+		File[] files = fc.getSelectedFiles();
+		for (int i = files.length; i > 0; --i)
+			openFile(files[i-1]);
 	}
 
@@ -71,9 +62,9 @@
 
 			if (asRawData(fn)) {
-				Collection<Collection<LatLon>> data;
+				Collection<Collection<GpsPoint>> data;
 				if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn)) {
 					data = new RawGpsReader(new FileReader(filename)).parse();
 				} else if (ExtensionFileFilter.filters[ExtensionFileFilter.CSV].acceptName(fn)) {
-					data = new LinkedList<Collection<LatLon>>();
+					data = new LinkedList<Collection<GpsPoint>>();
 					data.add(new RawCsvReader(new FileReader(filename)).parse());
 				} else
@@ -82,7 +73,8 @@
 			} else {
 				DataSet dataSet;
-				if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn))
+				if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn)) {
+					JOptionPane.showMessageDialog(Main.main, "Warning: Soon, it will be no longer possible to open GPX files as osm data. Please convert your files to .osm format.");
 					dataSet = new GpxReader(new FileReader(filename)).parse();
-				else if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(fn)) {
+				} else if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(fn)) {
 					try {
 						// temporary allow loading of old xml format.
@@ -91,5 +83,5 @@
 						if (x.getMessage().equals("Unknown version: null")) {
 							int answer = JOptionPane.showConfirmDialog(Main.main, 
-									"This seems to be an old 0.2 API XML file.\n" +
+									fn+" seems to be an old 0.2 API XML file.\n" +
 									"JOSM can try to open it with the old parser. This option\n" +
 									"will not be available in future JOSM version. You should\n" +
@@ -104,8 +96,8 @@
 					}					
 				} else if (ExtensionFileFilter.filters[ExtensionFileFilter.CSV].acceptName(fn)) {
-					JOptionPane.showMessageDialog(Main.main, "CSV Data import for non-GPS data is not implemented yet.");
+					JOptionPane.showMessageDialog(Main.main, fn+": CSV Data import for non-GPS data is not implemented yet.");
 					return;
 				} else {
-					JOptionPane.showMessageDialog(Main.main, "Unknown file extension: "+fn.substring(filename.getName().lastIndexOf('.')+1));
+					JOptionPane.showMessageDialog(Main.main, fn+": Unknown file extension: "+fn.substring(filename.getName().lastIndexOf('.')+1));
 					return;
 				}
@@ -140,5 +132,5 @@
 			return false;
 		return JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(
-				Main.main, "Do you want to open the file as raw gps data?",
+				Main.main, "Do you want to open "+fn+" as raw gps data?",
 				"Open as raw data?", JOptionPane.YES_NO_OPTION);
 	}
Index: src/org/openstreetmap/josm/actions/SaveAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/SaveAction.java	(revision 77)
+++ src/org/openstreetmap/josm/actions/SaveAction.java	(revision 78)
@@ -15,5 +15,4 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.LineSegment;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.io.GpxWriter;
 import org.openstreetmap.josm.io.OsmWriter;
@@ -24,8 +23,10 @@
  * @author imi
  */
-public class SaveAction extends JosmAction {
+public class SaveAction extends DiskAccessAction {
 
 	/**
 	 * Construct the action with "Save" as label.
+	 * @param layer Save only this layer. If <code>null</code>, save the whole Main 
+	 * 		data set.
 	 */
 	public SaveAction() {
@@ -41,16 +42,9 @@
 			return;
 
-		JFileChooser fc = new JFileChooser(Main.main.currentDirectory);
-		for (int i = 0; i < ExtensionFileFilter.filters.length; ++i)
-			fc.addChoosableFileFilter(ExtensionFileFilter.filters[i]);
-		fc.setAcceptAllFileFilterUsed(true);
-		fc.showSaveDialog(Main.main);
+		JFileChooser fc = createAndOpenFileChooser(false, false);
+		if (fc == null)
+			return;
+
 		File file = fc.getSelectedFile();
-		if (file == null)
-			return;
-		Main.main.currentDirectory = fc.getCurrentDirectory();
-		if (file.exists() && JOptionPane.YES_OPTION != 
-				JOptionPane.showConfirmDialog(Main.main, "File exists. Overwrite?", "Overwrite", JOptionPane.YES_NO_OPTION))
-			return;
 
 		try {
@@ -58,8 +52,9 @@
 			if (fn.indexOf('.') == -1) {
 				FileFilter ff = fc.getFileFilter();
-				if (ff instanceof ExtensionFileFilter) {
-					fn = fn + "." + ((ExtensionFileFilter)ff).defaultExtension;
-					file = new File(fn);
-				}
+				if (ff instanceof ExtensionFileFilter)
+					fn = "." + ((ExtensionFileFilter)ff).defaultExtension;
+				else
+					fn += ".osm";
+				file = new File(fn);
 			}
 			FileWriter fileWriter;
@@ -88,18 +83,3 @@
 		}
 	}
-
-	/**
-	 * Check the data set if it would be empty on save. It is empty, if it contains
-	 * no objects (after all objects that are created and deleted without beeing 
-	 * transfered to the server have been removed).
-	 *  
-	 * @return <code>true</code>, if a save result in an empty data set.
-	 */
-	private boolean isDataSetEmpty() {
-		for (OsmPrimitive osm : Main.main.ds.allPrimitives())
-			if (!osm.isDeleted() || osm.id > 0)
-				return false;
-		return true;
-	}
-
 }
Index: src/org/openstreetmap/josm/data/Bounds.java
===================================================================
--- src/org/openstreetmap/josm/data/Bounds.java	(revision 77)
+++ src/org/openstreetmap/josm/data/Bounds.java	(revision 78)
@@ -39,3 +39,13 @@
 		return "Bounds["+min.lat()+","+min.lon()+","+max.lat()+","+max.lon()+"]";
 	}
+
+	/**
+	 * Extend the bounds if necessary to include the given point.
+	 */
+	public void extend(LatLon ll) {
+		if (ll.lat() < min.lat() || ll.lon() < min.lon())
+			min = new LatLon(Math.min(ll.lat(), min.lat()), Math.min(ll.lon(), min.lon()));
+		if (ll.lat() > max.lat() || ll.lon() > max.lon())
+			max = new LatLon(Math.max(ll.lat(), max.lat()), Math.max(ll.lon(), max.lon()));
+	}
 }
Index: src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- src/org/openstreetmap/josm/data/Preferences.java	(revision 77)
+++ src/org/openstreetmap/josm/data/Preferences.java	(revision 78)
@@ -73,5 +73,8 @@
 	}
 	synchronized public boolean getBoolean(String key) {
-		return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : false;
+		return getBoolean(key, false);
+	}
+	synchronized public boolean getBoolean(String key, boolean def) {
+		return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : def;
 	}
 
Index: src/org/openstreetmap/josm/data/coor/Coordinate.java
===================================================================
--- src/org/openstreetmap/josm/data/coor/Coordinate.java	(revision 77)
+++ src/org/openstreetmap/josm/data/coor/Coordinate.java	(revision 78)
@@ -52,5 +52,5 @@
 	@Override
 	public boolean equals(Object obj) {
-		return obj instanceof EastNorth ? x == ((EastNorth)obj).x && ((EastNorth)obj).y == y : false;
+		return obj instanceof Coordinate ? x == ((Coordinate)obj).x && ((Coordinate)obj).y == y : false;
 	}
 
Index: src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 77)
+++ src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 78)
@@ -8,5 +8,5 @@
 
 /**
- * DataSet is the data behind the application. It can consist of only a few
+ * DataSet is the data behind the application. It can consists of only a few
  * points up to the whole osm database. DataSet's can be merged together, 
  * saved, (up/down/disk)loaded etc.
Index: src/org/openstreetmap/josm/data/osm/visitor/SelectionComponentVisitor.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/visitor/SelectionComponentVisitor.java	(revision 77)
+++ src/org/openstreetmap/josm/data/osm/visitor/SelectionComponentVisitor.java	(revision 78)
@@ -42,5 +42,5 @@
 				name = ls.id+" ("+ls.from.coor.lat()+","+ls.from.coor.lon()+") -> ("+ls.to.coor.lat()+","+ls.to.coor.lon()+")";
 		}
-		icon = ImageProvider.get("data", "linesegment");
+		icon = ImageProvider.get("data", "segment");
 	}
 
Index: src/org/openstreetmap/josm/data/projection/Projection.java
===================================================================
--- src/org/openstreetmap/josm/data/projection/Projection.java	(revision 77)
+++ src/org/openstreetmap/josm/data/projection/Projection.java	(revision 78)
@@ -12,5 +12,5 @@
 public interface Projection {
 
-	public static double MAX_LAT = 85;
+	public static double MAX_LAT = 85.05112877980659; // Mercator squares the world
 	public static double MAX_LON = 180;
 	public static final double MAX_SERVER_PRECISION = 1e12;
Index: src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapView.java	(revision 77)
+++ src/org/openstreetmap/josm/gui/MapView.java	(revision 78)
@@ -17,4 +17,5 @@
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
+import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
@@ -214,7 +215,11 @@
 			
 			if (v.min == null || v.max == null) {
-				// no bounds means standard scale and center 
-				center = Main.proj.latlon2eastNorth(new LatLon(51.526447, -0.14746371));
-				scale = 10;
+				// no bounds means whole world 
+				center = getProjection().latlon2eastNorth(new LatLon(0,0));
+				EastNorth world = getProjection().latlon2eastNorth(new LatLon(Projection.MAX_LAT,Projection.MAX_LON));
+				double scaleX = world.east()*2/w;
+				double scaleY = world.north()*2/h;
+				scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen
+				
 			} else {
 				center = new EastNorth(v.min.east()/2+v.max.east()/2, v.min.north()/2+v.max.north()/2);
Index: src/org/openstreetmap/josm/gui/PreferenceDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/PreferenceDialog.java	(revision 77)
+++ src/org/openstreetmap/josm/gui/PreferenceDialog.java	(revision 78)
@@ -176,5 +176,5 @@
 		// projection combo box
 		for (int i = 0; i < projectionCombo.getItemCount(); ++i) {
-			if (projectionCombo.getItemAt(i).toString().equals(Main.pref.get("projection"))) {
+			if (projectionCombo.getItemAt(i).getClass().getName().equals(Main.pref.get("projection"))) {
 				projectionCombo.setSelectedIndex(i);
 				break;
@@ -258,7 +258,8 @@
 		osmDataUsername.setToolTipText("Login name (email) to the OSM account.");
 		osmDataPassword.setToolTipText("Login password to the OSM account. Leave blank to not store any password.");
-		csvImportString.setToolTipText("<html>Import string specification. Currently, only lat/lon pairs are imported.<br>" +
+		csvImportString.setToolTipText("<html>Import string specification. lat/lon and time are imported.<br>" +
 				"<b>lat</b>: The latitude coordinate<br>" +
 				"<b>lon</b>: The longitude coordinate<br>" +
+				"<b>time</b>: The measured time as string<br>" +
 				"<b>ignore</b>: Skip this field<br>" +
 				"An example: \"ignore ignore lat lon\" will use ' ' as delimiter, skip the first two values and read then lat/lon.<br>" +
Index: src/org/openstreetmap/josm/gui/dialogs/LayerList.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/LayerList.java	(revision 77)
+++ src/org/openstreetmap/josm/gui/dialogs/LayerList.java	(revision 78)
@@ -2,5 +2,4 @@
 
 import java.awt.BorderLayout;
-import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
@@ -17,11 +16,7 @@
 import javax.swing.Icon;
 import javax.swing.JButton;
-import javax.swing.JColorChooser;
 import javax.swing.JLabel;
 import javax.swing.JList;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
-import javax.swing.JPopupMenu;
 import javax.swing.JScrollPane;
 import javax.swing.ListSelectionModel;
@@ -36,6 +31,4 @@
 import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
 import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.RawGpsDataLayer;
-import org.openstreetmap.josm.tools.ColorHelper;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.ImageProvider.OverlayPosition;
@@ -122,30 +115,7 @@
 		layers.addMouseListener(new MouseAdapter(){
 			private void openPopup(MouseEvent e) {
-				final int index = layers.locationToIndex(e.getPoint());
-				final Layer layer = (Layer)layers.getModel().getElementAt(index);
-				if (!(layer instanceof RawGpsDataLayer))
-					return; // currently only options for raw layers.
-				JPopupMenu menu = new JPopupMenu();
-				JMenuItem color = new JMenuItem("Customize Color");
-				color.addActionListener(new ActionListener(){
-					public void actionPerformed(ActionEvent e) {
-						String col = Main.pref.get("color.layer "+layer.name, Main.pref.get("color.gps point", ColorHelper.color2html(Color.gray)));
-						JColorChooser c = new JColorChooser(ColorHelper.html2color(col));
-						Object[] options = new Object[]{"OK", "Cancel", "Default"};
-						int answer = JOptionPane.showOptionDialog(Main.main, c, "Choose a color", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
-						switch (answer) {
-						case 0:
-							Main.pref.put("color.layer "+layer.name, ColorHelper.color2html(c.getColor()));
-							break;
-						case 1:
-							return;
-						case 2:
-							Main.pref.put("color.layer "+layer.name, null);
-							break;
-						}
-						Main.main.repaint();
-					}
-				});
-				menu.add(color);
+				int index = layers.locationToIndex(e.getPoint());
+				Layer layer = (Layer)layers.getModel().getElementAt(index);
+				LayerListPopup menu = new LayerListPopup(layer);
 				menu.show(LayerList.this, e.getX(), e.getY());
 			}
Index: src/org/openstreetmap/josm/gui/dialogs/LayerListPopup.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/LayerListPopup.java	(revision 78)
+++ src/org/openstreetmap/josm/gui/dialogs/LayerListPopup.java	(revision 78)
@@ -0,0 +1,68 @@
+package org.openstreetmap.josm.gui.dialogs;
+
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JColorChooser;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPopupMenu;
+import javax.swing.JSeparator;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.GpxExportAction;
+import org.openstreetmap.josm.actions.SaveAction;
+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.tools.ColorHelper;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+/**
+ * Popup menu handler for the layer list.
+ */
+public class LayerListPopup extends JPopupMenu {
+
+	public LayerListPopup(final Layer layer) {
+		if (layer instanceof OsmDataLayer)
+			add(new JMenuItem(new SaveAction()));
+
+		add(new JMenuItem(new GpxExportAction(layer)));
+		
+
+		if (layer instanceof RawGpsDataLayer) {
+			JMenuItem color = new JMenuItem("Customize Color", ImageProvider.get("colorchooser"));
+			color.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					String col = Main.pref.get("color.layer "+layer.name, Main.pref.get("color.gps point", ColorHelper.color2html(Color.gray)));
+					JColorChooser c = new JColorChooser(ColorHelper.html2color(col));
+					Object[] options = new Object[]{"OK", "Cancel", "Default"};
+					int answer = JOptionPane.showOptionDialog(Main.main, c, "Choose a color", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
+					switch (answer) {
+					case 0:
+						Main.pref.put("color.layer "+layer.name, ColorHelper.color2html(c.getColor()));
+						break;
+					case 1:
+						return;
+					case 2:
+						Main.pref.put("color.layer "+layer.name, null);
+						break;
+					}
+					Main.main.repaint();
+				}
+			});
+			add(color);
+		}
+
+		add(new JSeparator());
+		
+		JMenuItem info = new JMenuItem("Info", ImageProvider.get("info"));
+		info.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				JOptionPane.showMessageDialog(Main.main, layer.getInfoComponent());
+			}
+		});
+		add(info);
+	}
+}
Index: src/org/openstreetmap/josm/gui/layer/Layer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 77)
+++ src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 78)
@@ -78,3 +78,5 @@
 	 */
 	abstract public void visitBoundingBox(BoundingXYVisitor v);
+
+	abstract public Object getInfoComponent();
 }
Index: src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 77)
+++ src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 78)
@@ -2,4 +2,5 @@
 
 import java.awt.Graphics;
+import java.awt.GridBagLayout;
 import java.util.Collection;
 import java.util.HashSet;
@@ -10,4 +11,6 @@
 
 import javax.swing.Icon;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
 
 import org.openstreetmap.josm.Main;
@@ -21,5 +24,7 @@
 import org.openstreetmap.josm.data.osm.visitor.MergeVisitor;
 import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor;
+import org.openstreetmap.josm.data.osm.visitor.Visitor;
 import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
 
@@ -279,3 +284,38 @@
 		return size;
 	}
+
+	@Override
+	public Object getInfoComponent() {
+		final int[] normal = new int[3];		
+		final int[] deleted = new int[3];
+		final String[] names = {"node", "segment", "way"};
+		Visitor counter = new Visitor(){
+			private void inc(OsmPrimitive osm, int i) {
+				normal[i]++;
+				if (osm.isDeleted())
+					deleted[i]++;
+			}
+			public void visit(Node n) {
+				inc(n, 0);
+			}
+			public void visit(LineSegment ls) {
+				inc(ls, 1);
+			}
+			public void visit(Way w) {
+				inc(w, 2);
+			}
+		};
+		for (OsmPrimitive osm : data.allPrimitives())
+			osm.visit(counter);
+
+		JPanel p = new JPanel(new GridBagLayout());
+		p.add(new JLabel(name+" consists of:"), GBC.eol());
+		for (int i = 0; i < normal.length; ++i) {
+			String s = normal[i]+" "+names[i]+(normal[i] != 1 ?"s":"");
+			if (deleted[i] > 0)
+				s += " ("+deleted[i]+" deleted)";
+			p.add(new JLabel(s, ImageProvider.get("data", names[i]), JLabel.HORIZONTAL), GBC.eol().insets(15,0,0,0));
+		}
+		return p;
+	}
 }
Index: src/org/openstreetmap/josm/gui/layer/RawGpsDataLayer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/RawGpsDataLayer.java	(revision 77)
+++ src/org/openstreetmap/josm/gui/layer/RawGpsDataLayer.java	(revision 78)
@@ -5,5 +5,4 @@
 import java.awt.Point;
 import java.util.Collection;
-import java.util.LinkedList;
 
 import javax.swing.Icon;
@@ -28,22 +27,23 @@
 	private static Icon icon;
 	
+	public static class GpsPoint {
+		public final LatLon latlon;
+		public final EastNorth eastNorth;
+		public final String time;
+		public GpsPoint(LatLon ll, String t) {
+			latlon = ll; 
+			eastNorth = Main.proj.latlon2eastNorth(ll); 
+			time = t;
+		}
+	}
+	
 	/**
 	 * A list of ways which containing a list of points.
 	 */
-	private final Collection<Collection<LatLon>> data;
-	private Collection<Collection<EastNorth>> eastNorth;
+	public final Collection<Collection<GpsPoint>> data;
 
-	public RawGpsDataLayer(Collection<Collection<LatLon>> data, String name) {
+	public RawGpsDataLayer(Collection<Collection<GpsPoint>> data, String name) {
 		super(name);
 		this.data = data;
-
-		eastNorth = new LinkedList<Collection<EastNorth>>();
-		for (Collection<LatLon> c : data) {
-			Collection<EastNorth> eastNorthList = new LinkedList<EastNorth>();
-			for (LatLon ll : c)
-				eastNorthList.add(Main.proj.latlon2eastNorth(ll));
-			this.eastNorth.add(eastNorthList);
-		}
-
 		Main.pref.addPreferenceChangedListener(new PreferenceChangedListener(){
 			public void preferenceChanged(String key, String newValue) {
@@ -75,9 +75,9 @@
 			g.setColor(Color.GRAY);
 		Point old = null;
-		for (Collection<EastNorth> c : eastNorth) {
+		for (Collection<GpsPoint> c : data) {
 			if (!Main.pref.getBoolean("forceRawGpsLines"))
 				old = null;
-			for (EastNorth eastNorth : c) {
-				Point screen = mv.getPoint(eastNorth);
+			for (GpsPoint p : c) {
+				Point screen = mv.getPoint(p.eastNorth);
 				if (Main.pref.getBoolean("drawRawGpsLines") && old != null)
 					g.drawLine(old.x, old.y, screen.x, screen.y);
@@ -92,7 +92,7 @@
 	public String getToolTipText() {
 		int points = 0;
-		for (Collection<LatLon> c : data)
+		for (Collection<GpsPoint> c : data)
 			points += c.size();
-		return data.size()+" ways, "+points+" points.";
+		return data.size()+" tracks, "+points+" points.";
 	}
 
@@ -110,7 +110,19 @@
 	@Override
 	public void visitBoundingBox(BoundingXYVisitor v) {
-		for (Collection<EastNorth> c : eastNorth)
-			for (EastNorth eastNorth : c)
-				v.visit(eastNorth);
+		for (Collection<GpsPoint> c : data)
+			for (GpsPoint p : c)
+				v.visit(p.eastNorth);
+	}
+
+	@Override
+	public Object getInfoComponent() {
+		StringBuilder b = new StringBuilder();
+		int points = 0;
+		for (Collection<GpsPoint> c : data) {
+			b.append("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a track with "+c.size()+" points<br>");
+			points += c.size();
+		}
+		b.append("</html>");
+		return "<html>"+name+" consists of "+data.size()+" tracks ("+points+" points)<br>"+b.toString();
 	}
 }
Index: src/org/openstreetmap/josm/io/GpxWriter.java
===================================================================
--- src/org/openstreetmap/josm/io/GpxWriter.java	(revision 77)
+++ src/org/openstreetmap/josm/io/GpxWriter.java	(revision 78)
@@ -2,4 +2,5 @@
 
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.io.Writer;
 import java.util.Collection;
@@ -15,4 +16,6 @@
 import org.jdom.output.Format;
 import org.jdom.output.XMLOutputter;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.LineSegment;
@@ -20,4 +23,6 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.layer.RawGpsDataLayer.GpsPoint;
+import org.openstreetmap.josm.tools.XmlWriter;
 
 /**
@@ -49,5 +54,5 @@
 	 * This is the output writer to store the resulting data in.
 	 */
-	private Writer out;
+	private PrintWriter out;
 	/**
 	 * The dataset beeing processed.
@@ -73,5 +78,5 @@
 	 */
 	public GpxWriter(Writer out, DataSet ds) {
-		this.out = out;
+		this.out = new PrintWriter(out);
 		this.ds = ds;
 	}
@@ -318,3 +323,188 @@
 		ext.getChildren().addAll(extensions);
 	}
+
+
+	public GpxWriter(Writer writer, String name, String desc, String author, String email, String copyright, String year, String keywords) {
+		out = writer instanceof PrintWriter ? (PrintWriter)writer : new PrintWriter(writer);
+		out.println(XmlWriter.header());
+		out.println("<gpx version='1.1' creator='JOSM' xmlns='http://www.topografix.com/GPX/1/1'>");
+		out.println("  <metadata>");
+		if (!name.equals(""))
+			out.println("    <name>"+XmlWriter.encode(name)+"</name>");
+		if (!desc.equals(""))
+			out.println("    <desc>"+XmlWriter.encode(desc)+"</desc>");
+		if (!author.equals("")) {
+			out.println("    <author>");
+			out.println("      <name>"+XmlWriter.encode(author)+"</name>");
+			if (!email.equals(""))
+				out.println("      <email>"+XmlWriter.encode(email)+"</email>");
+			out.println("    </author>");
+			if (!copyright.equals("")) {
+				out.println("    <copyright author='"+XmlWriter.encode(author)+"'>");
+				if (!year.equals(""))
+					out.println("      <year>"+XmlWriter.encode(year)+"</year>");
+				out.println("      <license>"+XmlWriter.encode(copyright)+"</license>");
+				out.println("    </copyright>");
+			}
+		}
+		if (!keywords.equals("")) {
+			out.println("    <keywords>"+XmlWriter.encode(keywords)+"</keywords>");
+		}
+		// don't finish here, to give output functions the chance to add <bounds>
+	}
+
+	/**
+	 * Export the dataset to gpx. Only the physical line segment structure is
+	 * exported. To do this, the list of ways is processed. If a way span a 
+	 * sequence of line segments, this is added as one trkseg.
+	 * Then, all remaining line segments are added in one extra trk. Finally,
+	 * all remaining nodes are added as wpt.
+	 */
+	public void output(DataSet data) {
+		Collection<OsmPrimitive> all = data.allNonDeletedPrimitives();
+		if (all.isEmpty()) {
+			out.println("  </metadata>");
+			out.println("</gpx>");
+			return;
+		}
+		// calculate bounds
+		Bounds b = new Bounds(new LatLon(Double.MAX_VALUE, Double.MAX_VALUE), new LatLon(Double.MIN_VALUE, Double.MIN_VALUE));
+		for (Node n : data.nodes)
+			if (!n.isDeleted())
+				b.extend(n.coor);
+		out.println("    <bounds minlat='"+b.min.lat()+"' minlon='"+b.min.lon()+"' maxlat='"+b.max.lat()+"' maxlon='"+b.max.lon()+"' />");
+		out.println("  </metadata>");
+		
+		// add ways
+		for (Way w : data.ways) {
+			if (w.isDeleted())
+				continue;
+			out.println("  <trk>");
+			LineSegment oldLs = null;
+			for (LineSegment ls : w.segments) {
+				// end old segemnt, if no longer match a chain
+				if (oldLs != null && !oldLs.to.coor.equals(ls.from.coor)) {
+					out.println("    </trkseg>");
+					outputNode(oldLs.to, false);
+					all.remove(oldLs.to);
+					oldLs = null;
+				}
+				// start new segment if necessary
+				if (oldLs == null)
+					out.println("    <trkseg>");
+				outputNode(ls.from, false);
+				all.remove(ls.from);
+				oldLs = ls;
+				all.remove(ls);
+			}
+			// write last node if there
+			if (oldLs != null) {
+				outputNode(oldLs.to, false);
+				all.remove(oldLs.to);
+				out.println("    </trkseg>");
+			}
+			out.println("  </trk>");
+			all.remove(w);
+		}
+		
+		// add remaining line segments
+		Collection<LineSegment> lineSegments = new LinkedList<LineSegment>();
+		for (OsmPrimitive osm : all)
+			if (osm instanceof LineSegment)
+				lineSegments.add((LineSegment)osm);
+		if (!lineSegments.isEmpty()) {
+			out.println("  <trk>");
+			for (LineSegment ls : lineSegments) {
+				out.println("    <trkseg>");
+				outputNode(ls.from, false);
+				all.remove(ls.from);
+				outputNode(ls.to, false);
+				all.remove(ls.to);
+				out.println("    </trkseg>");
+				all.remove(ls);
+			}
+			out.println("  </trk>");
+		}
+		
+		// finally add the remaining nodes
+		for (OsmPrimitive osm : all) {
+			outputNode((Node)osm, true);
+		}
+		
+		out.println("</gpx>");
+	}
+
+
+	/**
+	 * Export the collection structure to gpx. The gpx will consists of only one
+	 * trk with as many trkseg as there are collections in the outer collection.
+	 */
+	public void output(Collection<Collection<GpsPoint>> data) {
+		if (data.size() == 0) {
+			out.println("  </metadata>");
+			out.println("</gpx>");
+			return;
+		}
+		// calculate bounds
+		Bounds b = new Bounds(new LatLon(Double.MAX_VALUE, Double.MAX_VALUE), new LatLon(Double.MIN_VALUE, Double.MIN_VALUE));
+		for (Collection<GpsPoint> c : data)
+			for (GpsPoint p : c)
+				b.extend(p.latlon);
+		out.println("    <bounds minlat='"+b.min.lat()+"' minlon='"+b.min.lon()+"' maxlat='"+b.max.lat()+"' maxlon='"+b.max.lon()+"' />");
+		out.println("  </metadata>");
+		
+		out.println("  <trk>");
+		for (Collection<GpsPoint> c : data) {
+			out.println("    <trkseg>");
+			LatLon last = null;
+			for (GpsPoint p : c) {
+				// skip double entries
+				if (p.latlon.equals(last))
+					continue;
+				last =  p.latlon;
+				LatLon ll = p.latlon;
+				out.print("      <trkpt lat='"+ll.lat()+"' lon='"+ll.lon()+"'");
+				if (p.time != null && !p.time.isEmpty()) {
+					out.println(">");
+					out.println("        <time>"+p.time+"</time>");
+					out.println("      </trkpt>");
+				} else
+					out.println(" />");
+			}
+			out.println("    </trkseg>");
+		}
+		out.println("  </trk>");
+		out.println("</gpx>");
+	}
+
+	private void outputNode(Node n, boolean wpt) {
+		out.print((wpt?"  <wpt":"      <trkpt")+" lat='"+n.coor.lat()+"' lon='"+n.coor.lon()+"'");
+		if (n.keys == null) {
+			out.println(" />");
+			return;
+		}
+		boolean found = false;
+		String[] possibleKeys = {"ele", "time", "magvar", "geoidheight", "name",
+				"cmt", "desc", "src", "link", "sym", "type", "fix", "sat",
+				"hdop", "vdop", "pdop", "ageofgpsdata", "dgpsid"};
+		Collection<String> keys = n.keySet();
+		for (String k : possibleKeys) {
+			if (keys.contains(k)) {
+				if (!found) {
+					found = true;
+					out.println(">");
+				}
+				if (k.equals("link")) {
+					out.println("        <link>");
+					out.println("          <text>"+XmlWriter.encode(n.get(k))+"</text>");
+					out.println("        </link>");
+				} else
+					out.println("        <"+k+">"+XmlWriter.encode(n.get(k))+"</"+k+">");
+			}
+		}
+		if (found)
+			out.println(wpt?"  </wpt>":"      </trkpt>");
+		else
+			out.println(" />");
+	}
 }
Index: src/org/openstreetmap/josm/io/OsmServerReader.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 77)
+++ src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 78)
@@ -11,6 +11,6 @@
 import org.jdom.JDOMException;
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.gui.layer.RawGpsDataLayer.GpsPoint;
 import org.xml.sax.SAXException;
 
@@ -47,8 +47,8 @@
 	 * 		ways.
 	 */
-	public Collection<Collection<LatLon>> parseRawGps() throws IOException, JDOMException {
+	public Collection<Collection<GpsPoint>> parseRawGps() throws IOException, JDOMException {
 		String url = Main.pref.get("osm-server.url")+"/0.3/trackpoints?bbox="+lon1+","+lat1+","+lon2+","+lat2+"&page=";
-		Collection<Collection<LatLon>> data = new LinkedList<Collection<LatLon>>();
-		Collection<LatLon> list = new LinkedList<LatLon>();
+		Collection<Collection<GpsPoint>> data = new LinkedList<Collection<GpsPoint>>();
+		Collection<GpsPoint> list = new LinkedList<GpsPoint>();
 		
 		for (int i = 0;;++i) {
@@ -57,7 +57,7 @@
 				break;
 			RawGpsReader gpsReader = new RawGpsReader(r);
-			Collection<Collection<LatLon>> allWays = gpsReader.parse();
+			Collection<Collection<GpsPoint>> allWays = gpsReader.parse();
 			boolean foundSomething = false;
-			for (Collection<LatLon> t : allWays) {
+			for (Collection<GpsPoint> t : allWays) {
 				if (!t.isEmpty()) {
 					foundSomething = true;
Index: src/org/openstreetmap/josm/io/OsmServerWriter.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 77)
+++ src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 78)
@@ -66,5 +66,4 @@
 	public void visit(Node n) {
 		if (n.id == 0 && !n.isDeleted()) {
-			n.put("created_by", "JOSM");
 			sendRequest("PUT", "node", n, true);
 		} else if (n.isDeleted()) {
@@ -81,5 +80,4 @@
 	public void visit(LineSegment ls) {
 		if (ls.id == 0 && !ls.isDeleted()) {
-			ls.put("created_by", "JOSM");
 			sendRequest("PUT", "segment", ls, true);
 		} else if (ls.isDeleted()) {
@@ -96,5 +94,4 @@
 	public void visit(Way w) {
 		if (w.id == 0 && !w.isDeleted()) {
-			w.put("created_by", "JOSM");
 			sendRequest("PUT", "way", w, true);
 		} else if (w.isDeleted()) {
Index: src/org/openstreetmap/josm/io/RawCsvReader.java
===================================================================
--- src/org/openstreetmap/josm/io/RawCsvReader.java	(revision 77)
+++ src/org/openstreetmap/josm/io/RawCsvReader.java	(revision 78)
@@ -12,4 +12,5 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.gui.layer.RawGpsDataLayer.GpsPoint;
 
 /**
@@ -28,6 +29,6 @@
 	}
 	
-	public Collection<LatLon> parse() throws JDOMException, IOException {
-		Collection<LatLon> data = new LinkedList<LatLon>();
+	public Collection<GpsPoint> parse() throws JDOMException, IOException {
+		Collection<GpsPoint> data = new LinkedList<GpsPoint>();
 		String formatStr = Main.pref.get("csvImportString");
 		if (formatStr == null)
@@ -63,4 +64,5 @@
 				StringTokenizer st = new StringTokenizer(line, delim);
 				double lat = 0, lon = 0;
+				String time = null;
 				for (String token : format) {
 					if (token.equals("lat"))
@@ -68,4 +70,6 @@
 					else if (token.equals("lon"))
 						lon = Double.parseDouble(st.nextToken());
+					else if (token.equals("time"))
+						time = (time == null?"":(time+" ")) + st.nextToken();
 					else if (token.equals("ignore"))
 						st.nextToken();
@@ -73,5 +77,5 @@
 						throw new JDOMException("Unknown data type: '"+token+"'."+(Main.pref.get("csvImportString").equals("") ? " Maybe add an format string in preferences." : ""));
 				}
-				data.add(new LatLon(lat, lon));
+				data.add(new GpsPoint(new LatLon(lat, lon), time));
 			}
 		} catch (RuntimeException e) {
Index: src/org/openstreetmap/josm/io/RawGpsReader.java
===================================================================
--- src/org/openstreetmap/josm/io/RawGpsReader.java	(revision 77)
+++ src/org/openstreetmap/josm/io/RawGpsReader.java	(revision 78)
@@ -5,5 +5,4 @@
 import java.util.Collection;
 import java.util.LinkedList;
-import java.util.List;
 
 import org.jdom.Element;
@@ -12,4 +11,5 @@
 import org.jdom.input.SAXBuilder;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.gui.layer.RawGpsDataLayer.GpsPoint;
 
 /**
@@ -42,5 +42,5 @@
 	 * Parse and return the read data
 	 */
-	public Collection<Collection<LatLon>> parse() throws JDOMException, IOException {
+	public Collection<Collection<GpsPoint>> parse() throws JDOMException, IOException {
 		final SAXBuilder builder = new SAXBuilder();
 		builder.setValidation(false);
@@ -55,6 +55,6 @@
 	 */
 	@SuppressWarnings("unchecked")
-	private Collection<Collection<LatLon>> parseData(Element root) throws JDOMException {
-		Collection<Collection<LatLon>> data = new LinkedList<Collection<LatLon>>();
+	private Collection<Collection<GpsPoint>> parseData(Element root) throws JDOMException {
+		Collection<Collection<GpsPoint>> data = new LinkedList<Collection<GpsPoint>>();
 
 		// workaround for bug where the server adds /gpx.asd to the namespace
@@ -62,16 +62,19 @@
 		
 		for (Object o : root.getChildren("wpt", GPX)) {
-			Collection<LatLon> line = new LinkedList<LatLon>();
-			line.add(new LatLon(parseDouble((Element)o, LatLonAttr.lat), parseDouble((Element)o, LatLonAttr.lon)));
+			Collection<GpsPoint> line = new LinkedList<GpsPoint>();
+			line.add(new GpsPoint(
+					new LatLon(parseDouble((Element)o, LatLonAttr.lat), parseDouble((Element)o, LatLonAttr.lon)),
+					((Element)o).getChildText("time", GPX)));
 			data.add(line);
-		}
-		for (Object o : root.getChildren("rte", GPX)) {
-			Collection<LatLon> line = parseLine(((Element)o).getChildren("rtept", GPX));
-			if (!line.isEmpty())
-				data.add(line);
 		}
 		for (Object o : root.getChildren("trk", GPX)) {
 			for (Object seg : ((Element)o).getChildren("trkseg", GPX)) {
-				Collection<LatLon> line = parseLine(((Element)seg).getChildren("trkpt", GPX));
+				Collection<GpsPoint> data1 = new LinkedList<GpsPoint>();
+				for (Object trkObj : ((Element)seg).getChildren("trkpt", GPX)) {
+					data1.add(new GpsPoint(
+							new LatLon(parseDouble((Element)trkObj, LatLonAttr.lat), parseDouble((Element)trkObj, LatLonAttr.lon)),
+							((Element)trkObj).getChildText("time", GPX)));
+				}
+				Collection<GpsPoint> line = data1;
 				if (!line.isEmpty())
 					data.add(line);
@@ -94,14 +97,3 @@
 		return d;
 	}
-
-	/**
-	 * Parse the list of waypoint - elements and return a collection with the
-	 * points read.
-	 */
-	private Collection<LatLon> parseLine(List<Element> wpt) throws JDOMException {
-		Collection<LatLon> data = new LinkedList<LatLon>();
-		for (Element e : wpt)
-			data.add(new LatLon(parseDouble(e, LatLonAttr.lat), parseDouble(e, LatLonAttr.lon)));
-		return data;
-	}
 }
