Ticket #4029: output.txt

File output.txt, 26.1 KB (added by Nakor, 9 years ago)

Temporary patch

Line 
1### Eclipse Workspace Patch 1.0
2#P core
3Index: src/org/openstreetmap/josm/actions/SaveSessionAction.java
4===================================================================
5--- src/org/openstreetmap/josm/actions/SaveSessionAction.java   (revision 0)
6+++ src/org/openstreetmap/josm/actions/SaveSessionAction.java   (revision 0)
7@@ -0,0 +1,48 @@
8+// License: GPL. For details, see LICENSE file.
9+package org.openstreetmap.josm.actions;
10+
11+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
12+import static org.openstreetmap.josm.tools.I18n.tr;
13+
14+import java.awt.event.ActionEvent;
15+import java.io.File;
16+
17+import org.openstreetmap.josm.gui.layer.Layer;
18+import org.openstreetmap.josm.io.SessionExporter;
19+
20+public class SaveSessionAction extends SaveActionBase {
21+
22+    public SaveSessionAction() {
23+        super(tr("Save Session"), "savesession", tr("Save the current session."),
24+                null);
25+        putValue("help", ht("/Action/Save"));
26+    }
27+
28+    @Override
29+    public void actionPerformed(ActionEvent arg0) {
30+        doSave();
31+
32+    }
33+
34+    @Override
35+    public boolean doSave() {
36+        File file = createAndOpenSaveFileChooser(tr("Save Session file"), "jos");
37+
38+
39+        SessionExporter exporter = new SessionExporter();
40+
41+        exporter.exportData(file);
42+
43+        return true;
44+
45+
46+
47+    }
48+
49+    @Override
50+    protected File getFile(Layer layer) {
51+        // TODO Auto-generated method stub
52+        return null;
53+    }
54+
55+}
56Index: src/org/openstreetmap/josm/io/AllFormatsImporter.java
57===================================================================
58--- src/org/openstreetmap/josm/io/AllFormatsImporter.java       (revision 3616)
59+++ src/org/openstreetmap/josm/io/AllFormatsImporter.java       (working copy)
60@@ -12,8 +12,8 @@
61  */
62 public class AllFormatsImporter extends FileImporter {
63     public AllFormatsImporter() {
64-        super(new ExtensionFileFilter("osm,xml,osm.gz,osm.bz2,osm.bz,gpx,gpx.gz,nmea,nme,nma,log,txt,wms,jpg", "", tr("All Formats")
65-                    + " (*.gpx *.osm *.nmea *.jpg ...)"));
66+        super(new ExtensionFileFilter("osm,xml,osm.gz,osm.bz2,osm.bz,gpx,gpx.gz,nmea,nme,nma,log,txt,wms,jpg,jos", "", tr("All Formats")
67+                + " (*.gpx *.osm *.nmea *.jpg ...)"));
68     }
69     @Override public boolean acceptFile(File pathname) {
70         return false;
71Index: src/org/openstreetmap/josm/io/FileImporter.java
72===================================================================
73--- src/org/openstreetmap/josm/io/FileImporter.java     (revision 3616)
74+++ src/org/openstreetmap/josm/io/FileImporter.java     (working copy)
75@@ -12,11 +12,13 @@
76 import org.openstreetmap.josm.Main;
77 import org.openstreetmap.josm.actions.ExtensionFileFilter;
78 import org.openstreetmap.josm.gui.HelpAwareOptionPane;
79+import org.openstreetmap.josm.gui.layer.Layer;
80 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
81 
82 public abstract class FileImporter implements Comparable<FileImporter> {
83 
84     public final ExtensionFileFilter filter;
85+    protected Layer layer;
86 
87     public FileImporter(ExtensionFileFilter filter) {
88         this.filter = filter;
89@@ -94,4 +96,12 @@
90         return (new Double(this.getPriority())).compareTo(other.getPriority());
91     }
92 
93+    /*
94+     * Returns the created layer
95+     */
96+    public Layer getLayer() {
97+        // TODO Auto-generated method stub
98+        return layer;
99+    }
100+
101 }
102Index: src/org/openstreetmap/josm/io/GpxImporter.java
103===================================================================
104--- src/org/openstreetmap/josm/io/GpxImporter.java      (revision 3616)
105+++ src/org/openstreetmap/josm/io/GpxImporter.java      (working copy)
106@@ -40,6 +40,7 @@
107             final boolean parsedProperly = r.parse(true);
108             r.data.storageFile = file;
109             final GpxLayer gpxLayer = new GpxLayer(r.data, fn, true);
110+            this.layer=gpxLayer;
111 
112             // FIXME: remove UI stuff from the IO subsystem
113             //
114Index: src/org/openstreetmap/josm/io/OsmImporter.java
115===================================================================
116--- src/org/openstreetmap/josm/io/OsmImporter.java      (revision 3616)
117+++ src/org/openstreetmap/josm/io/OsmImporter.java      (working copy)
118@@ -14,6 +14,7 @@
119 import org.openstreetmap.josm.Main;
120 import org.openstreetmap.josm.actions.ExtensionFileFilter;
121 import org.openstreetmap.josm.data.osm.DataSet;
122+import org.openstreetmap.josm.gui.layer.Layer;
123 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
124 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
125 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
126@@ -41,6 +42,7 @@
127     protected void importData(InputStream in, File associatedFile) throws IllegalDataException {
128         DataSet dataSet = OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE);
129         final OsmDataLayer layer = new OsmDataLayer(dataSet, associatedFile.getName(), associatedFile);
130+        this.layer=layer;
131         // FIXME: remove UI stuff from IO subsystem
132         //
133         Runnable uiStuff = new Runnable() {
134@@ -55,4 +57,10 @@
135             SwingUtilities.invokeLater(uiStuff);
136         }
137     }
138+
139+
140+    @Override
141+    public Layer getLayer() {
142+        return layer;
143+    }
144 }
145Index: src/org/openstreetmap/josm/io/SessionWriter.java
146===================================================================
147--- src/org/openstreetmap/josm/io/SessionWriter.java    (revision 0)
148+++ src/org/openstreetmap/josm/io/SessionWriter.java    (revision 0)
149@@ -0,0 +1,127 @@
150+// License: GPL. For details, see LICENSE file.
151+package org.openstreetmap.josm.io;
152+
153+import java.io.PrintWriter;
154+import java.util.Collection;
155+
156+import org.openstreetmap.josm.Main;
157+import org.openstreetmap.josm.data.ProjectionBounds;
158+import org.openstreetmap.josm.gui.layer.GpxLayer;
159+import org.openstreetmap.josm.gui.layer.Layer;
160+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
161+import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer;
162+import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry;
163+
164+public class SessionWriter extends XmlWriter {
165+
166+    public SessionWriter(PrintWriter out) {
167+        super(out);
168+        // TODO Auto-generated constructor stub
169+    }
170+
171+    public void header() {
172+        out.println("<?xml version='1.0' encoding='UTF-8'?>");
173+        out.print("<josmsession");
174+        out.println(" generator='JOSM'>");
175+    }
176+
177+    public void writeView() {
178+
179+        // What is the center?
180+        ProjectionBounds box = Main.map.mapView.getProjectionBounds();
181+
182+        out.print("<view");
183+        out.print(" minEast='");
184+        out.print(box.min.east());
185+        out.print("'");
186+        out.print(" minNorth='");
187+        out.print(box.min.north());
188+        out.print("'");
189+        out.print(" maxEast='");
190+        out.print(box.max.east());
191+        out.print("'");
192+        out.print(" maxNorth='");
193+        out.print(box.max.north());
194+        out.print("'");
195+        out.println(" />");
196+    }
197+
198+    public void writeLayers() {
199+        // Do we have layers?
200+        Collection<Layer> layers = null;
201+        layers = Main.map.mapView.getAllLayers();
202+
203+        for (Layer layer: layers)
204+        {
205+            if (layer instanceof OsmDataLayer) {
206+                writeOsmLayer(layer);
207+            }
208+            if (layer instanceof GpxLayer) {
209+                writeGpxLayer(layer);
210+            }
211+            if (layer instanceof GeoImageLayer) {
212+                writeGeoImageLayer(layer);
213+            }
214+        }
215+
216+    }
217+
218+    private void writeGeoImageLayer(Layer layer) {
219+        GeoImageLayer geoImageLayer = (GeoImageLayer) layer;
220+        out.print("<geoimagelayer gpxlayer='");
221+        out.print(geoImageLayer.getGpxLayer().getAssociatedFile().getAbsolutePath());
222+        out.print("' visible='");
223+        if (layer.isVisible()) {
224+            out.print("yes");
225+        }
226+        out.print("'");
227+        if (layer == Main.map.mapView.getActiveLayer()) {
228+            out.print(" active='yes'");
229+        }
230+        out.println(">");
231+        for (ImageEntry image: geoImageLayer.getImages()) {
232+            out.print("<image name='");
233+            out.print(image.getFile().getAbsolutePath());
234+            out.println("' />");
235+        }
236+        out.println("</geoimagelayer>");
237+    }
238+
239+    private void writeGenericLayer(String type, Layer layer) {
240+        out.print("<");
241+        out.print(type);
242+        out.print(" name='");
243+        out.print(layer.getAssociatedFile().getPath());
244+        out.print("'");
245+        out.print(" visible='");
246+        if (layer.isVisible()) {
247+            out.print("yes");
248+        }
249+        out.print("'");
250+        if (layer == Main.map.mapView.getActiveLayer()) {
251+            out.print(" active='yes'");
252+        }
253+        out.println(" />");    }
254+
255+
256+    private void writeGpxLayer(Layer layer) {
257+        writeGenericLayer("gpxlayer", layer);
258+    }
259+
260+    private void writeOsmLayer(Layer layer) {
261+        writeGenericLayer("osmlayer", layer);
262+
263+    }
264+
265+    public void footer() {
266+        out.println("</josmsession>");
267+    }
268+
269+    public void close() {
270+        out.close();
271+    }
272+
273+
274+
275+}
276+
277Index: src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
278===================================================================
279--- src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java    (revision 3616)
280+++ src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java    (working copy)
281@@ -258,9 +258,9 @@
282         }
283     }
284 
285-    public static void create(Collection<File> files, GpxLayer gpxLayer) {
286+    public static Layer create(Collection<File> files, GpxLayer gpxLayer) {
287         Loader loader = new Loader(files, gpxLayer);
288-        Main.worker.execute(loader);
289+        return loader.layer;
290     }
291 
292     private GeoImageLayer(final List<ImageEntry> data, GpxLayer gpxLayer) {
293@@ -799,4 +799,8 @@
294         }
295         return copy;
296     }
297+
298+    public Layer getGpxLayer() {
299+        return gpxLayer;
300+    }
301 }
302Index: src/org/openstreetmap/josm/io/SessionExporter.java
303===================================================================
304--- src/org/openstreetmap/josm/io/SessionExporter.java  (revision 0)
305+++ src/org/openstreetmap/josm/io/SessionExporter.java  (revision 0)
306@@ -0,0 +1,56 @@
307+// License: GPL. For details, see LICENSE file.
308+package org.openstreetmap.josm.io;
309+
310+import static org.openstreetmap.josm.tools.I18n.tr;
311+
312+import java.io.File;
313+import java.io.FileNotFoundException;
314+import java.io.FileOutputStream;
315+import java.io.IOException;
316+import java.io.OutputStream;
317+import java.io.OutputStreamWriter;
318+import java.io.PrintWriter;
319+import java.io.Writer;
320+
321+import javax.swing.JOptionPane;
322+
323+import org.openstreetmap.josm.Main;
324+import org.openstreetmap.josm.actions.ExtensionFileFilter;
325+
326+public class SessionExporter extends FileExporter {
327+
328+    public SessionExporter() {
329+        super(new ExtensionFileFilter("jos", "jos", tr("JOSM Session Files") + " (*.jos)"));
330+    }
331+
332+    public void exportData(File file) {
333+        try {
334+            OutputStream out = getOutputStream(file);
335+            Writer writer = new OutputStreamWriter(out, "UTF-8");
336+
337+            SessionWriter w = new SessionWriter(new PrintWriter(writer));
338+
339+            w.header();
340+            w.writeView();
341+            w.writeLayers();
342+            w.footer();
343+            w.close();
344+
345+        } catch (IOException e) {
346+            e.printStackTrace();
347+            JOptionPane.showMessageDialog(
348+                    Main.parent,
349+                    tr("<html>An error occurred while saving.<br>Error is:<br>{0}</html>", e.getMessage()),
350+                    tr("Error"),
351+                    JOptionPane.ERROR_MESSAGE
352+            );
353+
354+        }
355+    }
356+
357+    protected OutputStream getOutputStream(File file) throws FileNotFoundException, IOException {
358+        return new FileOutputStream(file);
359+    }
360+
361+}
362+
363Index: src/org/openstreetmap/josm/io/SessionReader.java
364===================================================================
365--- src/org/openstreetmap/josm/io/SessionReader.java    (revision 0)
366+++ src/org/openstreetmap/josm/io/SessionReader.java    (revision 0)
367@@ -0,0 +1,264 @@
368+// License: GPL. For details, see LICENSE file.
369+package org.openstreetmap.josm.io;
370+
371+import static org.openstreetmap.josm.tools.I18n.tr;
372+
373+import java.io.File;
374+import java.io.IOException;
375+import java.io.InputStream;
376+import java.util.ArrayList;
377+import java.util.Collection;
378+import java.util.List;
379+
380+import javax.xml.parsers.ParserConfigurationException;
381+import javax.xml.parsers.SAXParserFactory;
382+
383+import org.openstreetmap.josm.Main;
384+import org.openstreetmap.josm.actions.ExtensionFileFilter;
385+import org.openstreetmap.josm.data.ProjectionBounds;
386+import org.openstreetmap.josm.data.coor.EastNorth;
387+import org.openstreetmap.josm.gui.layer.GpxLayer;
388+import org.openstreetmap.josm.gui.layer.Layer;
389+import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer;
390+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
391+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
392+import org.openstreetmap.josm.tools.CheckParameterUtil;
393+import org.xml.sax.Attributes;
394+import org.xml.sax.InputSource;
395+import org.xml.sax.Locator;
396+import org.xml.sax.SAXException;
397+import org.xml.sax.SAXParseException;
398+import org.xml.sax.helpers.DefaultHandler;
399+
400+public class SessionReader {
401+
402+    private class Parser extends DefaultHandler {
403+        // Global attributes
404+        private Locator locator;
405+        private Layer activeLayer;
406+        private final List<Layer> layers = new ArrayList<Layer>();
407+        private final List<Layer> tmpLayers = new ArrayList<Layer>();
408+        private ProjectionBounds box;
409+
410+        // per-layer attributes
411+        private String layerName;
412+        private boolean active;
413+        private boolean visible;
414+        private Collection<File> files = new ArrayList<File>();
415+        public String parentLayerName;
416+        public String layerType="";
417+
418+        @Override
419+        public void setDocumentLocator(Locator locator) {
420+            this.locator = locator;
421+        }
422+
423+        @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
424+
425+            try {
426+                if (qName.equals("view")) {
427+                    EastNorth min = new EastNorth(Double.parseDouble(atts.getValue("minEast")), Double.parseDouble(atts.getValue("minNorth")));
428+                    EastNorth max = new EastNorth(Double.parseDouble(atts.getValue("maxEast")), Double.parseDouble(atts.getValue("maxNorth")));
429+                    this.box = new ProjectionBounds(min, max);
430+                } else if (qName.equals("osmlayer") || qName.equals("gpxlayer") || qName.equals("geoimagelayer")) {
431+                    newLayerCleanup();
432+                    initLayer(qName, atts);
433+                } else if (qName.equals("image")) {
434+                    String fileName = atts.getValue("name");
435+                    File file = new File(fileName);
436+                    files.add(file);
437+                } else {
438+                    System.out.println(tr("Undefined element ''{0}'' found in input stream. Skipping.", qName));
439+                }
440+            } catch (Exception e) {
441+                throw new SAXParseException(e.getMessage(), locator, e);
442+            }
443+        }
444+
445+        private void initLayer(String qName, Attributes atts) {
446+            String key;
447+            layerType = qName;
448+            layerName = atts.getValue("name");
449+            visible = false;
450+            key = atts.getValue("visible");
451+            if (key !=null){
452+                visible = key.equals("yes");
453+            }
454+            active = false;
455+            key = atts.getValue("active");
456+            if (key !=null){
457+                active = key.equals("yes");
458+            }
459+            parentLayerName = atts.getValue("gpxlayer");
460+
461+        }
462+
463+        private void newLayerCleanup() {
464+            if (layerType.equals("osmlayer")) {
465+                loadGenericLayer();
466+            }
467+            else if (layerType.equals("gpxlayer")) {
468+                Layer layer = null;
469+                for (Layer existingLayer: tmpLayers) {
470+                    if (existingLayer.getAssociatedFile().getAbsolutePath().equals(layerName)) {
471+                        layer = existingLayer;
472+                        break;
473+                    }
474+                }
475+                if (layer == null) {
476+                    // If not found create
477+                    loadGenericLayer();
478+                } else {
479+                    // If already loaded (as part of audio or images) put it in the main list
480+                    this.tmpLayers.remove(layer);
481+                    this.layers.add(layer);
482+                }
483+            }
484+            else if (layerType.equals("geoimagelayer")) {
485+                loadImageLayer();
486+            }
487+        }
488+        private void loadImageLayer() {
489+            Layer gpxLayer=null;
490+
491+
492+            // Look for parent layer
493+            for (Layer existingLayer: layers) {
494+                if (existingLayer.getAssociatedFile().getAbsolutePath().equals(parentLayerName)) {
495+                    gpxLayer=existingLayer;
496+                    break;
497+                }
498+            }
499+
500+            // Load it if not existing
501+            if (gpxLayer == null) {
502+                gpxLayer=importLayer(parentLayerName);
503+                this.tmpLayers.add(gpxLayer);
504+            }
505+
506+            Layer layer = GeoImageLayer.create(files, (GpxLayer)gpxLayer);
507+
508+
509+
510+            /*JpgImporter importer = new JpgImporter((GpxLayer)layer);
511+            try {
512+                importer.importData(files, NullProgressMonitor.INSTANCE);
513+            } catch (IOException e) {
514+                // TODO Auto-generated catch block
515+                e.printStackTrace();
516+            } catch (IllegalDataException e) {
517+                // TODO Auto-generated catch block
518+                e.printStackTrace();
519+            }
520+            layer=importer.getLayer();*/
521+            // FIXME : sometimes layer is null
522+            if (layer != null) {
523+                layer.setVisible(visible);
524+            }
525+            if (active) {
526+                this.activeLayer=layer;
527+            }
528+            this.layers.add(layer);
529+
530+
531+        }
532+
533+        private void loadGenericLayer() {
534+            Layer layer = importLayer(layerName);
535+            this.layers.add(layer);
536+        }
537+
538+        private Layer importLayer(String fileName) {
539+            Layer layer = null;
540+            File file = new File(fileName);
541+            FileImporter importer = null;
542+            for (FileImporter imp : ExtensionFileFilter.importers) {
543+                if (imp.acceptFile(file)) {
544+                    importer=imp;
545+                    break;
546+                }
547+            }
548+
549+            if (importer != null) {
550+                try {
551+                    importer.importData(file, NullProgressMonitor.INSTANCE);
552+                } catch (IOException e) {
553+                    // TODO Auto-generated catch block
554+                    e.printStackTrace();
555+                } catch (IllegalDataException e) {
556+                    // TODO Auto-generated catch block
557+                    e.printStackTrace();
558+                }
559+                layer=importer.getLayer();
560+                layer.setVisible(visible);
561+                if (active) {
562+                    this.activeLayer=layer;
563+                }
564+            }
565+            return layer;
566+        }
567+
568+        public void manageLayers(){
569+            int i=0;
570+            for (Layer layer: this.layers) {
571+                // FIXME: sometime layer is not yet in main list
572+                if (Main.map.mapView.getAllLayersAsList().indexOf(layer)>-1) {
573+                    Main.map.mapView.moveLayer(layer, i);
574+                }
575+                i+=1;
576+            }
577+
578+            if (this.activeLayer != null) {
579+                Main.map.mapView.setActiveLayer(activeLayer);
580+            }
581+        }
582+
583+        public void manageView() {
584+
585+            Main.map.mapView.zoomTo(this.box);
586+
587+        }
588+    }
589+
590+    public static void parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
591+        if (progressMonitor == null) {
592+            progressMonitor = NullProgressMonitor.INSTANCE;
593+        }
594+        CheckParameterUtil.ensureParameterNotNull(source, "source");
595+        SessionReader reader = new SessionReader();
596+        try {
597+            progressMonitor.beginTask(tr("Prepare Session data...", 2));
598+            progressMonitor.indeterminateSubTask(tr("Parsing Session data..."));
599+
600+            InputSource inputSource = new InputSource(UTFInputStreamReader.create(source, "UTF-8"));
601+            Parser parser = reader.new Parser();
602+            SAXParserFactory.newInstance().newSAXParser().parse(inputSource, parser);
603+            parser.newLayerCleanup();
604+            // FIXME: for some reason we have to wait or we get an exception as some layer not being in the list
605+            // when calling Main.map.mapView.moveLayer
606+            try {
607+                Thread.currentThread();
608+                Thread.sleep(1000);
609+            } catch (InterruptedException e) {
610+                // TODO Auto-generated catch block
611+                e.printStackTrace();
612+            }
613+            parser.manageLayers();
614+            progressMonitor.worked(1);
615+            parser.manageView();
616+            progressMonitor.worked(1);
617+        } catch(ParserConfigurationException e) {
618+            throw new IllegalDataException(e.getMessage(), e);
619+        } catch (SAXParseException e) {
620+            throw new IllegalDataException(tr("Line {0} column {1}: ", e.getLineNumber(), e.getColumnNumber()) + e.getMessage(), e);
621+        } catch(SAXException e) {
622+            throw new IllegalDataException(e.getMessage(), e);
623+        } catch(Exception e) {
624+            throw new IllegalDataException(e);
625+        } finally {
626+            progressMonitor.finishTask();
627+        }
628+    }
629+
630+
631+}
632Index: src/org/openstreetmap/josm/actions/ExtensionFileFilter.java
633===================================================================
634--- src/org/openstreetmap/josm/actions/ExtensionFileFilter.java (revision 3616)
635+++ src/org/openstreetmap/josm/actions/ExtensionFileFilter.java (working copy)
636@@ -44,6 +44,7 @@
637                 "org.openstreetmap.josm.io.NMEAImporter",
638                 "org.openstreetmap.josm.io.OsmBzip2Importer",
639                 "org.openstreetmap.josm.io.JpgImporter",
640+                "org.openstreetmap.josm.io.SessionImporter",
641                 "org.openstreetmap.josm.io.AllFormatsImporter"
642         };
643 
644Index: src/org/openstreetmap/josm/io/SessionImporter.java
645===================================================================
646--- src/org/openstreetmap/josm/io/SessionImporter.java  (revision 0)
647+++ src/org/openstreetmap/josm/io/SessionImporter.java  (revision 0)
648@@ -0,0 +1,41 @@
649+// License: GPL. For details, see LICENSE file.
650+package org.openstreetmap.josm.io;
651+
652+import static org.openstreetmap.josm.tools.I18n.tr;
653+
654+import java.io.File;
655+import java.io.FileInputStream;
656+import java.io.FileNotFoundException;
657+import java.io.IOException;
658+import java.io.InputStream;
659+
660+import org.openstreetmap.josm.actions.ExtensionFileFilter;
661+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
662+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
663+
664+public class SessionImporter extends FileImporter {
665+
666+    public SessionImporter() {
667+        super(new ExtensionFileFilter("jos", "jos", tr("OSM Session Files") + " (*.jos)"));
668+    }
669+
670+    public SessionImporter(ExtensionFileFilter filter) {
671+        super(filter);
672+    }
673+
674+    @Override public void importData(File file, ProgressMonitor progressMonitor) throws IOException, IllegalDataException {
675+        try {
676+            FileInputStream in = new FileInputStream(file);
677+            importData(in, file);
678+        } catch (FileNotFoundException e) {
679+            e.printStackTrace();
680+            throw new IOException(tr("File ''{0}'' does not exist.", file.getName()));
681+        }
682+    }
683+
684+    protected void importData(InputStream in, File associatedFile) throws IllegalDataException {
685+        SessionReader.parseDataSet(in, NullProgressMonitor.INSTANCE);
686+    }
687+
688+}
689+
690Index: images/savesession.png
691===================================================================
692Cannot display: file marked as a binary type.
693svn:mime-type = application/octet-stream
694
695Property changes on: images/savesession.png
696___________________________________________________________________
697Added: svn:mime-type
698   + application/octet-stream
699
700Index: src/org/openstreetmap/josm/gui/MainMenu.java
701===================================================================
702--- src/org/openstreetmap/josm/gui/MainMenu.java        (revision 3616)
703+++ src/org/openstreetmap/josm/gui/MainMenu.java        (working copy)
704@@ -59,6 +59,7 @@
705 import org.openstreetmap.josm.actions.ReverseWayAction;
706 import org.openstreetmap.josm.actions.SaveAction;
707 import org.openstreetmap.josm.actions.SaveAsAction;
708+import org.openstreetmap.josm.actions.SaveSessionAction;
709 import org.openstreetmap.josm.actions.SelectAllAction;
710 import org.openstreetmap.josm.actions.ShowStatusReportAction;
711 import org.openstreetmap.josm.actions.SimplifyWayAction;
712@@ -103,6 +104,7 @@
713     public final OpenLocationAction openLocation = new OpenLocationAction();
714     public final JosmAction save = new SaveAction();
715     public final JosmAction saveAs = new SaveAsAction();
716+    public final JosmAction saveSession = new SaveSessionAction();
717     public final JosmAction gpxExport = new GpxExportAction();
718     public final DownloadAction download = new DownloadAction();
719     public final DownloadPrimitiveAction downloadPrimitive = new DownloadPrimitiveAction();
720@@ -224,6 +226,7 @@
721         fileMenu.addSeparator();
722         add(fileMenu, save);
723         add(fileMenu, saveAs);
724+        add(fileMenu, saveSession);
725         add(fileMenu, gpxExport);
726         fileMenu.addSeparator();
727         add(fileMenu, download);
728Index: src/org/openstreetmap/josm/io/JpgImporter.java
729===================================================================
730--- src/org/openstreetmap/josm/io/JpgImporter.java      (revision 3616)
731+++ src/org/openstreetmap/josm/io/JpgImporter.java      (working copy)
732@@ -47,7 +47,7 @@
733             if (files.isEmpty())
734                 throw new IOException(tr("No image files found."));
735 
736-            GeoImageLayer.create(files, gpx);
737+            layer = GeoImageLayer.create(files, gpx);
738         } finally {
739             progressMonitor.finishTask();
740         }