001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.io;
003
004 import static org.openstreetmap.josm.tools.I18n.tr;
005
006 import java.io.File;
007 import java.io.FileInputStream;
008 import java.io.IOException;
009 import java.io.InputStream;
010 import java.util.zip.GZIPInputStream;
011
012 import javax.swing.JOptionPane;
013
014 import org.openstreetmap.josm.Main;
015 import org.openstreetmap.josm.actions.ExtensionFileFilter;
016 import org.openstreetmap.josm.data.gpx.GpxData;
017 import org.openstreetmap.josm.gui.layer.GpxLayer;
018 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
019 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
020 import org.openstreetmap.josm.gui.util.GuiHelper;
021 import org.xml.sax.SAXException;
022
023 /**
024 * File importer allowing to import GPX files (*.gpx/gpx.gz files).
025 *
026 */
027 public class GpxImporter extends FileImporter {
028
029 /**
030 * The GPX file filter (*.gpx and *.gpx.gz files).
031 */
032 public static final ExtensionFileFilter FILE_FILTER = new ExtensionFileFilter(
033 "gpx,gpx.gz", "gpx", tr("GPX Files") + " (*.gpx *.gpx.gz)");
034
035 /**
036 * Utility class containing imported GPX and marker layers, and a task to run after they are added to MapView.
037 */
038 public static class GpxImporterData {
039 /**
040 * The imported GPX layer. May be null if no GPX data.
041 */
042 private GpxLayer gpxLayer;
043 /**
044 * The imported marker layer. May be null if no marker.
045 */
046 private MarkerLayer markerLayer;
047 /**
048 * The task to run after GPX and/or marker layer has been added to MapView.
049 */
050 private Runnable postLayerTask;
051
052 public GpxImporterData(GpxLayer gpxLayer, MarkerLayer markerLayer, Runnable postLayerTask) {
053 this.gpxLayer = gpxLayer;
054 this.markerLayer = markerLayer;
055 this.postLayerTask = postLayerTask;
056 }
057
058 public GpxLayer getGpxLayer() {
059 return gpxLayer;
060 }
061
062 public MarkerLayer getMarkerLayer() {
063 return markerLayer;
064 }
065
066 public Runnable getPostLayerTask() {
067 return postLayerTask;
068 }
069 }
070
071 /**
072 * Constructs a new {@code GpxImporter}.
073 */
074 public GpxImporter() {
075 super(FILE_FILTER);
076 }
077
078 @Override
079 public void importData(File file, ProgressMonitor progressMonitor) throws IOException {
080 InputStream is;
081 if (file.getName().endsWith(".gpx.gz")) {
082 is = new GZIPInputStream(new FileInputStream(file));
083 } else {
084 is = new FileInputStream(file);
085 }
086 String fileName = file.getName();
087
088 try {
089 GpxReader r = new GpxReader(is);
090 boolean parsedProperly = r.parse(true);
091 r.data.storageFile = file;
092 addLayers(loadLayers(r.data, parsedProperly, fileName, tr("Markers from {0}", fileName)));
093 } catch (SAXException e) {
094 e.printStackTrace();
095 throw new IOException(tr("Parsing data for layer ''{0}'' failed", fileName));
096 }
097 }
098
099 /**
100 * Adds the specified GPX and marker layers to Map.main
101 * @param data The layers to add
102 * @see #loadLayers
103 */
104 public static void addLayers(final GpxImporterData data) {
105 // FIXME: remove UI stuff from the IO subsystem
106 GuiHelper.runInEDT(new Runnable() {
107 public void run() {
108 if (data.markerLayer != null) {
109 Main.main.addLayer(data.markerLayer);
110 }
111 if (data.gpxLayer != null) {
112 Main.main.addLayer(data.gpxLayer);
113 }
114 data.postLayerTask.run();
115 }
116 });
117 }
118
119 /**
120 * Replies the new GPX and marker layers corresponding to the specified GPX data.
121 * @param data The GPX data
122 * @param parsedProperly True if GPX data has been properly parsed by {@link GpxReader#parse}
123 * @param gpxLayerName The GPX layer name
124 * @param markerLayerName The marker layer name
125 * @return the new GPX and marker layers corresponding to the specified GPX data, to be used with {@link #addLayers}
126 * @see #addLayers
127 */
128 public static GpxImporterData loadLayers(final GpxData data, final boolean parsedProperly,
129 final String gpxLayerName, String markerLayerName) {
130 GpxLayer gpxLayer = null;
131 MarkerLayer markerLayer = null;
132 if (data.hasRoutePoints() || data.hasTrackPoints()) {
133 gpxLayer = new GpxLayer(data, gpxLayerName, data.storageFile != null);
134 }
135 if (Main.pref.getBoolean("marker.makeautomarkers", true) && !data.waypoints.isEmpty()) {
136 markerLayer = new MarkerLayer(data, markerLayerName, data.storageFile, gpxLayer);
137 if (markerLayer.data.isEmpty()) {
138 markerLayer = null;
139 }
140 }
141 Runnable postLayerTask = new Runnable() {
142 @Override
143 public void run() {
144 if (!parsedProperly) {
145 String msg;
146 if (data.storageFile == null) {
147 msg = tr("Error occurred while parsing gpx data for layer ''{0}''. Only a part of the file will be available.",
148 gpxLayerName);
149 } else {
150 msg = tr("Error occurred while parsing gpx file ''{0}''. Only a part of the file will be available.",
151 data.storageFile.getPath());
152 }
153 JOptionPane.showMessageDialog(null, msg);
154 }
155 }
156 };
157 return new GpxImporterData(gpxLayer, markerLayer, postLayerTask);
158 }
159
160 public static GpxImporterData loadLayers(InputStream is, final File associatedFile,
161 final String gpxLayerName, String markerLayerName, ProgressMonitor progressMonitor) throws IOException {
162 try {
163 final GpxReader r = new GpxReader(is);
164 final boolean parsedProperly = r.parse(true);
165 r.data.storageFile = associatedFile;
166 return loadLayers(r.data, parsedProperly, gpxLayerName, markerLayerName);
167 } catch (SAXException e) {
168 e.printStackTrace();
169 throw new IOException(tr("Parsing data for layer ''{0}'' failed", gpxLayerName));
170 }
171 }
172 }