Ticket #25017: #25017.patch
| File #25017.patch, 29.5 KB (added by , 22 minutes ago) |
|---|
-
src/org/openstreetmap/josm/data/validation/tests/TagChecker.java
### Eclipse Workspace Patch 1.0 #P josm diff --git src/org/openstreetmap/josm/data/validation/tests/TagChecker.java src/org/openstreetmap/josm/data/validation/tests/TagChecker.java index 7b501c6..8433975 100644
261 261 */ 262 262 private static void analysePresets() { 263 263 for (String key : TaggingPresets.getPresetKeys()) { 264 if (isKeyIgnored(key)) 264 if (isKeyIgnored(key)) { 265 265 continue; 266 Set<String> values = TaggingPresets.getPresetValues(key); 267 boolean allNumerical = !Utils.isEmpty(values) 266 } 267 final Set<String> values = TaggingPresets.getPresetValues(key); 268 final boolean allNumerical = !Utils.isEmpty(values) 268 269 && values.stream().allMatch(TagChecker::isNum); 269 270 if (allNumerical) { 270 271 ignoreForLevenshtein.add(key); … … 291 292 presetIndex.clear(); 292 293 ignoreForOuterMPSameTagCheck.clear(); 293 294 294 StringBuilder errorSources = new StringBuilder();295 final StringBuilder errorSources = new StringBuilder(); 295 296 for (String source : Config.getPref().getList(PREF_SOURCES, DEFAULT_SOURCES)) { 296 297 try ( 297 298 CachedFile cf = new CachedFile(source); … … 304 305 } 305 306 } 306 307 307 if (errorSources.length() > 0) 308 if (errorSources.length() > 0) { 308 309 throw new IOException(trn( 309 310 "Could not access data file:\n{0}", 310 311 "Could not access data files:\n{0}", errorSources.length(), errorSources)); 312 } 311 313 } 312 314 313 315 private static void parseSource(String source, BufferedReader reader) throws IOException { … … 337 339 } else if (line.charAt(0) == '+') { 338 340 okValue = line.substring(1); 339 341 } else if (line.charAt(0) == '-' && okValue != null) { 340 String hk = harmonizeKey(line.substring(1));342 final String hk = harmonizeKey(line.substring(1)); 341 343 if (!okValue.equals(hk) && harmonizedKeys.put(hk, okValue) != null && Logging.isDebugEnabled()) { 342 344 Logging.debug("Line was ignored: " + line); 343 345 } … … 364 366 return; 365 367 } 366 368 try { 367 String key = line.substring(0, 2);369 final String key = line.substring(0, 2); 368 370 line = line.substring(2); 369 371 370 372 switch (key) { … … 379 381 ignoreDataEndsWith.add(line); 380 382 break; 381 383 case "K:": 382 Tag tag = Tag.ofString(line);384 final Tag tag = Tag.ofString(line); 383 385 ignoreDataTag.add(tag); 384 386 oftenUsedTags.put(tag.getKey(), tag.getValue()); 385 387 addToKeyDictionary(tag.getKey()); … … 396 398 } 397 399 398 400 private static void addToKeyDictionary(String key) { 399 if (key != null) { 400 String hk = harmonizeKey(key); 401 if (!key.equals(hk)) { 402 harmonizedKeys.put(hk, key); 403 } 401 if (key == null) { 402 return; 403 } 404 final String hk = harmonizeKey(key); 405 if (!key.equals(hk)) { 406 harmonizedKeys.put(hk, key); 404 407 } 405 408 } 406 409 … … 410 413 */ 411 414 public static void initializePresets() { 412 415 413 if (!Config.getPref().getBoolean(PREF_CHECK_VALUES, true)) 416 if (!Config.getPref().getBoolean(PREF_CHECK_VALUES, true)) { 414 417 return; 418 } 415 419 416 Collection<TaggingPreset> presets = TaggingPresets.getTaggingPresets(); 417 if (!presets.isEmpty()) { 418 initAdditionalPresetsValueData(); 419 for (TaggingPreset p : presets) { 420 List<TaggingPresetItem> minData = new ArrayList<>(); 421 for (TaggingPresetItem i : p.data) { 422 if (i instanceof KeyedItem) { 423 if (!"none".equals(((KeyedItem) i).match())) 424 minData.add(i); 425 addPresetValue((KeyedItem) i); 426 } else if (i instanceof CheckGroup) { 427 for (Check c : ((CheckGroup) i).checks) { 428 if (!"none".equals(c.match())) 429 minData.add(c); 430 addPresetValue(c); 420 final Collection<TaggingPreset> presets = TaggingPresets.getTaggingPresets(); 421 if (presets.isEmpty()) { 422 return; 423 } 424 initAdditionalPresetsValueData(); 425 for (TaggingPreset p : presets) { 426 final List<TaggingPresetItem> minData = new ArrayList<>(); 427 for (TaggingPresetItem i : p.data) { 428 if (i instanceof KeyedItem) { 429 if (!"none".equals(((KeyedItem) i).match())) { 430 minData.add(i); 431 } 432 addPresetValue((KeyedItem) i); 433 } else if (i instanceof CheckGroup) { 434 for (Check c : ((CheckGroup) i).checks) { 435 if (!"none".equals(c.match())) { 436 minData.add(c); 431 437 } 438 addPresetValue(c); 432 439 } 433 440 } 434 if (!minData.isEmpty()) {435 presetIndex.put(p, minData);436 }441 } 442 if (!minData.isEmpty()) { 443 presetIndex.put(p, minData); 437 444 } 438 445 } 439 446 } … … 514 521 * @return {@code true} if the current unicode block is very unusual for the given key 515 522 */ 516 523 private static boolean isUnusualUnicodeBlock(String key, int c) { 517 UnicodeBlock b = UnicodeBlock.of(c);524 final UnicodeBlock b = UnicodeBlock.of(c); 518 525 return isUnusualPhoneticUse(key, b, c) || isUnusualBmpUse(b) || isUnusualSmpUse(b); 519 526 } 520 527 … … 579 586 if (TaggingPresets.isKeyInPresets(key)) { 580 587 return TaggingPresets.getPresetValues(key); 581 588 } 582 if (additionalPresetsValueData.contains(key)) 589 if (additionalPresetsValueData.contains(key)) { 583 590 return Collections.emptySet(); 591 } 584 592 // null means key is not known 585 593 return null; 586 594 } … … 625 633 * @since 9023 626 634 */ 627 635 public static boolean isTagIgnored(String key, String value) { 628 if (isKeyIgnored(key)) 636 if (isKeyIgnored(key)) { 629 637 return true; 638 } 630 639 final Set<String> values = getPresetValues(key); 631 if (values != null && values.isEmpty()) 640 if (values != null && values.isEmpty()) { 632 641 return true; 642 } 633 643 if (!isTagInPresets(key, value)) { 634 644 return ignoreDataTag.stream() 635 645 .anyMatch(a -> key.equals(a.getKey()) && value.equals(a.getValue())); … … 643 653 */ 644 654 @Override 645 655 public void check(OsmPrimitive p) { 646 if (!p.isTagged()) 656 if (!p.isTagged()) { 647 657 return; 658 } 648 659 649 660 // Just a collection to know if a primitive has been already marked with error 650 MultiMap<OsmPrimitive, String> withErrors = new MultiMap<>();661 final MultiMap<OsmPrimitive, String> withErrors = new MultiMap<>(); 651 662 652 663 for (Entry<String, String> prop : p.getKeys().entrySet()) { 653 String s = marktr("Tag ''{0}'' invalid.");654 String key = prop.getKey();655 String value = prop.getValue();664 final String s = marktr("Tag ''{0}'' invalid."); 665 final String key = prop.getKey(); 666 final String value = prop.getValue(); 656 667 657 668 if (checkKeys) { 658 669 checkSingleTagKeySimple(withErrors, p, s, key); … … 675 686 } 676 687 677 688 final Collection<TaggingPreset> matchingPresets; 678 TagMap tags;689 final TagMap tags; 679 690 if (checkPresetsTypes || checkRegions) { 680 691 tags = p.getKeys(); 681 692 matchingPresets = presetIndex.entrySet().stream() … … 703 714 * @param tags Tags from the primitive to check 704 715 */ 705 716 private void checkPresetsTypes(OsmPrimitive p, Collection<TaggingPreset> matchingPresets, Map<String, String> tags) { 706 TaggingPresetType presetType = TaggingPresetType.forPrimitive(p);707 EnumSet<TaggingPresetType> presetTypes = EnumSet.of(presetType);717 final TaggingPresetType presetType = TaggingPresetType.forPrimitive(p); 718 final EnumSet<TaggingPresetType> presetTypes = EnumSet.of(presetType); 708 719 709 Collection<TaggingPreset> matchingPresetsOK = matchingPresets.stream().filter(720 final Collection<TaggingPreset> matchingPresetsOK = matchingPresets.stream().filter( 710 721 tp -> tp.typeMatches(presetTypes)).collect(Collectors.toList()); 711 Collection<TaggingPreset> matchingPresetsKO = matchingPresets.stream().filter(722 final Collection<TaggingPreset> matchingPresetsKO = matchingPresets.stream().filter( 712 723 tp -> !tp.typeMatches(presetTypes)).collect(Collectors.toList()); 713 724 714 725 for (TaggingPreset tp : matchingPresetsKO) { 715 726 // Potential error, unless matching tags are all known by a supported preset 716 Map<String, String> matchingTags = tp.data.stream()727 final Map<String, String> matchingTags = tp.data.stream() 717 728 .filter(i -> Boolean.TRUE.equals(i.matches(tags))) 718 729 .filter(KeyedItem.class::isInstance).map(i -> ((KeyedItem) i).key) 719 730 .collect(Collectors.toMap(k -> k, tags::get, (o, n) -> n)); … … 737 748 * @param matchingPresets The presets to check against 738 749 */ 739 750 private void checkRegions(OsmPrimitive p, Collection<TaggingPreset> matchingPresets) { 740 LatLon center;751 final LatLon center; 741 752 if (p instanceof Node) { 742 753 center = ((Node) p).getCoor(); 743 754 } else { … … 809 820 */ 810 821 private void tagCheckReal(TaggingPreset preset, OsmPrimitive p, LatLon center, RegionSpecific data) { 811 822 // First, check if we aren't in the region for the tag 812 if ( latLonInRegions(center, data.regions()) == data.exclude_regions()823 if (!(latLonInRegions(center, data.regions()) == data.exclude_regions() 813 824 // Check to ensure that no nodes are in the region if the center is not in the region 814 && !primitiveInRegions(p, data.regions(), data.exclude_regions())) { 815 final String key; 816 final String value; 817 if (data instanceof PresetListEntry) { 818 key = ((PresetListEntry) data).cms.key; 819 value = ((PresetListEntry) data).value; 820 } else if (data instanceof KeyedItem) { 821 key = ((KeyedItem) data).key; 822 if (data instanceof Key) { 823 value = ((Key) data).value; 824 } else { 825 value = null; 826 } 825 && !primitiveInRegions(p, data.regions(), data.exclude_regions()))) { 826 return; 827 } 828 final String key; 829 final String value; 830 if (data instanceof PresetListEntry) { 831 key = ((PresetListEntry) data).cms.key; 832 value = ((PresetListEntry) data).value; 833 } else if (data instanceof KeyedItem) { 834 key = ((KeyedItem) data).key; 835 if (data instanceof Key) { 836 value = ((Key) data).value; 827 837 } else { 828 throw new JosmRuntimeException("Unknown implementor for RegionSpecific");838 value = null; 829 839 } 830 if (p.hasTag(key) && (value == null || value.equals(p.get(key)))) { 831 final TestError.Builder builder = TestError.builder(this, Severity.WARNING, INVALID_REGION) 832 .primitives(p); 833 if (value == null) { 834 builder.message(tr("Key from a preset is invalid in this region"), 835 marktr("Preset {0} should not have the key {1}"), 836 preset.getLocaleName(), key); 837 } else { 838 builder.message(tr("Value from a preset is invalid in this region"), 839 marktr("Preset {0} should not have the tag {1}={2}"), 840 preset.getLocaleName(), key, value); 841 } 842 errors.add(builder.build()); 840 } else { 841 throw new JosmRuntimeException("Unknown implementor for RegionSpecific"); 842 } 843 if (p.hasTag(key) && (value == null || value.equals(p.get(key)))) { 844 final TestError.Builder builder = TestError.builder(this, Severity.WARNING, INVALID_REGION) 845 .primitives(p); 846 if (value == null) { 847 builder.message(tr("Key from a preset is invalid in this region"), 848 marktr("Preset {0} should not have the key {1}"), 849 preset.getLocaleName(), key); 850 } else { 851 builder.message(tr("Value from a preset is invalid in this region"), 852 marktr("Preset {0} should not have the tag {1}={2}"), 853 preset.getLocaleName(), key, value); 843 854 } 855 errors.add(builder.build()); 844 856 } 845 857 } 846 858 … … 893 905 894 906 private void checkMultipolygonTags(OsmPrimitive p) { 895 907 if (p.isAnnotated() || p.keys() 896 .anyMatch(k -> k.matches("^(abandoned|construction|demolished|disused|planned|razed|removed|was).*"))) 908 .anyMatch(k -> k.matches("^(abandoned|construction|demolished|disused|planned|razed|removed|was).*"))) { 897 909 return; 910 } 898 911 899 912 checkOuterWaysOfRelation((Relation) p); 900 913 901 if (hasAcceptedPrimaryTagForMultipolygon(p)) 914 if (hasAcceptedPrimaryTagForMultipolygon(p)) { 902 915 return; 916 } 903 917 TestError.Builder builder = null; 904 918 if (p.hasKey("surface")) { 905 919 // accept often used tag surface=* as area tag 906 920 builder = TestError.builder(this, Severity.OTHER, MULTIPOLYGON_INCOMPLETE) 907 921 .message(tr(MULTIPOLYGON_TAGS), marktr("only {0} tag"), "surface"); 908 922 } else { 909 Map<String, String> filteredTags = p.getInterestingTags();923 final Map<String, String> filteredTags = p.getInterestingTags(); 910 924 filteredTags.remove("type"); 911 925 NO_AREA_KEYS.forEach(filteredTags::remove); 912 926 filteredTags.keySet().removeIf(key -> !key.matches("[a-z0-9:_]+")); … … 931 945 */ 932 946 private void checkOuterWaysOfRelation(Relation rel) { 933 947 for (Entry<String, String> tag : rel.getInterestingTags().entrySet()) { 934 if (ignoreForOuterMPSameTagCheck.contains(tag.getKey())) 948 if (ignoreForOuterMPSameTagCheck.contains(tag.getKey())) { 935 949 continue; 950 } 936 951 937 Set<Way> sameOuters = rel.getMembers().stream()952 final Set<Way> sameOuters = rel.getMembers().stream() 938 953 .filter(rm -> rm.isWay() && rm.getWay().isArea() && "outer".equals(rm.getRole()) 939 954 && tag.getValue().equals(rm.getWay().get(tag.getKey()))) 940 955 .map(RelationMember::getWay).collect(Collectors.toSet()); 941 956 if (!sameOuters.isEmpty()) { 942 List<OsmPrimitive> primitives = new ArrayList<>(sameOuters.size() + 1);957 final List<OsmPrimitive> primitives = new ArrayList<>(sameOuters.size() + 1); 943 958 primitives.add(rel); 944 959 primitives.addAll(sameOuters); 945 Way w = new Way();960 final Way w = new Way(); 946 961 w.put(tag.getKey(), tag.getValue()); 947 962 if (hasAcceptedPrimaryTagForMultipolygon(w)) { 948 963 errors.add(TestError.builder(this, Severity.WARNING, MULTIPOLYGON_SAME_TAG_ON_OUTER) … … 976 991 "speed_camera", "traffic_mirror", "trailhead", "turning_circle", "turning_loop", "toll_gantry") 977 992 || p.hasTagDifferent("tourism", "attraction", "artwork") 978 993 || p.hasTagDifferent("leisure", "picnic_table", "slipway", "firepit") 979 || p.hasTagDifferent("historic", "wayside_cross", "milestone")) 994 || p.hasTagDifferent("historic", "wayside_cross", "milestone")) { 980 995 return true; 996 } 981 997 if (p.hasTag("barrier", "hedge", "retaining_wall") 982 998 || p.hasTag("public_transport", "platform", "station") 983 999 || p.hasTag("railway", "platform") … … 986 1002 || p.hasTag("power", "substation", "generator", "plant", "switchgear", "converter", "sub_station") 987 1003 || p.hasTag(SEAMARK_TYPE, "harbour", "fairway", "anchorage", "landmark", "berth", "harbour_basin", 988 1004 "separation_zone") 989 || (p.get(SEAMARK_TYPE) != null && p.get(SEAMARK_TYPE).matches(".*\\_(area|zone)$"))) 1005 || (p.get(SEAMARK_TYPE) != null && p.get(SEAMARK_TYPE).matches(".*\\_(area|zone)$"))) { 990 1006 return true; 1007 } 991 1008 return p.hasTag("harbour", OsmUtils.TRUE_VALUE) 992 1009 || p.hasTag("flood_prone", OsmUtils.TRUE_VALUE) 993 1010 || p.hasTag("bridge", OsmUtils.TRUE_VALUE) … … 996 1013 } 997 1014 998 1015 private void checkSingleTagValueSimple(MultiMap<OsmPrimitive, String> withErrors, OsmPrimitive p, String s, String key, String value) { 999 if (!checkValues || value == null) 1016 if (!checkValues || value == null) { 1000 1017 return; 1018 } 1001 1019 if (containsUnwantedNonPrintingControlCharacter(value) && !withErrors.contains(p, "ICV")) { 1002 1020 errors.add(TestError.builder(this, Severity.WARNING, LOW_CHAR_VALUE) 1003 1021 .message(tr("Tag value contains non-printing (usually invisible) character"), s, key) … … 1045 1063 .build()); 1046 1064 withErrors.put(p, errTypeSpace); 1047 1065 } 1048 if (includeOtherSeverity && !value.equals(Entities.unescape(value)) && !withErrors.contains(p, "HTML")) { 1049 errors.add(TestError.builder(this, Severity.OTHER, INVALID_HTML) 1050 .message(tr("Property values contain HTML entity"), s, key) 1051 .primitives(p) 1052 .build()); 1053 withErrors.put(p, "HTML"); 1066 if (!(includeOtherSeverity && !value.equals(Entities.unescape(value)) && !withErrors.contains(p, "HTML"))) { 1067 return; 1054 1068 } 1069 errors.add(TestError.builder(this, Severity.OTHER, INVALID_HTML) 1070 .message(tr("Property values contain HTML entity"), s, key) 1071 .primitives(p) 1072 .build()); 1073 withErrors.put(p, "HTML"); 1055 1074 } 1056 1075 1057 1076 private void checkSingleTagKeySimple(MultiMap<OsmPrimitive, String> withErrors, OsmPrimitive p, String s, String key) { 1058 if (!checkKeys || key == null) 1077 if (!checkKeys || key == null) { 1059 1078 return; 1079 } 1060 1080 if (containsUnwantedNonPrintingControlCharacter(key) && !withErrors.contains(p, "ICK")) { 1061 1081 errors.add(TestError.builder(this, Severity.WARNING, LOW_CHAR_KEY) 1062 1082 .message(tr("Tag key contains non-printing character"), s, key) … … 1073 1093 .build()); 1074 1094 withErrors.put(p, "LK"); 1075 1095 } 1076 if (key.indexOf(' ') >= 0 && !withErrors.contains(p, "IPK")) { 1077 errors.add(TestError.builder(this, Severity.WARNING, INVALID_KEY_SPACE) 1078 .message(tr("Invalid white space in property key"), s, key) 1079 .primitives(p) 1080 .build()); 1081 withErrors.put(p, "IPK"); 1096 if (!(key.indexOf(' ') >= 0 && !withErrors.contains(p, "IPK"))) { 1097 return; 1082 1098 } 1099 errors.add(TestError.builder(this, Severity.WARNING, INVALID_KEY_SPACE) 1100 .message(tr("Invalid white space in property key"), s, key) 1101 .primitives(p) 1102 .build()); 1103 withErrors.put(p, "IPK"); 1083 1104 } 1084 1105 1085 1106 private void checkSingleTagComplex(MultiMap<OsmPrimitive, String> withErrors, OsmPrimitive p, String key, String value) { 1086 if (!checkValues || key == null || Utils.isEmpty(value)) 1107 if (!checkValues || key == null || Utils.isEmpty(value)) { 1087 1108 return; 1109 } 1088 1110 if (additionalPresetsValueData != null && !isTagIgnored(key, value)) { 1089 1111 if (!TaggingPresets.isKeyInPresets(key)) { 1090 1112 spellCheckKey(withErrors, p, key); … … 1105 1127 } 1106 1128 1107 1129 private void spellCheckKey(MultiMap<OsmPrimitive, String> withErrors, OsmPrimitive p, String key) { 1108 String prettifiedKey = harmonizeKey(key);1130 final String prettifiedKey = harmonizeKey(key); 1109 1131 String fixedKey; 1110 1132 if (ignoreDataEquals.contains(prettifiedKey)) { 1111 1133 fixedKey = prettifiedKey; … … 1140 1162 private void tryGuess(OsmPrimitive p, String key, String value, MultiMap<OsmPrimitive, String> withErrors) { 1141 1163 // try to fix common typos and check again if value is still unknown 1142 1164 final String harmonizedValue = harmonizeValue(value); 1143 if (Utils.isEmpty(harmonizedValue)) 1165 if (Utils.isEmpty(harmonizedValue)) { 1144 1166 return; 1167 } 1145 1168 String fixedValue; 1146 List<Set<String>> sets = new ArrayList<>();1147 Set<String> presetValues = getPresetValues(key);1148 if (presetValues != null) 1169 final List<Set<String>> sets = new ArrayList<>(); 1170 final Set<String> presetValues = getPresetValues(key); 1171 if (presetValues != null) { 1149 1172 sets.add(presetValues); 1150 Set<String> usedValues = oftenUsedTags.get(key); 1151 if (usedValues != null) 1173 } 1174 final Set<String> usedValues = oftenUsedTags.get(key); 1175 if (usedValues != null) { 1152 1176 sets.add(usedValues); 1177 } 1153 1178 fixedValue = sets.stream().anyMatch(possibleValues -> possibleValues.contains(harmonizedValue)) 1154 1179 ? harmonizedValue : null; 1155 1180 if (fixedValue == null && !ignoreForLevenshtein.contains(key)) { 1156 1181 int maxPresetValueLen = 0; 1157 List<String> fixVals = new ArrayList<>();1182 final List<String> fixVals = new ArrayList<>(); 1158 1183 // use Levenshtein distance to find typical typos 1159 1184 int minDist = MAX_LEVENSHTEIN_DISTANCE + 1; 1160 1185 for (Set<String> possibleValues: sets) { 1161 1186 for (String possibleVal : possibleValues) { 1162 if (possibleVal.isEmpty()) 1187 if (possibleVal.isEmpty()) { 1163 1188 continue; 1189 } 1164 1190 maxPresetValueLen = Math.max(maxPresetValueLen, possibleVal.length()); 1165 1191 if (harmonizedValue.length() < 3 && possibleVal.length() >= harmonizedValue.length() + MAX_LEVENSHTEIN_DISTANCE) { 1166 1192 // don't suggest fix value when given value is short and lengths are too different 1167 1193 // for example surface=u would result in surface=mud 1168 1194 continue; 1169 1195 } 1170 int dist = Utils.getLevenshteinDistance(possibleVal, harmonizedValue);1196 final int dist = Utils.getLevenshteinDistance(possibleVal, harmonizedValue); 1171 1197 if (dist >= harmonizedValue.length()) { 1172 1198 // short value, all characters are different. Don't warn, might say Value '10' for key 'fee' looks like 'no'. 1173 1199 continue; … … 1183 1209 } 1184 1210 if (minDist <= MAX_LEVENSHTEIN_DISTANCE && maxPresetValueLen > MAX_LEVENSHTEIN_DISTANCE 1185 1211 && !fixVals.isEmpty() 1212 && harmonizedValue != null 1186 1213 && (harmonizedValue.length() > 3 || minDist < MAX_LEVENSHTEIN_DISTANCE)) { 1187 1214 filterDeprecatedTags(p, key, fixVals); 1188 1215 if (!fixVals.isEmpty()) { … … 1224 1251 1225 1252 // see #19180 1226 1253 private void filterDeprecatedTags(OsmPrimitive p, String key, List<String> fixVals) { 1227 if (fixVals.isEmpty() || deprecatedChecker == null) 1254 if (fixVals.isEmpty() || deprecatedChecker == null) { 1228 1255 return; 1256 } 1229 1257 1230 int unchangedDeprecated = countDeprecated(p);1258 final int unchangedDeprecated = countDeprecated(p); 1231 1259 1232 1260 // see #19895: create deep clone. This complex method works even with locked files 1233 MergeSourceBuildingVisitor builder = new MergeSourceBuildingVisitor(p.getDataSet());1261 final MergeSourceBuildingVisitor builder = new MergeSourceBuildingVisitor(p.getDataSet()); 1234 1262 p.accept(builder); 1235 DataSet clonedDs = builder.build();1236 OsmPrimitive clone = clonedDs.getPrimitiveById(p.getPrimitiveId());1263 final DataSet clonedDs = builder.build(); 1264 final OsmPrimitive clone = clonedDs.getPrimitiveById(p.getPrimitiveId()); 1237 1265 1238 Iterator<String> iter = fixVals.iterator();1266 final Iterator<String> iter = fixVals.iterator(); 1239 1267 while (iter.hasNext()) { 1240 1268 clone.put(key, iter.next()); 1241 if (countDeprecated(clone) > unchangedDeprecated) 1269 if (countDeprecated(clone) > unchangedDeprecated) { 1242 1270 iter.remove(); 1271 } 1243 1272 } 1244 1273 } 1245 1274 1246 1275 private int countDeprecated(OsmPrimitive p) { 1247 if (deprecatedChecker == null) 1276 if (deprecatedChecker == null) { 1248 1277 return 0; 1278 } 1249 1279 deprecatedChecker.getErrors().clear(); 1250 1280 deprecatedChecker.visit(Collections.singleton(p), url -> url.endsWith("deprecated.mapcss")); 1251 1281 return deprecatedChecker.getErrors().size(); … … 1326 1356 1327 1357 @Override 1328 1358 public void addGui(JPanel testPanel) { 1329 GBC a = GBC.eol();1359 final GBC a = GBC.eol(); 1330 1360 a.anchor = GridBagConstraints.LINE_END; 1331 1361 1332 1362 testPanel.add(new JLabel(name+" :"), GBC.eol().insets(3, 0, 0, 0)); … … 1353 1383 testPanel.add(new JLabel(tr("Data sources ({0})", "*.cfg")), GBC.eol().insets(23, 0, 0, 0)); 1354 1384 testPanel.add(sourcesList, GBC.eol().fill(GridBagConstraints.HORIZONTAL).insets(23, 0, 0, 0)); 1355 1385 1356 ActionListener disableCheckActionListener = e -> handlePrefEnable();1386 final ActionListener disableCheckActionListener = e -> handlePrefEnable(); 1357 1387 prefCheckKeys.addActionListener(disableCheckActionListener); 1358 1388 prefCheckKeysBeforeUpload.addActionListener(disableCheckActionListener); 1359 1389 prefCheckComplex.addActionListener(disableCheckActionListener); … … 1398 1428 * Enables/disables the source list field 1399 1429 */ 1400 1430 public void handlePrefEnable() { 1401 boolean selected = prefCheckKeys.isSelected() || prefCheckKeysBeforeUpload.isSelected()1431 final boolean selected = prefCheckKeys.isSelected() || prefCheckKeysBeforeUpload.isSelected() 1402 1432 || prefCheckComplex.isSelected() || prefCheckComplexBeforeUpload.isSelected(); 1403 1433 sourcesList.setEnabled(selected); 1404 1434 } … … 1426 1456 1427 1457 @Override 1428 1458 public Command fixError(TestError testError) { 1429 List<Command> commands = new ArrayList<>(50);1459 final List<Command> commands = new ArrayList<>(50); 1430 1460 1431 Collection<? extends OsmPrimitive> primitives = testError.getPrimitives();1461 final Collection<? extends OsmPrimitive> primitives = testError.getPrimitives(); 1432 1462 for (OsmPrimitive p : primitives) { 1433 Map<String, String> tags = p.getKeys();1463 final Map<String, String> tags = p.getKeys(); 1434 1464 if (tags.isEmpty()) { 1435 1465 continue; 1436 1466 } 1437 1467 1438 1468 for (Entry<String, String> prop: tags.entrySet()) { 1439 String key = prop.getKey();1440 String value = prop.getValue();1469 final String key = prop.getKey(); 1470 final String value = prop.getValue(); 1441 1471 if (Utils.isStripEmpty(value)) { 1442 1472 commands.add(new ChangePropertyCommand(p, key, null)); 1443 1473 } else if (value.startsWith(" ") || value.endsWith(" ") || value.contains(" ")) { … … 1445 1475 } else if (key.startsWith(" ") || key.endsWith(" ") || key.contains(" ")) { 1446 1476 commands.add(new ChangePropertyKeyCommand(p, key, Utils.removeWhiteSpaces(key))); 1447 1477 } else { 1448 String evalue = Entities.unescape(value);1478 final String evalue = Entities.unescape(value); 1449 1479 if (!evalue.equals(value)) { 1450 1480 commands.add(new ChangePropertyCommand(p, key, evalue)); 1451 1481 } … … 1453 1483 } 1454 1484 } 1455 1485 1456 if (commands.isEmpty()) 1486 if (commands.isEmpty()) { 1457 1487 return null; 1458 if (commands.size() == 1) 1488 } 1489 if (commands.size() == 1) { 1459 1490 return commands.get(0); 1491 } 1460 1492 1461 1493 return new SequenceCommand(tr("Fix tags"), commands); 1462 1494 } 1463 1495 1464 1496 @Override 1465 1497 public boolean isFixable(TestError testError) { 1466 if (testError.getTester() instanceof TagChecker) { 1467 int code = testError.getCode(); 1468 return code == EMPTY_VALUES || code == INVALID_SPACE || 1469 code == INVALID_KEY_SPACE || code == INVALID_HTML || 1470 code == MULTIPLE_SPACES; 1498 if (!(testError.getTester() instanceof TagChecker)) { 1499 return false; 1471 1500 } 1472 1473 return false; 1501 final int code = testError.getCode(); 1502 return code == EMPTY_VALUES || code == INVALID_SPACE || 1503 code == INVALID_KEY_SPACE || code == INVALID_HTML || 1504 code == MULTIPLE_SPACES; 1474 1505 } 1475 1506 1476 1507 @Override
