Ticket #12282: xml_removal.patch

File xml_removal.patch, 49.4 KB (added by Don-vip, 5 years ago)
  • data/mappaint-style.xsd

     
    1 <?xml version="1.0" encoding="UTF-8"?>
    2 <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://josm.openstreetmap.de/mappaint-style-1.0"
    3         xmlns:tns="http://josm.openstreetmap.de/mappaint-style-1.0" elementFormDefault="qualified">
    4 
    5         <!--
    6                 Localized attributes (for example de.description are not supported by
    7                 xsd, so root element needs <anyAttribute/>
    8         -->
    9 
    10         <element name="rules" type="tns:root"/>
    11 
    12         <complexType name="root">
    13                 <sequence>
    14                         <choice minOccurs="0" maxOccurs="unbounded">
    15                                 <element name="rule" type="tns:rule" />
    16                         </choice>
    17                 </sequence>
    18                 <attribute name="name" type="string" />
    19                 <attribute name="author" type="string" />
    20                 <attribute name="version" type="string" />
    21                 <attribute name="shortdescription" type="string" />
    22                 <attribute name="description" type="string" />
    23                 <attribute name="link" type="string"/>
    24                 <attribute name="icon" type="string"/>
    25 
    26                 <anyAttribute processContents="skip"/>
    27         </complexType>
    28 
    29         <!-- TODO: ensure that at least one of results exists, but only one of each element, except for linemod which may have more,
    30         scale is totally optional, but each of the two may come only once -->
    31         <complexType name="rule">
    32                 <sequence>
    33                         <element name="condition" type="tns:condition" minOccurs="1" maxOccurs="unbounded" />
    34                         <choice minOccurs="1" maxOccurs="unbounded" >
    35                                 <group ref="tns:results" />
    36                                 <group ref="tns:scale" />
    37                         </choice>
    38                 </sequence>
    39         </complexType>
    40 
    41         <group name="results">
    42                 <choice>
    43                         <element name="icon" type="tns:icon" />
    44                         <element name="area" type="tns:area" />
    45                         <element name="line" type="tns:line" />
    46                         <element name="linemod" type="tns:linemod" maxOccurs="unbounded" />
    47                 </choice>
    48         </group>
    49 
    50         <group name="scale">
    51                 <choice>
    52                         <element name="scale_min" type="integer" />
    53                         <element name="scale_max" type="integer" />
    54                 </choice>
    55         </group>
    56 
    57         <complexType name="condition">
    58                 <!-- TODO restrict to k, k+v or k+b, other attribute combinations are illegal -->
    59                 <attribute name="k" type="string" use="required" />
    60                 <attribute name="v" type="string" />
    61                 <attribute name="b" type="tns:yesno" />
    62         </complexType>
    63 
    64         <complexType name="icon">
    65                 <attribute name="src" type="string" use="required" />
    66                 <attribute name="annotate" type="boolean" />
    67                 <attribute name="priority" type="integer" />
    68         </complexType>
    69 
    70         <complexType name="line">
    71                 <attribute name="width" type="integer" />
    72                 <attribute name="dashed" type="tns:dashed" />
    73                 <attribute name="realwidth" type="integer" />
    74                 <attribute name="colour" type="tns:color" />
    75                 <attribute name="dashedcolour" type="tns:color" />
    76                 <attribute name="priority" type="integer" />
    77         </complexType>
    78 
    79         <complexType name="area">
    80                 <attribute name="colour" type="tns:color" />
    81                 <attribute name="closed" type="boolean" />
    82                 <attribute name="priority" type="integer" />
    83         </complexType>
    84 
    85         <complexType name="linemod">
    86                 <attribute name="dashed" type="tns:dashed" />
    87                 <attribute name="realwidth" type="integer" />
    88                 <attribute name="colour" type="tns:color" />
    89                 <attribute name="dashedcolour" type="tns:color" />
    90                 <attribute name="mode" type="tns:modifier_mode" use="required" />
    91                 <attribute name="width" type="tns:width" />
    92         </complexType>
    93 
    94         <simpleType name="yesno">
    95                 <restriction base="string">
    96                         <enumeration value="yes"/>
    97                         <enumeration value="no"/>
    98                 </restriction>
    99         </simpleType>
    100 
    101         <simpleType name="dashed">
    102                 <restriction base="string">
    103                         <pattern value="\d+(,\d+)*"/>
    104                         <pattern value="(true|false)"/>
    105                 </restriction>
    106         </simpleType>
    107 
    108         <simpleType name="modifier_mode">
    109                 <restriction base="string">
    110                         <enumeration value="under"/>
    111                         <enumeration value="over"/>
    112                 </restriction>
    113         </simpleType>
    114 
    115         <simpleType name="color">
    116                 <restriction base="string">
    117                         <pattern value="([a-z0-9_]+#)?[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?"/>
    118                         <!-- name#color or color only, where color is 6 or 8 hex digits -->
    119                 </restriction>
    120         </simpleType>
    121 
    122         <simpleType name="width">
    123                 <restriction base="string">
    124                         <pattern value="\d+"/>
    125                         <pattern value="[+-]\d+"/>
    126                         <pattern value="\d+%"/>
    127                 </restriction>
    128         </simpleType>
    129 </schema>
  • src/org/openstreetmap/josm/gui/dialogs/InspectPrimitiveDialog.java

     
    3838import org.openstreetmap.josm.gui.NavigatableComponent;
    3939import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    4040import org.openstreetmap.josm.gui.mappaint.Cascade;
    41 import org.openstreetmap.josm.gui.mappaint.styleelement.StyleElement;
    4241import org.openstreetmap.josm.gui.mappaint.ElemStyles;
    4342import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
    4443import org.openstreetmap.josm.gui.mappaint.MultiCascade;
     
    4645import org.openstreetmap.josm.gui.mappaint.StyleElementList;
    4746import org.openstreetmap.josm.gui.mappaint.StyleSource;
    4847import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
    49 import org.openstreetmap.josm.gui.mappaint.xml.XmlStyleSource;
     48import org.openstreetmap.josm.gui.mappaint.styleelement.StyleElement;
    5049import org.openstreetmap.josm.gui.util.GuiHelper;
    5150import org.openstreetmap.josm.gui.widgets.JosmTextArea;
    5251import org.openstreetmap.josm.tools.GBC;
     
    422421    }
    423422
    424423    private static String getSort(StyleSource s) {
    425         if (s instanceof XmlStyleSource) {
    426             return tr("xml");
    427         } else if (s instanceof MapCSSStyleSource) {
     424        if (s instanceof MapCSSStyleSource) {
    428425            return tr("mapcss");
    429426        } else {
    430427            return tr("unknown");
  • src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java

     
    55
    66import java.io.File;
    77import java.io.IOException;
    8 import java.io.InputStreamReader;
    9 import java.nio.charset.StandardCharsets;
    108import java.util.ArrayList;
    119import java.util.Arrays;
    1210import java.util.Collection;
     
    2927import org.openstreetmap.josm.gui.mappaint.styleelement.MapImage;
    3028import org.openstreetmap.josm.gui.mappaint.styleelement.NodeElement;
    3129import org.openstreetmap.josm.gui.mappaint.styleelement.StyleElement;
    32 import org.openstreetmap.josm.gui.mappaint.xml.XmlStyleSource;
    3330import org.openstreetmap.josm.gui.preferences.SourceEntry;
    3431import org.openstreetmap.josm.gui.preferences.map.MapPaintPreference.MapPaintPrefHelper;
    3532import org.openstreetmap.josm.gui.progress.ProgressMonitor;
     
    279276    }
    280277
    281278    private static StyleSource fromSourceEntry(SourceEntry entry) {
    282         CachedFile cf = null;
    283279        try {
    284             Set<String> mimes = new HashSet<>();
    285             mimes.addAll(Arrays.asList(XmlStyleSource.XML_STYLE_MIME_TYPES.split(", ")));
    286             mimes.addAll(Arrays.asList(MapCSSStyleSource.MAPCSS_STYLE_MIME_TYPES.split(", ")));
    287             cf = new CachedFile(entry.url).setHttpAccept(Utils.join(", ", mimes));
    288             String zipEntryPath = cf.findZipEntryPath("mapcss", "style");
    289             if (zipEntryPath != null) {
    290                 entry.isZip = true;
    291                 entry.zipEntryPath = zipEntryPath;
    292                 return new MapCSSStyleSource(entry);
    293             }
    294             zipEntryPath = cf.findZipEntryPath("xml", "style");
    295             if (zipEntryPath != null)
    296                 return new XmlStyleSource(entry);
    297             if (Utils.hasExtension(entry.url, "mapcss"))
    298                 return new MapCSSStyleSource(entry);
    299             if (Utils.hasExtension(entry.url, "xml"))
    300                 return new XmlStyleSource(entry);
    301             else {
    302                 try (InputStreamReader reader = new InputStreamReader(cf.getInputStream(), StandardCharsets.UTF_8)) {
    303                     WHILE: while (true) {
    304                         int c = reader.read();
    305                         switch (c) {
    306                             case -1:
    307                                 break WHILE;
    308                             case ' ':
    309                             case '\t':
    310                             case '\n':
    311                             case '\r':
    312                                 continue;
    313                             case '<':
    314                                 return new XmlStyleSource(entry);
    315                             default:
    316                                 return new MapCSSStyleSource(entry);
    317                         }
    318                     }
     280            Set<String> mimes = new HashSet<>(Arrays.asList(MapCSSStyleSource.MAPCSS_STYLE_MIME_TYPES.split(", ")));
     281            try (CachedFile cf = new CachedFile(entry.url).setHttpAccept(Utils.join(", ", mimes))) {
     282                String zipEntryPath = cf.findZipEntryPath("mapcss", "style");
     283                if (zipEntryPath != null) {
     284                    entry.isZip = true;
     285                    entry.zipEntryPath = zipEntryPath;
     286                    return new MapCSSStyleSource(entry);
    319287                }
    320                 Main.warn("Could not detect style type. Using default (xml).");
    321                 return new XmlStyleSource(entry);
    322288            }
    323         } catch (IOException e) {
     289            return new MapCSSStyleSource(entry);
     290        } catch (Exception e) {
    324291            Main.warn(tr("Failed to load Mappaint styles from ''{0}''. Exception was: {1}", entry.url, e.toString()));
    325292            Main.error(e);
    326         } finally {
    327             if (cf != null) {
    328                 cf.close();
    329             }
    330293        }
    331294        return null;
    332295    }
  • src/org/openstreetmap/josm/gui/mappaint/xml/AreaPrototype.java

     
    1 // License: GPL. For details, see LICENSE file.
    2 package org.openstreetmap.josm.gui.mappaint.xml;
    3 
    4 import java.awt.Color;
    5 
    6 import org.openstreetmap.josm.gui.mappaint.Range;
    7 
    8 public class AreaPrototype extends Prototype {
    9     public Color color;
    10     public boolean closed; // if true, it does not apply to unclosed ways
    11 
    12     public AreaPrototype(AreaPrototype a, Range range) {
    13         super(range);
    14         this.color = a.color;
    15         this.closed = a.closed;
    16         this.priority = a.priority;
    17         this.conditions = a.conditions;
    18     }
    19 
    20     public AreaPrototype() {
    21         init();
    22     }
    23 
    24     public final void init() {
    25         priority = 0;
    26         range = Range.ZERO_TO_INFINITY;
    27         closed = false;
    28         color = null;
    29     }
    30 }
  • src/org/openstreetmap/josm/gui/mappaint/xml/IconPrototype.java

     
    1 // License: GPL. For details, see LICENSE file.
    2 package org.openstreetmap.josm.gui.mappaint.xml;
    3 
    4 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference;
    5 import org.openstreetmap.josm.gui.mappaint.Range;
    6 
    7 public class IconPrototype extends Prototype {
    8 
    9     public IconReference icon;
    10     public Boolean annotate;
    11 
    12     public IconPrototype(IconPrototype i, Range range) {
    13         super(range);
    14         this.icon = i.icon;
    15         this.annotate = i.annotate;
    16         this.priority = i.priority;
    17         this.conditions = i.conditions;
    18     }
    19 
    20     /**
    21      * Constructs a new {@code IconPrototype}.
    22      */
    23     public IconPrototype() {
    24         init();
    25     }
    26 
    27     public final void init() {
    28         priority = 0;
    29         range = Range.ZERO_TO_INFINITY;
    30         icon = null;
    31         annotate = null;
    32     }
    33 }
  • src/org/openstreetmap/josm/gui/mappaint/xml/LinePrototype.java

     
    1 // License: GPL. For details, see LICENSE file.
    2 package org.openstreetmap.josm.gui.mappaint.xml;
    3 
    4 import java.awt.Color;
    5 import java.util.List;
    6 
    7 import org.openstreetmap.josm.Main;
    8 import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
    9 import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
    10 import org.openstreetmap.josm.gui.mappaint.Range;
    11 import org.openstreetmap.josm.tools.I18n;
    12 
    13 public class LinePrototype extends Prototype {
    14 
    15     protected int width;
    16     public Integer realWidth; // the real width of this line in meter
    17     public Color color;
    18     protected List<Float> dashed;
    19     public Color dashedColor;
    20 
    21     public LinePrototype(LinePrototype s, Range range) {
    22         super(range);
    23         this.width = s.width;
    24         this.realWidth = s.realWidth;
    25         this.color = s.color;
    26         this.dashed = s.dashed;
    27         this.dashedColor = s.dashedColor;
    28         this.priority = s.priority;
    29         this.conditions = s.conditions;
    30     }
    31 
    32     /**
    33      * Constructs a new {@code LinePrototype}.
    34      */
    35     public LinePrototype() {
    36         init();
    37     }
    38 
    39     public void init() {
    40         priority = 0;
    41         range = Range.ZERO_TO_INFINITY;
    42         width = -1;
    43         realWidth = null;
    44         dashed = null;
    45         dashedColor = null;
    46         color = PaintColors.UNTAGGED.get();
    47     }
    48 
    49     public List<Float> getDashed() {
    50         return dashed;
    51     }
    52 
    53     public void setDashed(List<Float> dashed) {
    54         if (dashed == null || dashed.isEmpty()) {
    55             this.dashed = null;
    56             return;
    57         }
    58 
    59         boolean found = false;
    60         for (Float f : dashed) {
    61             if (f == null) {
    62                 this.dashed = null;
    63                 return;
    64             }
    65             if (f > 0) {
    66                 found = true;
    67             }
    68             if (f < 0) {
    69                 Main.error(I18n.tr("Illegal dash pattern, values must be positive"));
    70                 this.dashed = null;
    71                 return;
    72             }
    73         }
    74         if (found) {
    75             this.dashed = dashed;
    76         } else {
    77             Main.error(I18n.tr("Illegal dash pattern, at least one value must be > 0"));
    78         }
    79     }
    80 
    81     public int getWidth() {
    82         if (width == -1)
    83             return MapPaintSettings.INSTANCE.getDefaultSegmentWidth();
    84         return width;
    85     }
    86 
    87     public void setWidth(int width) {
    88         this.width = width;
    89     }
    90 }
  • src/org/openstreetmap/josm/gui/mappaint/xml/LinemodPrototype.java

     
    1 // License: GPL. For details, see LICENSE file.
    2 package org.openstreetmap.josm.gui.mappaint.xml;
    3 
    4 import org.openstreetmap.josm.gui.mappaint.Range;
    5 
    6 public class LinemodPrototype extends LinePrototype implements Comparable<LinemodPrototype> {
    7 
    8     public enum WidthMode { ABSOLUTE, PERCENT, OFFSET }
    9 
    10     public WidthMode widthMode;
    11     public boolean over;
    12 
    13     public LinemodPrototype(LinemodPrototype s, Range range) {
    14         super(s, range);
    15         this.over = s.over;
    16         this.widthMode = s.widthMode;
    17     }
    18 
    19     /**
    20      * Constructs a new {@code LinemodPrototype}.
    21      */
    22     public LinemodPrototype() {
    23         init();
    24     }
    25 
    26     @Override
    27     public final void init() {
    28         super.init();
    29         over = true;
    30         widthMode = WidthMode.ABSOLUTE;
    31     }
    32 
    33     /**
    34      * get width for overlays
    35      * @param ref reference width
    36      * @return width according to {@link #widthMode} with a minimal value of 1
    37      */
    38     public float getWidth(float ref) {
    39         float res;
    40         if (widthMode == WidthMode.ABSOLUTE) {
    41             res = width;
    42         } else if (widthMode == WidthMode.OFFSET) {
    43             res = ref + width;
    44         } else {
    45             if (width < 0) {
    46                 res = 0;
    47             } else {
    48                 res = ref*width/100;
    49             }
    50         }
    51         return res <= 0 ? 1 : res;
    52     }
    53 
    54     @Override
    55     public int getWidth() {
    56         throw new UnsupportedOperationException();
    57     }
    58 
    59     @Override
    60     public int compareTo(LinemodPrototype s) {
    61         if (s.priority != priority)
    62             return s.priority > priority ? 1 : -1;
    63             if (!over && s.over)
    64                 return -1;
    65             // we have no idea how to order other objects :-)
    66             return 0;
    67     }
    68 }
  • src/org/openstreetmap/josm/gui/mappaint/xml/Prototype.java

     
    1 // License: GPL. For details, see LICENSE file.
    2 package org.openstreetmap.josm.gui.mappaint.xml;
    3 
    4 import java.util.Collection;
    5 
    6 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    7 import org.openstreetmap.josm.data.osm.OsmUtils;
    8 import org.openstreetmap.josm.gui.mappaint.Range;
    9 
    10 public abstract class Prototype {
    11     // zoom range to display the feature
    12     public Range range;
    13 
    14     public int priority;
    15     public String code;
    16     public Collection<XmlCondition> conditions;
    17 
    18     public Prototype(Range range) {
    19         this.range = range;
    20     }
    21 
    22     /**
    23      * Constructs a new {@code Prototype}.
    24      */
    25     public Prototype() {
    26         // Allows subclassing
    27     }
    28 
    29     public String getCode() {
    30         if (code == null) {
    31             if (conditions == null || conditions.isEmpty()) {
    32                 code = "";
    33             } else {
    34                 final StringBuilder sb = new StringBuilder();
    35                 for (XmlCondition r: conditions) {
    36                     r.appendCode(sb);
    37                 }
    38                 code = sb.toString();
    39             }
    40         }
    41         return code;
    42     }
    43 
    44     public boolean check(OsmPrimitive primitive) {
    45         if (conditions == null)
    46             return true;
    47         for (XmlCondition r : conditions) {
    48             String k = primitive.get(r.key);
    49 
    50             if (k == null || (r.value != null && !k.equals(r.value)))
    51                 return false;
    52 
    53             String bv = OsmUtils.getNamedOsmBoolean(r.boolValue);
    54 
    55             if (bv != null && !bv.equals(OsmUtils.getNamedOsmBoolean(k)))
    56                 return false;
    57         }
    58         return true;
    59     }
    60 }
  • src/org/openstreetmap/josm/gui/mappaint/xml/XmlCondition.java

     
    1 // License: GPL. For details, see LICENSE file.
    2 package org.openstreetmap.josm.gui.mappaint.xml;
    3 
    4 import org.openstreetmap.josm.data.osm.OsmUtils;
    5 
    6 public class XmlCondition {
    7 
    8     public String key;
    9     public String value;
    10     public String boolValue;
    11 
    12     public XmlCondition() {
    13       init();
    14     }
    15 
    16     public XmlCondition(XmlCondition c) {
    17       key = c.key;
    18       value = c.value;
    19       boolValue = c.boolValue;
    20     }
    21 
    22     public String getKey() {
    23         if (value != null)
    24             return 'n' + key + '=' + value;
    25         else if (boolValue != null)
    26             return 'b' + key  + '=' + OsmUtils.getNamedOsmBoolean(boolValue);
    27         else
    28             return 'x' + key;
    29     }
    30 
    31     public final void init() {
    32       key = value = boolValue = null;
    33     }
    34 
    35     @Override
    36     public String toString() {
    37       return "Rule["+key+','+(boolValue != null ? "b="+boolValue : "v="+value)+']';
    38     }
    39 
    40     public void appendCode(StringBuilder sb) {
    41         sb.append("[k=").append(key);
    42 
    43         if (boolValue != null)
    44             sb.append(",b=").append(boolValue);
    45         else
    46             sb.append(",v=").append(value);
    47 
    48         sb.append(']');
    49     }
    50 }
  • src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSource.java

     
    1 // License: GPL. For details, see LICENSE file.
    2 package org.openstreetmap.josm.gui.mappaint.xml;
    3 
    4 import static org.openstreetmap.josm.tools.I18n.tr;
    5 
    6 import java.io.IOException;
    7 import java.io.InputStream;
    8 import java.io.InputStreamReader;
    9 import java.nio.charset.StandardCharsets;
    10 import java.util.Collection;
    11 import java.util.Collections;
    12 import java.util.HashMap;
    13 import java.util.LinkedList;
    14 import java.util.List;
    15 import java.util.Map;
    16 
    17 import org.openstreetmap.josm.Main;
    18 import org.openstreetmap.josm.data.osm.Node;
    19 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    20 import org.openstreetmap.josm.data.osm.OsmUtils;
    21 import org.openstreetmap.josm.data.osm.Relation;
    22 import org.openstreetmap.josm.data.osm.Way;
    23 import org.openstreetmap.josm.gui.mappaint.Cascade;
    24 import org.openstreetmap.josm.gui.mappaint.Keyword;
    25 import org.openstreetmap.josm.gui.mappaint.MultiCascade;
    26 import org.openstreetmap.josm.gui.mappaint.Range;
    27 import org.openstreetmap.josm.gui.mappaint.StyleKeys;
    28 import org.openstreetmap.josm.gui.mappaint.StyleSource;
    29 import org.openstreetmap.josm.gui.preferences.SourceEntry;
    30 import org.openstreetmap.josm.io.CachedFile;
    31 import org.openstreetmap.josm.tools.Utils;
    32 import org.openstreetmap.josm.tools.XmlObjectParser;
    33 import org.xml.sax.SAXException;
    34 import org.xml.sax.SAXParseException;
    35 
    36 public class XmlStyleSource extends StyleSource implements StyleKeys {
    37 
    38     /**
    39      * The accepted MIME types sent in the HTTP Accept header.
    40      * @since 6867
    41      */
    42     public static final String XML_STYLE_MIME_TYPES =
    43             "application/xml, text/xml, text/plain; q=0.8, application/zip, application/octet-stream; q=0.5";
    44 
    45     protected final Map<String, IconPrototype> icons = new HashMap<>();
    46     protected final Map<String, LinePrototype> lines = new HashMap<>();
    47     protected final Map<String, LinemodPrototype> modifiers = new HashMap<>();
    48     protected final Map<String, AreaPrototype> areas = new HashMap<>();
    49     protected final List<IconPrototype> iconsList = new LinkedList<>();
    50     protected final List<LinePrototype> linesList = new LinkedList<>();
    51     protected final List<LinemodPrototype> modifiersList = new LinkedList<>();
    52     protected final List<AreaPrototype> areasList = new LinkedList<>();
    53 
    54     public XmlStyleSource(String url, String name, String shortdescription) {
    55         super(url, name, shortdescription);
    56     }
    57 
    58     public XmlStyleSource(SourceEntry entry) {
    59         super(entry);
    60     }
    61 
    62     @Override
    63     protected void init() {
    64         super.init();
    65         icons.clear();
    66         lines.clear();
    67         modifiers.clear();
    68         areas.clear();
    69         iconsList.clear();
    70         linesList.clear();
    71         modifiersList.clear();
    72         areasList.clear();
    73     }
    74 
    75     @Override
    76     public void loadStyleSource() {
    77         init();
    78         try {
    79             try (
    80                 InputStream in = getSourceInputStream();
    81                 InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8)
    82             ) {
    83                 XmlObjectParser parser = new XmlObjectParser(new XmlStyleSourceHandler(this));
    84                 parser.startWithValidation(reader,
    85                         Main.getXMLBase()+"/mappaint-style-1.0",
    86                         "resource://data/mappaint-style.xsd");
    87                 while (parser.hasNext());
    88             }
    89         } catch (IOException e) {
    90             Main.warn(tr("Failed to load Mappaint styles from ''{0}''. Exception was: {1}", url, e.toString()));
    91             Main.error(e);
    92             logError(e);
    93         } catch (SAXParseException e) {
    94             Main.warn(tr("Failed to parse Mappaint styles from ''{0}''. Error was: [{1}:{2}] {3}",
    95                     url, e.getLineNumber(), e.getColumnNumber(), e.getMessage()));
    96             Main.error(e);
    97             logError(e);
    98         } catch (SAXException e) {
    99             Main.warn(tr("Failed to parse Mappaint styles from ''{0}''. Error was: {1}", url, e.getMessage()));
    100             Main.error(e);
    101             logError(e);
    102         }
    103     }
    104 
    105     @Override
    106     public InputStream getSourceInputStream() throws IOException {
    107         CachedFile cf = getCachedFile();
    108         InputStream zip = cf.findZipEntryInputStream("xml", "style");
    109         if (zip != null) {
    110             zipIcons = cf.getFile();
    111             return zip;
    112         } else {
    113             zipIcons = null;
    114             return cf.getInputStream();
    115         }
    116     }
    117 
    118     @Override
    119     @SuppressWarnings("resource")
    120     public CachedFile getCachedFile() throws IOException {
    121         return new CachedFile(url).setHttpAccept(XML_STYLE_MIME_TYPES); // NOSONAR
    122     }
    123 
    124     private static class WayPrototypesRecord {
    125         public LinePrototype line;
    126         public List<LinemodPrototype> linemods;
    127         public AreaPrototype area;
    128     }
    129 
    130     private <T extends Prototype> T update(T current, T candidate, Double scale, MultiCascade mc) {
    131         if (requiresUpdate(current, candidate, scale, mc))
    132             return candidate;
    133         else
    134             return current;
    135     }
    136 
    137     /**
    138      * checks whether a certain match is better than the current match
    139      * @param current can be null
    140      * @param candidate the new Prototype that could be used instead
    141      * @param scale ignored if null, otherwise checks if scale is within the range of candidate
    142      * @param mc side effect: update the valid region for the current MultiCascade
    143      * @return {@code true} if {@code candidate} is better than the current match
    144      */
    145     private static boolean requiresUpdate(Prototype current, Prototype candidate, Double scale, MultiCascade mc) {
    146         if (current == null || candidate.priority >= current.priority) {
    147             if (scale == null)
    148                 return true;
    149 
    150             if (candidate.range.contains(scale)) {
    151                 mc.range = Range.cut(mc.range, candidate.range);
    152                 return true;
    153             } else {
    154                 mc.range = mc.range.reduceAround(scale, candidate.range);
    155                 return false;
    156             }
    157         }
    158         return false;
    159     }
    160 
    161     private IconPrototype getNode(OsmPrimitive primitive, Double scale, MultiCascade mc) {
    162         IconPrototype icon = null;
    163         for (String key : primitive.keySet()) {
    164             String val = primitive.get(key);
    165             IconPrototype p;
    166             if ((p = icons.get('n' + key + '=' + val)) != null) {
    167                 icon = update(icon, p, scale, mc);
    168             }
    169             if ((p = icons.get('b' + key + '=' + OsmUtils.getNamedOsmBoolean(val))) != null) {
    170                 icon = update(icon, p, scale, mc);
    171             }
    172             if ((p = icons.get('x' + key)) != null) {
    173                 icon = update(icon, p, scale, mc);
    174             }
    175         }
    176         for (IconPrototype s : iconsList) {
    177             if (s.check(primitive)) {
    178                 icon = update(icon, s, scale, mc);
    179             }
    180         }
    181         return icon;
    182     }
    183 
    184     /**
    185      * @param primitive OSM primitive
    186      * @param closed The primitive is a closed way or we pretend it is closed.
    187      *  This is useful for multipolygon relations and outer ways of untagged
    188      *  multipolygon relations.
    189      * @param p helper
    190      * @param scale scale
    191      * @param mc multi cascade
    192      */
    193     private void get(OsmPrimitive primitive, boolean closed, WayPrototypesRecord p, Double scale, MultiCascade mc) {
    194         String lineIdx = null;
    195         Map<String, LinemodPrototype> overlayMap = new HashMap<>();
    196         boolean isNotArea = primitive.isKeyFalse("area");
    197         for (String key : primitive.keySet()) {
    198             String val = primitive.get(key);
    199             AreaPrototype styleArea;
    200             LinePrototype styleLine;
    201             LinemodPrototype styleLinemod;
    202             String idx = 'n' + key + '=' + val;
    203             if ((styleArea = areas.get(idx)) != null && (closed || !styleArea.closed) && !isNotArea) {
    204                 p.area = update(p.area, styleArea, scale, mc);
    205             }
    206             if ((styleLine = lines.get(idx)) != null) {
    207                 if (requiresUpdate(p.line, styleLine, scale, mc)) {
    208                     p.line = styleLine;
    209                     lineIdx = idx;
    210                 }
    211             }
    212             if ((styleLinemod = modifiers.get(idx)) != null) {
    213                 if (requiresUpdate(null, styleLinemod, scale, mc)) {
    214                     overlayMap.put(idx, styleLinemod);
    215                 }
    216             }
    217             idx = 'b' + key + '=' + OsmUtils.getNamedOsmBoolean(val);
    218             if ((styleArea = areas.get(idx)) != null && (closed || !styleArea.closed) && !isNotArea) {
    219                 p.area = update(p.area, styleArea, scale, mc);
    220             }
    221             if ((styleLine = lines.get(idx)) != null) {
    222                 if (requiresUpdate(p.line, styleLine, scale, mc)) {
    223                     p.line = styleLine;
    224                     lineIdx = idx;
    225                 }
    226             }
    227             if ((styleLinemod = modifiers.get(idx)) != null) {
    228                 if (requiresUpdate(null, styleLinemod, scale, mc)) {
    229                     overlayMap.put(idx, styleLinemod);
    230                 }
    231             }
    232             idx = 'x' + key;
    233             if ((styleArea = areas.get(idx)) != null && (closed || !styleArea.closed) && !isNotArea) {
    234                 p.area = update(p.area, styleArea, scale, mc);
    235             }
    236             if ((styleLine = lines.get(idx)) != null) {
    237                 if (requiresUpdate(p.line, styleLine, scale, mc)) {
    238                     p.line = styleLine;
    239                     lineIdx = idx;
    240                 }
    241             }
    242             if ((styleLinemod = modifiers.get(idx)) != null) {
    243                 if (requiresUpdate(null, styleLinemod, scale, mc)) {
    244                     overlayMap.put(idx, styleLinemod);
    245                 }
    246             }
    247         }
    248         for (AreaPrototype s : areasList) {
    249             if ((closed || !s.closed) && !isNotArea && s.check(primitive)) {
    250                 p.area = update(p.area, s, scale, mc);
    251             }
    252         }
    253         for (LinePrototype s : linesList) {
    254             if (s.check(primitive)) {
    255                 p.line = update(p.line, s, scale, mc);
    256             }
    257         }
    258         for (LinemodPrototype s : modifiersList) {
    259             if (s.check(primitive)) {
    260                 if (requiresUpdate(null, s, scale, mc)) {
    261                     overlayMap.put(s.getCode(), s);
    262                 }
    263             }
    264         }
    265         overlayMap.remove(lineIdx); // do not use overlay if linestyle is from the same rule (example: railway=tram)
    266         if (!overlayMap.isEmpty()) {
    267             List<LinemodPrototype> tmp = new LinkedList<>();
    268             if (p.linemods != null) {
    269                 tmp.addAll(p.linemods);
    270             }
    271             tmp.addAll(overlayMap.values());
    272             Collections.sort(tmp);
    273             p.linemods = tmp;
    274         }
    275     }
    276 
    277     public void add(XmlCondition c, Collection<XmlCondition> conditions, Prototype prot) {
    278          if (conditions != null) {
    279             prot.conditions = conditions;
    280             if (prot instanceof IconPrototype) {
    281                 iconsList.add((IconPrototype) prot);
    282             } else if (prot instanceof LinemodPrototype) {
    283                 modifiersList.add((LinemodPrototype) prot);
    284             } else if (prot instanceof LinePrototype) {
    285                 linesList.add((LinePrototype) prot);
    286             } else if (prot instanceof AreaPrototype) {
    287                 areasList.add((AreaPrototype) prot);
    288             } else
    289                 throw new RuntimeException();
    290          } else {
    291              String key = c.getKey();
    292             prot.code = key;
    293             if (prot instanceof IconPrototype) {
    294                 icons.put(key, (IconPrototype) prot);
    295             } else if (prot instanceof LinemodPrototype) {
    296                modifiers.put(key, (LinemodPrototype) prot);
    297             } else if (prot instanceof LinePrototype) {
    298                 lines.put(key, (LinePrototype) prot);
    299             } else if (prot instanceof AreaPrototype) {
    300                 areas.put(key, (AreaPrototype) prot);
    301             } else
    302                 throw new RuntimeException();
    303          }
    304      }
    305 
    306     @Override
    307     public void apply(MultiCascade mc, OsmPrimitive osm, double scale, boolean pretendWayIsClosed) {
    308         Cascade def = mc.getOrCreateCascade("default");
    309         boolean useMinMaxScale = Main.pref.getBoolean("mappaint.zoomLevelDisplay", false);
    310 
    311         if (osm instanceof Node || (osm instanceof Relation && "restriction".equals(osm.get("type")))) {
    312             IconPrototype icon = getNode(osm, useMinMaxScale ? scale : null, mc);
    313             if (icon != null) {
    314                 def.put(ICON_IMAGE, icon.icon);
    315                 if (osm instanceof Node) {
    316                     if (icon.annotate != null) {
    317                         if (icon.annotate) {
    318                             def.put(TEXT, Keyword.AUTO);
    319                         } else {
    320                             def.remove(TEXT);
    321                         }
    322                     }
    323                 }
    324             }
    325         } else if (osm instanceof Way || (osm instanceof Relation && ((Relation) osm).isMultipolygon())) {
    326             WayPrototypesRecord p = new WayPrototypesRecord();
    327             get(osm, pretendWayIsClosed || !(osm instanceof Way) || ((Way) osm).isClosed(), p, useMinMaxScale ? scale : null, mc);
    328             if (p.line != null) {
    329                 def.put(WIDTH, new Float(p.line.getWidth()));
    330                 def.putOrClear(REAL_WIDTH, p.line.realWidth != null ? new Float(p.line.realWidth) : null);
    331                 def.putOrClear(COLOR, p.line.color);
    332                 if (p.line.color != null) {
    333                     int alpha = p.line.color.getAlpha();
    334                     if (alpha != 255) {
    335                         def.put(OPACITY, Utils.color_int2float(alpha));
    336                     }
    337                 }
    338                 def.putOrClear(DASHES, p.line.getDashed());
    339                 def.putOrClear(DASHES_BACKGROUND_COLOR, p.line.dashedColor);
    340             }
    341             Float refWidth = def.get(WIDTH, null, Float.class);
    342             if (refWidth != null && p.linemods != null) {
    343                 int numOver = 0, numUnder = 0;
    344 
    345                 while (mc.hasLayer(String.format("over_%d", ++numOver)));
    346                 while (mc.hasLayer(String.format("under_%d", ++numUnder)));
    347 
    348                 for (LinemodPrototype mod : p.linemods) {
    349                     Cascade c;
    350                     if (mod.over) {
    351                         String layer = String.format("over_%d", numOver);
    352                         c = mc.getOrCreateCascade(layer);
    353                         c.put(OBJECT_Z_INDEX, new Float(numOver));
    354                         ++numOver;
    355                     } else {
    356                         String layer = String.format("under_%d", numUnder);
    357                         c = mc.getOrCreateCascade(layer);
    358                         c.put(OBJECT_Z_INDEX, new Float(-numUnder));
    359                         ++numUnder;
    360                     }
    361                     c.put(WIDTH, new Float(mod.getWidth(refWidth)));
    362                     c.putOrClear(COLOR, mod.color);
    363                     if (mod.color != null) {
    364                         int alpha = mod.color.getAlpha();
    365                         if (alpha != 255) {
    366                             c.put(OPACITY, Utils.color_int2float(alpha));
    367                         }
    368                     }
    369                     c.putOrClear(DASHES, mod.getDashed());
    370                     c.putOrClear(DASHES_BACKGROUND_COLOR, mod.dashedColor);
    371                 }
    372             }
    373             if (p.area != null) {
    374                 def.putOrClear(FILL_COLOR, p.area.color);
    375                 def.putOrClear(TEXT_POSITION, Keyword.CENTER);
    376                 def.putOrClear(TEXT, Keyword.AUTO);
    377                 def.remove(FILL_IMAGE);
    378             }
    379         }
    380     }
    381 }
  • src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSourceHandler.java

     
    1 // License: GPL. For details, see LICENSE file.
    2 package org.openstreetmap.josm.gui.mappaint.xml;
    3 
    4 import java.awt.Color;
    5 import java.util.Arrays;
    6 import java.util.Collection;
    7 import java.util.LinkedList;
    8 
    9 import org.openstreetmap.josm.Main;
    10 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference;
    11 import org.openstreetmap.josm.gui.mappaint.Range;
    12 import org.openstreetmap.josm.tools.ColorHelper;
    13 import org.xml.sax.Attributes;
    14 import org.xml.sax.helpers.DefaultHandler;
    15 
    16 public class XmlStyleSourceHandler extends DefaultHandler {
    17     private boolean inDoc, inRule, inCondition, inLine, inLineMod, inIcon, inArea, inScaleMax, inScaleMin;
    18     private boolean hadLine, hadLineMod, hadIcon, hadArea;
    19     private final RuleElem rule = new RuleElem();
    20 
    21     private final XmlStyleSource style;
    22 
    23     static class RuleElem {
    24         private final XmlCondition cond = new XmlCondition();
    25         private Collection<XmlCondition> conditions;
    26         private double scaleMax;
    27         private double scaleMin;
    28         private final LinePrototype line = new LinePrototype();
    29         private final LinemodPrototype linemod = new LinemodPrototype();
    30         private final AreaPrototype area = new AreaPrototype();
    31         private IconPrototype icon = new IconPrototype();
    32         public void init() {
    33             conditions = null;
    34             scaleMax = Double.POSITIVE_INFINITY;
    35             scaleMin = 0;
    36             line.init();
    37             cond.init();
    38             linemod.init();
    39             area.init();
    40             icon.init();
    41         }
    42     }
    43 
    44     public XmlStyleSourceHandler(XmlStyleSource style) {
    45         this.style = style;
    46         inDoc = inRule = inCondition = inLine = inIcon = inArea = false;
    47         rule.init();
    48     }
    49 
    50     private Color convertColor(String colString) {
    51         int i = colString.indexOf('#');
    52         Color ret;
    53         if (i < 0) {
    54             ret = Main.pref.getColor("mappaint."+style.getPrefName()+'.'+colString, Color.red);
    55         } else if (i == 0) {
    56             ret = ColorHelper.html2color(colString);
    57         } else {
    58             ret = Main.pref.getColor("mappaint."+style.getPrefName()+'.'+colString.substring(0, i),
    59                     ColorHelper.html2color(colString.substring(i)));
    60         }
    61         return ret;
    62     }
    63 
    64     @Override
    65     public void startDocument() {
    66         inDoc = true;
    67     }
    68 
    69     @Override
    70     public void endDocument() {
    71         inDoc = false;
    72     }
    73 
    74     private void error(String message) {
    75         String warning = style.getDisplayString() + " (" + rule.cond.key + '=' + rule.cond.value + "): " + message;
    76         Main.warn(warning);
    77         style.logError(new Exception(warning));
    78     }
    79 
    80     private void startElementLine(String qName, Attributes atts, LinePrototype line) {
    81         for (int count = 0; count < atts.getLength(); count++) {
    82             switch (atts.getQName(count)) {
    83             case "width":
    84                 String val = atts.getValue(count);
    85                 if (!(val.startsWith("+") || val.startsWith("-") || val.endsWith("%"))) {
    86                     line.setWidth(Integer.parseInt(val));
    87                 }
    88                 break;
    89             case "colour":
    90                 line.color = convertColor(atts.getValue(count));
    91                 break;
    92             case "realwidth":
    93                 line.realWidth = Integer.valueOf(atts.getValue(count));
    94                 break;
    95             case "dashed":
    96                 Float[] dashed;
    97                 try {
    98                     String[] parts = atts.getValue(count).split(",");
    99                     dashed = new Float[parts.length];
    100                     for (int i = 0; i < parts.length; i++) {
    101                         dashed[i] = (float) Integer.parseInt(parts[i]);
    102                     }
    103                 } catch (NumberFormatException nfe) {
    104                     boolean isDashed = Boolean.parseBoolean(atts.getValue(count));
    105                     if (isDashed) {
    106                         dashed = new Float[]{9f};
    107                     } else {
    108                         dashed = null;
    109                     }
    110                 }
    111                 line.setDashed(dashed == null ? null : Arrays.asList(dashed));
    112                 break;
    113             case "dashedcolour":
    114                 line.dashedColor = convertColor(atts.getValue(count));
    115                 break;
    116             case "priority":
    117                 line.priority = Integer.parseInt(atts.getValue(count));
    118                 break;
    119             case "mode":
    120                 if (line instanceof LinemodPrototype)
    121                     break;
    122             default:
    123                 error("The element \"" + qName + "\" has unknown attribute \"" + atts.getQName(count) + "\"!");
    124             }
    125         }
    126     }
    127 
    128     private void startElementLinemod(String qName, Attributes atts, LinemodPrototype line) {
    129         startElementLine(qName, atts, line);
    130         for (int count = 0; count < atts.getLength(); count++) {
    131             switch (atts.getQName(count)) {
    132             case "width":
    133                 String val = atts.getValue(count);
    134                 if (val.startsWith("+")) {
    135                     line.setWidth(Integer.parseInt(val.substring(1)));
    136                     line.widthMode = LinemodPrototype.WidthMode.OFFSET;
    137                 } else if (val.startsWith("-")) {
    138                     line.setWidth(Integer.parseInt(val));
    139                     line.widthMode = LinemodPrototype.WidthMode.OFFSET;
    140                 } else if (val.endsWith("%")) {
    141                     line.setWidth(Integer.parseInt(val.substring(0, val.length()-1)));
    142                     line.widthMode = LinemodPrototype.WidthMode.PERCENT;
    143                 } else {
    144                     line.setWidth(Integer.parseInt(val));
    145                 }
    146                 break;
    147             case "mode":
    148                 line.over = !"under".equals(atts.getValue(count));
    149                 break;
    150             }
    151         }
    152     }
    153 
    154     @Override
    155     public void startElement(String uri, String name, String qName, Attributes atts) {
    156         if (inDoc) {
    157             switch(qName) {
    158             case "rule":
    159                 inRule = true;
    160                 break;
    161             case "rules":
    162                 if (style.name == null) {
    163                     style.name = atts.getValue("name");
    164                 }
    165                 if (style.title == null) {
    166                     style.title = atts.getValue("shortdescription");
    167                 }
    168                 if (style.icon == null) {
    169                     style.icon = atts.getValue("icon");
    170                 }
    171                 break;
    172             case "scale_max":
    173                 inScaleMax = true;
    174                 break;
    175             case "scale_min":
    176                 inScaleMin = true;
    177                 break;
    178             case "condition":
    179                 if (inRule) {
    180                     inCondition = true;
    181                     XmlCondition c = rule.cond;
    182                     if (c.key != null) {
    183                         if (rule.conditions == null) {
    184                             rule.conditions = new LinkedList<>();
    185                         }
    186                         rule.conditions.add(new XmlCondition(rule.cond));
    187                         c = new XmlCondition();
    188                         rule.conditions.add(c);
    189                     }
    190                     for (int count = 0; count < atts.getLength(); count++) {
    191                         switch (atts.getQName(count)) {
    192                         case "k":
    193                             c.key = atts.getValue(count);
    194                             break;
    195                         case "v":
    196                             c.value = atts.getValue(count);
    197                             break;
    198                         case "b":
    199                             c.boolValue = atts.getValue(count);
    200                             break;
    201                         default:
    202                             error("The element \"" + qName + "\" has unknown attribute \"" + atts.getQName(count) + "\"!");
    203                         }
    204                     }
    205                     if (c.key == null) {
    206                         error("The condition has no key!");
    207                     }
    208                 }
    209                 break;
    210             case "line":
    211                 hadLine = inLine = true;
    212                 startElementLine(qName, atts, rule.line);
    213                 break;
    214             case "linemod":
    215                 hadLineMod = inLineMod = true;
    216                 startElementLinemod(qName, atts, rule.linemod);
    217                 break;
    218             case "icon":
    219                 inIcon = true;
    220                 for (int count = 0; count < atts.getLength(); count++) {
    221                     switch (atts.getQName(count)) {
    222                     case "src":
    223                         IconReference icon = new IconReference(atts.getValue(count), style);
    224                         hadIcon = (icon != null);
    225                         rule.icon.icon = icon;
    226                         break;
    227                     case "annotate":
    228                         rule.icon.annotate = Boolean.valueOf(atts.getValue(count));
    229                         break;
    230                     case "priority":
    231                         rule.icon.priority = Integer.parseInt(atts.getValue(count));
    232                         break;
    233                     default:
    234                         error("The element \"" + qName + "\" has unknown attribute \"" + atts.getQName(count) + "\"!");
    235                     }
    236                 }
    237                 break;
    238             case "area":
    239                 hadArea = inArea = true;
    240                 for (int count = 0; count < atts.getLength(); count++) {
    241                     switch (atts.getQName(count)) {
    242                     case "colour":
    243                         rule.area.color = convertColor(atts.getValue(count));
    244                         break;
    245                     case "closed":
    246                         rule.area.closed = Boolean.parseBoolean(atts.getValue(count));
    247                         break;
    248                     case "priority":
    249                         rule.area.priority = Integer.parseInt(atts.getValue(count));
    250                         break;
    251                     default:
    252                         error("The element \"" + qName + "\" has unknown attribute \"" + atts.getQName(count) + "\"!");
    253                     }
    254                 }
    255                 break;
    256             default:
    257                 error("The element \"" + qName + "\" is unknown!");
    258             }
    259         }
    260     }
    261 
    262     @Override
    263     public void endElement(String uri, String name, String qName) {
    264         if (inRule && "rule".equals(qName)) {
    265             if (hadLine) {
    266                 style.add(rule.cond, rule.conditions,
    267                         new LinePrototype(rule.line, new Range(rule.scaleMin, rule.scaleMax)));
    268             }
    269             if (hadLineMod) {
    270                 style.add(rule.cond, rule.conditions,
    271                         new LinemodPrototype(rule.linemod, new Range(rule.scaleMin, rule.scaleMax)));
    272             }
    273             if (hadIcon) {
    274                 style.add(rule.cond, rule.conditions,
    275                         new IconPrototype(rule.icon, new Range(rule.scaleMin, rule.scaleMax)));
    276             }
    277             if (hadArea) {
    278                 style.add(rule.cond, rule.conditions,
    279                         new AreaPrototype(rule.area, new Range(rule.scaleMin, rule.scaleMax)));
    280             }
    281             inRule = false;
    282             hadLine = hadLineMod = hadIcon = hadArea = false;
    283             rule.init();
    284         } else if (inCondition && "condition".equals(qName)) {
    285             inCondition = false;
    286         } else if (inLine && "line".equals(qName)) {
    287             inLine = false;
    288         } else if (inLineMod && "linemod".equals(qName)) {
    289             inLineMod = false;
    290         } else if (inIcon && "icon".equals(qName)) {
    291             inIcon = false;
    292         } else if (inArea && "area".equals(qName)) {
    293             inArea = false;
    294         } else if ("scale_max".equals(qName)) {
    295             inScaleMax = false;
    296         } else if ("scale_min".equals(qName)) {
    297             inScaleMin = false;
    298         }
    299     }
    300 
    301     @Override
    302     public void characters(char[] ch, int start, int length) {
    303         if (inScaleMax) {
    304             rule.scaleMax = Long.parseLong(new String(ch, start, length));
    305         } else if (inScaleMin) {
    306             rule.scaleMin = Long.parseLong(new String(ch, start, length));
    307         }
    308     }
    309 }
  • src/org/openstreetmap/josm/gui/mappaint/xml/package-info.java

     
    1 // License: GPL. For details, see LICENSE file.
    2 
    3 /**
    4  * Drawing system based on XML map styles. This is a legacy system, not maintained anymore.
    5  * For reference, see <a href="https://josm.openstreetmap.de/wiki/Styles/LegacyStandard">JOSM wiki</a>
    6  */
    7 package org.openstreetmap.josm.gui.mappaint.xml;