Index: trunk/src/org/openstreetmap/josm/actions/SessionSaveAsAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SessionSaveAsAction.java	(revision 5500)
+++ trunk/src/org/openstreetmap/josm/actions/SessionSaveAsAction.java	(revision 5501)
@@ -51,7 +51,4 @@
     private boolean zipRequired;
 
-    /**
-     * Construct the action with "Save" as label.
-     */
     public SessionSaveAsAction() {
         super(tr("Save Session As..."), "save_as", tr("Save the current session to a new file."), null, true, "save_as-session", true);
@@ -72,5 +69,5 @@
         for (Layer l : layers) {
             SessionLayerExporter ex = exporters.get(l);
-            if (ex.requiresZip()) {
+            if (ex != null && ex.requiresZip()) {
                 zipRequired = true;
                 break;
Index: trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java	(revision 5500)
+++ trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java	(revision 5501)
@@ -124,8 +124,8 @@
             GpxImporterData layers = GpxImporter.loadLayers(rawData, reader.isGpxParsedProperly(), name, tr("Markers from {0}", name));
             
-            GpxLayer gpxLayer = addOrMergeLayer(layers.gpxLayer, findGpxMergeLayer());
-            addOrMergeLayer(layers.markerLayer, findMarkerMergeLayer(gpxLayer));
+            GpxLayer gpxLayer = addOrMergeLayer(layers.getGpxLayer(), findGpxMergeLayer());
+            addOrMergeLayer(layers.getMarkerLayer(), findMarkerMergeLayer(gpxLayer));
             
-            layers.postLayerTask.run();
+            layers.getPostLayerTask().run();
         }
         
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java	(revision 5500)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java	(revision 5501)
@@ -170,5 +170,4 @@
     }
 
-
     /**
      * Plugins can add their Marker creation stuff at the bottom or top of this list
@@ -210,5 +209,4 @@
                 }
 
-
                 if (url == null) {
                     String symbolName = wpt.getString("symbol");
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 5500)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 5501)
@@ -68,9 +68,10 @@
     private Marker currentMarker;
 
+    @Deprecated
+    public MarkerLayer(GpxData indata, String name, File associatedFile, GpxLayer fromLayer, boolean addMouseHandlerInConstructor) {
+        this(indata, name, associatedFile, fromLayer);
+    }
+
     public MarkerLayer(GpxData indata, String name, File associatedFile, GpxLayer fromLayer) {
-        this(indata, name, associatedFile, fromLayer, true);
-    }
-
-    public MarkerLayer(GpxData indata, String name, File associatedFile, GpxLayer fromLayer, boolean addMouseHandlerInConstructor) {
         super(name);
         this.setAssociatedFile(associatedFile);
@@ -105,15 +106,8 @@
             }
         }
-
-        if (addMouseHandlerInConstructor) {
-            SwingUtilities.invokeLater(new Runnable(){
-                public void run() {
-                    addMouseHandler();
-                }
-            });
-        }
-    }
-
-    public void addMouseHandler() {
+    }
+
+    @Override
+    public void hookUpMapView() {
         Main.map.mapView.addMouseListener(new MouseAdapter() {
             @Override public void mousePressed(MouseEvent e) {
Index: trunk/src/org/openstreetmap/josm/io/GpxImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/GpxImporter.java	(revision 5500)
+++ trunk/src/org/openstreetmap/josm/io/GpxImporter.java	(revision 5501)
@@ -40,13 +40,31 @@
          * The imported GPX layer. May be null if no GPX data.
          */
-        public GpxLayer gpxLayer;
+        private GpxLayer gpxLayer;
         /**
          * The imported marker layer. May be null if no marker.
          */
-        public MarkerLayer markerLayer;
+        private MarkerLayer markerLayer;
         /**
          * The task to run after GPX and/or marker layer has been added to MapView.
          */
-        public Runnable postLayerTask;
+        private Runnable postLayerTask;
+
+        public GpxImporterData(GpxLayer gpxLayer, MarkerLayer markerLayer, Runnable postLayerTask) {
+            this.gpxLayer = gpxLayer;
+            this.markerLayer = markerLayer;
+            this.postLayerTask = postLayerTask;
+        }
+
+        public GpxLayer getGpxLayer() {
+            return gpxLayer;
+        }
+
+        public MarkerLayer getMarkerLayer() {
+            return markerLayer;
+        }
+
+        public Runnable getPostLayerTask() {
+            return postLayerTask;
+        }
     }
 
@@ -108,21 +126,20 @@
      * @see #addLayers
      */
-    public static GpxImporterData loadLayers(final GpxData data, final boolean parsedProperly, final String gpxLayerName, String markerLayerName) {
-        final GpxImporterData result = new GpxImporterData();
+    public static GpxImporterData loadLayers(final GpxData data, final boolean parsedProperly, 
+            final String gpxLayerName, String markerLayerName) {
+        GpxLayer gpxLayer = null;
+        MarkerLayer markerLayer = null;
         if (data.hasRoutePoints() || data.hasTrackPoints()) {
-            result.gpxLayer = new GpxLayer(data, gpxLayerName, data.storageFile != null);
+            gpxLayer = new GpxLayer(data, gpxLayerName, data.storageFile != null);
         }
         if (Main.pref.getBoolean("marker.makeautomarkers", true) && !data.waypoints.isEmpty()) {
-            result.markerLayer = new MarkerLayer(data, markerLayerName, data.storageFile, result.gpxLayer, false);
-            if (result.markerLayer.data.size() == 0) {
-                result.markerLayer = null;
+            markerLayer = new MarkerLayer(data, markerLayerName, data.storageFile, gpxLayer);
+            if (markerLayer.data.isEmpty()) {
+                markerLayer = null;
             }
         }
-        result.postLayerTask = new Runnable() {
+        Runnable postLayerTask = new Runnable() {
             @Override
             public void run() {
-                if (result.markerLayer != null) {
-                    result.markerLayer.addMouseHandler();
-                }
                 if (!parsedProperly) {
                     String msg;
@@ -138,5 +155,18 @@
             }
         };
-        return result;
+        return new GpxImporterData(gpxLayer, markerLayer, postLayerTask);
+    }
+
+    public static GpxImporterData loadLayers(InputStream is, final File associatedFile,
+            final String gpxLayerName, String markerLayerName, ProgressMonitor progressMonitor) throws IOException {
+        try {
+            final GpxReader r = new GpxReader(is);
+            final boolean parsedProperly = r.parse(true);
+            r.data.storageFile = associatedFile;
+            return loadLayers(r.data, parsedProperly, gpxLayerName, markerLayerName);
+        } catch (SAXException e) {
+            e.printStackTrace();
+            throw new IOException(tr("Parsing data for layer ''{0}'' failed", gpxLayerName));
+        }
     }
 }
Index: trunk/src/org/openstreetmap/josm/io/session/GpxTracksSessionExporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/GpxTracksSessionExporter.java	(revision 5501)
+++ trunk/src/org/openstreetmap/josm/io/session/GpxTracksSessionExporter.java	(revision 5501)
@@ -0,0 +1,190 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io.session;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.CardLayout;
+import java.awt.Component;
+import java.awt.Font;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+
+import org.openstreetmap.josm.gui.layer.GpxLayer;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.io.GpxWriter;
+import org.openstreetmap.josm.io.session.SessionWriter.ExportSupport;
+import org.openstreetmap.josm.tools.GBC;
+import org.w3c.dom.Element;
+
+public class GpxTracksSessionExporter implements SessionLayerExporter {
+
+    private GpxLayer layer;
+    private JRadioButton link, include;
+    private JCheckBox export;
+
+    public GpxTracksSessionExporter(GpxLayer layer) {
+        this.layer = layer;
+    }
+
+    @Override
+    public Collection<Layer> getDependencies() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Component getExportPanel() {
+        final JPanel p = new JPanel(new GridBagLayout());
+        JPanel topRow = new JPanel(new GridBagLayout());
+        export = new JCheckBox();
+        export.setSelected(true);
+        final JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEFT);
+        lbl.setToolTipText(layer.getToolTipText());
+
+        JLabel lblData = new JLabel(tr("Data:"));
+        /* I18n: Refer to a OSM data file in session file */ link = new JRadioButton(tr("local file"));
+        link.putClientProperty("actionname", "link");
+        link.setToolTipText(tr("Link to a OSM data file on your local disk."));
+        /* I18n: Include OSM data in session file */ include = new JRadioButton(tr("include"));
+        include.setToolTipText(tr("Include OSM data in the .joz session file."));
+        include.putClientProperty("actionname", "include");
+        ButtonGroup group = new ButtonGroup();
+        group.add(link);
+        group.add(include);
+
+        JPanel cardLink = new JPanel(new GridBagLayout());
+        final File file = layer.getAssociatedFile();
+        if (file != null) {
+            JTextField tf = new JTextField();
+            tf.setText(file.getPath());
+            tf.setEditable(false);
+            cardLink.add(tf, GBC.std());
+        } else {
+            cardLink.add(new JLabel(tr("No file association")), GBC.eol());
+        }
+
+        JPanel cardInclude = new JPanel(new GridBagLayout());
+        JLabel lblIncl = new JLabel(tr("OSM data will be included in the session file."));
+        lblIncl.setFont(lblIncl.getFont().deriveFont(Font.PLAIN));
+        cardInclude.add(lblIncl, GBC.eol().fill(GBC.HORIZONTAL));
+
+        final CardLayout cl = new CardLayout();
+        final JPanel cards = new JPanel(cl);
+        cards.add(cardLink, "link");
+        cards.add(cardInclude, "include");
+
+        if (file != null) {
+            link.setSelected(true);
+        } else {
+            link.setEnabled(false);
+            link.setToolTipText(tr("No file association"));
+            include.setSelected(true);
+            cl.show(cards, "include");
+        }
+
+        link.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                cl.show(cards, "link");
+            }
+        });
+        include.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                cl.show(cards, "include");
+            }
+        });
+
+        topRow.add(export, GBC.std());
+        topRow.add(lbl, GBC.std());
+        topRow.add(GBC.glue(1,0), GBC.std().fill(GBC.HORIZONTAL));
+        p.add(topRow, GBC.eol().fill(GBC.HORIZONTAL));
+        p.add(lblData, GBC.std().insets(10,0,0,0));
+        p.add(link, GBC.std());
+        p.add(include, GBC.eol());
+        p.add(cards, GBC.eol().insets(15,0,3,3));
+
+        export.addItemListener(new ItemListener() {
+            public void itemStateChanged(ItemEvent e) {
+                if (e.getStateChange() == ItemEvent.DESELECTED) {
+                    GuiHelper.setEnabledRec(p, false);
+                    export.setEnabled(true);
+                } else {
+                    GuiHelper.setEnabledRec(p, true);
+                    link.setEnabled(file != null);
+                }
+            }
+        });
+        return p;
+    }
+
+    @Override
+    public boolean shallExport() {
+        return export.isSelected();
+    }
+
+    @Override
+    public boolean requiresZip() {
+        return include.isSelected();
+    }
+
+    @Override
+    public Element export(ExportSupport support) throws IOException {
+        Element layerEl = support.createElement("layer");
+        layerEl.setAttribute("type", "tracks");
+        layerEl.setAttribute("version", "0.1");
+
+        Element file = support.createElement("file");
+        layerEl.appendChild(file);
+
+        if (requiresZip()) {
+            String zipPath = "layers/" + String.format("%02d", support.getLayerIndex()) + "/data.gpx";
+            file.appendChild(support.createTextNode(zipPath));
+            addDataFile(support.getOutputStreamZip(zipPath));
+        } else {
+            URI uri = layer.getAssociatedFile().toURI();
+            URL url = null;
+            try {
+                url = uri.toURL();
+            } catch (MalformedURLException e) {
+                throw new IOException(e);
+            }
+            file.appendChild(support.createTextNode(url.toString()));
+        }
+        return layerEl;
+    }
+
+    protected void addDataFile(OutputStream out) throws IOException {
+        Writer writer = null;
+        try {
+            writer = new OutputStreamWriter(out, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+        GpxWriter w = new GpxWriter(new PrintWriter(writer));
+        w.write(layer.data);
+        w.flush();
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/io/session/GpxTracksSessionImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/GpxTracksSessionImporter.java	(revision 5501)
+++ trunk/src/org/openstreetmap/josm/io/session/GpxTracksSessionImporter.java	(revision 5501)
@@ -0,0 +1,50 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io.session;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.GpxImporter;
+import org.openstreetmap.josm.io.IllegalDataException;
+import org.w3c.dom.Element;
+
+public class GpxTracksSessionImporter implements SessionLayerImporter {
+
+    @Override
+    public Layer load(Element elem, SessionReader.ImportSupport support, ProgressMonitor progressMonitor) throws IOException, IllegalDataException {
+        String version = elem.getAttribute("version");
+        if (!"0.1".equals(version)) {
+            throw new IllegalDataException(tr("Version ''{0}'' of meta data for gpx track layer is not supported. Expected: 0.1", version));
+        }
+        try {
+            XPathFactory xPathFactory = XPathFactory.newInstance();
+            XPath xpath = xPathFactory.newXPath();
+            XPathExpression fileExp = xpath.compile("file/text()");
+            String fileStr = (String) fileExp.evaluate(elem, XPathConstants.STRING);
+            if (fileStr == null || fileStr.equals("")) {
+                throw new IllegalDataException(tr("File name expected for layer no. {0}", support.getLayerIndex()));
+            }
+
+            GpxImporter importer = new GpxImporter();
+            InputStream in = support.getInputStream(fileStr);
+            GpxImporter.GpxImporterData importData = importer.loadLayers(in, support.getFile(fileStr), support.getLayerName(), null, progressMonitor);
+
+            support.addPostLayersTask(importData.getPostLayerTask());
+            return importData.getGpxLayer();
+
+        } catch (XPathExpressionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/io/session/OsmDataSessionExporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/OsmDataSessionExporter.java	(revision 5500)
+++ trunk/src/org/openstreetmap/josm/io/session/OsmDataSessionExporter.java	(revision 5501)
@@ -49,4 +49,6 @@
 
     private OsmDataLayer layer;
+    private JRadioButton link, include;
+    private JCheckBox export;
 
     public OsmDataSessionExporter(OsmDataLayer layer) {
@@ -55,8 +57,4 @@
 
     public OsmDataSessionExporter() {
-    }
-
-    public OsmDataSessionExporter newInstance(OsmDataLayer layer) {
-        return new OsmDataSessionExporter(layer);
     }
 
@@ -69,5 +67,7 @@
         public LayerSaveAction() {
             putValue(SMALL_ICON, new ImageProvider("save").setWidth(16).get());
-            putValue(SHORT_DESCRIPTION, tr("Layer contains unsaved data - save to file."));
+            putValue(SHORT_DESCRIPTION, layer.requiresSaveToFile() ? 
+                    tr("Layer contains unsaved data - save to file.") :
+                    tr("Layer does not contain unsaved data."));
             updateEnabledState();
         }
@@ -82,7 +82,4 @@
         }
     }
-
-    private JRadioButton link, include;
-    private JCheckBox export;
 
     @Override
Index: trunk/src/org/openstreetmap/josm/io/session/SessionReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/SessionReader.java	(revision 5500)
+++ trunk/src/org/openstreetmap/josm/io/session/SessionReader.java	(revision 5501)
@@ -57,4 +57,5 @@
         registerSessionLayerImporter("osm-data", OsmDataSessionImporter.class);
         registerSessionLayerImporter("imagery", ImagerySessionImporter.class);
+        registerSessionLayerImporter("tracks", GpxTracksSessionImporter.class);
     }
 
Index: trunk/src/org/openstreetmap/josm/io/session/SessionWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/SessionWriter.java	(revision 5500)
+++ trunk/src/org/openstreetmap/josm/io/session/SessionWriter.java	(revision 5501)
@@ -28,8 +28,5 @@
 import javax.xml.transform.stream.StreamResult;
 
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Text;
-
+import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
@@ -38,4 +35,7 @@
 import org.openstreetmap.josm.tools.MultiMap;
 import org.openstreetmap.josm.tools.Utils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
 
 public class SessionWriter {
@@ -47,4 +47,5 @@
         registerSessionLayerExporter(TMSLayer.class , ImagerySessionExporter.class);
         registerSessionLayerExporter(WMSLayer.class , ImagerySessionExporter.class);
+        registerSessionLayerExporter(GpxLayer.class , GpxTracksSessionExporter.class);
     }
 
@@ -86,4 +87,8 @@
     }
 
+    /**
+     * A class that provides some context for the individual {@link SessionLayerExporter}
+     * when doing the export.
+     */
     public class ExportSupport {
         private Document doc;
@@ -103,4 +108,8 @@
         }
 
+        /**
+         * Get the index of the layer that is currently exported.
+         * @return the index of the layer that is currently exported
+         */
         public int getLayerIndex() {
             return layerIndex;
@@ -108,7 +117,9 @@
 
         /**
-         * Create a file in the zip archive.
+         * Create a file inside the zip archive.
          *
-         * @return never close the output stream, but make sure to flush buffers
+         * @param zipPath the path inside the zip archive, e.g. "layers/03/data.xml"
+         * @return the OutputStream you can write to. Never close the returned
+         * output stream, but make sure to flush buffers.
          */
         public OutputStream getOutputStreamZip(String zipPath) throws IOException {
@@ -119,4 +130,13 @@
         }
 
+        /**
+         * Check, if the session is exported as a zip archive.
+         *
+         * @return true, if the session is exported as a zip archive (.joz file
+         * extension). It will always return true, if one of the
+         * {@link SessionLayerExporter} returns true for the
+         * {@link SessionLayerExporter#requiresZip()} method. Otherwise, the
+         * user can decide in the file chooser dialog.
+         */
         public boolean isZip() {
             return zip;
