Index: trunk/.settings/sf.eclipse.javacc.prefs
===================================================================
--- trunk/.settings/sf.eclipse.javacc.prefs	(revision 7325)
+++ trunk/.settings/sf.eclipse.javacc.prefs	(revision 7326)
@@ -1,4 +1,4 @@
 CLEAR_CONSOLE=true
-JAVACC_OPTIONS=-GRAMMAR_ENCODING\=UTF-8
+JAVACC_OPTIONS=-JDK_VERSION\=1.7 -GRAMMAR_ENCODING\=UTF-8
 JJDOC_OPTIONS=
 JJTREE_OPTIONS=
Index: trunk/src/org/openstreetmap/josm/actions/SessionLoadAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SessionLoadAction.java	(revision 7325)
+++ trunk/src/org/openstreetmap/josm/actions/SessionLoadAction.java	(revision 7326)
@@ -104,5 +104,4 @@
         @Override
         public void cancel() {
-            Thread.dumpStack();
             canceled = true;
         }
@@ -179,5 +178,5 @@
             }
         }
-        
+
         private void handleException(String dialogTitle, Exception e) {
             Main.error(e);
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 7325)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 7326)
@@ -73,4 +73,11 @@
     public AudioMarker syncAudioMarker = null;
 
+    /**
+     * Constructs a new {@code MarkerLayer}.
+     * @param indata The GPX data for this layer
+     * @param name The marker layer name
+     * @param associatedFile The associated GPX file
+     * @param fromLayer The associated GPX layer
+     */
     public MarkerLayer(GpxData indata, String name, File associatedFile, GpxLayer fromLayer) {
         super(name);
Index: trunk/src/org/openstreetmap/josm/io/NMEAImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/NMEAImporter.java	(revision 7325)
+++ trunk/src/org/openstreetmap/josm/io/NMEAImporter.java	(revision 7326)
@@ -20,7 +20,15 @@
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.io.GpxImporter.GpxImporterData;
 
+/**
+ * File importer allowing to import NMEA-0183 files (*.nmea/nme/nma/log/txt files).
+ * @since 1637
+ */
 public class NMEAImporter extends FileImporter {
 
+    /**
+     * The NMEA file filter (*.nmea *.nme *.nma *.log *.txt files).
+     */
     public static final ExtensionFileFilter FILE_FILTER = new ExtensionFileFilter(
             "nmea,nme,nma,log,txt", "nmea", tr("NMEA-0183 Files") + " (*.nmea *.nme *.nma *.log *.txt)");
@@ -42,5 +50,5 @@
                 final GpxLayer gpxLayer = new GpxLayer(r.data, fn, true);
                 final File fileFinal = file;
-    
+
                 GuiHelper.runInEDT(new Runnable() {
                     @Override
@@ -88,3 +96,11 @@
         }
     }
+
+    public static GpxImporterData loadLayers(InputStream is, final File associatedFile,
+            final String gpxLayerName, String markerLayerName) throws IOException {
+        final NmeaReader r = new NmeaReader(is);
+        final boolean parsedProperly = r.getNumberOfCoordinates() > 0;
+        r.data.storageFile = associatedFile;
+        return GpxImporter.loadLayers(r.data, parsedProperly, gpxLayerName, markerLayerName);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/session/GpxTracksSessionImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/GpxTracksSessionImporter.java	(revision 7325)
+++ trunk/src/org/openstreetmap/josm/io/session/GpxTracksSessionImporter.java	(revision 7326)
@@ -13,10 +13,10 @@
 import javax.xml.xpath.XPathFactory;
 
-import org.w3c.dom.Element;
-
 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.openstreetmap.josm.io.NMEAImporter;
+import org.w3c.dom.Element;
 
 public class GpxTracksSessionImporter implements SessionLayerImporter {
@@ -38,6 +38,12 @@
 
             try (InputStream in = support.getInputStream(fileStr)) {
-                GpxImporter.GpxImporterData importData = GpxImporter.loadLayers(in, support.getFile(fileStr), support.getLayerName(), null, progressMonitor);
-    
+                GpxImporter.GpxImporterData importData = null;
+
+                if (NMEAImporter.FILE_FILTER.acceptName(fileStr)) {
+                    importData = NMEAImporter.loadLayers(in, support.getFile(fileStr), support.getLayerName(), null);
+                } else {
+                    importData = GpxImporter.loadLayers(in, support.getFile(fileStr), support.getLayerName(), null, progressMonitor);
+                }
+
                 support.addPostLayersTask(importData.getPostLayerTask());
                 return importData.getGpxLayer();
@@ -45,5 +51,5 @@
 
         } catch (XPathExpressionException e) {
-            throw new RuntimeException(e);
+            throw new IllegalDataException(e);
         }
     }
Index: trunk/src/org/openstreetmap/josm/io/session/MarkerSessionImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/MarkerSessionImporter.java	(revision 7325)
+++ trunk/src/org/openstreetmap/josm/io/session/MarkerSessionImporter.java	(revision 7326)
@@ -14,6 +14,4 @@
 import javax.xml.xpath.XPathFactory;
 
-import org.w3c.dom.Element;
-
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
@@ -23,4 +21,5 @@
 import org.openstreetmap.josm.io.IllegalDataException;
 import org.openstreetmap.josm.io.session.SessionReader.ImportSupport;
+import org.w3c.dom.Element;
 
 public class MarkerSessionImporter implements SessionLayerImporter {
@@ -30,5 +29,5 @@
         String version = elem.getAttribute("version");
         if (!"0.1".equals(version)) {
-            throw new IllegalDataException(tr("Version ''{0}'' of meta data for imagery layer is not supported. Expected: 0.1", version));
+            throw new IllegalDataException(tr("Version ''{0}'' of meta data for marker layer is not supported. Expected: 0.1", version));
         }
         try {
@@ -43,7 +42,7 @@
             try (InputStream in = support.getInputStream(fileStr)) {
                 GpxImporter.GpxImporterData importData = GpxImporter.loadLayers(in, support.getFile(fileStr), support.getLayerName(), null, progressMonitor);
-    
+
                 support.addPostLayersTask(importData.getPostLayerTask());
-    
+
                 GpxLayer gpxLayer = null;
                 List<SessionReader.LayerDependency> deps = support.getLayerDependencies();
@@ -54,12 +53,14 @@
                     }
                 }
-    
+
                 MarkerLayer markerLayer = importData.getMarkerLayer();
-                markerLayer.fromLayer = gpxLayer;
-    
+                if (markerLayer != null) {
+                    markerLayer.fromLayer = gpxLayer;
+                }
+
                 return markerLayer;
             }
         } catch (XPathExpressionException e) {
-            throw new RuntimeException(e);
+            throw new IllegalDataException(e);
         }
     }
Index: trunk/src/org/openstreetmap/josm/io/session/OsmDataSessionImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/OsmDataSessionImporter.java	(revision 7325)
+++ trunk/src/org/openstreetmap/josm/io/session/OsmDataSessionImporter.java	(revision 7326)
@@ -13,6 +13,4 @@
 import javax.xml.xpath.XPathFactory;
 
-import org.w3c.dom.Element;
-
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
@@ -20,4 +18,5 @@
 import org.openstreetmap.josm.io.OsmImporter;
 import org.openstreetmap.josm.io.session.SessionReader.ImportSupport;
+import org.w3c.dom.Element;
 
 public class OsmDataSessionImporter implements SessionLayerImporter {
@@ -41,10 +40,10 @@
             try (InputStream in = support.getInputStream(fileStr)) {
                 OsmImporter.OsmImporterData importData = importer.loadLayer(in, support.getFile(fileStr), support.getLayerName(), progressMonitor);
-    
+
                 support.addPostLayersTask(importData.getPostLayerTask());
                 return importData.getLayer();
             }
         } catch (XPathExpressionException e) {
-            throw new RuntimeException(e);
+            throw new IllegalDataException(e);
         }
     }
