diff --git a/data/validator/numeric.mapcss b/data/validator/numeric.mapcss
index 5d3abbb..24b3978 100644
|
a
|
b
|
|
| 2 | 2 | |
| 3 | 3 | *[layer =~ /\+.*/] { |
| 4 | 4 | throwWarning: tr("layer tag with + sign"); |
| | 5 | fixAdd: concat("layer=", substring(tag("layer"), 1)); |
| 5 | 6 | assertMatch: "node layer=+1"; |
| 6 | 7 | assertNoMatch: "node layer=1"; |
| 7 | 8 | assertNoMatch: "node layer=-1"; |
diff --git a/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java b/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
index 853ae9e..488d779 100644
|
a
|
b
|
import org.openstreetmap.josm.data.validation.Severity;
|
| 28 | 28 | import org.openstreetmap.josm.data.validation.Test; |
| 29 | 29 | import org.openstreetmap.josm.data.validation.TestError; |
| 30 | 30 | import org.openstreetmap.josm.gui.mappaint.Environment; |
| 31 | | import org.openstreetmap.josm.gui.mappaint.mapcss.ExpressionFactory; |
| | 31 | import org.openstreetmap.josm.gui.mappaint.mapcss.Expression; |
| 32 | 32 | import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction; |
| 33 | 33 | import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule; |
| 34 | 34 | import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource; |
| … |
… |
public class MapCSSTagChecker extends Test {
|
| 56 | 56 | |
| 57 | 57 | static class TagCheck implements Predicate<OsmPrimitive> { |
| 58 | 58 | protected final List<Selector> selector; |
| 59 | | protected final List<Tag> change = new ArrayList<Tag>(); |
| | 59 | protected final List<PrimitiveToTag> change = new ArrayList<PrimitiveToTag>(); |
| 60 | 60 | protected final Map<String, String> keyChange = new LinkedHashMap<String, String>(); |
| 61 | 61 | protected final List<Tag> alternatives = new ArrayList<Tag>(); |
| 62 | 62 | protected final Map<String, Severity> errors = new HashMap<String, Severity>(); |
| … |
… |
public class MapCSSTagChecker extends Test {
|
| 66 | 66 | this.selector = selector; |
| 67 | 67 | } |
| 68 | 68 | |
| | 69 | static abstract class PrimitiveToTag implements Utils.Function<OsmPrimitive, Tag> { |
| | 70 | |
| | 71 | static PrimitiveToTag ofMapCSSObject(final Object obj, final boolean keyOnly) { |
| | 72 | if (obj instanceof Expression) { |
| | 73 | return new PrimitiveToTag() { |
| | 74 | @Override |
| | 75 | public Tag apply(OsmPrimitive p) { |
| | 76 | final String s = (String) ((Expression) obj).evaluate(new Environment().withPrimitive(p)); |
| | 77 | return keyOnly? new Tag(s) : Tag.ofString(s); |
| | 78 | } |
| | 79 | }; |
| | 80 | } else if (obj instanceof String) { |
| | 81 | final Tag tag = keyOnly ? new Tag((String) obj) : Tag.ofString((String) obj); |
| | 82 | return new PrimitiveToTag() { |
| | 83 | @Override |
| | 84 | public Tag apply(OsmPrimitive ignore) { |
| | 85 | return tag; |
| | 86 | } |
| | 87 | }; |
| | 88 | } else { |
| | 89 | return null; |
| | 90 | } |
| | 91 | } |
| | 92 | } |
| | 93 | |
| 69 | 94 | static TagCheck ofMapCSSRule(final MapCSSRule rule) { |
| 70 | 95 | final TagCheck check = new TagCheck(rule.selectors); |
| 71 | 96 | for (Instruction i : rule.declaration) { |
| 72 | 97 | if (i instanceof Instruction.AssignmentInstruction) { |
| 73 | 98 | final Instruction.AssignmentInstruction ai = (Instruction.AssignmentInstruction) i; |
| 74 | | final String val = ai.val instanceof ExpressionFactory.ArrayFunction |
| 75 | | ? (String) ((ExpressionFactory.ArrayFunction) ai.val).evaluate(new Environment()) |
| | 99 | final String val = ai.val instanceof Expression |
| | 100 | ? (String) ((Expression) ai.val).evaluate(new Environment()) |
| 76 | 101 | : ai.val instanceof String |
| 77 | 102 | ? (String) ai.val |
| 78 | 103 | : null; |
| 79 | 104 | if (ai.key.startsWith("throw")) { |
| 80 | 105 | final Severity severity = Severity.valueOf(ai.key.substring("throw".length()).toUpperCase()); |
| 81 | 106 | check.errors.put(val, severity); |
| 82 | | } else if ("fixAdd".equals(ai.key) && val != null) { |
| 83 | | check.change.add(Tag.ofString(val)); |
| 84 | | } else if ("fixRemove".equals(ai.key) && val != null) { |
| 85 | | CheckParameterUtil.ensureThat(!val.contains("="), "Unexpected '='. Please only specify the key to remove!"); |
| 86 | | check.change.add(new Tag(val)); |
| | 107 | } else if ("fixAdd".equals(ai.key)) { |
| | 108 | final PrimitiveToTag toTag = PrimitiveToTag.ofMapCSSObject(ai.val, false); |
| | 109 | check.change.add(toTag); |
| | 110 | } else if ("fixRemove".equals(ai.key)) { |
| | 111 | CheckParameterUtil.ensureThat(!(ai.val instanceof String) || !val.contains("="), "Unexpected '='. Please only specify the key to remove!"); |
| | 112 | final PrimitiveToTag toTag = PrimitiveToTag.ofMapCSSObject(ai.val, true); |
| | 113 | check.change.add(toTag); |
| 87 | 114 | } else if ("fixChangeKey".equals(ai.key) && val != null) { |
| 88 | 115 | CheckParameterUtil.ensureThat(val.contains("=>"), "Separate old from new key by '=>'!"); |
| 89 | 116 | final String[] x = val.split("=>", 2); |
| … |
… |
public class MapCSSTagChecker extends Test {
|
| 158 | 185 | return null; |
| 159 | 186 | } |
| 160 | 187 | Collection<Command> cmds = new LinkedList<Command>(); |
| 161 | | for (Tag tag : change) { |
| | 188 | for (PrimitiveToTag toTag : change) { |
| | 189 | final Tag tag = toTag.apply(p); |
| 162 | 190 | cmds.add(new ChangePropertyCommand(p, tag.getKey(), tag.getValue())); |
| 163 | 191 | } |
| 164 | 192 | for (Map.Entry<String, String> i : keyChange.entrySet()) { |
diff --git a/src/org/openstreetmap/josm/gui/mappaint/Cascade.java b/src/org/openstreetmap/josm/gui/mappaint/Cascade.java
index 0a9107a..26c2eb2 100644
|
a
|
b
|
public final class Cascade implements Cloneable {
|
| 114 | 114 | } |
| 115 | 115 | |
| 116 | 116 | private static Float toFloat(Object o) { |
| 117 | | if (o instanceof Float) |
| 118 | | return (Float) o; |
| 119 | | if (o instanceof Double) |
| 120 | | return new Float((Double) o); |
| 121 | | if (o instanceof Integer) |
| 122 | | return new Float((Integer) o); |
| | 117 | if (o instanceof Number) |
| | 118 | return ((Number) o).floatValue(); |
| 123 | 119 | if (o instanceof String && !((String) o).isEmpty()) { |
| 124 | 120 | try { |
| 125 | 121 | return Float.parseFloat((String) o); |
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java
index a3fdb3f..a1a994c 100644
|
a
|
b
|
public final class ExpressionFactory {
|
| 364 | 364 | System.arraycopy(args, 1, args, 0, args.length - 1); |
| 365 | 365 | return org.openstreetmap.josm.tools.I18n.tr(text, args); |
| 366 | 366 | } |
| | 367 | |
| | 368 | public static String substring(String s, /* due to missing Cascade.convertTo for int*/ float begin) { |
| | 369 | return s == null ? null : s.substring((int) begin); |
| | 370 | } |
| | 371 | |
| | 372 | public static String substring(String s, float begin, float end) { |
| | 373 | return s == null ? null : s.substring((int) begin, (int) end); |
| | 374 | } |
| | 375 | |
| | 376 | public static int length(String s) { |
| | 377 | return s == null ? 0 : s.length(); |
| | 378 | } |
| 367 | 379 | } |
| 368 | 380 | |
| 369 | 381 | /** |
diff --git a/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java b/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java
index 567bb0b..43eb475 100644
|
a
|
b
|
public class MapCSSTagCheckerTest {
|
| 42 | 42 | assertThat(checks.size(), is(1)); |
| 43 | 43 | final MapCSSTagChecker.TagCheck check = checks.get(0); |
| 44 | 44 | assertThat(check, notNullValue()); |
| 45 | | assertThat(check.change.get(0), is(new Tag("natural"))); |
| 46 | | assertThat(check.change.get(1), is(new Tag("natural", "wetland"))); |
| 47 | | assertThat(check.change.get(2), is(new Tag("wetland", "marsh"))); |
| | 45 | assertThat(check.change.get(0).apply(null), is(new Tag("natural"))); |
| | 46 | assertThat(check.change.get(1).apply(null), is(new Tag("natural", "wetland"))); |
| | 47 | assertThat(check.change.get(2).apply(null), is(new Tag("wetland", "marsh"))); |
| 48 | 48 | assertThat(check.errors.keySet().iterator().next(), is("natural=marsh is deprecated")); |
| 49 | 49 | final Node n1 = new Node(); |
| 50 | 50 | n1.put("natural", "marsh"); |