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 }