Index: trunk/src/org/openstreetmap/josm/io/session/SessionReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/SessionReader.java	(revision 7325)
+++ trunk/src/org/openstreetmap/josm/io/session/SessionReader.java	(revision 7326)
@@ -4,4 +4,5 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.GraphicsEnvironment;
 import java.io.BufferedInputStream;
 import java.io.File;
@@ -413,5 +414,5 @@
             String type = e.getAttribute("type");
             SessionLayerImporter imp = getSessionLayerImporter(type);
-            if (imp == null) {
+            if (imp == null && !GraphicsEnvironment.isHeadless()) {
                 CancelOrContinueDialog dialog = new CancelOrContinueDialog();
                 dialog.show(
@@ -427,5 +428,5 @@
                     continue;
                 }
-            } else {
+            } else if (imp != null) {
                 importers.put(idx, imp);
                 List<LayerDependency> depsImp = new ArrayList<>();
@@ -459,16 +460,18 @@
                 if (exception != null) {
                     Main.error(exception);
-                    CancelOrContinueDialog dialog = new CancelOrContinueDialog();
-                    dialog.show(
-                            tr("Error loading layer"),
-                            tr("<html>Could not load layer {0} ''{1}''.<br>Error is:<br>{2}</html>", idx, name, exception.getMessage()),
-                            JOptionPane.ERROR_MESSAGE,
-                            progressMonitor
-                            );
-                    if (dialog.isCancel()) {
-                        progressMonitor.cancel();
-                        return;
-                    } else {
-                        continue;
+                    if (!GraphicsEnvironment.isHeadless()) {
+                        CancelOrContinueDialog dialog = new CancelOrContinueDialog();
+                        dialog.show(
+                                tr("Error loading layer"),
+                                tr("<html>Could not load layer {0} ''{1}''.<br>Error is:<br>{2}</html>", idx, name, exception.getMessage()),
+                                JOptionPane.ERROR_MESSAGE,
+                                progressMonitor
+                                );
+                        if (dialog.isCancel()) {
+                            progressMonitor.cancel();
+                            return;
+                        } else {
+                            continue;
+                        }
                     }
                 }
Index: trunk/test/data/sessions/data.gpx
===================================================================
--- trunk/test/data/sessions/data.gpx	(revision 7326)
+++ trunk/test/data/sessions/data.gpx	(revision 7326)
@@ -0,0 +1,18 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<gpx version="1.1" creator="JOSM GPX export" xmlns="http://www.topografix.com/GPX/1/1"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+    xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
+  <trk>
+    <name><![CDATA[GPX test track]]></name>
+    <trkseg>
+      <trkpt lat="42.72665" lon="-0.00747">
+        <ele>1438.5</ele>
+        <time>2011-08-20T06:32:30Z</time>
+      </trkpt>
+      <trkpt lat="42.72659" lon="-0.00749">
+        <ele>1445.3</ele>
+        <time>2011-08-20T06:32:32Z</time>
+      </trkpt>
+    </trkseg>
+  </trk>
+</gpx>
Index: trunk/test/data/sessions/data.nmea
===================================================================
--- trunk/test/data/sessions/data.nmea	(revision 7326)
+++ trunk/test/data/sessions/data.nmea	(revision 7326)
@@ -0,0 +1,4 @@
+$GPGGA,073827.000,4552.9726,N,00913.7972,E,1,,,1158.0,M,,,,*19
+$GPRMC,073827.000,A,4552.9726,N,00913.7972,E,,,190714,,*0C
+$GPGGA,073832.000,4552.9745,N,00913.7865,E,1,,,1124.0,M,,,,*14
+$GPRMC,073832.000,A,4552.9745,N,00913.7865,E,,,190714,,*0A
Index: trunk/test/data/sessions/data.osm
===================================================================
--- trunk/test/data/sessions/data.osm	(revision 7326)
+++ trunk/test/data/sessions/data.osm	(revision 7326)
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' upload='true' generator='JOSM'>
+</osm>
Index: trunk/test/data/sessions/empty.jos
===================================================================
--- trunk/test/data/sessions/empty.jos	(revision 7326)
+++ trunk/test/data/sessions/empty.jos	(revision 7326)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<josm-session version="0.1">
+    <viewport>
+        <center lat="0.0" lon="0.0"/>
+        <scale meter-per-pixel="10"/>
+    </viewport>
+    <layers/>
+</josm-session>
Index: trunk/test/data/sessions/gpx.jos
===================================================================
--- trunk/test/data/sessions/gpx.jos	(revision 7326)
+++ trunk/test/data/sessions/gpx.jos	(revision 7326)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<josm-session version="0.1">
+    <viewport>
+        <center lat="0.0" lon="0.0"/>
+        <scale meter-per-pixel="10"/>
+    </viewport>
+    <layers>
+        <layer index="1" name="GPX layer name" type="tracks" version="0.1" visible="true">
+            <file>data.gpx</file>
+        </layer>
+    </layers>
+</josm-session>
Index: trunk/test/data/sessions/nmea.jos
===================================================================
--- trunk/test/data/sessions/nmea.jos	(revision 7326)
+++ trunk/test/data/sessions/nmea.jos	(revision 7326)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<josm-session version="0.1">
+    <viewport>
+        <center lat="45.882896268181526" lon="9.229861183898349"/>
+        <scale meter-per-pixel="0.018042533631306965"/>
+    </viewport>
+    <layers active="1">
+        <layer index="1" name="GPX layer name" type="tracks" version="0.1" visible="true">
+            <file>data.nmea</file>
+        </layer>
+    </layers>
+</josm-session>
Index: trunk/test/data/sessions/osm.jos
===================================================================
--- trunk/test/data/sessions/osm.jos	(revision 7326)
+++ trunk/test/data/sessions/osm.jos	(revision 7326)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<josm-session version="0.1">
+    <viewport>
+        <center lat="0.0" lon="0.0"/>
+        <scale meter-per-pixel="10"/>
+    </viewport>
+    <layers>
+        <layer index="1" name="OSM layer name" type="osm-data" version="0.1" visible="true">
+            <file>data.osm</file>
+        </layer>
+    </layers>
+</josm-session>
Index: trunk/test/unit/org/openstreetmap/josm/io/session/SessionReaderTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/io/session/SessionReaderTest.java	(revision 7326)
+++ trunk/test/unit/org/openstreetmap/josm/io/session/SessionReaderTest.java	(revision 7326)
@@ -0,0 +1,120 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io.session;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openstreetmap.josm.JOSMFixture;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.layer.GpxLayer;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
+import org.openstreetmap.josm.gui.preferences.ToolbarPreferences;
+import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
+import org.openstreetmap.josm.io.IllegalDataException;
+
+/**
+ * Unit tests for Session reading.
+ */
+public class SessionReaderTest {
+
+    /**
+     * Setup tests.
+     */
+    @BeforeClass
+    public static void setUpBeforeClass() {
+        JOSMFixture.createUnitTestFixture().init();
+        ProjectionPreference.setProjection();
+        Main.toolbar = new ToolbarPreferences();
+        new MainApplication();
+        Main.main.createMapFrame(null, null);
+    }
+
+    private static String getSessionDataDir() {
+        return TestUtils.getTestDataRoot() + "/sessions";
+    }
+
+    private List<Layer> testRead(String sessionFileName) throws IOException, IllegalDataException {
+        boolean zip = sessionFileName.endsWith(".joz");
+        File file = new File(getSessionDataDir()+"/"+sessionFileName);
+        SessionReader reader = new SessionReader();
+        reader.loadSession(file, zip, null);
+        return reader.getLayers();
+    }
+
+    /**
+     * Tests to read an empty .jos or .joz file.
+     * @throws IOException if any I/O error occurs
+     * @throws IllegalDataException is the test file is considered as invalid
+     */
+    @Test
+    public void testReadEmpty() throws IOException, IllegalDataException {
+        assertTrue(testRead("empty.jos").isEmpty());
+        assertTrue(testRead("empty.joz").isEmpty());
+    }
+
+    /**
+     * Tests to read a .jos or .joz file containing OSM data.
+     * @throws IOException if any I/O error occurs
+     * @throws IllegalDataException is the test file is considered as invalid
+     */
+    @Test
+    public void testReadOsm() throws IOException, IllegalDataException {
+        for (String file : new String[]{"osm.jos", "osm.joz"}) {
+            List<Layer> layers = testRead(file);
+            assertTrue(layers.size() == 1);
+            assertTrue(layers.get(0) instanceof OsmDataLayer);
+            OsmDataLayer osm = (OsmDataLayer) layers.get(0);
+            assertEquals(osm.getName(), "OSM layer name");
+        }
+    }
+
+    /**
+     * Tests to read a .jos or .joz file containing GPX data.
+     * @throws IOException if any I/O error occurs
+     * @throws IllegalDataException is the test file is considered as invalid
+     */
+    @Test
+    public void testReadGpx() throws IOException, IllegalDataException {
+        for (String file : new String[]{"gpx.jos", "gpx.joz", "nmea.jos"}) {
+            List<Layer> layers = testRead(file);
+            assertTrue(layers.size() == 1);
+            assertTrue(layers.get(0) instanceof GpxLayer);
+            GpxLayer gpx = (GpxLayer) layers.get(0);
+            assertEquals(gpx.getName(), "GPX layer name");
+        }
+    }
+
+    /**
+     * Tests to read a .joz file containing GPX and marker data.
+     * @throws IOException if any I/O error occurs
+     * @throws IllegalDataException is the test file is considered as invalid
+     */
+    @Test
+    public void testReadGpxAndMarker() throws IOException, IllegalDataException {
+        List<Layer> layers = testRead("gpx_markers.joz");
+        assertTrue(layers.size() == 2);
+        GpxLayer gpx = null;
+        MarkerLayer marker = null;
+        for (Layer layer : layers) {
+            if (layer instanceof GpxLayer) {
+                gpx = (GpxLayer) layer;
+            } else if (layer instanceof MarkerLayer) {
+                marker = (MarkerLayer) layer;
+            }
+        }
+        assertTrue(gpx != null);
+        assertTrue(marker != null);
+        assertEquals(gpx.getName(), "GPX layer name");
+        assertEquals(marker.getName(), "Marker layer name");
+    }
+}
Index: trunk/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java	(revision 7325)
+++ trunk/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java	(revision 7326)
@@ -13,5 +13,7 @@
 import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.MainApplication;
@@ -19,7 +21,9 @@
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
 import org.openstreetmap.josm.gui.preferences.ToolbarPreferences;
 import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
 import org.openstreetmap.josm.tools.MultiMap;
+import org.openstreetmap.josm.tools.Pair;
 
 /**
@@ -106,5 +110,5 @@
 
     private OsmDataLayer createOsmLayer() {
-        OsmDataLayer layer = new OsmDataLayer(new DataSet(), null, null);
+        OsmDataLayer layer = new OsmDataLayer(new DataSet(), "OSM layer name", null);
         layer.setAssociatedFile(new File("data.osm"));
         return layer;
@@ -112,7 +116,14 @@
 
     private GpxLayer createGpxLayer() {
-        GpxLayer layer = new GpxLayer(new GpxData());
+        GpxData data = new GpxData();
+        data.waypoints.add(new WayPoint(new LatLon(42.72665, -0.00747)));
+        data.waypoints.add(new WayPoint(new LatLon(42.72659, -0.00749)));
+        GpxLayer layer = new GpxLayer(data, "GPX layer name");
         layer.setAssociatedFile(new File("data.gpx"));
         return layer;
+    }
+
+    private MarkerLayer createMarkerLayer(GpxLayer gpx) {
+        return new MarkerLayer(gpx.data, "Marker layer name", gpx.getAssociatedFile(), gpx);
     }
 
@@ -170,3 +181,13 @@
         testWrite(Collections.<Layer>singletonList(createGpxLayer()), true);
     }
+
+    /**
+     * Tests to write a .joz file containing GPX and marker data.
+     * @throws IOException if any I/O error occurs
+     */
+    @Test
+    public void testWriteGpxAndMarkerJoz() throws IOException {
+        GpxLayer gpx = createGpxLayer();
+        testWrite(Pair.toArrayList(new Pair<Layer, Layer>(gpx, createMarkerLayer(gpx))), true);
+    }
 }
