Ticket #16796: GpxColors-v0.12.diff
File GpxColors-v0.12.diff, 103.8 KB (added by , 5 years ago) |
---|
-
data/gpx-drawing-extensions-1.0.xsd
1 <?xml version="1.0" encoding="UTF-8"?> 2 <schema targetNamespace="https://josm.openstreetmap.de/gpx-drawing-extensions-1.0" 3 elementFormDefault="qualified" 4 xmlns="http://www.w3.org/2001/XMLSchema" 5 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 6 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 7 xmlns:gpxd="https://josm.openstreetmap.de/gpx-drawing-extensions-1.0" 8 xsi:schemaLocation="https://josm.openstreetmap.de/gpx-drawing-extensions-1.0 https://josm.openstreetmap.de/gpx-drawing-extensions-1.0.xsd"> 9 10 <xsd:annotation> 11 <xsd:documentation> 12 This schema defines drawing extensions for the GPX 1.1 schema (http://www.topografix.com/GPX/1/1/gpx.xsd). 13 Elements in this schema should be used as child elements of the "extensions" element defined by the GPX schema. 14 </xsd:documentation> 15 </xsd:annotation> 16 17 <!-- Elements --> 18 19 <xsd:element name="color" type="gpxd:hexColor_type"> 20 <xsd:annotation> 21 <xsd:documentation> 22 The color of the element, i.e. #RRGGBB or #RRGGBBAA. 23 Note that applications should apply possible alpha values to the lines and opacity to the whole track. This means that overlapping parts of the 24 track with alpha values will look more intense than individual lines, whereas the opacity affects the whole track including overlapping parts. 25 </xsd:documentation> 26 </xsd:annotation> 27 </xsd:element> 28 29 <xsd:element name="opacity" type="gpxd:opacity_type"> 30 <xsd:annotation> 31 <xsd:documentation> 32 The opacity of the element between 0.00 and 1.00. 33 </xsd:documentation> 34 </xsd:annotation> 35 </xsd:element> 36 37 <xsd:element name="width" type="xsd:positiveInteger"> 38 <xsd:annotation> 39 <xsd:documentation> 40 The width of the line in pixels, applications may use a width relative to this value if required. 41 </xsd:documentation> 42 </xsd:annotation> 43 </xsd:element> 44 45 <xsd:element name="dashPattern" type="gpxd:dashPattern_type"> 46 <xsd:annotation> 47 <xsd:documentation> 48 The dash pattern of the line, see gpxd:dashPattern_type. Should always be relative to the width. 49 </xsd:documentation> 50 </xsd:annotation> 51 </xsd:element> 52 53 <!-- Types --> 54 55 <xsd:simpleType name="hexColor_type"> 56 <xsd:annotation> 57 <xsd:documentation> 58 The hexColor_type must be a # followed by a 6 or 8-digit hex representation of the color (with or without the alpha value). 59 </xsd:documentation> 60 </xsd:annotation> 61 <xsd:restriction base="xsd:string"> 62 <xsd:pattern value="\#([a-fA-F0-9]{6}|[a-fA-F0-9]{8})" /> 63 <xsd:whiteSpace value="collapse" /> 64 </xsd:restriction> 65 </xsd:simpleType> 66 67 <xsd:simpleType name="opacity_type"> 68 <xsd:annotation> 69 <xsd:documentation> 70 The opacity_type must be a decimal value between 0 and 1. 71 </xsd:documentation> 72 </xsd:annotation> 73 <xsd:restriction base="xsd:decimal"> 74 <xsd:minInclusive value="0" /> 75 <xsd:maxInclusive value="1" /> 76 </xsd:restriction> 77 </xsd:simpleType> 78 79 <xsd:simpleType name="dashPattern_type"> 80 <xsd:annotation> 81 <xsd:documentation> 82 The dashPattern_type can be 83 - a representation of the pattern as y-n-y-n-... with y being the relative length of the line that is 84 visible and n being the relative length of the line that is hidden to create a dashed / dotted line. 85 Has to have an even number of segments (at least two) and can contain multi-digit numbers. 86 - one of the following predefined values: 87 none, dash-long, dash-medium, dash-short, dot-sparse, dot-normal, dot-dense, dash-dot, dash-dot-dot 88 </xsd:documentation> 89 </xsd:annotation> 90 <xsd:restriction base="xsd:string"> <!-- use string based pattern instead of enum because both pattern and enums are allowed --> 91 <xsd:pattern value="\d+\-\d+(\-\d+\-\d+)*" /> <!-- pattern, see documentation above --> 92 <xsd:pattern value="none" /> <!-- 1-0, default value/line --> 93 <xsd:pattern value="dash-long" /> <!-- 6-2 --> 94 <xsd:pattern value="dash-medium" /> <!-- 4-4 --> 95 <xsd:pattern value="dash-short" /> <!-- 2-6 --> 96 <xsd:pattern value="dot-sparse" /> <!-- 1-4 --> 97 <xsd:pattern value="dot-normal" /> <!-- 1-2 --> 98 <xsd:pattern value="dot-dense" /> <!-- 1-1 --> 99 <xsd:pattern value="dash-dot" /> <!-- 4-2-1-2 --> 100 <xsd:pattern value="dash-dot-dot" /><!-- 4-2-1-2-1-2 --> 101 </xsd:restriction> 102 </xsd:simpleType> 103 104 </schema> 105 No newline at end of file -
src/org/openstreetmap/josm/data/gpx/Extensions.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.gpx; 3 3 4 import java.util. LinkedHashMap;4 import java.util.TreeMap; 5 5 6 import org.apache.commons.jcs.access.exception.InvalidArgumentException; 7 6 8 /** 7 * Data class for extensions in a GPX-File.9 * Data class for extensions of a specific type in a GPX-File (keys are case-insensitive). 8 10 */ 9 public class Extensions extends LinkedHashMap<String, String> {11 public final class Extensions extends TreeMap<String, String> { 10 12 11 13 private static final long serialVersionUID = 1L; 14 private String type; 12 15 13 16 /** 14 17 * Constructs a new {@code Extensions}. 18 * @param extensionType type of the extension, can be any <code>GpxConstants.EXTENSIONS_*</code> 15 19 */ 16 public Extensions() { 17 super(); 20 public Extensions(String extensionType) { 21 super(String.CASE_INSENSITIVE_ORDER); 22 if (!extensionType.startsWith(GpxConstants.EXTENSIONS_PREFIX)) 23 throw new InvalidExtensionException(); 24 type = extensionType; 18 25 } 26 27 /** 28 * Returns the prefix for the XML namespace. 29 * @return the prefix including the <code>:</code> 30 */ 31 public String getPrefix() { 32 return type.substring(type.lastIndexOf(".") + 1) + ":"; 33 } 34 35 /** 36 * @return type of the extension 37 */ 38 public String getType() { 39 return type; 40 } 41 42 /** 43 * InvalidExtensionException is thrown if the Extension value does not match the expected format 44 * @see GpxConstants#EXTENSIONS_PREFIX 45 */ 46 public static class InvalidExtensionException extends InvalidArgumentException { 47 /** 48 * Constructs a new {@link InvalidExtensionException} with a default error message 49 */ 50 public InvalidExtensionException() { 51 super("The extensionType must start with the extensions prefix."); 52 } 53 /** 54 * Constructs a new {@link InvalidExtensionException} with the given error message 55 * @param message 56 */ 57 public InvalidExtensionException(String message) { 58 super(message); 59 } 60 } 61 19 62 } -
src/org/openstreetmap/josm/data/gpx/GpxConstants.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.gpx; 3 3 4 import java.awt.Color; 4 5 import java.util.Arrays; 5 6 import java.util.Collection; 6 7 import java.util.Collections; 7 8 import java.util.List; 9 import java.util.Map; 10 import java.util.TreeMap; 8 11 9 12 import org.openstreetmap.josm.data.Bounds; 10 13 import org.openstreetmap.josm.spi.preferences.Config; … … 92 95 * @see GpxData#getMetaBounds() 93 96 */ 94 97 String META_BOUNDS = META_PREFIX + "bounds"; 98 95 99 /** 96 * A constant for the metadata hash map: the extension data. This is a {@link Extensions} object 97 * @see GpxData#addExtension(String, String) 100 * Prefix used for all extension values. 101 * Note that all extension values <b>must</b> end with the according XML namespace prefix (i.e <code>.josm</code> or <code>.gpxd</code>) 102 */ 103 String EXTENSIONS_PREFIX = "extensions."; 104 105 /** 106 * The JOSM extension data (josm:*). This is a {@link Extensions} object 107 * @see GpxData#addExtensionKey(String, String, String) 98 108 * @see GpxData#get(String) 99 109 */ 100 String META_EXTENSIONS = META_PREFIX + "extensions";110 String EXTENSIONS_JOSM = EXTENSIONS_PREFIX + "josm"; 101 111 102 112 /** 103 * A namespace for josm GPX extensions113 * The GPX drawing extension data (gpxd:*). This is a {@link Extensions} object 104 114 */ 105 String JOSM_EXTENSIONS_NAMESPACE_URI = Config.getUrls().getXMLBase() + "/gpx-extensions-1.0";115 String EXTENSIONS_DRAWING = EXTENSIONS_PREFIX + "gpxd"; 106 116 117 /** 118 * The Garmin GPX extension data (gpxx:*). This is a {@link Extensions} object 119 */ 120 String EXTENSIONS_GARMIN = EXTENSIONS_PREFIX + "gpxx"; 121 122 /** 123 * Namespace for JOSM GPX extensions 124 */ 125 String XML_URI_EXTENSIONS_JOSM = Config.getUrls().getXMLBase() + "/gpx-extensions-1.0"; 126 /** 127 * Location of the XSD schema for JOSM GPX extensions 128 */ 129 String XML_XSD_EXTENSIONS_JOSM = Config.getUrls().getXMLBase() + "/gpx-extensions-1.0.xsd"; 130 131 /** 132 * Namespace for GPX drawing extensions 133 */ 134 String XML_URI_EXTENSIONS_DRAWING = Config.getUrls().getXMLBase() + "/gpx-drawing-extensions-1.0"; 135 /** 136 * Location of the XSD schema for GPX drawing extensions 137 */ 138 String XML_XSD_EXTENSIONS_DRAWING = Config.getUrls().getXMLBase() + "/gpx-drawing-extensions-1.0.xsd"; 139 140 /** 141 * Namespace for Garmin GPX extensions 142 */ 143 String XML_URI_EXTENSIONS_GARMIN = "http://www.garmin.com/xmlschemas/GpxExtensions/v3"; 144 /** 145 * Location of the XSD schema for GPX drawing extensions 146 */ 147 String XML_XSD_EXTENSIONS_GARMIN = "http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd"; 148 107 149 /** Elevation (in meters) of the point. */ 108 150 String PT_ELE = "ele"; 109 151 … … 151 193 */ 152 194 List<String> WPT_KEYS = Collections.unmodifiableList(Arrays.asList(PT_ELE, PT_TIME, PT_MAGVAR, PT_GEOIDHEIGHT, 153 195 GPX_NAME, GPX_CMT, GPX_DESC, GPX_SRC, META_LINKS, PT_SYM, PT_TYPE, 154 PT_FIX, PT_SAT, PT_HDOP, PT_VDOP, PT_PDOP, PT_AGEOFDGPSDATA, PT_DGPSID, META_EXTENSIONS)); 196 PT_FIX, PT_SAT, PT_HDOP, PT_VDOP, PT_PDOP, PT_AGEOFDGPSDATA, PT_DGPSID, 197 EXTENSIONS_JOSM, EXTENSIONS_DRAWING, EXTENSIONS_GARMIN)); 155 198 156 199 /** 157 200 * Ordered list of all possible route and track keys. 158 201 */ 159 202 List<String> RTE_TRK_KEYS = Collections.unmodifiableList(Arrays.asList( 160 GPX_NAME, GPX_CMT, GPX_DESC, GPX_SRC, META_LINKS, "number", PT_TYPE, META_EXTENSIONS)); 203 GPX_NAME, GPX_CMT, GPX_DESC, GPX_SRC, META_LINKS, "number", PT_TYPE, 204 EXTENSIONS_JOSM, EXTENSIONS_DRAWING, EXTENSIONS_GARMIN)); 161 205 162 206 /** 207 * Possible extension namespaces 208 */ 209 List<String> SUPPORTED_EXTENSION_NAPMESPACES = Collections.unmodifiableList(Arrays.asList( 210 "josm", "gpxx", "gpxd")); 211 212 /** 213 * Map with all supported Garmin colors 214 */ 215 Map<String, Color> GARMIN_COLORS = Collections.unmodifiableMap( 216 new TreeMap<String, Color>(String.CASE_INSENSITIVE_ORDER) {{ 217 put("Black", Color.BLACK); 218 put("DarkRed", new Color(139, 0, 0)); 219 put("DarkGreen", new Color(0, 100, 0)); 220 put("DarkYellow", new Color(255, 170, 0)); 221 put("DarkBlue", new Color(0, 0, 139)); 222 put("DarkMagenta", new Color(139, 0, 139)); 223 put("DarkCyan", new Color(0, 139, 139)); 224 put("LightGray", Color.LIGHT_GRAY); 225 put("DarkGray", Color.DARK_GRAY); 226 put("Red", Color.RED); 227 put("Green", Color.GREEN); 228 put("Yellow", Color.YELLOW); 229 put("Blue", Color.BLUE); 230 put("Magenta", Color.MAGENTA); 231 put("Cyan", Color.CYAN); 232 put("White", Color.WHITE); 233 put("Transparent", new Color(0, 0, 0, 255)); 234 }}); 235 236 /** 163 237 * Possible fix values. 164 238 */ 165 239 Collection<String> FIX_VALUES = Collections.unmodifiableList(Arrays.asList("none", "2d", "3d", "dgps", "pps")); -
src/org/openstreetmap/josm/data/gpx/GpxData.java
65 65 * Addidionaly waypoints for this file. 66 66 */ 67 67 private final ArrayList<WayPoint> privateWaypoints = new ArrayList<>(); 68 private final GpxTrackChangeListener proxy = e -> fireInvalidate(); 68 private final GpxTrackChangeListener proxy = e -> {fireInvalidate(); modified = true;}; 69 private boolean modified = false; 69 70 70 71 /** 71 72 * Tracks. Access is discouraged, use {@link #getTracks()} to read. … … 881 882 private Line next; 882 883 private final boolean[] trackVisibility; 883 884 private Map<String, Object> trackAttributes; 885 private GpxTrack curTrack; 884 886 885 887 /** 886 888 * Constructs a new {@code LinesIterator}. … … 914 916 private Line getNext() { 915 917 if (itTracks != null) { 916 918 if (itTrackSegments != null && itTrackSegments.hasNext()) { 917 return new Line(itTrackSegments.next(), trackAttributes );919 return new Line(itTrackSegments.next(), trackAttributes, curTrack.getColor()); 918 920 } else { 919 921 while (itTracks.hasNext()) { 920 GpxTrack nxtTrack = itTracks.next();921 trackAttributes = nxtTrack.getAttributes();922 curTrack = itTracks.next(); 923 trackAttributes = curTrack.getAttributes(); 922 924 idxTracks++; 923 925 if (trackVisibility != null && !trackVisibility[idxTracks]) 924 926 continue; 925 itTrackSegments = nxtTrack.getSegments().iterator();927 itTrackSegments = curTrack.getSegments().iterator(); 926 928 if (itTrackSegments.hasNext()) { 927 return new Line(itTrackSegments.next(), trackAttributes );929 return new Line(itTrackSegments.next(), trackAttributes, curTrack.getColor()); 928 930 } 929 931 } 930 932 // if we get here, all the Tracks are finished; Continue with Routes … … 1060 1062 return source; 1061 1063 } 1062 1064 } 1065 1066 /** 1067 * @return whether anything (i.e. colors) have been modified 1068 */ 1069 public boolean isModified() { 1070 return modified; 1071 } 1063 1072 } -
src/org/openstreetmap/josm/data/gpx/GpxTrack.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.gpx; 3 3 4 import java.awt.Color; 4 5 import java.util.Collection; 5 6 import java.util.Map; 6 7 … … 7 8 import org.openstreetmap.josm.data.Bounds; 8 9 9 10 /** 10 * Read-only gpx track. Implementations doesn't have to be immutable, but should always be thread safe.11 * Gpx track. Implementations doesn't have to be immutable, but should always be thread safe. 11 12 * @since 444 12 13 */ 13 14 public interface GpxTrack extends IWithAttributes { … … 37 38 double length(); 38 39 39 40 /** 41 * Gets the color of this track. 42 * @return The color, <code>null</code> if not set or not supported by the implementation. 43 * @since xxx 44 */ 45 default Color getColor() { 46 return null; 47 } 48 49 /** 50 * Sets the color of this track. Not necessarily supported by all implementations. 51 * @param color 52 * @since xxx 53 */ 54 default void setColor(Color color) { 55 return; 56 } 57 58 /** 40 59 * Add a listener that listens to changes in the GPX track. 41 60 * @param l The listener 42 61 */ -
src/org/openstreetmap/josm/data/gpx/IWithAttributes.java
2 2 package org.openstreetmap.josm.data.gpx; 3 3 4 4 import java.util.Collection; 5 import java.util.Map; 5 6 6 7 /** 7 8 * Object with attributes (in the context of GPX data). … … 50 51 void put(String key, Object value); 51 52 52 53 /** 53 * Add a key / value pair that is not part of the GPX schema as an extension .54 * 54 * Add a key / value pair that is not part of the GPX schema as an extension and the extension attribute if not already present. 55 * @param extensionType type of the extension, can be any <code>GpxConstants.EXTENSIONS_*</code> or a string of format <code>"extensions.<i>xmlns_prefix</i>"</code> 55 56 * @param key the key 56 57 * @param value the value 58 * @see GpxConstants#EXTENSIONS_PREFIX 57 59 */ 58 void addExtension (String key, String value);60 void addExtensionKey(String extensionType, String key, String value); 59 61 62 /** 63 * Add key / value pairs that are not part of the GPX schema as extensions. 64 * @param extensionMap the <code>Map<String, String></code> with the key being the qualified name including prefix of the namespace 65 * @see GpxConstants#EXTENSIONS_PREFIX 66 * @see Extensions 67 */ 68 void addExtensions(Map<String, String> extensionMap); 69 70 /** 71 * Removes a key from the extension if present and the extension if empty 72 * @param extensionType type of the extension, can be any <code>GpxConstants.EXTENSIONS_*</code> or a string of format <code>"extensions.<i>xmlns_prefix</i>"</code> 73 * @param key the key, not case-sensitive 74 * @see GpxConstants#EXTENSIONS_PREFIX 75 */ 76 void removeExtensionKey(String extensionType, String key); 77 60 78 } -
src/org/openstreetmap/josm/data/gpx/ImmutableGpxTrack.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.gpx; 3 3 4 import java.awt.Color; 4 5 import java.util.ArrayList; 5 6 import java.util.Collection; 6 7 import java.util.Collections; … … 9 10 import java.util.Map; 10 11 11 12 import org.openstreetmap.josm.data.Bounds; 13 import org.openstreetmap.josm.tools.ListenerList; 14 import org.openstreetmap.josm.tools.Logging; 12 15 13 16 /** 14 17 * Immutable GPX track. 18 * Note that the color attributes are not immutable and may be modified by the user. 15 19 * @since 2907 16 20 */ 17 21 public class ImmutableGpxTrack extends WithAttributes implements GpxTrack { … … 19 23 private final List<GpxTrackSegment> segments; 20 24 private final double length; 21 25 private final Bounds bounds; 26 private Color colorCache; 27 private final ListenerList<GpxTrackChangeListener> listeners = ListenerList.create(); 22 28 23 29 /** 24 * Constructs a new {@code ImmutableGpxTrack} .30 * Constructs a new {@code ImmutableGpxTrack} and adds the extensions. 25 31 * @param trackSegs track segments 26 32 * @param attributes track attributes 33 * @param extensionMap map of extensions 27 34 */ 28 public ImmutableGpxTrack(Collection<Collection<WayPoint>> trackSegs, Map<String, Object> attributes ) {35 public ImmutableGpxTrack(Collection<Collection<WayPoint>> trackSegs, Map<String, Object> attributes, Map<String, String> extensionMap) { 29 36 List<GpxTrackSegment> newSegments = new ArrayList<>(); 30 37 for (Collection<WayPoint> trackSeg: trackSegs) { 31 38 if (trackSeg != null && !trackSeg.isEmpty()) { … … 32 39 newSegments.add(new ImmutableGpxTrackSegment(trackSeg)); 33 40 } 34 41 } 35 this.attr = Collections.unmodifiableMap(new HashMap<>(attributes)); 42 this.attr = new HashMap<>(attributes); 43 if (extensionMap != null) { 44 addExtensions(extensionMap); 45 } 36 46 this.segments = Collections.unmodifiableList(newSegments); 37 47 this.length = calculateLength(); 38 48 this.bounds = calculateBounds(); … … 39 49 } 40 50 41 51 /** 52 * Constructs a new {@code ImmutableGpxTrack}. 53 * @param trackSegs track segments 54 * @param attributes track attributes 55 */ 56 public ImmutableGpxTrack(Collection<Collection<WayPoint>> trackSegs, Map<String, Object> attributes) { 57 this(trackSegs, attributes, null); 58 } 59 60 /** 42 61 * Constructs a new {@code ImmutableGpxTrack} from {@code GpxTrackSegment} objects. 43 62 * @param segments The segments to build the track from. Input is not deep-copied, 44 63 * which means the caller may reuse the same segments to build … … 48 67 * @since 13210 49 68 */ 50 69 public ImmutableGpxTrack(List<GpxTrackSegment> segments, Map<String, Object> attributes) { 51 this.attr = Collections.unmodifiableMap(new HashMap<>(attributes));70 this.attr = new HashMap<>(attributes); 52 71 this.segments = Collections.unmodifiableList(segments); 53 72 this.length = calculateLength(); 54 73 this.bounds = calculateBounds(); … … 79 98 } 80 99 81 100 @Override 101 public void setColor(Color color) { 102 setColorAttr(color); 103 colorCache = color; 104 } 105 106 private void setColorAttr(Color color) { 107 removeExtensionKey(GpxConstants.EXTENSIONS_GARMIN, "displaycolor"); 108 if (color != null) { 109 addExtensionKey(EXTENSIONS_DRAWING, "color", String.format("#%02X%02X%02X", color.getRed(), color.getGreen(), color.getBlue())); 110 } else { 111 removeExtensionKey(EXTENSIONS_DRAWING, "color"); 112 } 113 } 114 115 @Override 116 public Color getColor() { 117 if (colorCache == null) { 118 colorCache = getColorFromAttr(attr); 119 } 120 return colorCache; 121 } 122 123 124 private Color getColorFromAttr(Map<String, Object> attr) { 125 Extensions gpxd = (Extensions) attr.get(GpxConstants.EXTENSIONS_DRAWING); 126 if (gpxd != null) { 127 String cs = gpxd.get("color"); 128 try { 129 return Color.decode(cs); 130 } catch (NumberFormatException ex) { 131 Logging.warn("Could not read gpxd color: " + cs); 132 } 133 } else { 134 Extensions gpxx = (Extensions) attr.get(GpxConstants.EXTENSIONS_GARMIN); 135 if (gpxx != null) { 136 String cs = gpxx.get("displaycolor"); 137 if (cs != null) { 138 Color cc = GpxConstants.GARMIN_COLORS.get(cs); 139 if (cc != null) { 140 return cc; 141 } 142 } 143 Logging.warn("Could not read garmin color: " + cs); 144 } 145 } 146 return null; 147 } 148 149 @Override 150 public void addExtensionKey(String extensionType, String key, String value) { 151 colorCache = null; 152 super.addExtensionKey(extensionType, key, value); 153 listeners.fireEvent(l -> l.gpxDataChanged(new GpxTrackChangeEvent(this))); 154 } 155 156 @Override 157 public void removeExtensionKey(String extensionType, String key) { 158 colorCache = null; 159 super.removeExtensionKey(extensionType, key); 160 listeners.fireEvent(l -> l.gpxDataChanged(new GpxTrackChangeEvent(this))); 161 } 162 163 @Override 82 164 public Map<String, Object> getAttributes() { 83 165 return attr; 84 166 } … … 119 201 return false; 120 202 return true; 121 203 } 204 205 @Override 206 public void addListener(GpxTrackChangeListener l) { 207 listeners.addListener(l); 208 } 209 210 @Override 211 public void removeListener(GpxTrackChangeListener l) { 212 listeners.removeListener(l); 213 } 214 122 215 } -
src/org/openstreetmap/josm/data/gpx/Line.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.gpx; 3 3 4 import java.awt.Color; 4 5 import java.util.Collection; 5 6 import java.util.Iterator; 6 7 import java.util.Map; … … 13 14 public class Line implements Collection<WayPoint> { 14 15 private final Collection<WayPoint> waypoints; 15 16 private final boolean unordered; 17 private final Color color; 16 18 17 19 /** 18 20 * Constructs a new {@code Line}. 19 21 * @param waypoints collection of waypoints 20 22 * @param attributes track/route attributes 23 * @param color color of the track 24 * 21 25 */ 22 public Line(Collection<WayPoint> waypoints, Map<String, Object> attributes) { 26 public Line(Collection<WayPoint> waypoints, Map<String, Object> attributes, Color color) { 27 this.color = color; 23 28 this.waypoints = Objects.requireNonNull(waypoints); 24 29 unordered = attributes.isEmpty() && waypoints.stream().allMatch(x -> x.get(GpxConstants.PT_TIME) == null); 25 30 } … … 29 34 * @param trackSegment track segment 30 35 * @param trackAttributes track attributes 31 36 */ 32 public Line(GpxTrackSegment trackSegment, Map<String, Object> trackAttributes ) {33 this(trackSegment.getWayPoints(), trackAttributes );37 public Line(GpxTrackSegment trackSegment, Map<String, Object> trackAttributes, Color color) { 38 this(trackSegment.getWayPoints(), trackAttributes, color); 34 39 } 35 40 36 41 /** … … 38 43 * @param route route 39 44 */ 40 45 public Line(GpxRoute route) { 41 this(route.routePoints, route.attr );46 this(route.routePoints, route.attr, null); 42 47 } 43 48 44 49 /** … … 49 54 return unordered; 50 55 } 51 56 57 /** 58 * Returns the track/route color 59 * @return the color 60 */ 61 public Color getColor() { 62 return color; 63 } 64 52 65 @Override 53 66 public int size() { 54 67 return waypoints.size(); -
src/org/openstreetmap/josm/data/gpx/WithAttributes.java
4 4 import java.util.Collection; 5 5 import java.util.HashMap; 6 6 import java.util.Map; 7 import java.util.Map.Entry; 7 8 8 9 /** 9 10 * Default implementation for IWithAttributes. … … 64 65 65 66 /** 66 67 * Put a key / value pair as a new attribute. 67 *68 68 * Overrides key / value pair with the same key (if present). 69 69 * 70 70 * @param key the key … … 75 75 attr.put(key, value); 76 76 } 77 77 78 /**79 * Add a key / value pair that is not part of the GPX schema as an extension.80 *81 * @param key the key82 * @param value the value83 */84 78 @Override 85 public void addExtension(String key, String value) { 86 if (!attr.containsKey(META_EXTENSIONS)) { 87 attr.put(META_EXTENSIONS, new Extensions()); 79 public void addExtensionKey(String extensionType, String key, String value) { 80 Extensions ext; 81 if (!attr.containsKey(extensionType)) { 82 ext = new Extensions(extensionType); 83 attr.put(extensionType, ext); 84 } else { 85 ext = (Extensions) attr.get(extensionType); 88 86 } 89 Extensions ext = (Extensions) attr.get(META_EXTENSIONS);90 87 ext.put(key, value); 91 88 } 92 89 93 90 @Override 91 public void addExtensions(Map<String, String> extensionMap) { 92 for (Entry<String, String> e : extensionMap.entrySet()) { 93 String k = e.getKey(); 94 int dot = k.indexOf(":"); 95 if (dot != -1) { 96 addExtensionKey(GpxConstants.EXTENSIONS_PREFIX + k.substring(0, dot), k.substring(dot + 1), e.getValue()); 97 } 98 } 99 } 100 101 @Override 102 public void removeExtensionKey(String extensionType, String key) { 103 Extensions ext = (Extensions) attr.get(extensionType); 104 if (ext != null) { 105 ext.remove(key); 106 if (ext.isEmpty()) { 107 attr.remove(extensionType); 108 } 109 } 110 } 111 112 @Override 94 113 public int hashCode() { 95 114 return 31 + ((attr == null) ? 0 : attr.hashCode()); 96 115 } … … 111 130 return false; 112 131 return true; 113 132 } 133 114 134 } -
src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
18 18 import java.util.Arrays; 19 19 import java.util.Collections; 20 20 import java.util.List; 21 import java.util.Objects;22 21 import java.util.concurrent.CopyOnWriteArrayList; 23 22 24 23 import javax.swing.AbstractAction; … … 44 43 import org.openstreetmap.josm.actions.MergeLayerAction; 45 44 import org.openstreetmap.josm.data.coor.EastNorth; 46 45 import org.openstreetmap.josm.data.imagery.OffsetBookmark; 47 import org.openstreetmap.josm.data.preferences.AbstractProperty;48 46 import org.openstreetmap.josm.gui.MainApplication; 49 47 import org.openstreetmap.josm.gui.MapFrame; 50 48 import org.openstreetmap.josm.gui.MapView; … … 601 599 label.setFont(label.getFont().deriveFont(Font.BOLD)); 602 600 } 603 601 if (Config.getPref().getBoolean("dialog.layer.colorname", true)) { 604 AbstractProperty<Color> prop = layer.getColorProperty(); 605 Color c = prop == null ? null : prop.get(); 606 if (c == null || model.getLayers().stream() 607 .map(Layer::getColorProperty) 608 .filter(Objects::nonNull) 609 .map(AbstractProperty::get) 610 .noneMatch(oc -> oc != null && !oc.equals(c))) { 611 /* not more than one color, don't use coloring */ 602 Color c = layer.getColor(); 603 if (c != null) { 604 label.setForeground(c); 605 } else { 612 606 label.setForeground(UIManager.getColor(isSelected ? "Table.selectionForeground" : "Table.foreground")); 613 } else {614 label.setForeground(c);615 607 } 616 608 } 617 609 label.setIcon(layer.getIcon()); -
src/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityAction.java
593 593 List<Layer> layers = layerSupplier.get(); 594 594 for (Layer l : layers) { 595 595 if (l instanceof GpxLayer) { 596 l. getColorProperty().put(color);596 l.setColor(color); 597 597 } 598 598 } 599 599 highlightColor(color); … … 602 602 add(colorPanel, GBC.std().weight(1, 1).fill().insets(5)); 603 603 panels.put(color, colorPanel); 604 604 605 List<Color> colors = layerSupplier.get().stream().map(l -> l.getColor Property().get()).distinct().collect(Collectors.toList());605 List<Color> colors = layerSupplier.get().stream().map(l -> l.getColor()).distinct().collect(Collectors.toList()); 606 606 if (colors.size() == 1) { 607 607 highlightColor(colors.get(0)); 608 608 } … … 611 611 @Override 612 612 public void updateLayers(List<Layer> layers, boolean allVisible, boolean allHidden) { 613 613 List<Color> colors = layers.stream().filter(l -> l instanceof GpxLayer) 614 .map(l -> ((GpxLayer) l).getColor Property().get())614 .map(l -> ((GpxLayer) l).getColor()) 615 615 .distinct() 616 616 .collect(Collectors.toList()); 617 617 if (colors.size() == 1) { -
src/org/openstreetmap/josm/gui/io/importexport/GpxExporter.java
26 26 27 27 import org.openstreetmap.josm.data.gpx.GpxConstants; 28 28 import org.openstreetmap.josm.data.gpx.GpxData; 29 import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil; 29 30 import org.openstreetmap.josm.gui.ExtendedDialog; 30 31 import org.openstreetmap.josm.gui.MainApplication; 31 32 import org.openstreetmap.josm.gui.layer.GpxLayer; … … 148 149 p.add(new JLabel(tr("Keywords")), GBC.eol()); 149 150 JosmTextField keywords = new JosmTextField(); 150 151 keywords.setText(gpxData.getString(META_KEYWORDS)); 151 p.add(keywords, GBC.eo p().fill(GBC.HORIZONTAL));152 p.add(keywords, GBC.eol().fill(GBC.HORIZONTAL)); 152 153 154 boolean sel = Config.getPref().getBoolean("gpx.export.colors", true); 155 JCheckBox colors = new JCheckBox(tr("Save track colors in GPX file"), sel); 156 p.add(colors, GBC.eol().fill(GBC.HORIZONTAL)); 157 JCheckBox garmin = new JCheckBox(tr("Use Garmin compatible GPX extensions"), 158 Config.getPref().getBoolean("gpx.export.colors.garmin", false)); 159 garmin.setEnabled(sel); 160 p.add(garmin, GBC.eop().fill(GBC.HORIZONTAL).insets(20, 0, 0, 0)); 161 162 153 163 ExtendedDialog ed = new ExtendedDialog(MainApplication.getMainFrame(), 154 164 tr("Export options"), 155 165 tr("Export and Save"), tr("Cancel")) … … 156 166 .setButtonIcons("exportgpx", "cancel") 157 167 .setContent(p); 158 168 169 colors.addActionListener(l -> { 170 garmin.setEnabled(colors.isSelected()); 171 }); 172 173 garmin.addActionListener(l -> { 174 if (garmin.isSelected() && 175 !ConditionalOptionPaneUtil.showConfirmationDialog( 176 "gpx_color_garmin", 177 ed, 178 new JLabel(tr("<html>Garmin track extensions only support 16 colors. If you continue, the closest supported<br>track color will be used and information such as width and opacity will be lost.</html>")), 179 tr("Information"), 180 JOptionPane.OK_CANCEL_OPTION, 181 JOptionPane.INFORMATION_MESSAGE, 182 JOptionPane.OK_OPTION)) { 183 garmin.setSelected(false); 184 } 185 }); 186 159 187 if (ed.showDialog().getValue() != 1) { 160 188 setCanceled(true); 161 189 return; … … 169 197 if (!copyright.getText().isEmpty()) { 170 198 Config.getPref().put("lastCopyright", copyright.getText()); 171 199 } 200 Config.getPref().putBoolean("gpx.export.colors", colors.isSelected()); 201 Config.getPref().putBoolean("gpx.export.colors.garmin", garmin.isSelected()); 202 String colorFormat = null; 203 if (colors.isSelected()) { 204 colorFormat = garmin.isSelected() 205 ? GpxConstants.EXTENSIONS_GARMIN 206 : GpxConstants.EXTENSIONS_DRAWING; 207 } 172 208 173 209 if (layer instanceof OsmDataLayer) { 174 210 gpxData = ((OsmDataLayer) layer).toGpxData(); … … 206 242 } 207 243 208 244 try (OutputStream fo = Compression.getCompressedFileOutputStream(file)) { 209 new GpxWriter(fo).write(gpxData); 245 GpxWriter w = new GpxWriter(fo); 246 w.write(gpxData, colorFormat); 247 w.close(); 210 248 fo.flush(); 211 249 } catch (IOException | InvalidPathException ex) { 212 250 Logging.error(ex); -
src/org/openstreetmap/josm/gui/layer/CustomizeColor.java
18 18 import javax.swing.JMenuItem; 19 19 import javax.swing.JOptionPane; 20 20 21 import org.openstreetmap.josm.data.preferences.AbstractProperty;22 21 import org.openstreetmap.josm.gui.MainApplication; 23 22 import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 24 23 import org.openstreetmap.josm.gui.layer.Layer.LayerAction; 25 24 import org.openstreetmap.josm.gui.layer.Layer.MultiLayerAction; 26 import org.openstreetmap.josm.tools.CheckParameterUtil;27 25 import org.openstreetmap.josm.tools.ImageProvider; 28 26 29 27 /** … … 33 31 * of a certain {@link GpxLayer} or {@link org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer}. 34 32 */ 35 33 public class CustomizeColor extends AbstractAction implements LayerAction, MultiLayerAction { 36 private final transient List< AbstractProperty<Color>> colors;34 private final transient List<Layer> colorLayers; 37 35 38 36 /** 39 37 * Constructs a new {@code CustomizeColor} for a given list of layers. … … 42 40 public CustomizeColor(List<Layer> l) { 43 41 super(tr("Customize Color")); 44 42 new ImageProvider("colorchooser").getResource().attachImageIcon(this, true); 45 colors = l.stream().map(Layer::getColorProperty).collect(Collectors.toList()); 46 CheckParameterUtil.ensureThat(colors.stream().allMatch(Objects::nonNull), "All layers must have colors."); 43 colorLayers = l.stream().filter(Objects::nonNull).filter(Layer::hasColor).collect(Collectors.toList()); 47 44 putValue("help", ht("/Action/LayerCustomizeColor")); 48 45 } 49 46 … … 57 54 58 55 @Override 59 56 public boolean supportLayers(List<Layer> layers) { 60 return layers.stream().allMatch(l -> l. getColorProperty() != null);57 return layers.stream().allMatch(l -> l.hasColor()); 61 58 } 62 59 63 60 @Override … … 72 69 73 70 @Override 74 71 public void actionPerformed(ActionEvent e) { 75 Color cl = color s.stream().map(AbstractProperty::get).filter(Objects::nonNull).findAny().orElse(Color.GRAY);72 Color cl = colorLayers.stream().filter(Objects::nonNull).map(Layer::getColor).filter(Objects::nonNull).findAny().orElse(Color.GRAY); 76 73 JColorChooser c = new JColorChooser(cl); 77 74 Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")}; 78 75 int answer = JOptionPane.showOptionDialog( … … 87 84 ); 88 85 switch (answer) { 89 86 case 0: 90 color s.stream().forEach(prop -> prop.put(c.getColor()));87 colorLayers.stream().forEach(l -> l.setColor(c.getColor())); 91 88 break; 92 89 case 1: 93 90 return; 94 91 case 2: 95 color s.stream().forEach(prop -> prop.put(null));92 colorLayers.stream().forEach(l -> l.setColor(null)); 96 93 break; 97 94 } 98 95 // TODO: Make the layer dialog listen to property change events so that this is not needed any more. -
src/org/openstreetmap/josm/gui/layer/GpxLayer.java
4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 import static org.openstreetmap.josm.tools.I18n.trn; 6 6 7 import java.awt.Color; 7 8 import java.awt.Dimension; 8 9 import java.awt.Graphics2D; 9 10 import java.awt.event.ActionEvent; … … 31 32 import org.openstreetmap.josm.data.gpx.GpxData.GpxDataChangeListener; 32 33 import org.openstreetmap.josm.data.gpx.GpxTrack; 33 34 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; 34 import org.openstreetmap.josm.data.preferences.NamedColorProperty;35 35 import org.openstreetmap.josm.data.projection.Projection; 36 36 import org.openstreetmap.josm.gui.MapView; 37 37 import org.openstreetmap.josm.gui.dialogs.LayerListDialog; … … 53 53 /** 54 54 * A layer that displays data from a Gpx file / the OSM gpx downloads. 55 55 */ 56 public class GpxLayer extends Layer implements ExpertModeChangeListener {56 public class GpxLayer extends AbstractModifiableLayer implements ExpertModeChangeListener { 57 57 58 58 /** GPX data */ 59 59 public GpxData data; … … 107 107 } 108 108 109 109 @Override 110 protected NamedColorProperty getBaseColorProperty() { 111 return GpxDrawHelper.DEFAULT_COLOR; 110 public Color getColor() { 111 Color[] c = data.getTracks().stream().map(t -> t.getColor()).distinct().toArray(Color[]::new); 112 return c.length == 1 ? c[0] : null; //only return if exactly one distinct color present 112 113 } 113 114 115 @Override 116 public void setColor(Color color) { 117 for (GpxTrack trk : data.getTracks()) { 118 trk.setColor(color); 119 } 120 } 121 122 @Override 123 public boolean hasColor() { 124 return true; 125 } 126 114 127 /** 115 128 * Returns a human readable string that shows the timespan of the given track 116 129 * @param trk The GPX track for which timespan is displayed … … 473 486 public void expertChanged(boolean isExpert) { 474 487 this.isExpertMode = isExpert; 475 488 } 489 490 @Override 491 public boolean isModified() { 492 return data.isModified(); 493 } 494 495 @Override 496 public boolean requiresSaveToFile() { 497 return isModified() && isLocalFile(); 498 } 476 499 } -
src/org/openstreetmap/josm/gui/layer/Layer.java
25 25 import org.openstreetmap.josm.actions.SaveAsAction; 26 26 import org.openstreetmap.josm.data.ProjectionBounds; 27 27 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; 28 import org.openstreetmap.josm.data.preferences.AbstractProperty;29 import org.openstreetmap.josm.data.preferences.AbstractProperty.ValueChangeListener;30 import org.openstreetmap.josm.data.preferences.NamedColorProperty;31 28 import org.openstreetmap.josm.data.projection.Projection; 32 29 import org.openstreetmap.josm.data.projection.ProjectionChangeListener; 33 30 import org.openstreetmap.josm.gui.MainApplication; … … 164 161 */ 165 162 private File associatedFile; 166 163 167 private final ValueChangeListener<Object> invalidateListener = change -> invalidate();168 164 private boolean isDestroyed; 169 165 170 166 /** … … 198 194 public abstract Icon getIcon(); 199 195 200 196 /** 201 * Gets the color property to use for this layer. 202 * @return The color property. 203 * @since 10824 197 * @return whether the layer has / can handle colors. 204 198 */ 205 public AbstractProperty<Color> getColorProperty() { 206 NamedColorProperty base = getBaseColorProperty(); 207 if (base != null) { 208 return base.getChildColor(NamedColorProperty.COLOR_CATEGORY_LAYER, getName(), base.getName()); 209 } else { 210 return null; 211 } 199 public boolean hasColor() { 200 return false; 212 201 } 213 202 214 203 /** 215 * Gets the color property that stores the default color for this layer. 216 * @return The property or <code>null</code> if this layer is not colored. 217 * @since 10824 204 * Return the current color of the layer 205 * @return null when not present or not supported 218 206 */ 219 p rotected NamedColorProperty getBaseColorProperty() {207 public Color getColor() { 220 208 return null; 221 209 } 222 210 223 private void addColorPropertyListener() {224 AbstractProperty<Color> colorProperty = getColorProperty();225 if (colorProperty != null) {226 colorProperty.addListener(invalidateListener);227 }211 /** 212 * Sets the color for this layer. Nothing happens if not supported by the layer 213 * @param color the color to be set 214 */ 215 public void setColor(Color color) { 228 216 } 229 217 230 private void removeColorPropertyListener() {231 AbstractProperty<Color> colorProperty = getColorProperty();232 if (colorProperty != null) {233 colorProperty.removeListener(invalidateListener);234 }235 }236 237 218 /** 238 219 * @return A small tooltip hint about some statistics for this layer. 239 220 */ … … 302 283 } 303 284 isDestroyed = true; 304 285 // Override in subclasses if needed 305 removeColorPropertyListener();306 286 } 307 287 308 288 /** … … 339 319 * @param name the name. If null, the name is set to the empty string. 340 320 */ 341 321 public void setName(String name) { 342 if (this.name != null) {343 removeColorPropertyListener();344 }345 322 String oldValue = this.name; 346 323 this.name = Optional.ofNullable(name).orElse(""); 347 324 if (!this.name.equals(oldValue)) { 348 325 propertyChangeSupport.firePropertyChange(NAME_PROP, oldValue, this.name); 349 326 } 350 351 // re-add listener352 addColorPropertyListener();353 327 invalidate(); 354 328 } 355 329 -
src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
31 31 import java.util.LinkedHashMap; 32 32 import java.util.List; 33 33 import java.util.Map; 34 import java.util.Map.Entry; 34 35 import java.util.Set; 35 36 import java.util.concurrent.CopyOnWriteArrayList; 36 37 import java.util.concurrent.atomic.AtomicBoolean; … … 747 748 } 748 749 Collection<Collection<WayPoint>> trk = new ArrayList<>(); 749 750 Map<String, Object> trkAttr = new HashMap<>(); 750 751 String name = w.get("name"); 752 if (name != null) { 753 trkAttr.put("name", name); 751 Map<String, String> trkExts = new HashMap<>(); 752 for (Entry<String, String> e : w.getKeys().entrySet()) { 753 String k = e.getKey(); 754 String v = e.getValue(); 755 if (GpxConstants.RTE_TRK_KEYS.contains(e.getKey())) { 756 trkAttr.put(k, v); 757 } else if (GpxConstants.SUPPORTED_EXTENSION_NAPMESPACES.stream().anyMatch( 758 s -> k.startsWith(s + ":"))) { 759 trkExts.put(k, v); 760 } 754 761 } 755 762 756 763 List<WayPoint> trkseg = null; … … 769 776 trkseg.add(nodeToWayPoint(n)); 770 777 } 771 778 772 gpxData.addTrack(new ImmutableGpxTrack(trk, trkAttr ));779 gpxData.addTrack(new ImmutableGpxTrack(trk, trkAttr, trkExts)); 773 780 }); 774 781 } 775 782 -
src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java
4 4 import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 5 5 import static org.openstreetmap.josm.tools.I18n.tr; 6 6 7 import java.awt.Color; 7 8 import java.awt.Component; 8 9 import java.awt.Dimension; 9 10 import java.awt.GridBagLayout; … … 12 13 import java.awt.event.MouseEvent; 13 14 import java.awt.event.MouseListener; 14 15 import java.io.Serializable; 16 import java.util.ArrayList; 15 17 import java.util.Arrays; 16 18 import java.util.Comparator; 19 import java.util.List; 17 20 import java.util.Map; 21 import java.util.Objects; 18 22 import java.util.Optional; 19 23 20 24 import javax.swing.AbstractAction; 25 import javax.swing.JColorChooser; 21 26 import javax.swing.JComponent; 22 27 import javax.swing.JLabel; 28 import javax.swing.JOptionPane; 23 29 import javax.swing.JPanel; 24 30 import javax.swing.JScrollPane; 25 31 import javax.swing.JTable; 26 32 import javax.swing.JToggleButton; 27 33 import javax.swing.ListSelectionModel; 34 import javax.swing.event.TableModelEvent; 28 35 import javax.swing.table.DefaultTableModel; 29 36 import javax.swing.table.TableCellRenderer; 30 37 import javax.swing.table.TableRowSorter; 31 38 39 import org.apache.commons.jcs.access.exception.InvalidArgumentException; 32 40 import org.openstreetmap.josm.data.SystemOfMeasurement; 33 41 import org.openstreetmap.josm.data.gpx.GpxConstants; 34 42 import org.openstreetmap.josm.data.gpx.GpxTrack; … … 55 63 * @param layer The associated GPX layer 56 64 */ 57 65 public ChooseTrackVisibilityAction(final GpxLayer layer) { 58 super(tr("Choose visible tracks"));66 super(tr("Choose track visibility and colors")); 59 67 new ImageProvider("dialogs/filter").getResource().attachImageIcon(this, true); 60 68 this.layer = layer; 61 69 putValue("help", ht("/Action/ChooseTrackVisibility")); … … 116 124 String time = GpxLayer.getTimespanForTrack(trk); 117 125 TrackLength length = new TrackLength(trk.length()); 118 126 String url = (String) Optional.ofNullable(attr.get("url")).orElse(""); 119 tracks[i] = new Object[]{name, desc, time, length, url };127 tracks[i] = new Object[]{name, desc, time, length, url, trk}; 120 128 i++; 121 129 } 122 130 return tracks; 123 131 } 124 132 133 private void showColorDialog(List<GpxTrack> tracks) { 134 Color cl = tracks.stream().filter(Objects::nonNull) 135 .map(GpxTrack::getColor).filter(Objects::nonNull) 136 .findAny().orElse(GpxDrawHelper.DEFAULT_COLOR_PROPERTY.get()); 137 JColorChooser c = new JColorChooser(cl); 138 Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")}; 139 int answer = JOptionPane.showOptionDialog( 140 MainApplication.getMainFrame(), 141 c, 142 tr("Choose a color"), 143 JOptionPane.OK_CANCEL_OPTION, 144 JOptionPane.PLAIN_MESSAGE, 145 null, 146 options, 147 options[0] 148 ); 149 switch (answer) { 150 case 0: 151 tracks.stream().forEach(t -> t.setColor(c.getColor())); 152 break; 153 case 1: 154 return; 155 case 2: 156 tracks.stream().forEach(t -> t.setColor(null)); 157 break; 158 } 159 table.repaint(); 160 } 161 125 162 /** 126 163 * Builds an non-editable table whose 5th column will open a browser when double clicked. 127 164 * The table will fill its parent. … … 138 175 if (c instanceof JComponent) { 139 176 JComponent jc = (JComponent) c; 140 177 jc.setToolTipText(getValueAt(row, col).toString()); 178 if (content.length > row 179 && content[row].length > 5 180 && content[row][5] instanceof GpxTrack) { 181 Color color = ((GpxTrack) content[row][5]).getColor(); 182 if (color != null) { 183 double brightness = Math.sqrt(Math.pow(color.getRed(), 2) * .241 184 + Math.pow(color.getGreen(), 2) * .691 185 + Math.pow(color.getBlue(), 2) * .068); 186 if (brightness > 250) { 187 color = color.darker(); 188 } 189 if (isRowSelected(row)) { 190 jc.setBackground(color); 191 if (brightness <= 130) { 192 jc.setForeground(Color.WHITE); 193 } else { 194 jc.setForeground(Color.BLACK); 195 } 196 } else { 197 if (brightness > 200) { 198 color = color.darker(); //brightness >250 is darkened twice on purpose 199 } 200 jc.setForeground(color); 201 jc.setBackground(Color.WHITE); 202 } 203 } 204 } 141 205 } 142 206 return c; 143 207 } … … 144 208 145 209 @Override 146 210 public boolean isCellEditable(int rowIndex, int colIndex) { 147 return false;211 return colIndex <= 1; 148 212 } 213 214 @Override 215 public void tableChanged(TableModelEvent e) { 216 super.tableChanged(e); 217 int col = e.getColumn(); 218 int row = e.getFirstRow(); 219 if (row >= 0 && row < content.length && col >= 0 && col <= 1) { 220 Object t = content[row][5]; 221 String val = (String) getValueAt(row, col); 222 if (t != null && t instanceof GpxTrack) { 223 GpxTrack trk = (GpxTrack) t; 224 if (col == 0) { 225 trk.put("name", val); 226 } else { 227 trk.put("desc", val); 228 } 229 } else { 230 throw new InvalidArgumentException(); 231 } 232 } 233 } 149 234 }; 150 235 // define how to sort row 151 236 TableRowSorter<DefaultTableModel> rowSorter = new TableRowSorter<>(); … … 249 334 250 335 msg.add(new JLabel(tr("<html>Select all tracks that you want to be displayed. " + 251 336 "You can drag select a range of tracks or use CTRL+Click to select specific ones. " + 252 "The map is updated live in the background. Open the URLs by double clicking them .</html>")),337 "The map is updated live in the background. Open the URLs by double clicking them, edit name and description by double clicking the cell.</html>")), 253 338 GBC.eop().fill(GBC.HORIZONTAL)); 254 339 // build table 255 340 final boolean[] trackVisibilityBackup = layer.trackVisibility.clone(); 256 table = buildTable(buildTableContents()); 341 Object[][] content = buildTableContents(); 342 table = buildTable(content); 257 343 selectVisibleTracksInTable(); 258 344 listenToSelectionChanges(); 259 345 // make the table scrollable … … 262 348 263 349 int v = 1; 264 350 // build dialog 265 ExtendedDialog ed = new ExtendedDialog(MainApplication.getMainFrame(), tr("Set track visibility for {0}", layer.getName()), 266 tr("Show all"), tr("Show selected only"), tr("Cancel")); 267 ed.setButtonIcons("eye", "dialogs/filter", "cancel"); 351 ExtendedDialog ed = new ExtendedDialog(MainApplication.getMainFrame(), 352 tr("Set track visibility for {0}", layer.getName()), 353 tr("Set color for selected tracks..."), tr("Show all"), tr("Show selected only"), tr("Cancel")) { 354 @Override 355 protected void buttonAction(int buttonIndex, ActionEvent evt) { 356 if (buttonIndex == 0) { 357 List<GpxTrack> trks = new ArrayList<>(); 358 for (int i : table.getSelectedRows()) { 359 Object trk = content[i][5]; 360 if (trk != null && trk instanceof GpxTrack) { 361 trks.add((GpxTrack) trk); 362 } 363 } 364 showColorDialog(trks); 365 } else { 366 super.buttonAction(buttonIndex, evt); 367 } 368 } 369 }; 370 ed.setButtonIcons("colorchooser", "eye", "dialogs/filter", "cancel"); 268 371 ed.setContent(msg, false); 269 372 ed.setDefaultButton(2); 270 373 ed.setCancelButton(3); … … 275 378 dateFilter.saveInPrefs(); 276 379 v = ed.getValue(); 277 380 // cancel for unknown buttons and copy back original settings 278 if (v != 1 && v != 2) {381 if (v != 2 && v != 3) { 279 382 layer.trackVisibility = Arrays.copyOf(trackVisibilityBackup, layer.trackVisibility.length); 280 383 MainApplication.getMap().repaint(); 281 384 return; 282 385 } 283 // set visibility ( 1 = show all, 2= filter). If no tracks are selected386 // set visibility (2 = show all, 3 = filter). If no tracks are selected 284 387 // set all of them visible and... 285 388 ListSelectionModel s = table.getSelectionModel(); 286 final boolean all = v == 1|| s.isSelectionEmpty();389 final boolean all = v == 2 || s.isSelectionEmpty(); 287 390 for (int i = 0; i < layer.trackVisibility.length; i++) { 288 391 layer.trackVisibility[table.convertRowIndexToModel(i)] = all || s.isSelectedIndex(i); 289 392 } … … 290 393 // layer has been changed 291 394 layer.invalidate(); 292 395 // ...sync with layer visibility instead to avoid having two ways to hide everything 293 layer.setVisible(v == 1|| !s.isSelectionEmpty());396 layer.setVisible(v == 2 || !s.isSelectionEmpty()); 294 397 } 295 398 } -
src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java
7 7 import java.awt.event.ActionEvent; 8 8 import java.awt.event.ActionListener; 9 9 import java.util.ArrayList; 10 import java.util.Collection;11 10 import java.util.Date; 12 11 import java.util.List; 12 import java.util.Map; 13 13 import java.util.Map.Entry; 14 14 15 15 import javax.swing.BorderFactory; … … 19 19 import javax.swing.JPanel; 20 20 import javax.swing.JRadioButton; 21 21 22 import org.openstreetmap.josm.data.gpx.Extensions; 22 23 import org.openstreetmap.josm.data.gpx.GpxConstants; 23 24 import org.openstreetmap.josm.data.gpx.GpxTrack; 24 25 import org.openstreetmap.josm.data.gpx.GpxTrackSegment; … … 25 26 import org.openstreetmap.josm.data.gpx.WayPoint; 26 27 import org.openstreetmap.josm.data.osm.DataSet; 27 28 import org.openstreetmap.josm.data.osm.Node; 29 import org.openstreetmap.josm.data.osm.OsmPrimitive; 28 30 import org.openstreetmap.josm.data.osm.Way; 29 31 import org.openstreetmap.josm.gui.ExtendedDialog; 30 32 import org.openstreetmap.josm.gui.MainApplication; … … 64 66 List<Node> nodes = new ArrayList<>(); 65 67 for (WayPoint p : segment.getWayPoints()) { 66 68 Node n = new Node(p.getCoor()); 67 for (Entry<String, Object> entry : p.attr.entrySet()) { 68 String key = entry.getKey(); 69 Object obj = p.get(key); 70 if (check && !keys.contains(key) && (obj instanceof String || obj instanceof Date)) { 71 keys.add(key); 72 } 73 if (obj instanceof String) { 74 String str = (String) obj; 75 if (!none) { 76 // only convert when required 77 n.put(key, str); 78 } 79 } else if (obj instanceof Date && GpxConstants.PT_TIME.equals(key)) { 80 // timestamps should always be converted 81 Date date = (Date) obj; 82 if (!none) { //... but the tag will only be set when required 83 n.put(key, DateUtils.fromDate(date)); 84 } 85 n.setTimestamp(date); 86 } 87 } 69 addAttributes(p.attr, n, keys, check, none); 88 70 ds.addPrimitive(n); 89 71 nodes.add(n); 90 72 } 91 73 Way w = new Way(); 92 74 w.setNodes(nodes); 75 addAttributes(trk.getAttributes(), w, keys, check, none); 93 76 ds.addPrimitive(w); 94 77 } 95 78 } … … 125 108 return ds; 126 109 } 127 110 111 private static void addAttributes(Map<String, Object> attr, OsmPrimitive n, List<String> keys, boolean check, boolean none) { 112 for (Entry<String, Object> entry : attr.entrySet()) { 113 String key = entry.getKey(); 114 Object obj = entry.getValue(); 115 if (!none) { 116 // only convert when required 117 if (check && !keys.contains(key) && (obj instanceof String || obj instanceof Date)) { 118 keys.add(key); 119 } 120 if (obj instanceof String) { 121 n.put(key, (String) obj); 122 } else if (obj instanceof Extensions) { 123 Extensions ext = (Extensions) obj; 124 String pre = ext.getPrefix(); 125 for (Entry<String, String> e : ext.entrySet()) { 126 String k = pre + e.getKey(); 127 if (check && !keys.contains(k)) { 128 keys.add(k); 129 } 130 n.put(k, e.getValue()); 131 } 132 } 133 } 134 if (obj instanceof Date && GpxConstants.PT_TIME.equals(key)) { 135 // timestamps should always be converted 136 Date date = (Date) obj; 137 if (!none) { //... but the tag will only be set when required 138 n.put(key, DateUtils.fromDate(date)); 139 } 140 n.setTimestamp(date); 141 } 142 } 143 } 144 128 145 /** 129 146 * Filters the tags of the given {@link DataSet} 130 147 * @param ds The {@link DataSet} … … 133 150 * @since 14103 134 151 */ 135 152 public DataSet filterDataSet(DataSet ds, List<String> listPos) { 136 Collection<Node> nodes = ds.getNodes(); 137 for (Node n : nodes) { 138 for (String key : n.keySet()) { 153 for (OsmPrimitive p : ds.getPrimitives(p -> p instanceof Node || p instanceof Way)) { 154 for (String key : p.keySet()) { 139 155 if (listPos == null || !listPos.contains(key)) { 140 n.put(key, null);156 p.put(key, null); 141 157 } 142 158 } 143 159 } -
src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java
68 68 * The color that is used for drawing GPX points. 69 69 * @since 10824 70 70 */ 71 public static final NamedColorProperty DEFAULT_COLOR = new NamedColorProperty(marktr("gps point"), Color.magenta);71 public static final NamedColorProperty DEFAULT_COLOR_PROPERTY = new NamedColorProperty(marktr("gps point"), Color.magenta); 72 72 73 73 private final GpxData data; 74 74 private final GpxLayer layer; … … 258 258 } 259 259 260 260 /** 261 * Get the default color for gps tracks for specified layer262 * @param layerName name of the GpxLayer263 * @param ignoreCustom do not use preferences264 * @return the color or null if the color is not constant265 */266 public Color getColor(String layerName, boolean ignoreCustom) {267 if (ignoreCustom || getColorMode(layerName) == ColorMode.NONE) {268 return DEFAULT_COLOR.getChildColor(269 NamedColorProperty.COLOR_CATEGORY_LAYER,270 layerName,271 DEFAULT_COLOR.getName()).get();272 } else {273 return null;274 }275 }276 277 /**278 261 * Read coloring mode for specified layer from preferences 279 262 * @param layerName name of the GpxLayer 280 263 * @return coloring mode … … 289 272 return ColorMode.NONE; 290 273 } 291 274 292 /** Reads generic color from preferences (usually gray)293 * @return the color294 **/295 public static Color getGenericColor() {296 return DEFAULT_COLOR.get();297 }298 299 275 /** 300 276 * Read all drawing-related settings from preferences 301 277 * @param layerName layer name used to access its specific preferences … … 337 313 338 314 // shrink to range 339 315 heatMapDrawGain = Utils.clamp(heatMapDrawGain, -10, 10); 340 341 neutralColor = getColor(layerName, true); 316 neutralColor = DEFAULT_COLOR_PROPERTY.get(); 342 317 velocityScale.setNoDataColor(neutralColor); 343 318 dateScale.setNoDataColor(neutralColor); 344 319 hdopScale.setNoDataColor(neutralColor); … … 577 552 } 578 553 for (WayPoint trkPnt : segment) { 579 554 LatLon c = trkPnt.getCoor(); 580 trkPnt.customColoring = neutralColor;555 trkPnt.customColoring = segment.getColor(); 581 556 if (Double.isNaN(c.lat()) || Double.isNaN(c.lon())) { 582 557 continue; 583 558 } … … 624 599 } 625 600 } else { // make sure we reset outdated data 626 601 trkPnt.drawLine = false; 627 color = neutralColor;602 color = segment.getColor(); 628 603 } 629 604 if (color != null) { 630 605 trkPnt.customColoring = color; -
src/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarker.java
103 103 GpxLink link = new GpxLink(audioUrl.toString()); 104 104 link.type = "audio"; 105 105 wpt.put(GpxConstants.META_LINKS, Collections.singleton(link)); 106 wpt.addExtension ("offset", Double.toString(offset));107 wpt.addExtension ("sync-offset", Double.toString(syncOffset));106 wpt.addExtensionKey(GpxConstants.EXTENSIONS_JOSM, "offset", Double.toString(offset)); 107 wpt.addExtensionKey(GpxConstants.EXTENSIONS_JOSM, "sync-offset", Double.toString(syncOffset)); 108 108 return wpt; 109 109 } 110 110 } -
src/org/openstreetmap/josm/gui/layer/markerlayer/DefaultMarkerProducers.java
45 45 return Collections.singleton(marker); 46 46 } else if (Utils.hasExtension(urlStr, "wav", "mp3", "aac", "aif", "aiff")) { 47 47 final AudioMarker audioMarker = new AudioMarker(wpt.getCoor(), wpt, url, parentLayer, time, offset); 48 Extensions exts = (Extensions) wpt.get(GpxConstants.META_EXTENSIONS);49 if ( exts != null && exts.containsKey("offset")) {48 Extensions josmExts = (Extensions) wpt.get(GpxConstants.EXTENSIONS_JOSM); 49 if (josmExts != null && josmExts.containsKey("offset")) { 50 50 try { 51 audioMarker.syncOffset = Double.parseDouble( exts.get("sync-offset"));51 audioMarker.syncOffset = Double.parseDouble(josmExts.get("sync-offset")); 52 52 } catch (NumberFormatException nfe) { 53 53 Logging.warn(nfe); 54 54 } -
src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java
247 247 WayPoint wpt = new WayPoint(getCoor()); 248 248 wpt.setTimeInMillis((long) (time * 1000)); 249 249 if (text != null) { 250 wpt.addExtension ("text", text);250 wpt.addExtensionKey(GpxConstants.EXTENSIONS_JOSM, "text", text); 251 251 } else if (dataProvider != null) { 252 252 for (String key : dataProvider.getTemplateKeys()) { 253 253 Object value = dataProvider.getTemplateValue(key, false); -
src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java
77 77 public AudioMarker syncAudioMarker; 78 78 79 79 private static final Color DEFAULT_COLOR = Color.magenta; 80 private static final NamedColorProperty COLOR_PROPERTY = new NamedColorProperty(marktr("gps marker"), DEFAULT_COLOR); 80 /** 81 * The color that is used for drawing markers. 82 */ 83 public static final NamedColorProperty DEFAULT_COLOR_PROPERTY = new NamedColorProperty(marktr("gps marker"), DEFAULT_COLOR); 81 84 82 85 /** 83 86 * Constructs a new {@code MarkerLayer}. … … 123 126 // audio file) calculate the offset relative to the first marker of 124 127 // that group. This way the user can jump to the corresponding 125 128 // playback positions in a long audio track. 126 Extensions exts = (Extensions) wpt.get(GpxConstants.META_EXTENSIONS);127 if ( exts != null && exts.containsKey("offset")) {129 Extensions josmExts = (Extensions) wpt.get(GpxConstants.EXTENSIONS_JOSM); 130 if (josmExts != null && josmExts.containsKey("offset")) { 128 131 try { 129 offset = Double.valueOf( exts.get("offset"));132 offset = Double.valueOf(josmExts.get("offset")); 130 133 } catch (NumberFormatException nfe) { 131 134 Logging.warn(nfe); 132 135 } … … 173 176 } 174 177 175 178 @Override 176 protected NamedColorProperty getBaseColorProperty() {177 return COLOR_PROPERTY;178 }179 180 /* for preferences */181 public static Color getGenericColor() {182 return COLOR_PROPERTY.get();183 }184 185 @Override186 179 public void paint(Graphics2D g, MapView mv, Bounds box) { 187 180 boolean showTextOrIcon = isTextOrIconShown(); 188 g.setColor(getColorProperty().get()); 189 181 g.setColor(DEFAULT_COLOR_PROPERTY.get()); 190 182 if (mousePressed) { 191 183 boolean mousePressedTmp = mousePressed; 192 184 Point mousePos = mv.getMousePosition(); // Get mouse position only when necessary (it's the slowest part of marker layer painting) -
src/org/openstreetmap/josm/gui/preferences/display/ColorPreference.java
390 390 PaintColors.values(); 391 391 ConflictColors.getColors(); 392 392 Severity.getColors(); 393 MarkerLayer. getGenericColor();394 GpxDrawHelper. getGenericColor();393 MarkerLayer.DEFAULT_COLOR_PROPERTY.get(); 394 GpxDrawHelper.DEFAULT_COLOR_PROPERTY.get(); 395 395 OsmDataLayer.getOutsideColor(); 396 396 MapScaler.getColor(); 397 397 MapStatus.getColors(); -
src/org/openstreetmap/josm/gui/preferences/display/GPXSettingsPanel.java
4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 import static org.openstreetmap.josm.tools.I18n.trc; 6 6 7 import java.awt.Color;8 7 import java.awt.Component; 9 8 import java.awt.Dimension; 10 9 import java.awt.GridBagLayout; … … 24 23 25 24 import org.openstreetmap.josm.actions.ExpertToggleAction; 26 25 import org.openstreetmap.josm.data.PreferencesUtils; 27 import org.openstreetmap.josm.data.preferences.NamedColorProperty;28 26 import org.openstreetmap.josm.gui.MainApplication; 29 27 import org.openstreetmap.josm.gui.layer.gpx.GpxDrawHelper; 30 28 import org.openstreetmap.josm.gui.layer.markerlayer.Marker; … … 326 324 if (null != dim) { 327 325 // get image size of environment 328 326 final int iconSize = (int) dim.getHeight(); 329 final Color color; 330 // ask the GPX draw for the correct color of that layer ( if there is one ) 331 if (null != layerName) { 332 color = GpxDrawHelper.DEFAULT_COLOR.getChildColor( 333 NamedColorProperty.COLOR_CATEGORY_LAYER, layerName, GpxDrawHelper.DEFAULT_COLOR.getName()).get(); 334 } else { 335 color = GpxDrawHelper.DEFAULT_COLOR.getDefaultValue(); 336 } 337 colorTypeHeatIconLabel.setIcon(GpxDrawHelper.getColorMapImageIcon(color, colorTypeHeatMapTune.getSelectedIndex(), iconSize)); 327 colorTypeHeatIconLabel.setIcon(GpxDrawHelper.getColorMapImageIcon( 328 GpxDrawHelper.DEFAULT_COLOR_PROPERTY.get(), 329 colorTypeHeatMapTune.getSelectedIndex(), 330 iconSize)); 338 331 } 339 332 }); 340 333 -
src/org/openstreetmap/josm/io/GpxReader.java
76 76 private State currentState = State.INIT; 77 77 78 78 private GpxLink currentLink; 79 private Extensions currentExtensions;79 private Map<String, String> currentExtensionMap = new HashMap<>(); 80 80 private Stack<State> states; 81 81 private final Stack<String> elements = new Stack<>(); 82 82 … … 159 159 case "extensions": 160 160 states.push(currentState); 161 161 currentState = State.EXT; 162 currentExtensions = new Extensions();163 162 break; 164 163 case "gpx": 165 164 if (atts.getValue("creator") != null && atts.getValue("creator").startsWith("Nokia Sports Tracker")) { … … 178 177 case "extensions": 179 178 states.push(currentState); 180 179 currentState = State.EXT; 181 currentExtensions = new Extensions();182 180 break; 183 181 case "copyright": 184 182 states.push(currentState); … … 228 226 case "extensions": 229 227 states.push(currentState); 230 228 currentState = State.EXT; 231 currentExtensions = new Extensions();232 229 break; 233 230 default: // Do nothing 234 231 } … … 250 247 case "extensions": 251 248 states.push(currentState); 252 249 currentState = State.EXT; 253 currentExtensions = new Extensions();254 250 break; 255 251 default: // Do nothing 256 252 } … … 270 266 case "extensions": 271 267 states.push(currentState); 272 268 currentState = State.EXT; 273 currentExtensions = new Extensions();274 269 break; 275 270 default: // Do nothing 276 271 } … … 349 344 if ((currentState == State.METADATA && "metadata".equals(localName)) || 350 345 (currentState == State.GPX && "gpx".equals(localName))) { 351 346 convertUrlToLink(data.attr); 352 if (currentExtensions != null && !currentExtensions.isEmpty()) { 353 data.put(META_EXTENSIONS, currentExtensions); 354 } 347 data.addExtensions(currentExtensionMap); 355 348 currentState = states.pop(); 356 349 } 357 350 break; … … 464 457 case "wpt": 465 458 currentState = states.pop(); 466 459 convertUrlToLink(currentWayPoint.attr); 467 if (currentExtensions != null && !currentExtensions.isEmpty()) { 468 currentWayPoint.put(META_EXTENSIONS, currentExtensions); 469 } 460 currentWayPoint.addExtensions(currentExtensionMap); 470 461 data.waypoints.add(currentWayPoint); 462 currentExtensionMap = new HashMap<>(); 471 463 break; 472 464 default: // Do nothing 473 465 } … … 483 475 case "trk": 484 476 currentState = states.pop(); 485 477 convertUrlToLink(currentTrackAttr); 486 data.addTrack(new ImmutableGpxTrack(currentTrack, currentTrackAttr)); 478 ImmutableGpxTrack trk = new ImmutableGpxTrack(currentTrack, currentTrackAttr, currentExtensionMap); 479 data.addTrack(trk); 480 currentExtensionMap = new HashMap<>(); 487 481 break; 488 482 case "name": 489 483 case "cmt": … … 499 493 } 500 494 break; 501 495 case EXT: 496 String acc; 502 497 if ("extensions".equals(localName)) { 503 498 currentState = states.pop(); 504 } else if (JOSM_EXTENSIONS_NAMESPACE_URI.equals(namespaceURI)) { 505 // only interested in extensions written by JOSM 506 currentExtensions.put(localName, accumulator.toString()); 499 } else if ((acc = accumulator.toString().trim()).length() > 0) { 500 currentExtensionMap.put(qName, acc); 507 501 } 508 502 break; 509 503 default: … … 519 513 default: // Do nothing 520 514 } 521 515 } 516 accumulator.setLength(0); 522 517 } 523 518 524 519 @Override … … 525 520 public void endDocument() throws SAXException { 526 521 if (!states.empty()) 527 522 throw new SAXException(tr("Parse error: invalid document structure for GPX document.")); 528 Extensions metaExt = (Extensions) data.get(META_EXTENSIONS);529 if ( metaExt != null && "true".equals(metaExt.get("from-server"))) {523 Extensions josmMetaExt = (Extensions) data.get(EXTENSIONS_JOSM); 524 if (josmMetaExt != null && "true".equals(josmMetaExt.get("from-server"))) { 530 525 data.fromServer = true; 531 526 } 532 527 gpxData = data; -
src/org/openstreetmap/josm/io/GpxWriter.java
3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.awt.Color; 6 7 import java.io.BufferedWriter; 7 8 import java.io.OutputStream; 8 9 import java.io.OutputStreamWriter; 9 10 import java.io.PrintWriter; 10 11 import java.nio.charset.StandardCharsets; 12 import java.util.AbstractMap.SimpleEntry; 13 import java.util.ArrayList; 11 14 import java.util.Collection; 12 15 import java.util.Date; 16 import java.util.HashMap; 13 17 import java.util.List; 14 18 import java.util.Map; 15 19 import java.util.Map.Entry; … … 59 63 private static final int ROUTE_POINT = 1; 60 64 private static final int TRACK_POINT = 2; 61 65 66 private HashMap<String, Entry<String, String>> extlinks = new HashMap<>(); 67 62 68 /** 63 69 * Writes the given GPX data. 64 70 * @param data The data to write 65 71 */ 66 72 public void write(GpxData data) { 73 write(data, EXTENSIONS_DRAWING); 74 } 75 76 /** 77 * Writes the given GPX data. 78 * 79 * @param data The data to write 80 * @param colorFormat determines if colors are saved and which extension is to be used, can be 81 * {@link GpxConstants#EXTENSIONS_GARMIN}, {@link GpxConstants#EXTENSIONS_DRAWING} or <code>null</code> 82 */ 83 public void write(GpxData data, String colorFormat) { 67 84 this.data = data; 68 85 // We write JOSM specific meta information into gpx 'extensions' elements. 69 86 // In particular it is noted whether the gpx data is from the OSM server … … 71 88 // and some extra synchronization info for export of AudioMarkers. 72 89 // It is checked in advance, if any extensions are used, so we know whether 73 90 // a namespace declaration is necessary. 74 boolean hasExtensions = data.fromServer; 75 if (!hasExtensions) { 91 92 boolean hasJosmExtension = data.fromServer, 93 hasGpxxExtension = false, 94 hasGpxdExtension = false, 95 searchGpxx = EXTENSIONS_GARMIN.equals(colorFormat), 96 searchGpxd = EXTENSIONS_DRAWING.equals(colorFormat); 97 98 if (!hasJosmExtension) { 76 99 for (WayPoint wpt : data.waypoints) { 77 Extensions extensions = (Extensions) wpt.get( META_EXTENSIONS);100 Extensions extensions = (Extensions) wpt.get(EXTENSIONS_JOSM); 78 101 if (extensions != null && !extensions.isEmpty()) { 79 has Extensions= true;102 hasJosmExtension = true; 80 103 break; 81 104 } 82 105 } 83 106 } 84 107 108 if (searchGpxx || searchGpxd) { 109 110 HashMap<Color, String> closestColorCache = new HashMap<>(); 111 112 for (GpxTrack trk : data.getTracks()) { 113 Extensions gpxx = (Extensions) trk.get(EXTENSIONS_GARMIN), 114 gpxd = (Extensions) trk.get(EXTENSIONS_DRAWING); 115 String gpxxC = null, gpxdC = null; 116 117 if (gpxd != null) { 118 gpxdC = gpxd.get("color"); 119 } 120 if (gpxx != null) { 121 gpxxC = gpxx.get("displaycolor"); 122 } 123 124 if (searchGpxd && gpxdC == null && gpxx != null && gpxxC != null) { 125 //Convert GPXX to GPXD 126 Color c = GARMIN_COLORS.get(gpxxC); 127 if (c != null) { 128 //Remove GPXX 129 trk.removeExtensionKey(EXTENSIONS_GARMIN, "displaycolor"); 130 //Put GPXD 131 trk.setColor(c); 132 hasGpxdExtension = true; 133 } else { 134 Logging.warn("Could not read garmin color: " + gpxxC); 135 } 136 } else if (searchGpxx && gpxxC == null && gpxd != null && gpxdC != null) { 137 //Convert GPXD to GPXX 138 try { 139 Color c = Color.decode(gpxdC); 140 //Remove GPXD 141 trk.removeExtensionKey(EXTENSIONS_DRAWING, "color"); 142 //Put GPXX 143 String colorString = null; 144 double closestDiff = -1; 145 146 if (closestColorCache.containsKey(c)) { 147 colorString = closestColorCache.get(c); 148 } else { 149 //find closest garmin color 150 for (Entry<String, Color> e : GARMIN_COLORS.entrySet()) { 151 double diff = colorDist(e.getValue(), c); 152 if (closestDiff < 0 || diff < closestDiff) { 153 colorString = e.getKey(); 154 closestDiff = diff; 155 if (closestDiff == 0) break; 156 } 157 } 158 closestColorCache.put(c, colorString); 159 } 160 trk.addExtensionKey(EXTENSIONS_GARMIN, "DisplayColor", colorString); 161 hasGpxxExtension = true; 162 } catch (NumberFormatException ex) { 163 Logging.warn("Could not read gpxd color: " + gpxdC); 164 } 165 } 166 //Must be checked again because of conversion above 167 if (!hasGpxdExtension && gpxd != null && !gpxd.isEmpty()) { 168 hasGpxdExtension = true; 169 } 170 if (!hasGpxxExtension && gpxx != null && !gpxx.isEmpty()) { 171 hasGpxxExtension = true; 172 } 173 } 174 } 175 85 176 out.println("<?xml version='1.0' encoding='UTF-8'?>"); 86 177 out.println("<gpx version=\"1.1\" creator=\"JOSM GPX export\" xmlns=\"http://www.topografix.com/GPX/1/1\""); 87 out.println((hasExtensions ? String.format(" xmlns:josm=\"%s\"%n", JOSM_EXTENSIONS_NAMESPACE_URI) : "") + 88 " xmlns:xsi=\""+XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI+"\""); 89 out.println(" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">"); 178 179 String schemaLocations = "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"; 180 181 if (hasJosmExtension) { 182 extlinks.put(GpxConstants.EXTENSIONS_JOSM, new SimpleEntry<>(GpxConstants.XML_URI_EXTENSIONS_JOSM, GpxConstants.XML_XSD_EXTENSIONS_JOSM)); 183 } 184 if (hasGpxdExtension) { 185 extlinks.put(GpxConstants.EXTENSIONS_DRAWING, new SimpleEntry<>(GpxConstants.XML_URI_EXTENSIONS_DRAWING, GpxConstants.XML_XSD_EXTENSIONS_DRAWING)); 186 } 187 if (hasGpxxExtension) { 188 extlinks.put(GpxConstants.EXTENSIONS_GARMIN, new SimpleEntry<>(GpxConstants.XML_URI_EXTENSIONS_GARMIN, GpxConstants.XML_XSD_EXTENSIONS_GARMIN)); 189 } 190 191 for (Entry<String, Entry<String, String>> e : extlinks.entrySet()) { 192 String k = e.getKey(); 193 Entry<String, String> v = e.getValue(); 194 if (!k.startsWith(EXTENSIONS_PREFIX)) { 195 throw new Extensions.InvalidExtensionException(); 196 } 197 out.println(String.format(" xmlns:%s=\"%s\"", k.substring(k.lastIndexOf(".") + 1), v.getKey())); 198 schemaLocations += " " + v.getKey() + " " + v.getValue(); 199 } 200 201 out.println(" xmlns:xsi=\""+XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI+"\""); 202 out.println(String.format(" xsi:schemaLocation=\"%s\">", schemaLocations)); 90 203 indent = " "; 91 204 writeMetaData(); 92 205 writeWayPoints(); … … 97 210 } 98 211 99 212 private void writeAttr(IWithAttributes obj, List<String> keys) { 213 List<Extensions> allExtensions = new ArrayList<>(); 100 214 for (String key : keys) { 101 215 if (META_LINKS.equals(key)) { 102 216 Collection<GpxLink> lValue = obj.<GpxLink>getCollection(key); … … 105 219 gpxLink(link); 106 220 } 107 221 } 108 } else if (META_EXTENSIONS.equals(key)) { 109 Extensions extensions = (Extensions) obj.get(key); 110 if (extensions != null) { 111 gpxExtensions(extensions); 222 } else if (key != null && key.startsWith(EXTENSIONS_PREFIX)) { 223 Extensions ex = (Extensions) obj.get(key); 224 if (ex != null && !ex.isEmpty()) { 225 //ex.setType(key); 226 allExtensions.add(ex); 112 227 } 113 228 } else { 114 229 String value = obj.getString(key); … … 126 241 } 127 242 } 128 243 } 244 gpxExtensions(allExtensions); 129 245 } 130 246 247 double colorDist(Color c1, Color c2) { 248 // Simple Euclidean distance between two colors 249 return Math.sqrt(Math.pow(c1.getRed() - c2.getRed(), 2) 250 + Math.pow(c1.getGreen() - c2.getGreen(), 2) 251 + Math.pow(c1.getBlue() - c2.getBlue(), 2)); 252 } 253 254 131 255 private void writeMetaData() { 132 256 Map<String, Object> attr = data.attr; 133 257 openln("metadata"); … … 318 442 } 319 443 } 320 444 321 private void gpxExtensions( Extensions extensions) {322 if ( extensions != null && !extensions.isEmpty()) {445 private void gpxExtensions(List<Extensions> allExtensions) { 446 if (!allExtensions.isEmpty()) { 323 447 openln("extensions"); 324 for (Entry<String, String> e : extensions.entrySet()) { 325 simpleTag("josm:" + e.getKey(), e.getValue()); 448 for (Extensions extensions : allExtensions) { 449 if (extlinks.containsKey(extensions.getType())) { 450 //making sure links were actually added / filter if no colors are to be saved at all. 451 //TODO: probably makes more sense to do the conversion here instead of in the beginning 452 //note that the colors will actually change during the conversion to GPXX 453 boolean garmin = EXTENSIONS_GARMIN.equals(extensions.getType()); 454 if (garmin) { //allow nested Garmin TrackExtension. Not ideal but does the job. 455 openln("gpxx:TrackExtension"); 456 } 457 for (Entry<String, String> e : extensions.entrySet()) { 458 simpleTag(extensions.getPrefix() + e.getKey(), e.getValue()); 459 } 460 if (garmin) { 461 closeln("gpxx:TrackExtension"); 462 } 463 } 326 464 } 327 465 closeln("extensions"); 328 466 } -
test/unit/org/openstreetmap/josm/data/gpx/GpxDataTest.java
473 473 public void testEqualsContract() { 474 474 TestUtils.assumeWorkingEqualsVerifier(); 475 475 EqualsVerifier.forClass(GpxData.class).usingGetClass() 476 .withIgnoredFields("attr", "creator", "fromServer", "storageFile", "listeners", "tracks", "routes", "waypoints", "proxy", "segSpans" )476 .withIgnoredFields("attr", "creator", "fromServer", "storageFile", "listeners", "tracks", "routes", "waypoints", "proxy", "segSpans", "modified") 477 477 .withPrefabValues(WayPoint.class, new WayPoint(LatLon.NORTH_POLE), new WayPoint(LatLon.SOUTH_POLE)) 478 478 .withPrefabValues(ListenerList.class, ListenerList.create(), ListenerList.create()) 479 479 .verify(); -
test/unit/org/openstreetmap/josm/data/gpx/ImmutableGpxTrackTest.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.gpx; 3 3 4 import static org.junit.Assert.assertEquals; 5 import static org.junit.Assert.assertNull; 6 7 import java.awt.Color; 8 import java.util.ArrayList; 9 import java.util.HashMap; 10 import java.util.Map; 11 4 12 import org.junit.Rule; 5 13 import org.junit.Test; 6 14 import org.openstreetmap.josm.TestUtils; 7 15 import org.openstreetmap.josm.testutils.JOSMTestRules; 16 import org.openstreetmap.josm.tools.ListenerList; 8 17 9 18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 10 19 import nl.jqno.equalsverifier.EqualsVerifier; … … 23 32 public JOSMTestRules test = new JOSMTestRules(); 24 33 25 34 /** 35 * Tests weather the track can read and write colors. 36 */ 37 @Test 38 public void testColors() { 39 GpxTrack trk = new ImmutableGpxTrack(new ArrayList<GpxTrackSegment>(), new HashMap<>()); 40 trk.addExtensions(Map.of("gpxd:color", "#FF0000")); 41 assertEquals(trk.getColor(), Color.RED); 42 trk.addExtensionKey(GpxConstants.EXTENSIONS_DRAWING, "color", "#00FF00"); 43 assertEquals(trk.getColor(), Color.GREEN); 44 trk.removeExtensionKey(GpxConstants.EXTENSIONS_DRAWING, "color"); 45 assertNull(trk.getColor()); 46 trk.addExtensionKey(GpxConstants.EXTENSIONS_GARMIN, "DisplayColor", "Blue"); 47 assertEquals(trk.getColor(), Color.BLUE); 48 trk.setColor(null); 49 assertNull(trk.getColor()); 50 trk.addExtensions(Map.of("gpxx:DisplayColor", "Cyan")); 51 assertEquals(trk.getColor(), Color.CYAN); 52 trk.setColor(Color.YELLOW); 53 assertEquals(trk.getColor(), Color.YELLOW); 54 } 55 56 /** 26 57 * Unit test of methods {@link ImmutableGpxTrack#equals} and {@link ImmutableGpxTrack#hashCode}. 27 58 */ 28 59 @Test … … 30 61 TestUtils.assumeWorkingEqualsVerifier(); 31 62 EqualsVerifier.forClass(ImmutableGpxTrack.class).usingGetClass() 32 63 .suppress(Warning.NONFINAL_FIELDS) 33 .withIgnoredFields("bounds", "length") 64 .withPrefabValues(ListenerList.class, ListenerList.create(), ListenerList.create()) 65 .withIgnoredFields("bounds", "length", "colorCache", "listeners") 34 66 .verify(); 35 67 } 36 68 } -
test/unit/org/openstreetmap/josm/gui/layer/GpxLayerTest.java
3 3 4 4 import static org.junit.Assert.assertEquals; 5 5 import static org.junit.Assert.assertFalse; 6 import static org.junit.Assert.assertNull; 6 7 import static org.junit.Assert.assertTrue; 7 8 8 9 import java.awt.Color; … … 10 11 import java.util.ArrayList; 11 12 import java.util.Collection; 12 13 import java.util.HashMap; 14 import java.util.Map; 13 15 import java.util.TimeZone; 14 16 15 17 import javax.swing.JScrollPane; … … 18 20 import org.junit.Test; 19 21 import org.openstreetmap.josm.TestUtils; 20 22 import org.openstreetmap.josm.data.gpx.GpxData; 23 import org.openstreetmap.josm.data.gpx.GpxTrackSegment; 21 24 import org.openstreetmap.josm.data.gpx.ImmutableGpxTrack; 22 25 import org.openstreetmap.josm.data.gpx.WayPoint; 23 26 import org.openstreetmap.josm.data.osm.DataSet; … … 73 76 @Test 74 77 public void testGpxLayer() throws Exception { 75 78 GpxLayer layer = new GpxLayer(new GpxData(), "foo", false); 79 ImmutableGpxTrack trk = new ImmutableGpxTrack(new ArrayList<GpxTrackSegment>(), new HashMap<>()); 80 trk.addExtensions(Map.of("gpxd:color", "#FF0000")); 81 layer.data.addTrack(trk); 82 76 83 assertEquals("foo", layer.getName()); 77 84 assertFalse(layer.isLocalFile()); 78 assertEquals( Color.MAGENTA, layer.getColorProperty().get());79 assertEquals("<html> 0 tracks(0 segments), 0 routes, 0 waypoints<br>Length: < 0.01 m<br></html>", layer.getToolTipText());85 assertEquals(layer.getColor(), Color.RED); 86 assertEquals("<html>1 track (0 segments), 0 routes, 0 waypoints<br>Length: < 0.01 m<br></html>", layer.getToolTipText()); 80 87 81 88 GpxLayer layer2 = new GpxLayer(new GpxData(), "bar", true); 82 89 assertEquals("bar", layer2.getName()); 83 90 assertTrue(layer2.isLocalFile()); 84 assert Equals(Color.MAGENTA, layer2.getColorProperty().get());91 assertNull(layer2.getColor()); 85 92 assertEquals("<html>0 tracks (0 segments), 0 routes, 0 waypoints<br>Length: < 0.01 m<br></html>", layer2.getToolTipText()); 86 93 87 94 assertTrue(layer.checkSaveConditions()); -
test/unit/org/openstreetmap/josm/gui/layer/LayerTest.java
7 7 import static org.junit.Assert.assertNull; 8 8 import static org.junit.Assert.assertTrue; 9 9 10 import java.awt.Color;11 10 import java.io.File; 12 11 13 12 import org.junit.Before; 14 13 import org.junit.Rule; 15 14 import org.junit.Test; 16 import org.openstreetmap.josm.data.preferences.AbstractProperty;17 import org.openstreetmap.josm.data.preferences.NamedColorProperty;18 15 import org.openstreetmap.josm.data.projection.ProjectionRegistry; 19 16 import org.openstreetmap.josm.testutils.JOSMTestRules; 20 17 … … 43 40 } 44 41 45 42 /** 46 * Test {@link Layer#getColorProperty()}47 */48 @Test49 public void testGetColorProperty() {50 assertEquals(null, testLayer.getColorProperty());51 52 AbstractProperty<Color> color = new LayerManagerTest.TestLayer() {53 @Override54 protected NamedColorProperty getBaseColorProperty() {55 return new NamedColorProperty("x", Color.BLACK);56 }57 }.getColorProperty();58 59 assertEquals(Color.BLACK, color.get());60 assertEquals(Color.BLACK, color.getDefaultValue());61 assertEquals("clr.layer.Test Layer.x", color.getKey());62 }63 64 /**65 43 * Test of {@link Layer#isInfoResizable} 66 44 */ 67 45 @Test … … 97 75 testLayer.setName("Test Layer2"); 98 76 assertEquals("Test Layer2", testLayer.getName()); 99 77 100 testLayer = new LayerManagerTest.TestLayer() { 101 @Override 102 public AbstractProperty<Color> getColorProperty() { 103 return new NamedColorProperty("test", Color.RED); 104 } 105 }; 78 testLayer = new LayerManagerTest.TestLayer(); 106 79 107 80 testLayer.setName("Test Layer2"); 108 81 testLayer.setName(null); -
test/unit/org/openstreetmap/josm/gui/layer/MarkerLayerTest.java
1 // License: GPL. For details, see LICENSE file.2 package org.openstreetmap.josm.gui.layer;3 4 import static org.junit.Assert.assertNotNull;5 import static org.junit.Assert.assertNull;6 7 import org.junit.Rule;8 import org.junit.Test;9 import org.openstreetmap.josm.data.gpx.GpxData;10 import org.openstreetmap.josm.data.osm.DataSet;11 import org.openstreetmap.josm.gui.MainApplication;12 import org.openstreetmap.josm.gui.MapFrame;13 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;14 import org.openstreetmap.josm.testutils.JOSMTestRules;15 16 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;17 18 /**19 * Unit tests of {@link MarkerLayer} class.20 */21 public class MarkerLayerTest {22 23 /**24 * For creating layers25 */26 @Rule27 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")28 public JOSMTestRules test = new JOSMTestRules().main().projection();29 30 /**31 * Unit test of {@code Main.map.mapView.playHeadMarker}.32 */33 @Test34 public void testPlayHeadMarker() {35 try {36 MainApplication.getLayerManager().addLayer(new OsmDataLayer(new DataSet(), "", null));37 MapFrame map = MainApplication.getMap();38 MarkerLayer layer = new MarkerLayer(new GpxData(), null, null, null);39 assertNull(map.mapView.playHeadMarker);40 MainApplication.getLayerManager().addLayer(layer);41 assertNotNull(map.mapView.playHeadMarker);42 MainApplication.getLayerManager().removeLayer(layer);43 } finally {44 if (MainApplication.isDisplayingMapView()) {45 MainApplication.getMap().mapView.playHeadMarker = null;46 }47 }48 }49 } -
test/unit/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarkerTest.java
Property changes on: test/unit/org/openstreetmap/josm/gui/layer/MarkerLayerTest.java ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property
45 45 assertEquals("2", marker.getText()); 46 46 WayPoint wpt = marker.convertToWayPoint(); 47 47 assertEquals(LatLon.ZERO, wpt.getCoor()); 48 Extensions ext = (Extensions) wpt.get(GpxConstants. META_EXTENSIONS);48 Extensions ext = (Extensions) wpt.get(GpxConstants.EXTENSIONS_JOSM); 49 49 assertEquals("2.0", ext.get("offset")); 50 50 } 51 51 } -
test/unit/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayerTest.java
3 3 4 4 import static org.junit.Assert.assertEquals; 5 5 import static org.junit.Assert.assertNotNull; 6 import static org.junit.Assert.assertNull; 6 7 import static org.junit.Assert.assertTrue; 7 8 8 import java.awt.Color;9 9 import java.util.Arrays; 10 10 11 11 import org.junit.Before; … … 16 16 import org.openstreetmap.josm.data.gpx.GpxData; 17 17 import org.openstreetmap.josm.data.gpx.GpxLink; 18 18 import org.openstreetmap.josm.data.gpx.WayPoint; 19 import org.openstreetmap.josm.data.osm.DataSet; 19 20 import org.openstreetmap.josm.gui.MainApplication; 21 import org.openstreetmap.josm.gui.MapFrame; 22 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 20 23 import org.openstreetmap.josm.spi.preferences.Config; 21 24 import org.openstreetmap.josm.testutils.JOSMTestRules; 22 25 … … 28 31 public class MarkerLayerTest { 29 32 30 33 /** 31 * Setup tests34 * For creating layers 32 35 */ 33 36 @Rule 34 37 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") … … 47 50 */ 48 51 @Test 49 52 public void testMarkerLayer() { 50 assertEquals(Color.magenta, MarkerLayer.getGenericColor());53 //assertEquals(Color.magenta, MarkerLayer.getGenericColor()); 51 54 MarkerLayer layer = new MarkerLayer(new GpxData(), "foo", null, null); 52 55 MainApplication.getLayerManager().addLayer(layer); 53 56 54 57 assertEquals("foo", layer.getName()); 55 assert Equals(Color.magenta, layer.getColorProperty().get());58 assertNull(layer.getColor()); 56 59 assertNotNull(layer.getIcon()); 57 60 assertEquals("0 markers", layer.getToolTipText()); 58 61 assertEquals("<html>foo consists of 0 markers</html>", layer.getInfoComponent()); … … 61 64 GpxData gpx = new GpxData(); 62 65 WayPoint wpt = new WayPoint(LatLon.ZERO); 63 66 wpt.attr.put(GpxConstants.META_LINKS, Arrays.asList(new GpxLink("https://josm.openstreetmap.de"))); 64 wpt.addExtension ("offset", "1.0");67 wpt.addExtensionKey(GpxConstants.EXTENSIONS_JOSM, "offset", "1.0"); 65 68 gpx.waypoints.add(wpt); 66 69 wpt = new WayPoint(LatLon.ZERO); 67 wpt.addExtension ("offset", "NaN");70 wpt.addExtensionKey(GpxConstants.EXTENSIONS_JOSM, "offset", "NaN"); 68 71 gpx.waypoints.add(wpt); 69 72 layer = new MarkerLayer(gpx, "bar", null, null); 70 73 71 74 assertEquals("bar", layer.getName()); 72 assert Equals(Color.magenta, layer.getColorProperty().get());75 assertNull(layer.getColor()); 73 76 assertNotNull(layer.getIcon()); 74 77 assertEquals("3 markers", layer.getToolTipText()); 75 78 assertEquals("<html>bar consists of 3 markers</html>", layer.getInfoComponent()); 76 79 assertTrue(layer.getMenuEntries().length > 10); 77 80 } 81 82 /** 83 * Unit test of {@code Main.map.mapView.playHeadMarker}. 84 */ 85 @Test 86 public void testPlayHeadMarker() { 87 try { 88 MainApplication.getLayerManager().addLayer(new OsmDataLayer(new DataSet(), "", null)); 89 MapFrame map = MainApplication.getMap(); 90 MarkerLayer layer = new MarkerLayer(new GpxData(), null, null, null); 91 assertNull(map.mapView.playHeadMarker); 92 MainApplication.getLayerManager().addLayer(layer); 93 assertNotNull(map.mapView.playHeadMarker); 94 MainApplication.getLayerManager().removeLayer(layer); 95 } finally { 96 if (MainApplication.isDisplayingMapView()) { 97 MainApplication.getMap().mapView.playHeadMarker = null; 98 } 99 } 100 } 78 101 } -
test/unit/org/openstreetmap/josm/io/GpxWriterTest.java
Property changes on: test/unit/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayerTest.java ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property
87 87 " <vdop>0.9</vdop>%n" + 88 88 " <pdop>1.2</pdop>%n"); 89 89 } 90 91 /** 92 * Tests if extensions are handled correctly when reading and writing. 93 * Source file contains 4 tracks 94 * - 1x gpxx colors (garmin) 95 * - 1x gpxd colors 96 * - 2x no colors 97 * one of the tracks without colors is assigned a new color 98 * Then the layer is exported twice 99 * - once using gpxx extensions and 100 * - once using gpxd extensions 101 */ 102 @Test 103 public void testExtensions() { 104 //TODO 105 } 106 90 107 }