Ticket #21813: 21813.patch
| File 21813.patch, 18.8 KB (added by , 4 years ago) |
|---|
-
src/org/openstreetmap/josm/io/session/GpxTracksSessionExporter.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.io.session; 3 3 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 import java.io.IOException; 4 7 import java.io.OutputStream; 5 8 import java.io.OutputStreamWriter; 6 9 import java.io.PrintWriter; … … 8 11 import java.nio.charset.StandardCharsets; 9 12 import java.time.Instant; 10 13 14 import javax.swing.JCheckBox; 15 import javax.swing.JPanel; 16 11 17 import org.openstreetmap.josm.gui.layer.GpxLayer; 12 18 import org.openstreetmap.josm.io.GpxWriter; 19 import org.openstreetmap.josm.io.session.SessionWriter.ExportSupport; 20 import org.openstreetmap.josm.tools.GBC; 21 import org.w3c.dom.Element; 13 22 14 23 /** 15 24 * Session exporter for {@link GpxLayer}. … … 18 27 public class GpxTracksSessionExporter extends GenericSessionExporter<GpxLayer> { 19 28 20 29 private Instant metaTime; 30 private JCheckBox chkMarkers; 31 private boolean hasMarkerLayer; 21 32 22 33 /** 23 34 * Constructs a new {@code GpxTracksSessionExporter}. … … 32 43 if (layer.data == null) { 33 44 throw new IllegalArgumentException("GPX layer without data: " + layer); 34 45 } 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; 35 78 } 36 79 37 80 @Override -
src/org/openstreetmap/josm/io/session/GpxTracksSessionImporter.java
19 19 import org.openstreetmap.josm.gui.layer.Layer; 20 20 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 21 21 import org.openstreetmap.josm.io.IllegalDataException; 22 import org.openstreetmap.josm.tools.Logging; 22 23 import org.openstreetmap.josm.tools.Utils; 23 24 import org.w3c.dom.Element; 25 import org.w3c.dom.Node; 26 import org.w3c.dom.NodeList; 24 27 25 28 /** 26 29 * Session exporter for {@link GpxLayer}. … … 57 60 if (importData.getGpxLayer() != null && importData.getGpxLayer().data != null) { 58 61 importData.getGpxLayer().data.fromSession = true; 59 62 } 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 } 60 73 61 74 support.addPostLayersTask(importData.getPostLayerTask()); 62 75 return getLayer(importData); -
src/org/openstreetmap/josm/io/session/MarkerSessionExporter.java
34 34 public class MarkerSessionExporter extends AbstractSessionExporter<MarkerLayer> { 35 35 36 36 private Instant metaTime; 37 private boolean canExport = true; 37 38 38 39 /** 39 40 * Constructs a new {@code MarkerSessionExporter}. … … 53 54 54 55 @Override 55 56 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 } 56 62 final JPanel p = new JPanel(new GridBagLayout()); 57 export.setSelected(true);58 63 final JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEADING); 59 64 lbl.setToolTipText(layer.getToolTipText()); 60 65 lbl.setLabelFor(export); … … 66 71 67 72 @Override 68 73 public boolean requiresZip() { 69 return true;74 return canExport; 70 75 } 71 76 72 77 @Override 73 78 public Element export(ExportSupport support) throws IOException { 79 if (!canExport) return null; 80 74 81 Element layerEl = support.createElement("layer"); 75 82 layerEl.setAttribute("type", "markers"); 76 83 layerEl.setAttribute("version", "0.1"); -
src/org/openstreetmap/josm/io/session/MarkerSessionImporter.java
48 48 49 49 support.addPostLayersTask(importData.getPostLayerTask()); 50 50 51 importData.getGpxLayer().destroy(); 51 52 return importData.getMarkerLayer(); 52 53 } 53 54 } catch (XPathExpressionException e) { -
src/org/openstreetmap/josm/io/session/SessionReader.java
14 14 import java.net.URISyntaxException; 15 15 import java.nio.charset.StandardCharsets; 16 16 import java.nio.file.Files; 17 import java.util.AbstractMap.SimpleEntry; 17 18 import java.util.ArrayList; 18 19 import java.util.Collection; 19 20 import java.util.Collections; … … 250 251 private final String layerName; 251 252 private final int layerIndex; 252 253 private final List<LayerDependency> layerDependencies; 254 private Map<Integer, Entry<Layer, Element>> subLayers; 253 255 254 256 /** 255 257 * Path of the file inside the zip archive. … … 279 281 } 280 282 281 283 /** 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 /** 282 309 * Return an InputStream for a URI from a .jos/.joz file. 283 310 * 284 311 * The following forms are supported: … … 506 533 List<Integer> sorted = Utils.topologicalSort(deps); 507 534 final Map<Integer, Layer> layersMap = new TreeMap<>(Collections.reverseOrder()); 508 535 final Map<Integer, SessionLayerImporter> importers = new HashMap<>(); 509 final Map<Integer, String> names = new HashMap<>();510 536 511 537 progressMonitor.setTicksCount(sorted.size()); 512 538 LAYER: for (int idx: sorted) { … … 519 545 return; 520 546 } 521 547 String name = e.getAttribute("name"); 522 names.put(idx, name);523 548 if (!e.hasAttribute("type")) { 524 549 error(tr("missing mandatory attribute ''type'' for element ''layer''")); 525 550 return; … … 595 620 } 596 621 597 622 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 598 635 } 599 636 progressMonitor.worked(1); 600 637 } 601 638 639 602 640 layers = new ArrayList<>(); 603 641 for (Entry<Integer, Layer> entry : layersMap.entrySet()) { 604 642 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); 611 645 } 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); 619 665 } 620 layer.setName(names.get(entry.getKey()));621 layers.add(layer);622 666 } 623 667 } 624 668 -
src/org/openstreetmap/josm/io/session/SessionWriter.java
174 174 } 175 175 176 176 /** 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 /** 177 187 * Create a file inside the zip archive. 178 188 * 179 189 * @param zipPath the path inside the zip archive, e.g. "layers/03/data.xml" … … 234 244 SessionLayerExporter exporter = exporters.get(layer); 235 245 ExportSupport support = new ExportSupport(doc, index+1); 236 246 Element el = exporter.export(support); 247 if (el == null) continue; 237 248 el.setAttribute("index", Integer.toString(index+1)); 238 249 el.setAttribute("name", layer.getName()); 239 250 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
50 50 /** 51 51 * Unit tests for Session writing. 52 52 */ 53 class SessionWriterTest {53 public class SessionWriterTest { 54 54 55 55 protected static final class OsmHeadlessJosExporter extends OsmDataSessionExporter { 56 56 public OsmHeadlessJosExporter(OsmDataLayer layer) { … … 122 122 } 123 123 for (final Layer l : layers) { 124 124 SessionLayerExporter s = SessionWriter.getSessionLayerExporter(l); 125 s.getExportPanel(); 125 126 exporters.put(l, s); 126 127 if (s instanceof GpxTracksSessionExporter) { 127 128 ((GpxTracksSessionExporter) s).setMetaTime(Instant.parse("2021-10-16T18:27:12.351Z")); … … 153 154 } 154 155 } 155 156 156 private OsmDataLayer createOsmLayer() { 157 /** 158 * Returns OSM layer 159 * @return OSM layer 160 */ 161 public static OsmDataLayer createOsmLayer() { 157 162 OsmDataLayer layer = new OsmDataLayer(new DataSet(), "OSM layer name", null); 158 163 layer.setAssociatedFile(new File("data.osm")); 159 164 return layer; 160 165 } 161 166 162 private GpxLayer createGpxLayer() { 167 /**Returns GPX layer 168 * @return GPX layer 169 */ 170 public static GpxLayer createGpxLayer() { 163 171 GpxData data = new GpxData(); 164 172 WayPoint wp = new WayPoint(new LatLon(42.72665, -0.00747)); 165 173 wp.setInstant(Instant.parse("2021-01-01T10:15:30.00Z")); … … 170 178 return layer; 171 179 } 172 180 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) { 174 187 MarkerLayer layer = new MarkerLayer(gpx.data, "Marker layer name", gpx.getAssociatedFile(), gpx); 175 188 layer.setOpacity(0.5); 176 189 layer.setColor(new Color(0x12345678, true)); 190 gpx.setLinkedMarkerLayer(layer); 177 191 return layer; 178 192 } 179 193 180 private ImageryLayer createImageryLayer() { 194 /** 195 * Returns ImageryLayer 196 * @return ImageryLayer 197 */ 198 public static ImageryLayer createImageryLayer() { 181 199 TMSLayer layer = new TMSLayer(new ImageryInfo("the name", "http://www.url.com/")); 182 200 layer.getDisplaySettings().setOffsetBookmark( 183 201 new OffsetBookmark(ProjectionRegistry.getProjection().toCode(), layer.getInfo().getId(), layer.getInfo().getName(), "", 12, 34)); 184 202 return layer; 185 203 } 186 204 187 private NoteLayer createNoteLayer() { 205 /** 206 * Returns NoteLayer 207 * @return NoteLayer 208 */ 209 public static NoteLayer createNoteLayer() { 188 210 return new NoteLayer(Arrays.asList(new Note(LatLon.ZERO)), "layer name"); 189 211 } 190 212 … … 249 271 @Test 250 272 void testWriteGpxAndMarkerJoz() throws IOException { 251 273 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); 253 276 254 Path path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers .jos");277 Path path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers_combined.jos"); 255 278 String expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", ""); 256 279 String actual = new String(bytes.get("session.jos"), StandardCharsets.UTF_8).replace("\r", ""); 257 280 assertEquals(expected, actual); … … 261 284 actual = new String(bytes.get("layers/01/data.gpx"), StandardCharsets.UTF_8).replace("\r", ""); 262 285 assertEquals(expected, actual); 263 286 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 264 303 path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/markers.gpx"); 265 304 expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", ""); 266 305 actual = new String(bytes.get("layers/02/data.gpx"), StandardCharsets.UTF_8).replace("\r", ""); 267 306 assertEquals(expected, actual); 307 268 308 } 269 309 270 310 /**
