001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.io.File; 007import java.io.FileInputStream; 008import java.io.IOException; 009import java.io.InputStream; 010import java.util.zip.GZIPInputStream; 011 012import javax.swing.JOptionPane; 013 014import org.openstreetmap.josm.Main; 015import org.openstreetmap.josm.actions.ExtensionFileFilter; 016import org.openstreetmap.josm.data.gpx.GpxData; 017import org.openstreetmap.josm.gui.layer.GpxLayer; 018import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer; 019import org.openstreetmap.josm.gui.progress.ProgressMonitor; 020import org.openstreetmap.josm.gui.util.GuiHelper; 021import org.xml.sax.SAXException; 022 023/** 024 * File importer allowing to import GPX files (*.gpx/gpx.gz files). 025 * 026 */ 027public 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.getGpxData().storageFile = file; 092 addLayers(loadLayers(r.getGpxData(), 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 @Override 108 public void run() { 109 if (data.markerLayer != null) { 110 Main.main.addLayer(data.markerLayer); 111 } 112 if (data.gpxLayer != null) { 113 Main.main.addLayer(data.gpxLayer); 114 } 115 data.postLayerTask.run(); 116 } 117 }); 118 } 119 120 /** 121 * Replies the new GPX and marker layers corresponding to the specified GPX data. 122 * @param data The GPX data 123 * @param parsedProperly True if GPX data has been properly parsed by {@link GpxReader#parse} 124 * @param gpxLayerName The GPX layer name 125 * @param markerLayerName The marker layer name 126 * @return the new GPX and marker layers corresponding to the specified GPX data, to be used with {@link #addLayers} 127 * @see #addLayers 128 */ 129 public static GpxImporterData loadLayers(final GpxData data, final boolean parsedProperly, 130 final String gpxLayerName, String markerLayerName) { 131 GpxLayer gpxLayer = null; 132 MarkerLayer markerLayer = null; 133 if (data.hasRoutePoints() || data.hasTrackPoints()) { 134 gpxLayer = new GpxLayer(data, gpxLayerName, data.storageFile != null); 135 } 136 if (Main.pref.getBoolean("marker.makeautomarkers", true) && !data.waypoints.isEmpty()) { 137 markerLayer = new MarkerLayer(data, markerLayerName, data.storageFile, gpxLayer); 138 if (markerLayer.data.isEmpty()) { 139 markerLayer = null; 140 } 141 } 142 Runnable postLayerTask = new Runnable() { 143 @Override 144 public void run() { 145 if (!parsedProperly) { 146 String msg; 147 if (data.storageFile == null) { 148 msg = tr("Error occurred while parsing gpx data for layer ''{0}''. Only a part of the file will be available.", 149 gpxLayerName); 150 } else { 151 msg = tr("Error occurred while parsing gpx file ''{0}''. Only a part of the file will be available.", 152 data.storageFile.getPath()); 153 } 154 JOptionPane.showMessageDialog(null, msg); 155 } 156 } 157 }; 158 return new GpxImporterData(gpxLayer, markerLayer, postLayerTask); 159 } 160 161 public static GpxImporterData loadLayers(InputStream is, final File associatedFile, 162 final String gpxLayerName, String markerLayerName, ProgressMonitor progressMonitor) throws IOException { 163 try { 164 final GpxReader r = new GpxReader(is); 165 final boolean parsedProperly = r.parse(true); 166 r.getGpxData().storageFile = associatedFile; 167 return loadLayers(r.getGpxData(), parsedProperly, gpxLayerName, markerLayerName); 168 } catch (SAXException e) { 169 e.printStackTrace(); 170 throw new IOException(tr("Parsing data for layer ''{0}'' failed", gpxLayerName)); 171 } 172 } 173}