// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.io;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.JOptionPane;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.ExtensionFileFilter;
import org.openstreetmap.josm.data.gpx.GpxData;
import org.openstreetmap.josm.gui.layer.GpxLayer;
import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
import org.openstreetmap.josm.gui.progress.ProgressMonitor;
import org.openstreetmap.josm.gui.util.GuiHelper;
import org.xml.sax.SAXException;
/**
* File importer allowing to import GPX files (*.gpx/gpx.gz files).
*
*/
public class GpxImporter extends FileImporter {
/**
* The GPX file filter (*.gpx and *.gpx.gz files).
*/
public static final ExtensionFileFilter FILE_FILTER = new ExtensionFileFilter(
"gpx,gpx.gz,gpx.bz2", "gpx", tr("GPX Files") + " (*.gpx *.gpx.gz, *.gpx.bz2)");
/**
* Utility class containing imported GPX and marker layers, and a task to run after they are added to MapView.
*/
public static class GpxImporterData {
/**
* The imported GPX layer. May be null if no GPX data.
*/
private GpxLayer gpxLayer;
/**
* The imported marker layer. May be null if no marker.
*/
private MarkerLayer markerLayer;
/**
* The task to run after GPX and/or marker layer has been added to MapView.
*/
private Runnable postLayerTask;
public GpxImporterData(GpxLayer gpxLayer, MarkerLayer markerLayer, Runnable postLayerTask) {
this.gpxLayer = gpxLayer;
this.markerLayer = markerLayer;
this.postLayerTask = postLayerTask;
}
public GpxLayer getGpxLayer() {
return gpxLayer;
}
public MarkerLayer getMarkerLayer() {
return markerLayer;
}
public Runnable getPostLayerTask() {
return postLayerTask;
}
}
/**
* Constructs a new {@code GpxImporter}.
*/
public GpxImporter() {
super(FILE_FILTER);
}
@Override
public void importData(File file, ProgressMonitor progressMonitor) throws IOException {
final String fileName = file.getName();
try (InputStream is = Compression.getUncompressedFileInputStream(file)) {
GpxReader r = new GpxReader(is);
boolean parsedProperly = r.parse(true);
r.getGpxData().storageFile = file;
addLayers(loadLayers(r.getGpxData(), parsedProperly, fileName, tr("Markers from {0}", fileName)));
} catch (SAXException e) {
Main.error(e);
throw new IOException(tr("Parsing data for layer ''{0}'' failed", fileName), e);
}
}
/**
* Adds the specified GPX and marker layers to Map.main
* @param data The layers to add
* @see #loadLayers
*/
public static void addLayers(final GpxImporterData data) {
// FIXME: remove UI stuff from the IO subsystem
GuiHelper.runInEDT(new Runnable() {
@Override
public void run() {
if (data.markerLayer != null) {
Main.main.addLayer(data.markerLayer);
}
if (data.gpxLayer != null) {
Main.main.addLayer(data.gpxLayer);
}
data.postLayerTask.run();
}
});
}
/**
* Replies the new GPX and marker layers corresponding to the specified GPX data.
* @param data The GPX data
* @param parsedProperly True if GPX data has been properly parsed by {@link GpxReader#parse}
* @param gpxLayerName The GPX layer name
* @param markerLayerName The marker layer name
* @return the new GPX and marker layers corresponding to the specified GPX data, to be used with {@link #addLayers}
* @see #addLayers
*/
public static GpxImporterData loadLayers(final GpxData data, final boolean parsedProperly,
final String gpxLayerName, String markerLayerName) {
GpxLayer gpxLayer = null;
MarkerLayer markerLayer = null;
if (data.hasRoutePoints() || data.hasTrackPoints()) {
gpxLayer = new GpxLayer(data, gpxLayerName, data.storageFile != null);
}
if (Main.pref.getBoolean("marker.makeautomarkers", true) && !data.waypoints.isEmpty()) {
markerLayer = new MarkerLayer(data, markerLayerName, data.storageFile, gpxLayer);
if (markerLayer.data.isEmpty()) {
markerLayer = null;
}
}
Runnable postLayerTask = new Runnable() {
@Override
public void run() {
if (!parsedProperly) {
String msg;
if (data.storageFile == null) {
msg = tr("Error occurred while parsing gpx data for layer ''{0}''. Only a part of the file will be available.",
gpxLayerName);
} else {
msg = tr("Error occurred while parsing gpx file ''{0}''. Only a part of the file will be available.",
data.storageFile.getPath());
}
JOptionPane.showMessageDialog(null, msg);
}
}
};
return new GpxImporterData(gpxLayer, markerLayer, postLayerTask);
}
public static GpxImporterData loadLayers(InputStream is, final File associatedFile,
final String gpxLayerName, String markerLayerName, ProgressMonitor progressMonitor) throws IOException {
try {
final GpxReader r = new GpxReader(is);
final boolean parsedProperly = r.parse(true);
r.getGpxData().storageFile = associatedFile;
return loadLayers(r.getGpxData(), parsedProperly, gpxLayerName, markerLayerName);
} catch (SAXException e) {
Main.error(e);
throw new IOException(tr("Parsing data for layer ''{0}'' failed", gpxLayerName), e);
}
}
}