// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.gui.layer.gpx; import static org.openstreetmap.josm.gui.help.HelpUtil.ht; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Optional; import javax.swing.AbstractAction; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.gpx.GpxConstants; import org.openstreetmap.josm.data.gpx.GpxTrack; import org.openstreetmap.josm.data.gpx.GpxTrackSegment; import org.openstreetmap.josm.data.gpx.WayPoint; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil; import org.openstreetmap.josm.gui.layer.GpxLayer; import org.openstreetmap.josm.gui.layer.Layer; import org.openstreetmap.josm.gui.layer.OsmDataLayer; import org.openstreetmap.josm.gui.layer.markerlayer.Marker; import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer; import org.openstreetmap.josm.gui.widgets.UrlLabel; import org.openstreetmap.josm.tools.GBC; import org.openstreetmap.josm.tools.ImageProvider; import org.openstreetmap.josm.tools.UncheckedParseException; import org.openstreetmap.josm.tools.date.DateUtils; /** * An abstract action for a conversion from a {@code T} {@link Layer} to a {@link OsmDataLayer}. * @param <T> the source layer class */ public abstract class ConvertToDataLayerAction<T extends Layer> extends AbstractAction { /** source layer */ protected final transient T layer; /** * Constructs a new {@code ConvertToDataLayerAction} * @param layer source layer */ protected ConvertToDataLayerAction(final T layer) { super(tr("Convert to data layer"), ImageProvider.get("converttoosm")); this.layer = layer; putValue("help", ht("/Action/ConvertToDataLayer")); } /** * Converts a {@link GpxLayer} to a {@link OsmDataLayer}. */ public static class FromGpxLayer extends ConvertToDataLayerAction<GpxLayer> { /** * Creates a new {@code FromGpxLayer}. * @param layer the source layer */ public FromGpxLayer(GpxLayer layer) { super(layer); } @Override public DataSet convert() { final DataSet ds = new DataSet(); for (GpxTrack trk : layer.data.tracks) { for (GpxTrackSegment segment : trk.getSegments()) { List<Node> nodes = new ArrayList<>(); for (WayPoint p : segment.getWayPoints()) { Node n = new Node(p.getCoor()); String timestr = p.getString(GpxConstants.PT_TIME); if (timestr != null) { try { n.setTimestamp(DateUtils.fromString(timestr)); } catch (UncheckedParseException e) { Main.warn(e, false); } } ds.addPrimitive(n); nodes.add(n); } Way w = new Way(); w.setNodes(nodes); ds.addPrimitive(w); } } return ds; } } /** * Converts a {@link MarkerLayer} to a {@link OsmDataLayer}. */ public static class FromMarkerLayer extends ConvertToDataLayerAction<MarkerLayer> { /** * Converts a {@link MarkerLayer} to a {@link OsmDataLayer}. * @param layer marker layer */ public FromMarkerLayer(MarkerLayer layer) { super(layer); } @Override public DataSet convert() { final DataSet ds = new DataSet(); for (Marker marker : layer.data) { final Node node = new Node(marker.getCoor()); final Collection<String> mapping = Main.pref.getCollection("gpx.to-osm-mapping", Arrays.asList( GpxConstants.GPX_NAME, "name", GpxConstants.GPX_DESC, "description", GpxConstants.GPX_CMT, "note", GpxConstants.GPX_SRC, "source", GpxConstants.PT_SYM, "gpxicon")); if (mapping.size() % 2 == 0) { final Iterator<String> it = mapping.iterator(); while (it.hasNext()) { final String gpxKey = it.next(); final String osmKey = it.next(); Optional.ofNullable(marker.getTemplateValue(gpxKey, false)) .map(String::valueOf) .ifPresent(s -> node.put(osmKey, s)); } } else { Main.warn("Invalid gpx.to-osm-mapping Einstein setting: expecting even number of entries"); } ds.addPrimitive(node); } return ds; } } /** * Performs the conversion to a {@link DataSet}. * @return the resulting dataset */ public abstract DataSet convert(); @Override public void actionPerformed(ActionEvent e) { JPanel msg = new JPanel(new GridBagLayout()); msg.add(new JLabel( tr("<html>Upload of unprocessed GPS data as map data is considered harmful.<br>" + "If you want to upload traces, look here:</html>")), GBC.eol()); msg.add(new UrlLabel(Main.getOSMWebsite() + "/traces", 2), GBC.eop()); if (!ConditionalOptionPaneUtil.showConfirmationDialog("convert_to_data", Main.parent, msg, tr("Warning"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, JOptionPane.OK_OPTION)) { return; } final DataSet ds = convert(); final OsmDataLayer osmLayer = new OsmDataLayer(ds, tr("Converted from: {0}", layer.getName()), null); if (layer.getAssociatedFile() != null) { osmLayer.setAssociatedFile(new File(layer.getAssociatedFile().getParentFile(), layer.getAssociatedFile().getName() + ".osm")); } osmLayer.setUploadDiscouraged(true); Main.getLayerManager().addLayer(osmLayer); Main.getLayerManager().removeLayer(layer); } }