Ticket #21813: 21813.patch

File 21813.patch, 18.8 KB (added by Bjoeni, 4 years ago)
  • src/org/openstreetmap/josm/io/session/GpxTracksSessionExporter.java

     
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.io.session;
    33
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.io.IOException;
    47import java.io.OutputStream;
    58import java.io.OutputStreamWriter;
    69import java.io.PrintWriter;
     
    811import java.nio.charset.StandardCharsets;
    912import java.time.Instant;
    1013
     14import javax.swing.JCheckBox;
     15import javax.swing.JPanel;
     16
    1117import org.openstreetmap.josm.gui.layer.GpxLayer;
    1218import org.openstreetmap.josm.io.GpxWriter;
     19import org.openstreetmap.josm.io.session.SessionWriter.ExportSupport;
     20import org.openstreetmap.josm.tools.GBC;
     21import org.w3c.dom.Element;
    1322
    1423/**
    1524 * Session exporter for {@link GpxLayer}.
     
    1827public class GpxTracksSessionExporter extends GenericSessionExporter<GpxLayer> {
    1928
    2029    private Instant metaTime;
     30    private JCheckBox chkMarkers;
     31    private boolean hasMarkerLayer;
    2132
    2233    /**
    2334     * Constructs a new {@code GpxTracksSessionExporter}.
     
    3243        if (layer.data == null) {
    3344            throw new IllegalArgumentException("GPX layer without data: " + layer);
    3445        }
     46
     47        hasMarkerLayer = layer.getLinkedMarkerLayer() != null
     48                && layer.getLinkedMarkerLayer().data != null
     49                && !layer.getLinkedMarkerLayer().data.isEmpty();
     50    }
     51
     52    @Override
     53    public JPanel getExportPanel() {
     54        JPanel p = super.getExportPanel();
     55        if (hasMarkerLayer) {
     56            chkMarkers = new JCheckBox();
     57            chkMarkers.setText(tr("include marker layer \"{0}\"", layer.getLinkedMarkerLayer().getName()));
     58            chkMarkers.setSelected(true);
     59            p.add(chkMarkers, GBC.eol().insets(12, 0, 0, 5));
     60        }
     61        return p;
     62    }
     63
     64    @Override
     65    public Element export(ExportSupport support) throws IOException {
     66        Element el = super.export(support);
     67        if (hasMarkerLayer && (chkMarkers == null || chkMarkers.isSelected())) {
     68            Element markerEl = support.createElement("markerLayer");
     69            markerEl.setAttribute("index", Integer.toString(support.getLayerIndexOf(layer.getLinkedMarkerLayer())));
     70            markerEl.setAttribute("name", layer.getLinkedMarkerLayer().getName());
     71            markerEl.setAttribute("visible", Boolean.toString(layer.getLinkedMarkerLayer().isVisible()));
     72            if (layer.getLinkedMarkerLayer().getOpacity() != 1) {
     73                markerEl.setAttribute("opacity", Double.toString(layer.getLinkedMarkerLayer().getOpacity()));
     74            }
     75            el.appendChild(markerEl);
     76        }
     77        return el;
    3578    }
    3679
    3780    @Override
  • src/org/openstreetmap/josm/io/session/GpxTracksSessionImporter.java

     
    1919import org.openstreetmap.josm.gui.layer.Layer;
    2020import org.openstreetmap.josm.gui.progress.ProgressMonitor;
    2121import org.openstreetmap.josm.io.IllegalDataException;
     22import org.openstreetmap.josm.tools.Logging;
    2223import org.openstreetmap.josm.tools.Utils;
    2324import org.w3c.dom.Element;
     25import org.w3c.dom.Node;
     26import org.w3c.dom.NodeList;
    2427
    2528/**
    2629 * Session exporter for {@link GpxLayer}.
     
    5760                if (importData.getGpxLayer() != null && importData.getGpxLayer().data != null) {
    5861                    importData.getGpxLayer().data.fromSession = true;
    5962                }
     63                NodeList markerNodes = elem.getElementsByTagName("markerLayer");
     64                if (markerNodes.getLength() > 0 && markerNodes.item(0).getNodeType() == Node.ELEMENT_NODE) {
     65                    Element markerEl = (Element) markerNodes.item(0);
     66                    try {
     67                        int index = Integer.parseInt(markerEl.getAttribute("index"));
     68                        support.addSubLayer(index, importData.getMarkerLayer(), markerEl);
     69                    } catch (NumberFormatException ex) {
     70                        Logging.warn(ex);
     71                    }
     72                }
    6073
    6174                support.addPostLayersTask(importData.getPostLayerTask());
    6275                return getLayer(importData);
  • src/org/openstreetmap/josm/io/session/MarkerSessionExporter.java

     
    3434public class MarkerSessionExporter extends AbstractSessionExporter<MarkerLayer> {
    3535
    3636    private Instant metaTime;
     37    private boolean canExport = true;
    3738
    3839    /**
    3940     * Constructs a new {@code MarkerSessionExporter}.
     
    5354
    5455    @Override
    5556    public Component getExportPanel() {
     57        export.setSelected(true); //true even when not shown to the user as the index should be reserved for the corresponding GPX layer
     58        if (layer.fromLayer != null && layer.fromLayer.getData() != null) {
     59            canExport = false;
     60            return null;
     61        }
    5662        final JPanel p = new JPanel(new GridBagLayout());
    57         export.setSelected(true);
    5863        final JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEADING);
    5964        lbl.setToolTipText(layer.getToolTipText());
    6065        lbl.setLabelFor(export);
     
    6671
    6772    @Override
    6873    public boolean requiresZip() {
    69         return true;
     74        return canExport;
    7075    }
    7176
    7277    @Override
    7378    public Element export(ExportSupport support) throws IOException {
     79        if (!canExport) return null;
     80
    7481        Element layerEl = support.createElement("layer");
    7582        layerEl.setAttribute("type", "markers");
    7683        layerEl.setAttribute("version", "0.1");
  • src/org/openstreetmap/josm/io/session/MarkerSessionImporter.java

     
    4848
    4949                support.addPostLayersTask(importData.getPostLayerTask());
    5050
     51                importData.getGpxLayer().destroy();
    5152                return importData.getMarkerLayer();
    5253            }
    5354        } catch (XPathExpressionException e) {
  • src/org/openstreetmap/josm/io/session/SessionReader.java

     
    1414import java.net.URISyntaxException;
    1515import java.nio.charset.StandardCharsets;
    1616import java.nio.file.Files;
     17import java.util.AbstractMap.SimpleEntry;
    1718import java.util.ArrayList;
    1819import java.util.Collection;
    1920import java.util.Collections;
     
    250251        private final String layerName;
    251252        private final int layerIndex;
    252253        private final List<LayerDependency> layerDependencies;
     254        private Map<Integer, Entry<Layer, Element>> subLayers;
    253255
    254256        /**
    255257         * Path of the file inside the zip archive.
     
    279281        }
    280282
    281283        /**
     284         * Add sub layers
     285         * @param idx index
     286         * @param layer sub layer
     287         * @param el The XML element of the sub layer.
     288         *           Should contain "index" and "name" attributes.
     289         *           Can contain "opacity" and "visible" attributes
     290         * @since xxx
     291         */
     292        public void addSubLayer(int idx, Layer layer, Element el) {
     293            if (subLayers == null) {
     294                subLayers = new HashMap<>();
     295            }
     296            subLayers.put(idx, new SimpleEntry<>(layer, el));
     297        }
     298
     299        /**
     300         * Returns the sub layers
     301         * @return the sub layers. Can be null.
     302         * @since xxx
     303         */
     304        public Map<Integer, Entry<Layer, Element>> getSubLayers() {
     305            return subLayers;
     306        }
     307
     308        /**
    282309         * Return an InputStream for a URI from a .jos/.joz file.
    283310         *
    284311         * The following forms are supported:
     
    506533        List<Integer> sorted = Utils.topologicalSort(deps);
    507534        final Map<Integer, Layer> layersMap = new TreeMap<>(Collections.reverseOrder());
    508535        final Map<Integer, SessionLayerImporter> importers = new HashMap<>();
    509         final Map<Integer, String> names = new HashMap<>();
    510536
    511537        progressMonitor.setTicksCount(sorted.size());
    512538        LAYER: for (int idx: sorted) {
     
    519545                return;
    520546            }
    521547            String name = e.getAttribute("name");
    522             names.put(idx, name);
    523548            if (!e.hasAttribute("type")) {
    524549                error(tr("missing mandatory attribute ''type'' for element ''layer''"));
    525550                return;
     
    595620                }
    596621
    597622                layersMap.put(idx, layer);
     623                setLayerAttributes(layer, e);
     624
     625                if (support.getSubLayers() != null) {
     626                    support.getSubLayers().forEach((Integer markerIndex, Entry<Layer, Element> entry) -> {
     627                        Layer subLayer = entry.getKey();
     628                        Element subElement = entry.getValue();
     629
     630                        layersMap.put(markerIndex, subLayer);
     631                        setLayerAttributes(subLayer, subElement);
     632                    });
     633                }
     634
    598635            }
    599636            progressMonitor.worked(1);
    600637        }
    601638
     639
    602640        layers = new ArrayList<>();
    603641        for (Entry<Integer, Layer> entry : layersMap.entrySet()) {
    604642            Layer layer = entry.getValue();
    605             if (layer == null) {
    606                 continue;
    607             }
    608             Element el = elems.get(entry.getKey());
    609             if (el.hasAttribute("visible")) {
    610                 layer.setVisible(Boolean.parseBoolean(el.getAttribute("visible")));
     643            if (layer != null) {
     644                layers.add(layer);
    611645            }
    612             if (el.hasAttribute("opacity")) {
    613                 try {
    614                     double opacity = Double.parseDouble(el.getAttribute("opacity"));
    615                     layer.setOpacity(opacity);
    616                 } catch (NumberFormatException ex) {
    617                     Logging.warn(ex);
    618                 }
     646        }
     647    }
     648
     649    private static void setLayerAttributes(Layer layer, Element e) {
     650        if (layer == null)
     651            return;
     652
     653        if (e.hasAttribute("name")) {
     654            layer.setName(e.getAttribute("name"));
     655        }
     656        if (e.hasAttribute("visible")) {
     657            layer.setVisible(Boolean.parseBoolean(e.getAttribute("visible")));
     658        }
     659        if (e.hasAttribute("opacity")) {
     660            try {
     661                double opacity = Double.parseDouble(e.getAttribute("opacity"));
     662                layer.setOpacity(opacity);
     663            } catch (NumberFormatException ex) {
     664                Logging.warn(ex);
    619665            }
    620             layer.setName(names.get(entry.getKey()));
    621             layers.add(layer);
    622666        }
    623667    }
    624668
  • src/org/openstreetmap/josm/io/session/SessionWriter.java

     
    174174        }
    175175
    176176        /**
     177         * Get the index of the specified layer
     178         * @param layer the layer
     179         * @return the index of the specified layer
     180         * @since xxx
     181         */
     182        public int getLayerIndexOf(Layer layer) {
     183            return layers.indexOf(layer) + 1;
     184        }
     185
     186        /**
    177187         * Create a file inside the zip archive.
    178188         *
    179189         * @param zipPath the path inside the zip archive, e.g. "layers/03/data.xml"
     
    234244            SessionLayerExporter exporter = exporters.get(layer);
    235245            ExportSupport support = new ExportSupport(doc, index+1);
    236246            Element el = exporter.export(support);
     247            if (el == null) continue;
    237248            el.setAttribute("index", Integer.toString(index+1));
    238249            el.setAttribute("name", layer.getName());
    239250            el.setAttribute("visible", Boolean.toString(layer.isVisible()));
  • test/data/sessions/gpx_markers_combined.jos

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<josm-session version="0.1">
     3    <viewport>
     4        <center lat="0.0" lon="0.0"/>
     5        <scale meter-per-pixel="10.000000"/>
     6    </viewport>
     7    <projection>
     8        <projection-choice>
     9            <id>core:mercator</id>
     10            <parameters/>
     11        </projection-choice>
     12        <code>EPSG:3857</code>
     13    </projection>
     14    <layers>
     15        <layer index="1" name="GPX layer name" type="tracks" version="0.1" visible="true">
     16            <file>layers/01/data.gpx</file>
     17            <markerLayer index="2" name="Marker layer name" opacity="0.5" visible="true"/>
     18        </layer>
     19    </layers>
     20</josm-session>
  • test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java

     
    5050/**
    5151 * Unit tests for Session writing.
    5252 */
    53 class SessionWriterTest {
     53public class SessionWriterTest {
    5454
    5555    protected static final class OsmHeadlessJosExporter extends OsmDataSessionExporter {
    5656        public OsmHeadlessJosExporter(OsmDataLayer layer) {
     
    122122        }
    123123        for (final Layer l : layers) {
    124124            SessionLayerExporter s = SessionWriter.getSessionLayerExporter(l);
     125            s.getExportPanel();
    125126            exporters.put(l, s);
    126127            if (s instanceof GpxTracksSessionExporter) {
    127128                ((GpxTracksSessionExporter) s).setMetaTime(Instant.parse("2021-10-16T18:27:12.351Z"));
     
    153154        }
    154155    }
    155156
    156     private OsmDataLayer createOsmLayer() {
     157    /**
     158     * Returns OSM layer
     159     * @return OSM layer
     160     */
     161    public static OsmDataLayer createOsmLayer() {
    157162        OsmDataLayer layer = new OsmDataLayer(new DataSet(), "OSM layer name", null);
    158163        layer.setAssociatedFile(new File("data.osm"));
    159164        return layer;
    160165    }
    161166
    162     private GpxLayer createGpxLayer() {
     167    /**Returns GPX layer
     168     * @return GPX layer
     169     */
     170    public static GpxLayer createGpxLayer() {
    163171        GpxData data = new GpxData();
    164172        WayPoint wp = new WayPoint(new LatLon(42.72665, -0.00747));
    165173        wp.setInstant(Instant.parse("2021-01-01T10:15:30.00Z"));
     
    170178        return layer;
    171179    }
    172180
    173     private MarkerLayer createMarkerLayer(GpxLayer gpx) {
     181    /**
     182     * Returns MarkerLayer
     183     * @param gpx linked GPX layer
     184     * @return MarkerLayer
     185     */
     186    public static MarkerLayer createMarkerLayer(GpxLayer gpx) {
    174187        MarkerLayer layer = new MarkerLayer(gpx.data, "Marker layer name", gpx.getAssociatedFile(), gpx);
    175188        layer.setOpacity(0.5);
    176189        layer.setColor(new Color(0x12345678, true));
     190        gpx.setLinkedMarkerLayer(layer);
    177191        return layer;
    178192    }
    179193
    180     private ImageryLayer createImageryLayer() {
     194    /**
     195     * Returns ImageryLayer
     196     * @return ImageryLayer
     197     */
     198    public static ImageryLayer createImageryLayer() {
    181199        TMSLayer layer = new TMSLayer(new ImageryInfo("the name", "http://www.url.com/"));
    182200        layer.getDisplaySettings().setOffsetBookmark(
    183201                new OffsetBookmark(ProjectionRegistry.getProjection().toCode(), layer.getInfo().getId(), layer.getInfo().getName(), "", 12, 34));
    184202        return layer;
    185203    }
    186204
    187     private NoteLayer createNoteLayer() {
     205    /**
     206     * Returns NoteLayer
     207     * @return NoteLayer
     208     */
     209    public static NoteLayer createNoteLayer() {
    188210        return new NoteLayer(Arrays.asList(new Note(LatLon.ZERO)), "layer name");
    189211    }
    190212
     
    249271    @Test
    250272    void testWriteGpxAndMarkerJoz() throws IOException {
    251273        GpxLayer gpx = createGpxLayer();
    252         Map<String, byte[]> bytes = testWrite(Arrays.asList(gpx, createMarkerLayer(gpx)), true);
     274        MarkerLayer markers = createMarkerLayer(gpx);
     275        Map<String, byte[]> bytes = testWrite(Arrays.asList(gpx, markers), true);
    253276
    254         Path path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers.jos");
     277        Path path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers_combined.jos");
    255278        String expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
    256279        String actual = new String(bytes.get("session.jos"), StandardCharsets.UTF_8).replace("\r", "");
    257280        assertEquals(expected, actual);
     
    261284        actual = new String(bytes.get("layers/01/data.gpx"), StandardCharsets.UTF_8).replace("\r", "");
    262285        assertEquals(expected, actual);
    263286
     287        //Test writing when the marker layer has no corresponding GPX layer:
     288        gpx.setLinkedMarkerLayer(null);
     289        markers.fromLayer = null;
     290        markers.data.transferLayerPrefs(gpx.data.getLayerPrefs());
     291        bytes = testWrite(Arrays.asList(gpx, markers), true);
     292
     293        path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers.jos");
     294        expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
     295        actual = new String(bytes.get("session.jos"), StandardCharsets.UTF_8).replace("\r", "");
     296        assertEquals(expected, actual);
     297
     298        path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/data_export.gpx");
     299        expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
     300        actual = new String(bytes.get("layers/01/data.gpx"), StandardCharsets.UTF_8).replace("\r", "");
     301        assertEquals(expected, actual);
     302
    264303        path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/markers.gpx");
    265304        expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
    266305        actual = new String(bytes.get("layers/02/data.gpx"), StandardCharsets.UTF_8).replace("\r", "");
    267306        assertEquals(expected, actual);
     307
    268308    }
    269309
    270310    /**