001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io.session;
003
004import java.awt.Component;
005import java.awt.GridBagLayout;
006import java.io.IOException;
007import java.io.OutputStream;
008import java.io.OutputStreamWriter;
009import java.io.PrintWriter;
010import java.io.Writer;
011import java.nio.charset.StandardCharsets;
012import java.time.Instant;
013import java.util.Collection;
014import java.util.Collections;
015
016import javax.swing.JLabel;
017import javax.swing.JPanel;
018import javax.swing.SwingConstants;
019
020import org.openstreetmap.josm.data.gpx.GpxData;
021import org.openstreetmap.josm.gui.MainApplication;
022import org.openstreetmap.josm.gui.layer.Layer;
023import org.openstreetmap.josm.gui.layer.markerlayer.Marker;
024import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
025import org.openstreetmap.josm.io.GpxWriter;
026import org.openstreetmap.josm.io.session.SessionWriter.ExportSupport;
027import org.openstreetmap.josm.tools.GBC;
028import org.w3c.dom.Element;
029
030/**
031 * Session exporter for {@link MarkerLayer}.
032 * @since 5684
033 */
034public class MarkerSessionExporter extends AbstractSessionExporter<MarkerLayer> {
035
036    private Instant metaTime;
037
038    /**
039     * Constructs a new {@code MarkerSessionExporter}.
040     * @param layer marker layer to export
041     */
042    public MarkerSessionExporter(MarkerLayer layer) { // NO_UCD (unused code)
043        super(layer);
044    }
045
046    @Override
047    public Collection<Layer> getDependencies() {
048        Layer gpxLayer = layer.fromLayer;
049        if (gpxLayer != null && MainApplication.getLayerManager().containsLayer(gpxLayer))
050            return Collections.singleton(gpxLayer);
051        return Collections.emptySet();
052    }
053
054    @Override
055    public Component getExportPanel() {
056        final JPanel p = new JPanel(new GridBagLayout());
057        export.setSelected(true);
058        final JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEADING);
059        lbl.setToolTipText(layer.getToolTipText());
060        lbl.setLabelFor(export);
061        p.add(export, GBC.std());
062        p.add(lbl, GBC.std());
063        p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
064        return p;
065    }
066
067    @Override
068    public boolean requiresZip() {
069        return true;
070    }
071
072    @Override
073    public Element export(ExportSupport support) throws IOException {
074        Element layerEl = support.createElement("layer");
075        layerEl.setAttribute("type", "markers");
076        layerEl.setAttribute("version", "0.1");
077
078        Element file = support.createElement("file");
079        layerEl.appendChild(file);
080
081        String zipPath = "layers/" + String.format("%02d", support.getLayerIndex()) + "/data.gpx";
082        file.appendChild(support.createTextNode(zipPath));
083        addDataFile(support.getOutputStreamZip(zipPath));
084
085        return layerEl;
086    }
087
088    @SuppressWarnings("resource")
089    protected void addDataFile(OutputStream out) {
090        Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
091        MarkerWriter w = new MarkerWriter(new PrintWriter(writer));
092        if (metaTime != null) {
093            w.setMetaTime(metaTime);
094        }
095        w.write(layer);
096        w.flush();
097    }
098
099    protected void setMetaTime(Instant metaTime) {
100        this.metaTime = metaTime;
101    }
102
103    /**
104     * Writes GPX file from marker data.
105     */
106    public static class MarkerWriter extends GpxWriter {
107
108        /**
109         * Constructs a new {@code MarkerWriter}.
110         * @param out The output writer
111         */
112        public MarkerWriter(PrintWriter out) {
113            super(out);
114        }
115
116        /**
117         * Writes the given markers data.
118         * @param layer The layer data to write
119         */
120        public void write(MarkerLayer layer) {
121            GpxData data = new GpxData();
122            layer.data.getLayerPrefs().forEach((k, v) -> {
123                if (k != null && k.indexOf("markers.") == 0) {
124                    data.getLayerPrefs().put(k, v);
125                }
126            });
127            data.put(GpxData.META_DESC, "exported JOSM marker layer");
128            for (Marker m : layer.data) {
129                data.waypoints.add(m.convertToWayPoint());
130            }
131            super.write(data);
132        }
133    }
134}