Changeset 11129 in josm
- Timestamp:
- 2016-10-15T00:17:47+02:00 (8 years ago)
- Location:
- trunk
- Files:
-
- 1 deleted
- 34 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/validation/TestError.java
r10880 r11129 2 2 package org.openstreetmap.josm.data.validation; 3 3 4 import java.text.MessageFormat; 4 5 import java.util.ArrayList; 6 import java.util.Arrays; 5 7 import java.util.Collection; 6 8 import java.util.Collections; 7 9 import java.util.List; 10 import java.util.Locale; 8 11 import java.util.TreeSet; 12 import java.util.function.Supplier; 9 13 10 14 import org.openstreetmap.josm.Main; … … 26 30 import org.openstreetmap.josm.data.validation.util.MultipleNameVisitor; 27 31 import org.openstreetmap.josm.tools.AlphanumComparator; 32 import org.openstreetmap.josm.tools.CheckParameterUtil; 33 import org.openstreetmap.josm.tools.I18n; 28 34 29 35 /** … … 39 45 private String message; 40 46 /** Deeper error description */ 41 private String description;42 private String descriptionEn;47 private final String description; 48 private final String descriptionEn; 43 49 /** The affected primitives */ 44 50 private Collection<? extends OsmPrimitive> primitives; 45 51 /** The primitives or way segments to be highlighted */ 46 private Collection<?> highlighted;52 private final Collection<?> highlighted; 47 53 /** The tester that raised this error */ 48 54 private Test tester; 49 55 /** Internal code used by testers to classify errors */ 50 private int code;56 private final int code; 51 57 /** If this error is selected */ 52 58 private boolean selected; 59 /** Supplying a command to fix the error */ 60 private final Supplier<Command> fixingCommand; 61 62 /** 63 * A builder for a {@code TestError}. 64 * @since 11129 65 */ 66 public static final class Builder { 67 private final Test tester; 68 private final Severity severity; 69 private final int code; 70 private String message; 71 private String description; 72 private String descriptionEn; 73 private Collection<? extends OsmPrimitive> primitives; 74 private Collection<?> highlighted; 75 private Supplier<Command> fixingCommand; 76 77 private Builder(Test tester, Severity severity, int code) { 78 this.tester = tester; 79 this.severity = severity; 80 this.code = code; 81 } 82 83 /** 84 * Sets the error message. 85 * 86 * @param message The error message 87 * @return {@code this} 88 */ 89 public Builder message(String message) { 90 this.message = message; 91 return this; 92 } 93 94 /** 95 * Sets the error message. 96 * 97 * @param message The the message of this error group 98 * @param description The translated description of this error 99 * @param descriptionEn The English description (for ignoring errors) 100 * @return {@code this} 101 */ 102 public Builder messageWithManuallyTranslatedDescription(String message, String description, String descriptionEn) { 103 this.message = message; 104 this.description = description; 105 this.descriptionEn = descriptionEn; 106 return this; 107 } 108 109 /** 110 * Sets the error message. 111 * 112 * @param message The the message of this error group 113 * @param marktrDescription The {@linkplain I18n#marktr prepared for i18n} description of this error 114 * @param args The description arguments to be applied in {@link I18n#tr(String, Object...)} 115 * @return {@code this} 116 */ 117 public Builder message(String message, String marktrDescription, Object... args) { 118 this.message = message; 119 this.description = I18n.tr(marktrDescription, args); 120 this.descriptionEn = new MessageFormat(marktrDescription, Locale.ENGLISH).format(args); 121 return this; 122 } 123 124 /** 125 * Sets the primitives affected by this error. 126 * 127 * @param primitives the primitives affected by this error 128 * @return {@code this} 129 */ 130 public Builder primitives(OsmPrimitive... primitives) { 131 return primitives(Arrays.asList(primitives)); 132 } 133 134 /** 135 * Sets the primitives affected by this error. 136 * 137 * @param primitives the primitives affected by this error 138 * @return {@code this} 139 */ 140 public Builder primitives(Collection<? extends OsmPrimitive> primitives) { 141 CheckParameterUtil.ensureThat(this.primitives != null, "primitives already set"); 142 this.primitives = primitives; 143 return this; 144 } 145 146 /** 147 * Sets the primitives to highlight when selecting this error. 148 * 149 * @param highlighted the primitives to highlight 150 * @return {@code this} 151 * @see ValidatorVisitor#visit(OsmPrimitive) 152 */ 153 public Builder highlight(OsmPrimitive... highlighted) { 154 return highlight(Arrays.asList(highlighted)); 155 } 156 157 /** 158 * Sets the primitives to highlight when selecting this error. 159 * 160 * @param highlighted the primitives to highlight 161 * @return {@code this} 162 * @see ValidatorVisitor#visit(OsmPrimitive) 163 */ 164 public Builder highlight(Collection<? extends OsmPrimitive> highlighted) { 165 CheckParameterUtil.ensureThat(this.highlighted != null, "highlighted already set"); 166 this.highlighted = highlighted; 167 return this; 168 } 169 170 /** 171 * Sets the way segments to highlight when selecting this error. 172 * 173 * @param highlighted the way segments to highlight 174 * @return {@code this} 175 * @see ValidatorVisitor#visit(WaySegment) 176 */ 177 public Builder highlightWaySegments(Collection<WaySegment> highlighted) { 178 CheckParameterUtil.ensureThat(this.highlighted != null, "highlighted already set"); 179 this.highlighted = highlighted; 180 return this; 181 } 182 183 /** 184 * Sets the node pairs to highlight when selecting this error. 185 * 186 * @param highlighted the node pairs to highlight 187 * @return {@code this} 188 * @see ValidatorVisitor#visit(List) 189 */ 190 public Builder highlightNodePairs(Collection<List<Node>> highlighted) { 191 CheckParameterUtil.ensureThat(this.highlighted != null, "highlighted already set"); 192 this.highlighted = highlighted; 193 return this; 194 } 195 196 /** 197 * Sets a supplier to obtain a command to fix the error. 198 * 199 * @param fixingCommand the fix supplier 200 * @return {@code this} 201 */ 202 public Builder fix(Supplier<Command> fixingCommand) { 203 CheckParameterUtil.ensureThat(this.fixingCommand != null, "fixingCommand already set"); 204 this.fixingCommand = fixingCommand; 205 return this; 206 } 207 208 /** 209 * Returns a new test error with the specified values 210 * 211 * @return a new test error with the specified values 212 * @throws IllegalArgumentException when {@link #message} or {@link #primitives} is null/empty. 213 */ 214 public TestError build() { 215 CheckParameterUtil.ensureParameterNotNull(message, "message not set"); 216 CheckParameterUtil.ensureParameterNotNull(primitives, "primitives not set"); 217 CheckParameterUtil.ensureThat(!primitives.isEmpty(), "primitives is empty"); 218 if (this.highlighted == null) { 219 this.highlighted = Collections.emptySet(); 220 } 221 return new TestError(this); 222 } 223 } 224 225 /** 226 * Starts building a new {@code TestError} 227 * @param tester The tester 228 * @param severity The severity of this error 229 * @param code The test error reference code 230 * @return a new test builder 231 * @since 11129 232 */ 233 public static Builder builder(Test tester, Severity severity, int code) { 234 return new Builder(tester, severity, code); 235 } 236 237 private TestError(Builder builder) { 238 this.tester = builder.tester; 239 this.severity = builder.severity; 240 this.message = builder.message; 241 this.description = builder.description; 242 this.descriptionEn = builder.descriptionEn; 243 this.primitives = builder.primitives; 244 this.highlighted = builder.highlighted; 245 this.code = builder.code; 246 this.fixingCommand = builder.fixingCommand; 247 } 53 248 54 249 /** … … 62 257 * @param primitives The affected primitives 63 258 * @param highlighted OSM primitives to highlight 64 */ 259 * @deprecated Use {@link #builder} instead. Will be removed in 2016-12. 260 */ 261 @Deprecated 65 262 public TestError(Test tester, Severity severity, String message, String description, String descriptionEn, 66 263 int code, Collection<? extends OsmPrimitive> primitives, Collection<?> highlighted) { … … 73 270 this.highlighted = highlighted; 74 271 this.code = code; 272 this.fixingCommand = null; 75 273 } 76 274 … … 83 281 * @param primitives The affected primitives 84 282 * @param highlighted OSM primitives to highlight 85 */ 283 * @deprecated Use {@link #builder} instead. Will be removed in 2016-12. 284 */ 285 @Deprecated 86 286 public TestError(Test tester, Severity severity, String message, int code, Collection<? extends OsmPrimitive> primitives, 87 287 Collection<?> highlighted) { … … 98 298 * @param code The test error reference code 99 299 * @param primitives The affected primitives 100 */ 300 * @deprecated Use {@link #builder} instead. Will be removed in 2016-12. 301 */ 302 @Deprecated 101 303 public TestError(Test tester, Severity severity, String message, String description, String descriptionEn, 102 304 int code, Collection<? extends OsmPrimitive> primitives) { … … 111 313 * @param code The test error reference code 112 314 * @param primitives The affected primitives 113 */ 315 * @deprecated Use {@link #builder} instead. Will be removed in 2016-12. 316 */ 317 @Deprecated 114 318 public TestError(Test tester, Severity severity, String message, int code, Collection<? extends OsmPrimitive> primitives) { 115 319 this(tester, severity, message, null, null, code, primitives, primitives); … … 123 327 * @param code The test error reference code 124 328 * @param primitive The affected primitive 125 */ 329 * @deprecated Use {@link #builder} instead. Will be removed in 2016-12. 330 */ 331 @Deprecated 126 332 public TestError(Test tester, Severity severity, String message, int code, OsmPrimitive primitive) { 127 333 this(tester, severity, message, null, null, code, Collections.singletonList(primitive), Collections … … 138 344 * @param code The test error reference code 139 345 * @param primitive The affected primitive 140 */ 346 * @deprecated Use {@link #builder} instead. Will be removed in 2016-12. 347 */ 348 @Deprecated 141 349 public TestError(Test tester, Severity severity, String message, String description, String descriptionEn, 142 350 int code, OsmPrimitive primitive) { … … 163 371 * Sets the error message 164 372 * @param message The error message 165 */ 373 * @deprecated Use {@link #builder} instead. Will be removed in 2016-12. 374 */ 375 @Deprecated 166 376 public void setMessage(String message) { 167 377 this.message = message; … … 192 402 /** 193 403 * Sets the list of primitives affected by this error 194 * @param primitives the list of primitives affected by this error 195 */ 404 * @param primitives the list of primitives affected by this error* 405 * @deprecated Use {@link #builder} instead. Will be removed in 2016-12. 406 */ 407 @Deprecated 196 408 public void setPrimitives(List<? extends OsmPrimitive> primitives) { 197 409 this.primitives = primitives; … … 209 421 * Sets the severity of this error 210 422 * @param severity the severity of this error 211 */ 423 * @deprecated Use {@link #builder} instead. Will be removed in 2016-12. 424 */ 425 @Deprecated 212 426 public void setSeverity(Severity severity) { 213 427 this.severity = severity; … … 272 486 * Set the tester that raised the error. 273 487 * @param tester te tester 274 */ 488 * @deprecated Use {@link #builder} instead. Will be removed in 2016-12. 489 */ 490 @Deprecated 275 491 public void setTester(Test tester) { 276 492 this.tester = tester; … … 291 507 */ 292 508 public boolean isFixable() { 293 return tester != null && tester.isFixable(this);509 return fixingCommand != null || ((tester != null) && tester.isFixable(this)); 294 510 } 295 511 … … 300 516 */ 301 517 public Command getFix() { 518 // obtain fix from the error 519 final Command fix = fixingCommand != null ? fixingCommand.get() : null; 520 if (fix != null) { 521 return fix; 522 } 523 524 // obtain fix from the tester 302 525 if (tester == null || !tester.isFixable(this) || primitives.isEmpty()) 303 526 return null; -
trunk/src/org/openstreetmap/josm/data/validation/tests/Addresses.java
r10657 r11129 7 7 import java.util.ArrayList; 8 8 import java.util.Collection; 9 import java.util.Collections;10 9 import java.util.HashMap; 11 10 import java.util.HashSet; … … 51 50 // CHECKSTYLE.ON: SingleSpaceSeparator 52 51 53 protected static class AddressError extends TestError {54 55 public AddressError(Addresses tester, int code, OsmPrimitive p, String message) {56 this(tester, code, Collections.singleton(p), message);57 }58 59 public AddressError(Addresses tester, int code, Collection<OsmPrimitive> collection, String message) {60 this(tester, code, collection, message, null, null);61 }62 63 public AddressError(Addresses tester, int code, Collection<OsmPrimitive> collection, String message,64 String description, String englishDescription) {65 this(tester, code, Severity.WARNING, collection, message, description, englishDescription);66 }67 68 public AddressError(Addresses tester, int code, Severity severity, Collection<OsmPrimitive> collection, String message,69 String description, String englishDescription) {70 super(tester, severity, message, description, englishDescription, code, collection);71 }72 }73 74 52 /** 75 53 * Constructor … … 98 76 List<OsmPrimitive> errorList = new ArrayList<>(list); 99 77 errorList.add(0, p); 100 errors.add(new AddressError(this, MULTIPLE_STREET_RELATIONS, level, errorList, 101 tr("Multiple associatedStreet relations"), null, null)); 78 errors.add(TestError.builder(this, level, MULTIPLE_STREET_RELATIONS) 79 .message(tr("Multiple associatedStreet relations")) 80 .primitives(errorList) 81 .build()); 102 82 } 103 83 return list; … … 119 99 } 120 100 // No street found 121 errors.add(new AddressError(this, HOUSE_NUMBER_WITHOUT_STREET, p, tr("House number without street"))); 101 errors.add(TestError.builder(this, Severity.WARNING, HOUSE_NUMBER_WITHOUT_STREET) 102 .message(tr("House number without street")) 103 .primitives(p) 104 .build()); 122 105 } 123 106 } … … 179 162 } 180 163 // Report duplicate house numbers 181 String englishDescription = marktr("House number ''{0}'' duplicated");182 164 for (Entry<String, List<OsmPrimitive>> entry : map.entrySet()) { 183 165 List<OsmPrimitive> list = entry.getValue(); 184 166 if (list.size() > 1) { 185 errors.add(new AddressError(this, DUPLICATE_HOUSE_NUMBER, list, 186 tr("Duplicate house numbers"), tr(englishDescription, entry.getKey()), englishDescription)); 167 errors.add(TestError.builder(this, Severity.WARNING, DUPLICATE_HOUSE_NUMBER) 168 .message(tr("Duplicate house numbers"), marktr("House number ''{0}'' duplicated"), entry.getKey()) 169 .primitives(list) 170 .build()); 187 171 } 188 172 } 189 173 // Report wrong street names 190 174 if (!wrongStreetNames.isEmpty()) { 191 errors.add(new AddressError(this, MULTIPLE_STREET_NAMES, wrongStreetNames, 192 tr("Multiple street names in relation"))); 175 errors.add(TestError.builder(this, Severity.WARNING, MULTIPLE_STREET_NAMES) 176 .message(tr("Multiple street names in relation")) 177 .primitives(wrongStreetNames) 178 .build()); 193 179 } 194 180 // Report addresses too far away … … 245 231 List<OsmPrimitive> errorList = new ArrayList<>(street); 246 232 errorList.add(0, house); 247 errors.add(new AddressError(this, HOUSE_NUMBER_TOO_FAR, errorList, 248 tr("House number too far from street"))); 233 errors.add(TestError.builder(this, Severity.WARNING, HOUSE_NUMBER_TOO_FAR) 234 .message(tr("House number too far from street")) 235 .primitives(errorList) 236 .build()); 249 237 } 250 238 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/ApiCapabilitiesTest.java
r7937 r11129 50 50 message = tr("Way contains more than {0} nodes. It should be split or simplified", maxNodes); 51 51 } 52 errors.add(new TestError(this, Severity.ERROR, message, MAX_WAY_NODES_ERROR, w)); 52 errors.add(TestError.builder(this, Severity.ERROR, MAX_WAY_NODES_ERROR) 53 .message(message) 54 .primitives(w) 55 .build()); 53 56 } 54 57 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/BarriersEntrances.java
r8378 r11129 33 33 } 34 34 } 35 errors.add(new TestError(this, Severity.WARNING, tr("Barrier entrance not set on a barrier"), BARRIER_ENTRANCE_WITHOUT_BARRIER, n)); 35 errors.add(TestError 36 .builder(this, Severity.WARNING, BARRIER_ENTRANCE_WITHOUT_BARRIER) 37 .message(tr("Barrier entrance not set on a barrier")) 38 .primitives(n) 39 .build()); 36 40 } 37 41 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/Coastlines.java
r10991 r11129 147 147 // simple closed ways are reported by WronglyOrderedWays 148 148 if (visited.size() > 1 && nodes.get(0) == nodes.get(nodes.size()-1) && Geometry.isClockwise(nodes)) { 149 errors.add(new TestError(this, Severity.WARNING, tr("Reversed coastline: land not on left side"), 150 WRONG_ORDER_COASTLINE, visited)); 149 errors.add(TestError.builder(this, Severity.WARNING, WRONG_ORDER_COASTLINE) 150 .message(tr("Reversed coastline: land not on left side")) 151 .primitives(visited) 152 .build()); 151 153 } 152 154 } … … 226 228 } 227 229 if (errCode != REVERSED_COASTLINE) 228 errors.add(new TestError(this, Severity.ERROR, msg, errCode, primitives, Collections.singletonList(n))); 230 errors.add(TestError.builder(this, Severity.ERROR, errCode) 231 .message(msg) 232 .primitives(primitives) 233 .highlight(n) 234 .build()); 229 235 else 230 errors.add(new TestError(this, Severity.ERROR, msg, errCode, primitives)); 236 errors.add(TestError.builder(this, Severity.ERROR, errCode) 237 .message(msg) 238 .primitives(primitives) 239 .build()); 231 240 } 232 241 -
trunk/src/org/openstreetmap/josm/data/validation/tests/ConditionalKeys.java
r10715 r11129 167 167 Pattern.compile(":conditional(:.*)?$").asPredicate())) { 168 168 if (!isKeyValid(key)) { 169 errors.add(new TestError(this, Severity.WARNING, tr("Wrong syntax in {0} key", key), 3201, p)); 169 errors.add(TestError.builder(this, Severity.WARNING, 3201) 170 .message(tr("Wrong syntax in {0} key", key)) 171 .primitives(p) 172 .build()); 170 173 continue; 171 174 } … … 173 176 final String error = validateValue(key, value); 174 177 if (error != null) { 175 errors.add(new TestError(this, Severity.WARNING, tr("Error in {0} value: {1}", key, error), 3202, p)); 178 errors.add(TestError.builder(this, Severity.WARNING, 3202) 179 .message(tr("Error in {0} value: {1}", key, error)) 180 .primitives(p) 181 .build()); 176 182 } 177 183 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/CrossingWays.java
r10803 r11129 247 247 248 248 final String message = createMessage(es1.way, es2.way); 249 errors.add( new TestError(this, Severity.WARNING,250 message,251 CROSSING_WAYS,252 prims,253 highlight));249 errors.add(TestError.builder(this, Severity.WARNING, CROSSING_WAYS) 250 .message(message) 251 .primitives(prims) 252 .highlightWaySegments(highlight) 253 .build()); 254 254 seenWays.put(prims, highlight); 255 255 } else { -
trunk/src/org/openstreetmap/josm/data/validation/tests/DuplicateNode.java
r11062 r11129 32 32 import org.openstreetmap.josm.data.validation.TestError; 33 33 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 34 import org.openstreetmap.josm.tools.CheckParameterUtil;35 34 import org.openstreetmap.josm.tools.MultiMap; 36 35 … … 84 83 LatLon coorK = getLatLon(k); 85 84 return coorK == null ? 0 : coorK.hashCode(); 86 }87 }88 89 private static class DuplicateNodeTestError extends TestError {90 DuplicateNodeTestError(Test parentTest, Severity severity, String msg, int code, Set<OsmPrimitive> primitives) {91 super(parentTest, severity, tr("Duplicated nodes"), tr(msg), msg, code, primitives);92 CheckParameterUtil.ensureThat(!primitives.isEmpty(), "Empty primitives: " + msg);93 85 } 94 86 } … … 214 206 215 207 if (nbType > 1) { 216 errors.add(new DuplicateNodeTestError( 217 parentTest, 218 Severity.WARNING, 219 marktr("Mixed type duplicated nodes"), 220 DUPLICATE_NODE_MIXED, 221 primitives 222 )); 208 errors.add(TestError.builder(parentTest, Severity.WARNING, DUPLICATE_NODE_MIXED) 209 .message(marktr("Mixed type duplicated nodes")) 210 .primitives(primitives) 211 .build()); 223 212 } else if (typeMap.get("highway")) { 224 errors.add(new DuplicateNodeTestError( 225 parentTest, 226 Severity.ERROR, 227 marktr("Highway duplicated nodes"), 228 DUPLICATE_NODE_HIGHWAY, 229 primitives 230 )); 213 errors.add(TestError.builder(parentTest, Severity.ERROR, DUPLICATE_NODE_HIGHWAY) 214 .message(marktr("Highway duplicated nodes")) 215 .primitives(primitives) 216 .build()); 231 217 } else if (typeMap.get("railway")) { 232 errors.add(new DuplicateNodeTestError( 233 parentTest, 234 Severity.ERROR, 235 marktr("Railway duplicated nodes"), 236 DUPLICATE_NODE_RAILWAY, 237 primitives 238 )); 218 errors.add(TestError.builder(parentTest, Severity.ERROR, DUPLICATE_NODE_RAILWAY) 219 .message(marktr("Railway duplicated nodes")) 220 .primitives(primitives) 221 .build()); 239 222 } else if (typeMap.get("waterway")) { 240 errors.add(new DuplicateNodeTestError( 241 parentTest, 242 Severity.ERROR, 243 marktr("Waterway duplicated nodes"), 244 DUPLICATE_NODE_WATERWAY, 245 primitives 246 )); 223 errors.add(TestError.builder(parentTest, Severity.ERROR, DUPLICATE_NODE_WATERWAY) 224 .message(marktr("Waterway duplicated nodes")) 225 .primitives(primitives) 226 .build()); 247 227 } else if (typeMap.get("boundary")) { 248 errors.add(new DuplicateNodeTestError( 249 parentTest, 250 Severity.ERROR, 251 marktr("Boundary duplicated nodes"), 252 DUPLICATE_NODE_BOUNDARY, 253 primitives 254 )); 228 errors.add(TestError.builder(parentTest, Severity.ERROR, DUPLICATE_NODE_BOUNDARY) 229 .message(marktr("Boundary duplicated nodes")) 230 .primitives(primitives) 231 .build()); 255 232 } else if (typeMap.get("power")) { 256 errors.add(new DuplicateNodeTestError( 257 parentTest, 258 Severity.ERROR, 259 marktr("Power duplicated nodes"), 260 DUPLICATE_NODE_POWER, 261 primitives 262 )); 233 errors.add(TestError.builder(parentTest, Severity.ERROR, DUPLICATE_NODE_POWER) 234 .message(marktr("Power duplicated nodes")) 235 .primitives(primitives) 236 .build()); 263 237 } else if (typeMap.get("natural")) { 264 errors.add(new DuplicateNodeTestError( 265 parentTest, 266 Severity.ERROR, 267 marktr("Natural duplicated nodes"), 268 DUPLICATE_NODE_NATURAL, 269 primitives 270 )); 238 errors.add(TestError.builder(parentTest, Severity.ERROR, DUPLICATE_NODE_NATURAL) 239 .message(marktr("Natural duplicated nodes")) 240 .primitives(primitives) 241 .build()); 271 242 } else if (typeMap.get("building")) { 272 errors.add(new DuplicateNodeTestError( 273 parentTest, 274 Severity.ERROR, 275 marktr("Building duplicated nodes"), 276 DUPLICATE_NODE_BUILDING, 277 primitives 278 )); 243 errors.add(TestError.builder(parentTest, Severity.ERROR, DUPLICATE_NODE_BUILDING) 244 .message(marktr("Building duplicated nodes")) 245 .primitives(primitives) 246 .build()); 279 247 } else if (typeMap.get("landuse")) { 280 errors.add(new DuplicateNodeTestError( 281 parentTest, 282 Severity.ERROR, 283 marktr("Landuse duplicated nodes"), 284 DUPLICATE_NODE_LANDUSE, 285 primitives 286 )); 248 errors.add(TestError.builder(parentTest, Severity.ERROR, DUPLICATE_NODE_LANDUSE) 249 .message(marktr("Landuse duplicated nodes")) 250 .primitives(primitives) 251 .build()); 287 252 } else { 288 errors.add(new DuplicateNodeTestError( 289 parentTest, 290 Severity.WARNING, 291 marktr("Other duplicated nodes"), 292 DUPLICATE_NODE_OTHER, 293 primitives 294 )); 253 errors.add(TestError.builder(parentTest, Severity.WARNING, DUPLICATE_NODE_OTHER) 254 .message(marktr("Other duplicated nodes")) 255 .primitives(primitives) 256 .build()); 295 257 } 296 258 it.remove(); … … 305 267 } 306 268 if (duplicates.size() > 1) { 307 errors.add(new TestError( 308 parentTest, 309 Severity.WARNING, 310 tr("Nodes at same position"), 311 DUPLICATE_NODE, 312 duplicates 313 )); 269 errors.add(TestError.builder(parentTest, Severity.WARNING, DUPLICATE_NODE) 270 .message(tr("Nodes at same position")) 271 .primitives(duplicates) 272 .build()); 314 273 } 315 274 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/DuplicateRelation.java
r9371 r11129 203 203 for (Set<OsmPrimitive> duplicated : relations.values()) { 204 204 if (duplicated.size() > 1) { 205 TestError testError = new TestError(this, Severity.ERROR, tr("Duplicated relations"), DUPLICATE_RELATION, duplicated); 205 TestError testError = TestError.builder(this, Severity.ERROR, DUPLICATE_RELATION) 206 .message(tr("Duplicated relations")) 207 .primitives(duplicated) 208 .build(); 206 209 errors.add(testError); 207 210 } … … 210 213 for (Set<OsmPrimitive> duplicated : relationsNoKeys.values()) { 211 214 if (duplicated.size() > 1) { 212 TestError testError = new TestError(this, Severity.WARNING, tr("Relations with same members"), SAME_RELATION, duplicated); 215 TestError testError = TestError.builder(this, Severity.WARNING, SAME_RELATION) 216 .message(tr("Relations with same members")) 217 .primitives(duplicated) 218 .build(); 213 219 errors.add(testError); 214 220 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/DuplicateWay.java
r9371 r11129 123 123 for (Set<OsmPrimitive> duplicated : ways.values()) { 124 124 if (duplicated.size() > 1) { 125 TestError testError = new TestError(this, Severity.ERROR, tr("Duplicated ways"), DUPLICATE_WAY, duplicated); 125 TestError testError = TestError.builder(this, Severity.ERROR, DUPLICATE_WAY) 126 .message(tr("Duplicated ways")) 127 .primitives(duplicated) 128 .build(); 126 129 errors.add(testError); 127 130 } … … 150 153 continue; 151 154 } 152 TestError testError = new TestError(this, Severity.WARNING, tr("Ways with same position"), SAME_WAY, sameway); 155 TestError testError = TestError.builder(this, Severity.WARNING, SAME_WAY) 156 .message(tr("Ways with same position")) 157 .primitives(sameway) 158 .build(); 153 159 errors.add(testError); 154 160 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/DuplicatedWayNodes.java
r8382 r11129 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.util.Arrays;7 6 import java.util.Collections; 8 7 import java.util.Iterator; … … 43 42 } 44 43 if (lastN == n) { 45 errors.add(new TestError(this, Severity.ERROR, tr("Duplicated way nodes"), DUPLICATE_WAY_NODE, 46 Arrays.asList(w), Arrays.asList(n))); 44 errors.add(TestError.builder(this, Severity.ERROR, DUPLICATE_WAY_NODE) 45 .message(tr("Duplicated way nodes")) 46 .primitives(w) 47 .highlight(n) 48 .build()); 47 49 break; 48 50 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/Highways.java
r10657 r11129 8 8 import java.util.HashMap; 9 9 import java.util.HashSet; 10 import java.util.Iterator;11 10 import java.util.List; 12 11 import java.util.Locale; … … 15 14 16 15 import org.openstreetmap.josm.command.ChangePropertyCommand; 17 import org.openstreetmap.josm.command.Command;18 16 import org.openstreetmap.josm.data.osm.Node; 19 17 import org.openstreetmap.josm.data.osm.OsmPrimitive; 20 18 import org.openstreetmap.josm.data.osm.OsmUtils; 21 19 import org.openstreetmap.josm.data.osm.Way; 22 import org.openstreetmap.josm.data.validation.FixableTestError;23 20 import org.openstreetmap.josm.data.validation.Severity; 24 21 import org.openstreetmap.josm.data.validation.Test; … … 76 73 } 77 74 78 protected static class WrongRoundaboutHighway extends TestError {79 80 public final String correctValue;81 82 public WrongRoundaboutHighway(Highways tester, Way w, String key) {83 super(tester, Severity.WARNING,84 tr("Incorrect roundabout (highway: {0} instead of {1})", w.get("highway"), key),85 WRONG_ROUNDABOUT_HIGHWAY, w);86 this.correctValue = key;87 }88 }89 90 75 @Override 91 76 public void visit(Node n) { … … 147 132 // Error when the highway tags do not match 148 133 if (!w.get("highway").equals(s)) { 149 errors.add(new WrongRoundaboutHighway(this, w, s)); 134 errors.add(TestError.builder(this, Severity.WARNING, WRONG_ROUNDABOUT_HIGHWAY) 135 .message(tr("Incorrect roundabout (highway: {0} instead of {1})", w.get("highway"), s)) 136 .primitives(w) 137 .fix(() -> new ChangePropertyCommand(w, "highway", s)) 138 .build()); 150 139 } 151 140 break; … … 180 169 private void testHighwayLink(final Way way) { 181 170 if (!isHighwayLinkOkay(way)) { 182 errors.add(new TestError(this, Severity.WARNING, 183 tr("Highway link is not linked to adequate highway/link"), SOURCE_WRONG_LINK, way)); 171 errors.add(TestError.builder(this, Severity.WARNING, SOURCE_WRONG_LINK) 172 .message(tr("Highway link is not linked to adequate highway/link")) 173 .primitives(way) 174 .build()); 184 175 } 185 176 } … … 213 204 } 214 205 if ((leftByPedestrians || leftByCyclists) && leftByCars) { 215 errors.add(new TestError(this, Severity.OTHER, tr("Missing pedestrian crossing information"), 216 MISSING_PEDESTRIAN_CROSSING, n)); 206 errors.add(TestError.builder(this, Severity.OTHER, MISSING_PEDESTRIAN_CROSSING) 207 .message(tr("Missing pedestrian crossing information")) 208 .primitives(n) 209 .build()); 217 210 return; 218 211 } … … 249 242 String country = value.substring(0, index); 250 243 if (!ISO_COUNTRIES.contains(country)) { 244 final TestError.Builder error = TestError.builder(this, Severity.WARNING, SOURCE_MAXSPEED_UNKNOWN_COUNTRY_CODE) 245 .message(tr("Unknown country code: {0}", country)) 246 .primitives(p); 251 247 if ("UK".equals(country)) { 252 errors.add(new FixableTestError(this, Severity.WARNING, 253 tr("Unknown country code: {0}", country), SOURCE_MAXSPEED_UNKNOWN_COUNTRY_CODE, p, 254 new ChangePropertyCommand(p, SOURCE_MAXSPEED, value.replace("UK:", "GB:")))); 248 errors.add(error.fix(() -> new ChangePropertyCommand(p, SOURCE_MAXSPEED, value.replace("UK:", "GB:"))).build()); 255 249 } else { 256 errors.add(new TestError(this, Severity.WARNING, 257 tr("Unknown country code: {0}", country), SOURCE_MAXSPEED_UNKNOWN_COUNTRY_CODE, p)); 250 errors.add(error.build()); 258 251 } 259 252 } … … 261 254 String context = value.substring(index+1); 262 255 if (!KNOWN_SOURCE_MAXSPEED_CONTEXTS.contains(context)) { 263 errors.add(new TestError(this, Severity.WARNING, 264 tr("Unknown source:maxspeed context: {0}", context), SOURCE_MAXSPEED_UNKNOWN_CONTEXT, p)); 256 errors.add(TestError.builder(this, Severity.WARNING, SOURCE_MAXSPEED_UNKNOWN_CONTEXT) 257 .message(tr("Unknown source:maxspeed context: {0}", context)) 258 .primitives(p) 259 .build()); 265 260 } 266 261 // TODO: Check coherence of context against maxspeed … … 268 263 } 269 264 } 270 271 @Override272 public boolean isFixable(TestError testError) {273 return testError instanceof WrongRoundaboutHighway;274 }275 276 @Override277 public Command fixError(TestError testError) {278 if (testError instanceof WrongRoundaboutHighway) {279 // primitives list can be empty if all primitives have been purged280 Iterator<? extends OsmPrimitive> it = testError.getPrimitives().iterator();281 if (it.hasNext()) {282 return new ChangePropertyCommand(it.next(),283 "highway", ((WrongRoundaboutHighway) testError).correctValue);284 }285 }286 return null;287 }288 265 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/InternetTags.java
r10472 r11129 2 2 package org.openstreetmap.josm.data.validation.tests; 3 3 4 import static org.openstreetmap.josm.tools.I18n.marktr; 4 5 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 … … 102 103 return doValidateTag(p, k, proto+value, validator, code); 103 104 } 104 String msg = tr("''{0}'': {1}", k, errMsg); 105 // todo obtain English message for ignore functionality 106 error = new TestError(this, Severity.WARNING, validator.getValidatorName(), msg, msg, code, p); 105 error = TestError.builder(this, Severity.WARNING, code) 106 .message(validator.getValidatorName(), marktr("''{0}'': {1}"), k, errMsg) 107 .primitives(p) 108 .build(); 107 109 } 108 110 return error; -
trunk/src/org/openstreetmap/josm/data/validation/tests/Lanes.java
r10638 r11129 49 49 if (lanesCount.size() > 1) { 50 50 // if not all numbers are the same 51 errors.add(new TestError(this, Severity.WARNING, message, 3100, p)); 51 errors.add(TestError.builder(this, Severity.WARNING, 3100) 52 .message(message) 53 .primitives(p) 54 .build()); 52 55 } else if (lanesCount.size() == 1 && p.hasKey(lanesKey)) { 53 56 // ensure that lanes <= *:lanes 54 57 try { 55 58 if (Integer.parseInt(p.get(lanesKey)) > lanesCount.iterator().next()) { 56 errors.add(new TestError(this, Severity.WARNING, tr("Number of {0} greater than {1}", lanesKey, "*:" + lanesKey), 3100, p)); 59 errors.add(TestError.builder(this, Severity.WARNING, 3100) 60 .message(tr("Number of {0} greater than {1}", lanesKey, "*:" + lanesKey)) 61 .primitives(p) 62 .build()); 57 63 } 58 64 } catch (NumberFormatException ignore) { … … 69 75 try { 70 76 if (Integer.parseInt(lanes) < Integer.parseInt(forward) + Integer.parseInt(backward)) { 71 errors.add(new TestError(this, Severity.WARNING, 72 tr("Number of {0} greater than {1}", tr("{0}+{1}", "lanes:forward", "lanes:backward"), "lanes"), 3101, p)); 77 errors.add(TestError.builder(this, Severity.WARNING, 3101) 78 .message(tr("Number of {0} greater than {1}", tr("{0}+{1}", "lanes:forward", "lanes:backward"), "lanes")) 79 .primitives(p) 80 .build()); 73 81 } 74 82 } catch (NumberFormatException ignore) { -
trunk/src/org/openstreetmap/josm/data/validation/tests/LongSegment.java
r11100 r11129 2 2 package org.openstreetmap.josm.data.validation.tests; 3 3 4 import static org.openstreetmap.josm.tools.I18n.marktr; 4 5 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 … … 40 41 if (length > maxlength) { 41 42 length /= 1000.0; 42 errors.add( new TestError(this, Severity.WARNING, tr("Long segments"),43 tr("Very long segment of {0} kilometers", length.intValue()),44 String.format("Very long segment of %d kilometers", length.intValue()),45 LONG_SEGMENT, w));43 errors.add(TestError.builder(this, Severity.WARNING, LONG_SEGMENT) 44 .message(tr("Long segments"), marktr("Very long segment of {0} kilometers"), length.intValue()) 45 .primitives(w) 46 .build()); 46 47 } 47 48 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
r11111 r11129 39 39 import org.openstreetmap.josm.data.osm.OsmUtils; 40 40 import org.openstreetmap.josm.data.osm.Tag; 41 import org.openstreetmap.josm.data.validation.FixableTestError;42 41 import org.openstreetmap.josm.data.validation.Severity; 43 42 import org.openstreetmap.josm.data.validation.Test; … … 567 566 TestError getErrorForPrimitive(OsmPrimitive p) { 568 567 final Environment env = new Environment(p); 569 return getErrorForPrimitive(p, whichSelectorMatchesEnvironment(env), env );570 } 571 572 TestError getErrorForPrimitive(OsmPrimitive p, Selector matchingSelector, Environment env ) {568 return getErrorForPrimitive(p, whichSelectorMatchesEnvironment(env), env, null); 569 } 570 571 TestError getErrorForPrimitive(OsmPrimitive p, Selector matchingSelector, Environment env, Test tester) { 573 572 if (matchingSelector != null && !errors.isEmpty()) { 574 573 final Command fix = fixPrimitive(p); … … 582 581 primitives = Collections.singletonList(p); 583 582 } 583 final TestError.Builder error = TestError.builder(tester, getSeverity(), 3000) 584 .messageWithManuallyTranslatedDescription(description1, description2, matchingSelector.toString()) 585 .primitives(primitives); 584 586 if (fix != null) { 585 return new FixableTestError(null, getSeverity(), description1, description2, matchingSelector.toString(), 3000, 586 primitives, fix); 587 return error.fix(() -> fix).build(); 587 588 } else { 588 return new TestError(null, getSeverity(), description1, description2, matchingSelector.toString(), 3000, primitives);589 return error.build(); 589 590 } 590 591 } else { … … 685 686 if (selector != null) { 686 687 check.rule.declaration.execute(env); 687 final TestError error = check.getErrorForPrimitive(p, selector, env );688 final TestError error = check.getErrorForPrimitive(p, selector, env, new MapCSSTagCheckerAndRule(check.rule)); 688 689 if (error != null) { 689 error.setTester(new MapCSSTagCheckerAndRule(check.rule));690 690 r.add(error); 691 691 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java
r10000 r11129 2 2 package org.openstreetmap.josm.data.validation.tests; 3 3 4 import static org.openstreetmap.josm.tools.I18n.marktr; 4 5 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 import static org.openstreetmap.josm.tools.I18n.trn; 6 7 7 8 import java.awt.geom.GeneralPath; 8 import java.text.MessageFormat;9 9 import java.util.ArrayList; 10 10 import java.util.Arrays; … … 12 12 import java.util.Collections; 13 13 import java.util.HashSet; 14 import java.util.LinkedList;15 14 import java.util.List; 16 15 import java.util.Set; … … 148 147 } 149 148 } 150 errors.add(new TestError(this, Severity.WARNING, tr("Area style way is not closed"), NOT_CLOSED, 151 Collections.singletonList(w), Arrays.asList(nodes.get(0), nodes.get(nodes.size() - 1)))); 149 errors.add(TestError.builder(this, Severity.WARNING, NOT_CLOSED) 150 .message(tr("Area style way is not closed")) 151 .primitives(w) 152 .highlight(Arrays.asList(nodes.get(0), nodes.get(nodes.size() - 1))) 153 .build()); 152 154 } 153 155 } … … 186 188 } 187 189 if (!hasOuterWay) { 188 addError(r, new TestError(this, Severity.WARNING, tr("No outer way for multipolygon"), MISSING_OUTER_WAY, r)); 190 errors.add(TestError.builder(this, Severity.WARNING, MISSING_OUTER_WAY) 191 .message(tr("No outer way for multipolygon")) 192 .primitives(r) 193 .build()); 189 194 } 190 195 } … … 204 209 final String roleInNewMP = memberInNewMP.iterator().next().getRole(); 205 210 if (!member.getRole().equals(roleInNewMP)) { 206 List<OsmPrimitive> l = new ArrayList<>(); 207 l.add(r); 208 l.add(member.getMember()); 209 addError(r, new TestError(this, Severity.WARNING, RelationChecker.ROLE_VERIF_PROBLEM_MSG, 210 tr("Role for ''{0}'' should be ''{1}''", 211 member.getMember().getDisplayName(DefaultNameFormatter.getInstance()), roleInNewMP), 212 MessageFormat.format("Role for ''{0}'' should be ''{1}''", 213 member.getMember().getDisplayName(DefaultNameFormatter.getInstance()), roleInNewMP), 214 WRONG_MEMBER_ROLE, l, Collections.singleton(member.getMember()))); 211 errors.add(TestError.builder(this, Severity.WARNING, WRONG_MEMBER_ROLE) 212 .message(RelationChecker.ROLE_VERIF_PROBLEM_MSG, 213 marktr("Role for ''{0}'' should be ''{1}''"), 214 member.getMember().getDisplayName(DefaultNameFormatter.getInstance()), roleInNewMP) 215 .primitives(addRelationIfNeeded(r, member.getMember())) 216 .highlight(member.getMember()) 217 .build()); 215 218 } 216 219 } … … 242 245 } 243 246 if (area == null) { 244 addError(r, new TestError(this, Severity.OTHER, tr("No area style for multipolygon"), NO_STYLE, r)); 247 errors.add(TestError.builder(this, Severity.OTHER, NO_STYLE) 248 .message(tr("No area style for multipolygon")) 249 .primitives(r) 250 .build()); 245 251 } else { 246 252 /* old style multipolygon - solve: copy tags from outer way to multipolygon */ 247 addError(r, new TestError(this, Severity.WARNING,248 trn("Multipolygon relation should be tagged with area tags and not the outer way",253 errors.add(TestError.builder(this, Severity.WARNING, NO_STYLE_POLYGON) 254 .message(trn("Multipolygon relation should be tagged with area tags and not the outer way", 249 255 "Multipolygon relation should be tagged with area tags and not the outer ways", 250 polygon.getOuterWays().size()), 251 NO_STYLE_POLYGON, r)); 256 polygon.getOuterWays().size())) 257 .primitives(r) 258 .build()); 252 259 } 253 260 } … … 258 265 259 266 if (areaInner != null && area.equals(areaInner)) { 260 List<OsmPrimitive> l = new ArrayList<>(); 261 l.add(r); 262 l.add(wInner); 263 addError(r, new TestError(this, Severity.OTHER, 264 tr("With the currently used mappaint style the style for inner way equals the multipolygon style"), 265 INNER_STYLE_MISMATCH, l, Collections.singletonList(wInner))); 267 errors.add(TestError.builder(this, Severity.OTHER, INNER_STYLE_MISMATCH) 268 .message(tr("With the currently used mappaint style the style for inner way equals the multipolygon style")) 269 .primitives(addRelationIfNeeded(r, wInner)) 270 .highlight(wInner) 271 .build()); 266 272 } 267 273 } … … 269 275 AreaElement areaOuter = ElemStyles.getAreaElemStyle(wOuter, false); 270 276 if (areaOuter != null) { 271 List<OsmPrimitive> l = new ArrayList<>();272 l.add(r);273 l.add(wOuter);274 277 if (!area.equals(areaOuter)) { 275 addError(r, new TestError(this, Severity.OTHER, !areaStyle ? tr("Style for outer way mismatches") 276 : tr("With the currently used mappaint style(s) the style for outer way mismatches the area style"), 277 OUTER_STYLE_MISMATCH, l, Collections.singletonList(wOuter))); 278 String message = !areaStyle ? tr("Style for outer way mismatches") 279 : tr("With the currently used mappaint style(s) the style for outer way mismatches the area style"); 280 errors.add(TestError.builder(this, Severity.OTHER, OUTER_STYLE_MISMATCH) 281 .message(message) 282 .primitives(addRelationIfNeeded(r, wOuter)) 283 .highlight(wOuter) 284 .build()); 278 285 } else if (areaStyle) { /* style on outer way of multipolygon, but equal to polygon */ 279 addError(r, new TestError(this, Severity.WARNING, tr("Area style on outer way"), OUTER_STYLE, 280 l, Collections.singletonList(wOuter))); 286 errors.add(TestError.builder(this, Severity.WARNING, OUTER_STYLE) 287 .message(tr("Area style on outer way")) 288 .primitives(addRelationIfNeeded(r, wOuter)) 289 .highlight(wOuter) 290 .build()); 281 291 } 282 292 } … … 298 308 List<Node> openNodes = polygon.getOpenEnds(); 299 309 if (!openNodes.isEmpty()) { 300 List<OsmPrimitive> primitives = new LinkedList<>(); 301 primitives.add(r); 302 primitives.addAll(openNodes); 303 addError(r, new TestError(this, Severity.WARNING, tr("Multipolygon is not closed"), NON_CLOSED_WAY, primitives, openNodes)); 310 errors.add(TestError.builder(this, Severity.WARNING, NON_CLOSED_WAY) 311 .message(tr("Multipolygon is not closed")) 312 .primitives(addRelationIfNeeded(r, openNodes)) 313 .highlight(openNodes) 314 .build()); 304 315 } 305 316 … … 328 339 } 329 340 if (outside) { 330 addError(r, new TestError(this, Severity.WARNING, tr("Multipolygon inner way is outside"), 331 INNER_WAY_OUTSIDE, Collections.singletonList(r), Arrays.asList(pdInner.getNodes()))); 341 errors.add(TestError.builder(this, Severity.WARNING, INNER_WAY_OUTSIDE) 342 .message(tr("Multipolygon inner way is outside")) 343 .primitives(r) 344 .highlightNodePairs(Collections.singletonList(pdInner.getNodes())) 345 .build()); 332 346 } 333 347 } … … 339 353 PolyData pdOther = polygons.get(idx); 340 354 if (pdOther != null) { 341 addError(r, new TestError(this, Severity.WARNING, tr("Intersection between multipolygon ways"), 342 CROSSING_WAYS, Collections.singletonList(r), Arrays.asList(pd.getNodes(), pdOther.getNodes()))); 355 errors.add(TestError.builder(this, Severity.WARNING, CROSSING_WAYS) 356 .message(tr("Intersection between multipolygon ways")) 357 .primitives(r) 358 .highlightNodePairs(Arrays.asList(pd.getNodes(), pdOther.getNodes())) 359 .build()); 343 360 } 344 361 } … … 357 374 if (rm.isWay()) { 358 375 if (!(rm.hasRole("inner", "outer") || !rm.hasRole())) { 359 addError(r, new TestError(this, Severity.WARNING, tr("No useful role for multipolygon member"), 360 WRONG_MEMBER_ROLE, rm.getMember())); 376 errors.add(TestError.builder(this, Severity.WARNING, WRONG_MEMBER_ROLE) 377 .message(tr("No useful role for multipolygon member")) 378 .primitives(addRelationIfNeeded(r, rm.getMember())) 379 .build()); 361 380 } 362 381 } else { 363 382 if (!rm.hasRole("admin_centre", "label", "subarea", "land_area")) { 364 addError(r, new TestError(this, Severity.WARNING, tr("Non-Way in multipolygon"), WRONG_MEMBER_TYPE, rm.getMember())); 365 } 366 } 367 } 368 } 369 370 private static void addRelationIfNeeded(TestError error, Relation r) { 383 errors.add(TestError.builder(this, Severity.WARNING, WRONG_MEMBER_TYPE) 384 .message(tr("Non-Way in multipolygon")) 385 .primitives(addRelationIfNeeded(r, rm.getMember())) 386 .build()); 387 } 388 } 389 } 390 } 391 392 private static Collection<? extends OsmPrimitive> addRelationIfNeeded(Relation r, OsmPrimitive primitive) { 393 return addRelationIfNeeded(r, Collections.singleton(primitive)); 394 } 395 396 private static Collection<? extends OsmPrimitive> addRelationIfNeeded(Relation r, Collection<? extends OsmPrimitive> primitives) { 371 397 // Fix #8212 : if the error references only incomplete primitives, 372 398 // add multipolygon in order to let user select something and fix the error 373 Collection<? extends OsmPrimitive> primitives = error.getPrimitives();374 399 if (!primitives.contains(r)) { 375 400 for (OsmPrimitive p : primitives) { 376 401 if (!p.isIncomplete()) { 377 return ;402 return null; 378 403 } 379 404 } … … 382 407 List<OsmPrimitive> newPrimitives = new ArrayList<OsmPrimitive>(primitives); 383 408 newPrimitives.add(0, r); 384 error.setPrimitives(newPrimitives); 385 } 386 } 387 388 private void addError(Relation r, TestError error) { 389 addRelationIfNeeded(error, r); 390 errors.add(error); 391 } 409 return newPrimitives; 410 } else { 411 return primitives; 412 } 413 } 414 392 415 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/NameMismatch.java
r8510 r11129 2 2 package org.openstreetmap.josm.data.validation.tests; 3 3 4 import static org.openstreetmap.josm.tools.I18n.marktr; 4 5 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 … … 51 52 */ 52 53 private void missingTranslation(OsmPrimitive p, String name) { 53 errors.add( new TestError(this, Severity.OTHER,54 tr("Missing name:* translation"),55 tr("Missing name:*={0}. Add tag with correct language key.", name),56 String.format("Missing name:*=%s. Add tag with correct language key.", name), NAME_TRANSLATION_MISSING, p));54 errors.add(TestError.builder(this, Severity.OTHER, NAME_TRANSLATION_MISSING) 55 .message(tr("Missing name:* translation"), marktr("Missing name:*={0}. Add tag with correct language key."), name) 56 .primitives(p) 57 .build()); 57 58 } 58 59 … … 80 81 81 82 if (name == null) { 82 errors.add(new TestError(this, Severity.OTHER, 83 tr("A name is missing, even though name:* exists."), 84 NAME_MISSING, p)); 83 errors.add(TestError.builder(this, Severity.OTHER, NAME_MISSING) 84 .message(tr("A name is missing, even though name:* exists.")) 85 .primitives(p) 86 .build()); 85 87 return; 86 88 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/OpeningHourTest.java
r11042 r11129 18 18 import org.openstreetmap.josm.command.ChangePropertyCommand; 19 19 import org.openstreetmap.josm.data.osm.OsmPrimitive; 20 import org.openstreetmap.josm.data.validation.FixableTestError;21 20 import org.openstreetmap.josm.data.validation.Severity; 22 21 import org.openstreetmap.josm.data.validation.Test; … … 132 131 */ 133 132 public TestError getTestError(final OsmPrimitive p, final String key) { 134 final String messageEn = message; // todo obtain English message for ignore functionality 133 final TestError.Builder error = TestError.builder(OpeningHourTest.this, severity, 2901) 134 .message(tr("Opening hours syntax"), message) // todo obtain English message for ignore functionality 135 .primitives(p); 135 136 if (prettifiedValue == null || prettifiedValue.equals(p.get(key))) { 136 return new TestError(OpeningHourTest.this, severity, tr("Opening hours syntax"), message, messageEn, 2901, p);137 return error.build(); 137 138 } else { 138 return new FixableTestError(OpeningHourTest.this, severity, tr("Opening hours syntax"), message, messageEn, 2901, p, 139 new ChangePropertyCommand(p, key, prettifiedValue)); 139 return error.fix(() -> new ChangePropertyCommand(p, key, prettifiedValue)).build(); 140 140 } 141 141 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/OverlappingWays.java
r10715 r11129 140 140 } 141 141 142 preliminaryErrors.add(new TestError(this, 143 type < OVERLAPPING_HIGHWAY_AREA ? Severity.WARNING : Severity.OTHER, 144 errortype, type, prims, duplicated)); 142 Severity severity = type < OVERLAPPING_HIGHWAY_AREA ? Severity.WARNING : Severity.OTHER; 143 preliminaryErrors.add(TestError.builder(this, severity, type) 144 .message(errortype) 145 .primitives(prims) 146 .highlightWaySegments(duplicated) 147 .build()); 145 148 seenWays.put(currentWays, duplicated); 146 149 } else { /* way seen, mark highlight layer only */ … … 202 205 final Set<WaySegment> duplicateWaySegment = checkDuplicateWaySegment(w); 203 206 if (duplicateWaySegment != null) { 204 errors.add(new TestError(this, Severity.ERROR, tr("Way contains segment twice"), 205 DUPLICATE_WAY_SEGMENT, Collections.singleton(w), duplicateWaySegment)); 207 errors.add(TestError.builder(this, Severity.ERROR, DUPLICATE_WAY_SEGMENT) 208 .message(tr("Way contains segment twice")) 209 .primitives(w) 210 .highlightWaySegments(duplicateWaySegment) 211 .build()); 206 212 return; 207 213 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/PowerLines.java
r10657 r11129 7 7 import java.util.Arrays; 8 8 import java.util.Collection; 9 import java.util.HashMap;10 import java.util.Iterator;11 9 import java.util.List; 12 import java.util.Map;13 10 14 11 import org.openstreetmap.josm.Main; 15 12 import org.openstreetmap.josm.command.ChangePropertyCommand; 16 import org.openstreetmap.josm.command.Command;17 13 import org.openstreetmap.josm.data.osm.Node; 18 14 import org.openstreetmap.josm.data.osm.OsmPrimitive; … … 48 44 "portal", "terminal", "insulator"); 49 45 50 private final Map<Way, String> towerPoleTagMap = new HashMap<>(); 51 52 private final List<PowerLineError> potentialErrors = new ArrayList<>(); 46 private final List<TestError> potentialErrors = new ArrayList<>(); 53 47 54 48 private final List<OsmPrimitive> powerStations = new ArrayList<>(); … … 66 60 if (isPowerLine(w) && !w.hasTag("location", "underground")) { 67 61 String fixValue = null; 68 boolean erroneous = false; 62 TestError.Builder error = null; 63 Node errorNode = null; 69 64 boolean canFix = false; 70 65 for (Node n : w.getNodes()) { … … 72 67 if (!isPowerAllowed(n) && IN_DOWNLOADED_AREA.test(n)) { 73 68 if (!w.isFirstLastNode(n) || !isPowerStation(n)) { 74 potentialErrors.add(new PowerLineError(this, n, w)); 75 erroneous = true; 69 error = TestError.builder(this, Severity.WARNING, POWER_LINES) 70 .message(tr("Missing power tower/pole within power line")) 71 .primitives(n); 72 errorNode = n; 76 73 } 77 74 } … … 85 82 } 86 83 } 87 if (erroneous && canFix) { 88 towerPoleTagMap.put(w, fixValue); 84 if (error != null && canFix) { 85 final ChangePropertyCommand fix = new ChangePropertyCommand(errorNode, "power", fixValue); 86 potentialErrors.add(error.fix(() -> fix).build()); 87 } else if (error != null) { 88 potentialErrors.add(error.build()); 89 89 } 90 90 } else if (w.isClosed() && isPowerStation(w)) { … … 104 104 public void startTest(ProgressMonitor progressMonitor) { 105 105 super.startTest(progressMonitor); 106 towerPoleTagMap.clear();107 106 powerStations.clear(); 108 107 potentialErrors.clear(); … … 111 110 @Override 112 111 public void endTest() { 113 for (PowerLineError e : potentialErrors) { 114 Node n = e.getNode(); 115 if (n != null && !isInPowerStation(n)) { 116 errors.add(e); 117 } 112 for (TestError e : potentialErrors) { 113 e.getPrimitives().stream() 114 .map(Node.class::cast) 115 .filter(n -> !isInPowerStation(n)) 116 .findAny() 117 .ifPresent(ignore -> errors.add(e)); 118 118 } 119 119 potentialErrors.clear(); … … 143 143 } 144 144 145 @Override146 public Command fixError(TestError testError) {147 if (testError instanceof PowerLineError && isFixable(testError)) {148 // primitives list can be empty if all primitives have been purged149 Iterator<? extends OsmPrimitive> it = testError.getPrimitives().iterator();150 if (it.hasNext()) {151 return new ChangePropertyCommand(it.next(),152 "power", towerPoleTagMap.get(((PowerLineError) testError).line));153 }154 }155 return null;156 }157 158 @Override159 public boolean isFixable(TestError testError) {160 return testError instanceof PowerLineError && towerPoleTagMap.containsKey(((PowerLineError) testError).line);161 }162 163 145 /** 164 146 * Determines if the specified way denotes a power line. … … 218 200 return v != null && values != null && values.contains(v); 219 201 } 220 221 protected static class PowerLineError extends TestError {222 private final Way line;223 224 public PowerLineError(PowerLines tester, Node n, Way line) {225 super(tester, Severity.WARNING,226 tr("Missing power tower/pole within power line"), POWER_LINES, n);227 this.line = line;228 }229 230 public final Node getNode() {231 // primitives list can be empty if all primitives have been purged232 Iterator<? extends OsmPrimitive> it = getPrimitives().iterator();233 return it.hasNext() ? (Node) it.next() : null;234 }235 }236 202 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/PublicTransportRouteTest.java
r10144 r11129 5 5 6 6 import java.util.ArrayList; 7 import java.util.Arrays;8 7 import java.util.HashSet; 9 8 import java.util.List; … … 48 47 for (RelationMember member : r.getMembers()) { 49 48 if (member.hasRole("forward", "backward")) { 50 errors.add(new TestError(this, Severity.WARNING, tr("Route relation contains a ''{0}'' role", "forward/backward"), 3601, r)); 49 errors.add(TestError.builder(this, Severity.WARNING, 3601) 50 .message(tr("Route relation contains a ''{0}'' role", "forward/backward")) 51 .primitives(r) 52 .build()); 51 53 return; 52 54 } else if (member.hasRole("") && OsmPrimitiveType.WAY.equals(member.getType())) { … … 67 69 || WayConnectionType.Direction.NONE.equals(link.direction); 68 70 if (hasError) { 69 errors.add(new TestError(this, Severity.WARNING, tr("Route relation contains a gap"), 3602, r)); 71 errors.add(TestError.builder(this, Severity.WARNING, 3602) 72 .message(tr("Route relation contains a gap")) 73 .primitives(r) 74 .build()); 70 75 return; 71 76 } … … 76 81 && OsmPrimitiveType.NODE.equals(member.getType()) 77 82 && !routeNodes.contains(member.getNode())) { 78 errors.add(new TestError(this, Severity.WARNING, 79 tr("Stop position not part of route"), 3603, Arrays.asList(member.getMember(), r))); 83 errors.add(TestError.builder(this, Severity.WARNING, 3603) 84 .message(tr("Stop position not part of route")) 85 .primitives(member.getMember(), r) 86 .build()); 80 87 } 81 88 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/RelationChecker.java
r10981 r11129 5 5 import static org.openstreetmap.josm.tools.I18n.tr; 6 6 7 import java.text.MessageFormat;8 7 import java.util.Collection; 9 8 import java.util.EnumSet; … … 116 115 if (allroles.isEmpty() && n.hasTag("type", "route") 117 116 && n.hasTag("route", "train", "subway", "monorail", "tram", "bus", "trolleybus", "aerialway", "ferry")) { 118 errors.add(new TestError(this, Severity.WARNING, 119 tr("Route scheme is unspecified. Add {0} ({1}=public_transport; {2}=legacy)", "public_transport:version", "2", "1"), 120 RELATION_UNKNOWN, n)); 117 errors.add(TestError.builder(this, Severity.WARNING, RELATION_UNKNOWN) 118 .message(tr("Route scheme is unspecified. Add {0} ({1}=public_transport; {2}=legacy)", "public_transport:version", "2", "1")) 119 .primitives(n) 120 .build()); 121 121 } else if (allroles.isEmpty()) { 122 errors.add(new TestError(this, Severity.WARNING, tr("Relation type is unknown"), RELATION_UNKNOWN, n)); 122 errors.add(TestError.builder(this, Severity.WARNING, RELATION_UNKNOWN) 123 .message(tr("Relation type is unknown")) 124 .primitives(n) 125 .build()); 123 126 } 124 127 125 128 Map<String, RoleInfo> map = buildRoleInfoMap(n); 126 129 if (map.isEmpty()) { 127 errors.add(new TestError(this, Severity.ERROR, tr("Relation is empty"), RELATION_EMPTY, n)); 130 errors.add(TestError.builder(this, Severity.ERROR, RELATION_EMPTY) 131 .message(tr("Relation is empty")) 132 .primitives(n) 133 .build()); 128 134 } else if (!allroles.isEmpty()) { 129 135 checkRoles(n, allroles, map); … … 230 236 // different present, for which memberExpression will match 231 237 // but stash the error in case no better reason will be found later 232 String s = marktr("Role member does not match expression {0} in template {1}"); 233 possibleMatchError = new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG, 234 tr(s, r.memberExpression, rolePreset.name), s, WRONG_TYPE, 235 member.getMember().isUsable() ? member.getMember() : n); 238 possibleMatchError = TestError.builder(this, Severity.WARNING, WRONG_TYPE) 239 .message(ROLE_VERIF_PROBLEM_MSG, 240 marktr("Role member does not match expression {0} in template {1}"), 241 r.memberExpression, rolePreset.name) 242 .primitives(member.getMember().isUsable() ? member.getMember() : n) 243 .build(); 236 244 } 237 245 } … … 252 260 // no errors found till now. So member at least failed at matching the type 253 261 // it could also fail at memberExpression, but we can't guess at which 254 String s = marktr("Role member type {0} does not match accepted list of {1} in template {2}");255 262 256 263 // prepare Set of all accepted types in template … … 263 270 String typesStr = types.stream().map(x -> tr(x.getName())).collect(Collectors.joining("/")); 264 271 265 errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG, 266 tr(s, member.getType(), typesStr, rolePreset.name), s, WRONG_TYPE, 267 member.getMember().isUsable() ? member.getMember() : n)); 272 errors.add(TestError.builder(this, Severity.WARNING, WRONG_TYPE) 273 .message(ROLE_VERIF_PROBLEM_MSG, 274 marktr("Role member type {0} does not match accepted list of {1} in template {2}"), 275 member.getType(), typesStr, rolePreset.name) 276 .primitives(member.getMember().isUsable() ? member.getMember() : n) 277 .build()); 268 278 } 269 279 return false; … … 301 311 302 312 if (!key.isEmpty()) { 303 String s = marktr("Role {0} unknown in templates {1}"); 304 305 errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG, 306 tr(s, key, templates), MessageFormat.format(s, key), ROLE_UNKNOWN, n)); 313 314 errors.add(TestError.builder(this, Severity.WARNING, ROLE_UNKNOWN) 315 .message(ROLE_VERIF_PROBLEM_MSG, marktr("Role {0} unknown in templates {1}"), key, templates) 316 .primitives(n) 317 .build()); 307 318 } else { 308 String s = marktr("Empty role type found when expecting one of {0}"); 309 errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG, 310 tr(s, templates), s, ROLE_EMPTY, n)); 319 errors.add(TestError.builder(this, Severity.WARNING, ROLE_EMPTY) 320 .message(ROLE_VERIF_PROBLEM_MSG, marktr("Empty role type found when expecting one of {0}"), templates) 321 .primitives(n) 322 .build()); 311 323 } 312 324 } … … 319 331 if (count != vc) { 320 332 if (count == 0) { 321 String s = marktr("Role {0} missing"); 322 errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG, 323 tr(s, keyname), MessageFormat.format(s, keyname), ROLE_MISSING, n)); 333 errors.add(TestError.builder(this, Severity.WARNING, ROLE_MISSING) 334 .message(ROLE_VERIF_PROBLEM_MSG, marktr("Role {0} missing"), keyname) 335 .primitives(n) 336 .build()); 324 337 } else if (vc > count) { 325 String s = marktr("Number of {0} roles too low ({1})"); 326 errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG, 327 tr(s, keyname, count), MessageFormat.format(s, keyname, count), LOW_COUNT, n)); 338 errors.add(TestError.builder(this, Severity.WARNING, LOW_COUNT) 339 .message(ROLE_VERIF_PROBLEM_MSG, marktr("Number of {0} roles too low ({1})"), keyname, count) 340 .primitives(n) 341 .build()); 328 342 } else { 329 String s = marktr("Number of {0} roles too high ({1})"); 330 errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG, 331 tr(s, keyname, count), MessageFormat.format(s, keyname, count), HIGH_COUNT, n)); 343 errors.add(TestError.builder(this, Severity.WARNING, HIGH_COUNT) 344 .message(ROLE_VERIF_PROBLEM_MSG, marktr("Number of {0} roles too high ({1})"), keyname, count) 345 .primitives(n) 346 .build()); 332 347 } 333 348 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/SelfIntersectingWay.java
r8382 r11129 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.util.Arrays;7 6 import java.util.HashSet; 8 7 import java.util.Set; … … 37 36 Node n = w.getNode(i); 38 37 if (nodes.contains(n)) { 39 errors.add(new TestError(this, 40 Severity.WARNING, tr("Self-intersecting ways"), SELF_INTERSECT, 41 Arrays.asList(w), Arrays.asList(n))); 38 errors.add(TestError.builder(this, Severity.WARNING, SELF_INTERSECT) 39 .message(tr("Self-intersecting ways")) 40 .primitives(w) 41 .highlight(n) 42 .build()); 42 43 break; 43 44 } else { -
trunk/src/org/openstreetmap/josm/data/validation/tests/SimilarNamedWays.java
r10721 r11129 97 97 primitives.add(w); 98 98 primitives.add(w2); 99 errors.add(new TestError(this, Severity.WARNING, tr("Similarly named ways"), SIMILAR_NAMED, primitives)); 99 errors.add(TestError.builder(this, Severity.WARNING, SIMILAR_NAMED) 100 .message(tr("Similarly named ways")) 101 .primitives(primitives) 102 .build()); 100 103 errorWays.put(w, w2); 101 104 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java
r11042 r11129 9 9 import java.io.BufferedReader; 10 10 import java.io.IOException; 11 import java.text.MessageFormat;12 11 import java.util.ArrayList; 13 12 import java.util.Arrays; … … 37 36 import org.openstreetmap.josm.data.osm.OsmUtils; 38 37 import org.openstreetmap.josm.data.osm.Tag; 39 import org.openstreetmap.josm.data.validation.FixableTestError;40 38 import org.openstreetmap.josm.data.validation.Severity; 41 39 import org.openstreetmap.josm.data.validation.Test.TagTest; … … 392 390 for (CheckerData d : checkerData) { 393 391 if (d.match(p, keys)) { 394 errors.add(new TestError(this, d.getSeverity(), tr("Suspicious tag/value combinations"), 395 d.getDescription(), d.getDescriptionOrig(), d.getCode(), p)); 392 errors.add(TestError.builder(this, d.getSeverity(), d.getCode()) 393 .message(tr("Suspicious tag/value combinations"), d.getDescription()) 394 .primitives(p) 395 .build()); 396 396 withErrors.put(p, "TC"); 397 397 } … … 404 404 String value = prop.getValue(); 405 405 if (checkValues && (containsLow(value)) && !withErrors.contains(p, "ICV")) { 406 errors.add(new TestError(this, Severity.WARNING, tr("Tag value contains character with code less than 0x20"), 407 tr(s, key), MessageFormat.format(s, key), LOW_CHAR_VALUE, p)); 406 errors.add(TestError.builder(this, Severity.WARNING, LOW_CHAR_VALUE) 407 .message(tr("Tag value contains character with code less than 0x20"), s, key) 408 .primitives(p) 409 .build()); 408 410 withErrors.put(p, "ICV"); 409 411 } 410 412 if (checkKeys && (containsLow(key)) && !withErrors.contains(p, "ICK")) { 411 errors.add(new TestError(this, Severity.WARNING, tr("Tag key contains character with code less than 0x20"), 412 tr(s, key), MessageFormat.format(s, key), LOW_CHAR_KEY, p)); 413 errors.add(TestError.builder(this, Severity.WARNING, LOW_CHAR_KEY) 414 .message(tr("Tag key contains character with code less than 0x20"), s, key) 415 .primitives(p) 416 .build()); 413 417 withErrors.put(p, "ICK"); 414 418 } 415 419 if (checkValues && (value != null && value.length() > 255) && !withErrors.contains(p, "LV")) { 416 errors.add(new TestError(this, Severity.ERROR, tr("Tag value longer than allowed"), 417 tr(s, key), MessageFormat.format(s, key), LONG_VALUE, p)); 420 errors.add(TestError.builder(this, Severity.ERROR, LONG_VALUE) 421 .message(tr("Tag value longer than allowed"), s, key) 422 .primitives(p) 423 .build()); 418 424 withErrors.put(p, "LV"); 419 425 } 420 426 if (checkKeys && (key != null && key.length() > 255) && !withErrors.contains(p, "LK")) { 421 errors.add(new TestError(this, Severity.ERROR, tr("Tag key longer than allowed"), 422 tr(s, key), MessageFormat.format(s, key), LONG_KEY, p)); 427 errors.add(TestError.builder(this, Severity.ERROR, LONG_KEY) 428 .message(tr("Tag key longer than allowed"), s, key) 429 .primitives(p) 430 .build()); 423 431 withErrors.put(p, "LK"); 424 432 } 425 433 if (checkValues && (value == null || value.trim().isEmpty()) && !withErrors.contains(p, "EV")) { 426 errors.add(new TestError(this, Severity.WARNING, tr("Tags with empty values"), 427 tr(s, key), MessageFormat.format(s, key), EMPTY_VALUES, p)); 434 errors.add(TestError.builder(this, Severity.WARNING, EMPTY_VALUES) 435 .message(tr("Tags with empty values"), s, key) 436 .primitives(p) 437 .build()); 428 438 withErrors.put(p, "EV"); 429 439 } 430 440 if (checkKeys && key != null && key.indexOf(' ') >= 0 && !withErrors.contains(p, "IPK")) { 431 errors.add(new TestError(this, Severity.WARNING, tr("Invalid white space in property key"), 432 tr(s, key), MessageFormat.format(s, key), INVALID_KEY_SPACE, p)); 441 errors.add(TestError.builder(this, Severity.WARNING, INVALID_KEY_SPACE) 442 .message(tr("Invalid white space in property key"), s, key) 443 .primitives(p) 444 .build()); 433 445 withErrors.put(p, "IPK"); 434 446 } 435 447 if (checkValues && value != null && (value.startsWith(" ") || value.endsWith(" ")) && !withErrors.contains(p, "SPACE")) { 436 errors.add(new TestError(this, Severity.WARNING, tr("Property values start or end with white space"), 437 tr(s, key), MessageFormat.format(s, key), INVALID_SPACE, p)); 448 errors.add(TestError.builder(this, Severity.WARNING, INVALID_SPACE) 449 .message(tr("Property values start or end with white space"), s, key) 450 .primitives(p) 451 .build()); 438 452 withErrors.put(p, "SPACE"); 439 453 } 440 454 if (checkValues && value != null && value.contains(" ") && !withErrors.contains(p, "SPACE")) { 441 errors.add(new TestError(this, Severity.WARNING, tr("Property values contain multiple white spaces"), 442 tr(s, key), MessageFormat.format(s, key), MULTIPLE_SPACES, p)); 455 errors.add(TestError.builder(this, Severity.WARNING, MULTIPLE_SPACES) 456 .message(tr("Property values contain multiple white spaces"), s, key) 457 .primitives(p) 458 .build()); 443 459 withErrors.put(p, "SPACE"); 444 460 } 445 461 if (checkValues && value != null && !value.equals(Entities.unescape(value)) && !withErrors.contains(p, "HTML")) { 446 errors.add(new TestError(this, Severity.OTHER, tr("Property values contain HTML entity"), 447 tr(s, key), MessageFormat.format(s, key), INVALID_HTML, p)); 462 errors.add(TestError.builder(this, Severity.OTHER, INVALID_HTML) 463 .message(tr("Property values contain HTML entity"), s, key) 464 .primitives(p) 465 .build()); 448 466 withErrors.put(p, "HTML"); 449 467 } … … 455 473 if (fixedKey != null && !"".equals(fixedKey) && !fixedKey.equals(key)) { 456 474 // misspelled preset key 457 String i = marktr("Key ''{0}'' looks like ''{1}''."); 458 final TestError error; 475 final TestError.Builder error = TestError.builder(this, Severity.WARNING, MISSPELLED_KEY) 476 .message(tr("Misspelled property key"), marktr("Key ''{0}'' looks like ''{1}''."), key, fixedKey) 477 .primitives(p); 459 478 if (p.hasKey(fixedKey)) { 460 error = new TestError(this, Severity.WARNING, tr("Misspelled property key"), 461 tr(i, key, fixedKey), 462 MessageFormat.format(i, key, fixedKey), MISSPELLED_KEY, p); 479 errors.add(error.build()); 463 480 } else { 464 error = new FixableTestError(this, Severity.WARNING, tr("Misspelled property key"), 465 tr(i, key, fixedKey), 466 MessageFormat.format(i, key, fixedKey), MISSPELLED_KEY, p, 467 new ChangePropertyKeyCommand(p, key, fixedKey)); 481 errors.add(error.fix(() -> new ChangePropertyKeyCommand(p, key, fixedKey)).build()); 468 482 } 469 errors.add(error);470 483 withErrors.put(p, "WPK"); 471 484 } else { 472 String i = marktr("Key ''{0}'' not in presets."); 473 errors.add(new TestError(this, Severity.OTHER, tr("Presets do not contain property key"), 474 tr(i, key), MessageFormat.format(i, key), INVALID_VALUE, p)); 485 errors.add(TestError.builder(this, Severity.OTHER, INVALID_VALUE) 486 .message(tr("Presets do not contain property key"), marktr("Key ''{0}'' not in presets."), key) 487 .primitives(p) 488 .build()); 475 489 withErrors.put(p, "UPK"); 476 490 } … … 480 494 Map<String, String> possibleValues = getPossibleValues(presetsValueData.get(key)); 481 495 if (possibleValues.containsKey(fixedValue)) { 482 fi xedValue= possibleValues.get(fixedValue);496 final String newKey = possibleValues.get(fixedValue); 483 497 // misspelled preset value 484 String i = marktr("Value ''{0}'' for key ''{1}'' looks like ''{2}''."); 485 errors.add(new FixableTestError(this, Severity.WARNING, tr("Misspelled property value"), 486 tr(i, prop.getValue(), key, fixedValue), MessageFormat.format(i, prop.getValue(), fixedValue), 487 MISSPELLED_VALUE, p, new ChangePropertyCommand(p, key, fixedValue))); 498 errors.add(TestError.builder(this, Severity.WARNING, MISSPELLED_VALUE) 499 .message(tr("Misspelled property value"), 500 marktr("Value ''{0}'' for key ''{1}'' looks like ''{2}''."), prop.getValue(), key, fixedValue) 501 .primitives(p) 502 .fix(() -> new ChangePropertyCommand(p, key, newKey)) 503 .build()); 488 504 withErrors.put(p, "WPV"); 489 505 } else { 490 506 // unknown preset value 491 String i = marktr("Value ''{0}'' for key ''{1}'' not in presets."); 492 errors.add(new TestError(this, Severity.OTHER, tr("Presets do not contain property value"), 493 tr(i, prop.getValue(), key), MessageFormat.format(i, prop.getValue(), key), INVALID_VALUE, p)); 507 errors.add(TestError.builder(this, Severity.OTHER, INVALID_VALUE) 508 .message(tr("Presets do not contain property value"), 509 marktr("Value ''{0}'' for key ''{1}'' not in presets."), prop.getValue(), key) 510 .primitives(p) 511 .build()); 494 512 withErrors.put(p, "UPV"); 495 513 } … … 502 520 || key.contains("todo") || key.toLowerCase(Locale.ENGLISH).contains("fixme")) 503 521 && !withErrors.contains(p, "FIXME")) { 504 errors.add(new TestError(this, Severity.OTHER, 505 tr("FIXMES"), FIXME, p)); 522 errors.add(TestError.builder(this, Severity.OTHER, FIXME) 523 .message(tr("FIXMES")) 524 .primitives(p) 525 .build()); 506 526 withErrors.put(p, "FIXME"); 507 527 } … … 646 666 List<Command> commands = new ArrayList<>(50); 647 667 648 if (testError instanceof FixableTestError) { 649 commands.add(testError.getFix()); 650 } else { 651 Collection<? extends OsmPrimitive> primitives = testError.getPrimitives(); 652 for (OsmPrimitive p : primitives) { 653 Map<String, String> tags = p.getKeys(); 654 if (tags == null || tags.isEmpty()) { 655 continue; 656 } 657 658 for (Entry<String, String> prop: tags.entrySet()) { 659 String key = prop.getKey(); 660 String value = prop.getValue(); 661 if (value == null || value.trim().isEmpty()) { 662 commands.add(new ChangePropertyCommand(p, key, null)); 663 } else if (value.startsWith(" ") || value.endsWith(" ") || value.contains(" ")) { 664 commands.add(new ChangePropertyCommand(p, key, Tag.removeWhiteSpaces(value))); 665 } else if (key.startsWith(" ") || key.endsWith(" ") || key.contains(" ")) { 666 commands.add(new ChangePropertyKeyCommand(p, key, Tag.removeWhiteSpaces(key))); 667 } else { 668 String evalue = Entities.unescape(value); 669 if (!evalue.equals(value)) { 670 commands.add(new ChangePropertyCommand(p, key, evalue)); 671 } 668 Collection<? extends OsmPrimitive> primitives = testError.getPrimitives(); 669 for (OsmPrimitive p : primitives) { 670 Map<String, String> tags = p.getKeys(); 671 if (tags == null || tags.isEmpty()) { 672 continue; 673 } 674 675 for (Entry<String, String> prop: tags.entrySet()) { 676 String key = prop.getKey(); 677 String value = prop.getValue(); 678 if (value == null || value.trim().isEmpty()) { 679 commands.add(new ChangePropertyCommand(p, key, null)); 680 } else if (value.startsWith(" ") || value.endsWith(" ") || value.contains(" ")) { 681 commands.add(new ChangePropertyCommand(p, key, Tag.removeWhiteSpaces(value))); 682 } else if (key.startsWith(" ") || key.endsWith(" ") || key.contains(" ")) { 683 commands.add(new ChangePropertyKeyCommand(p, key, Tag.removeWhiteSpaces(key))); 684 } else { 685 String evalue = Entities.unescape(value); 686 if (!evalue.equals(value)) { 687 commands.add(new ChangePropertyCommand(p, key, evalue)); 672 688 } 673 689 } … … 840 856 841 857 public String getDescription() { 842 return tr(description);843 }844 845 public String getDescriptionOrig() {846 858 return description; 847 859 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/TurnrestrictionTest.java
r9244 r11129 5 5 6 6 import java.util.ArrayList; 7 import java.util.Arrays;8 import java.util.Collections;9 7 import java.util.List; 10 8 … … 99 97 break; 100 98 default: 101 errors.add(new TestError(this, Severity.WARNING, tr("Unknown role"), UNKNOWN_ROLE, 102 l, Collections.singletonList(m))); 99 errors.add(TestError.builder(this, Severity.WARNING, UNKNOWN_ROLE) 100 .message(tr("Unknown role")) 101 .primitives(l) 102 .highlight(m.getMember()) 103 .build()); 103 104 } 104 105 } else if (m.isNode()) { … … 115 116 } 116 117 } else { 117 errors.add(new TestError(this, Severity.WARNING, tr("Unknown role"), UNKNOWN_ROLE, 118 l, Collections.singletonList(m))); 118 errors.add(TestError.builder(this, Severity.WARNING, UNKNOWN_ROLE) 119 .message(tr("Unknown role")) 120 .primitives(l) 121 .highlight(m.getMember()) 122 .build()); 119 123 } 120 124 } else { 121 errors.add(new TestError(this, Severity.WARNING, tr("Unknown member type"), UNKNOWN_TYPE, 122 l, Collections.singletonList(m))); 125 errors.add(TestError.builder(this, Severity.WARNING, UNKNOWN_TYPE) 126 .message(tr("Unknown member type")) 127 .primitives(l) 128 .highlight(m.getMember()) 129 .build()); 123 130 } 124 131 } 125 132 if (morefrom) { 126 errors.add(new TestError(this, Severity.ERROR, tr("More than one \"from\" way found"), MORE_FROM, r)); 133 errors.add(TestError.builder(this, Severity.ERROR, MORE_FROM) 134 .message(tr("More than one \"from\" way found")) 135 .primitives(r) 136 .build()); 127 137 } 128 138 if (moreto) { 129 errors.add(new TestError(this, Severity.ERROR, tr("More than one \"to\" way found"), MORE_TO, r)); 139 errors.add(TestError.builder(this, Severity.ERROR, MORE_TO) 140 .message(tr("More than one \"to\" way found")) 141 .primitives(r) 142 .build()); 130 143 } 131 144 if (morevia) { 132 errors.add(new TestError(this, Severity.ERROR, tr("More than one \"via\" node found"), MORE_VIA, r)); 145 errors.add(TestError.builder(this, Severity.ERROR, MORE_VIA) 146 .message(tr("More than one \"via\" node found")) 147 .primitives(r) 148 .build()); 133 149 } 134 150 if (mixvia) { 135 errors.add(new TestError(this, Severity.ERROR, tr("Cannot mix node and way for role \"via\""), MIX_VIA, r)); 151 errors.add(TestError.builder(this, Severity.ERROR, MIX_VIA) 152 .message(tr("Cannot mix node and way for role \"via\"")) 153 .primitives(r) 154 .build()); 136 155 } 137 156 138 157 if (fromWay == null) { 139 errors.add(new TestError(this, Severity.ERROR, tr("No \"from\" way found"), NO_FROM, r)); 158 errors.add(TestError.builder(this, Severity.ERROR, NO_FROM) 159 .message(tr("No \"from\" way found")) 160 .primitives(r) 161 .build()); 140 162 return; 141 163 } 142 164 if (toWay == null) { 143 errors.add(new TestError(this, Severity.ERROR, tr("No \"to\" way found"), NO_TO, r)); 165 errors.add(TestError.builder(this, Severity.ERROR, NO_TO) 166 .message(tr("No \"to\" way found")) 167 .primitives(r) 168 .build()); 144 169 return; 145 170 } 146 171 if (fromWay.equals(toWay)) { 147 errors.add(new TestError(this, r.hasTag("restriction", "no_u_turn") ? Severity.OTHER : Severity.WARNING, 148 tr("\"from\" way equals \"to\" way"), FROM_EQUALS_TO, r)); 172 Severity severity = r.hasTag("restriction", "no_u_turn") ? Severity.OTHER : Severity.WARNING; 173 errors.add(TestError.builder(this, severity, FROM_EQUALS_TO) 174 .message(tr("\"from\" way equals \"to\" way")) 175 .primitives(r) 176 .build()); 149 177 } 150 178 if (via.isEmpty()) { 151 errors.add(new TestError(this, Severity.ERROR, tr("No \"via\" node or way found"), NO_VIA, r)); 179 errors.add(TestError.builder(this, Severity.ERROR, NO_VIA) 180 .message(tr("No \"via\" node or way found")) 181 .primitives(r) 182 .build()); 152 183 return; 153 184 } … … 160 191 tr("The \"from\" way does not start or end at a \"via\" node."), FROM_VIA_NODE); 161 192 if (toWay.isOneway() != 0 && viaNode.equals(toWay.lastNode(true))) { 162 errors.add(new TestError(this, Severity.WARNING, tr("Superfluous turnrestriction as \"to\" way is oneway"), SUPERFLUOUS, r)); 193 errors.add(TestError.builder(this, Severity.WARNING, SUPERFLUOUS) 194 .message(tr("Superfluous turnrestriction as \"to\" way is oneway")) 195 .primitives(r) 196 .build()); 163 197 return; 164 198 } … … 178 212 } 179 213 if (toWay.isOneway() != 0 && ((Way) via.get(via.size() - 1)).isFirstLastNode(toWay.lastNode(true))) { 180 errors.add(new TestError(this, Severity.WARNING, tr("Superfluous turnrestriction as \"to\" way is oneway"), SUPERFLUOUS, r)); 214 errors.add(TestError.builder(this, Severity.WARNING, SUPERFLUOUS) 215 .message(tr("Superfluous turnrestriction as \"to\" way is oneway")) 216 .primitives(r) 217 .build()); 181 218 return; 182 219 } … … 206 243 } 207 244 if (!c) { 208 errors.add(new TestError(this, Severity.ERROR, msg, code, Arrays.asList(previous, current))); 245 errors.add(TestError.builder(this, Severity.ERROR, code) 246 .message(msg) 247 .primitives(previous, current) 248 .build()); 209 249 } 210 250 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/UnclosedWays.java
r10755 r11129 5 5 import static org.openstreetmap.josm.tools.I18n.tr; 6 6 7 import java.text.MessageFormat;8 7 import java.util.Arrays; 9 8 import java.util.Collections; … … 96 95 String value = w.get(key); 97 96 if (isValueErroneous(value)) { 98 // CHECKSTYLE.OFF: SingleSpaceSeparator 99 String type = engMessage.contains("{0}") ? tr(engMessage, tr(value)) : tr(engMessage); 100 String etype = engMessage.contains("{0}") ? MessageFormat.format(engMessage, value) : engMessage; 101 // CHECKSTYLE.ON: SingleSpaceSeparator 102 return new TestError(test, Severity.WARNING, tr("Unclosed way"), 103 type, etype, code, Arrays.asList(w), 104 // The important parts of an unclosed way are the first and 105 // the last node which should be connected, therefore we highlight them 106 Arrays.asList(w.firstNode(), w.lastNode())); 97 return TestError.builder(test, Severity.WARNING, code) 98 .message(tr("Unclosed way"), engMessage, engMessage.contains("{0}") ? new Object[]{value} : new Object[]{}) 99 .primitives(w) 100 .highlight(Arrays.asList(w.firstNode(), w.lastNode())) 101 .build(); 107 102 } 108 103 return null; -
trunk/src/org/openstreetmap/josm/data/validation/tests/UnconnectedWays.java
r10776 r11129 8 8 import java.awt.geom.Point2D; 9 9 import java.util.ArrayList; 10 import java.util.Arrays;11 10 import java.util.Collection; 12 11 import java.util.Collections; … … 264 263 protected final void addErrors(Severity severity, Map<Node, Way> errorMap, String message) { 265 264 for (Map.Entry<Node, Way> error : errorMap.entrySet()) { 266 errors.add(new TestError(this, severity, message, UNCONNECTED_WAYS, 267 Arrays.asList(error.getKey(), error.getValue()), 268 Arrays.asList(error.getKey()))); 265 errors.add(TestError.builder(this, severity, UNCONNECTED_WAYS) 266 .message(message) 267 .primitives(error.getKey(), error.getValue()) 268 .highlight(error.getKey()) 269 .build()); 269 270 } 270 271 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/UntaggedNode.java
r10657 r11129 44 44 45 45 if (!n.hasKeys() && IN_DOWNLOADED_AREA.test(n)) { 46 String msg = marktr("No tags"); 47 errors.add(new TestError(this, Severity.WARNING, ERROR_MESSAGE, tr(msg), msg, UNTAGGED_NODE_BLANK, n)); 46 errors.add(TestError.builder(this, Severity.WARNING, UNTAGGED_NODE_BLANK) 47 .message(ERROR_MESSAGE, marktr("No tags")) 48 .primitives(n) 49 .build()); 48 50 return; 49 51 } … … 56 58 if (key.toLowerCase(Locale.ENGLISH).contains("fixme") || value.toLowerCase(Locale.ENGLISH).contains("fixme")) { 57 59 /* translation note: don't translate quoted words */ 58 String msg = marktr("Has tag containing ''fixme'' or ''FIXME''"); 59 errors.add(new TestError(this, Severity.WARNING, ERROR_MESSAGE, tr(msg), msg, UNTAGGED_NODE_FIXME, (OsmPrimitive) n)); 60 errors.add(TestError.builder(this, Severity.WARNING, UNTAGGED_NODE_FIXME) 61 .message(ERROR_MESSAGE, marktr("Has tag containing ''fixme'' or ''FIXME''")) 62 .primitives((OsmPrimitive) n) 63 .build()); 60 64 return; 61 65 } … … 81 85 } 82 86 if (msg != null) { 83 errors.add(new TestError(this, Severity.WARNING, ERROR_MESSAGE, tr(msg), msg, code, (OsmPrimitive) n)); 87 errors.add(TestError.builder(this, Severity.WARNING, code) 88 .message(ERROR_MESSAGE, msg) 89 .primitives((OsmPrimitive) n) 90 .build()); 84 91 return; 85 92 } 86 93 // Does not happen, but just to be sure. Maybe definition of uninteresting tags changes in future. 87 errors.add(new TestError(this, Severity.WARNING, ERROR_MESSAGE, tr("Other"), "Other", UNTAGGED_NODE_OTHER, (OsmPrimitive) n)); 94 errors.add(TestError.builder(this, Severity.WARNING, UNTAGGED_NODE_OTHER) 95 .message(ERROR_MESSAGE, marktr("Other")) 96 .primitives((OsmPrimitive) n) 97 .build()); 88 98 } 89 99 -
trunk/src/org/openstreetmap/josm/data/validation/tests/UntaggedWay.java
r10448 r11129 98 98 99 99 if (!hasName && !isJunction) { 100 errors.add(new TestError(this, Severity.WARNING, tr("Unnamed ways"), UNNAMED_WAY, w)); 100 errors.add(TestError.builder(this, Severity.WARNING, UNNAMED_WAY) 101 .message(tr("Unnamed ways")) 102 .primitives(w) 103 .build()); 101 104 } else if (isJunction) { 102 errors.add(new TestError(this, Severity.OTHER, tr("Unnamed junction"), UNNAMED_JUNCTION, w)); 105 errors.add(TestError.builder(this, Severity.OTHER, UNNAMED_JUNCTION) 106 .message(tr("Unnamed junction")) 107 .primitives(w) 108 .build()); 103 109 } 104 110 } … … 107 113 if (!w.isTagged() && !waysUsedInRelations.contains(w)) { 108 114 if (w.hasKeys()) { 109 errors.add(new TestError(this, Severity.WARNING, tr("Untagged ways (commented)"), COMMENTED_WAY, w)); 115 errors.add(TestError.builder(this, Severity.WARNING, COMMENTED_WAY) 116 .message(tr("Untagged ways (commented)")) 117 .primitives(w) 118 .build()); 110 119 } else { 111 errors.add(new TestError(this, Severity.WARNING, tr("Untagged ways"), UNTAGGED_WAY, w)); 120 errors.add(TestError.builder(this, Severity.WARNING, UNTAGGED_WAY) 121 .message(tr("Untagged ways")) 122 .primitives(w) 123 .build()); 112 124 } 113 125 } 114 126 115 127 if (w.getNodesCount() == 0) { 116 errors.add(new TestError(this, Severity.ERROR, tr("Empty ways"), EMPTY_WAY, w)); 128 errors.add(TestError.builder(this, Severity.ERROR, EMPTY_WAY) 129 .message(tr("Empty ways")) 130 .primitives(w) 131 .build()); 117 132 } else if (w.getNodesCount() == 1) { 118 errors.add(new TestError(this, Severity.ERROR, tr("One node ways"), ONE_NODE_WAY, w)); 133 errors.add(TestError.builder(this, Severity.ERROR, ONE_NODE_WAY) 134 .message(tr("One node ways")) 135 .primitives(w) 136 .build()); 119 137 } 120 138 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/WayConnectedToArea.java
r10715 r11129 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.util.Arrays;7 6 import java.util.List; 8 7 … … 92 91 return; 93 92 } 94 errors.add(new TestError(this, Severity.WARNING, 95 tr("Way terminates on Area"), 2301, 96 Arrays.asList(w, p), 97 Arrays.asList(wayNode))); 93 errors.add(TestError.builder(this, Severity.WARNING, 2301) 94 .message(tr("Way terminates on Area")) 95 .primitives(w, p) 96 .highlight(wayNode) 97 .build()); 98 98 } 99 99 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/WronglyOrderedWays.java
r10378 r11129 3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 import java.util.Collections;7 5 8 6 import org.openstreetmap.josm.data.osm.Way; … … 51 49 52 50 private void reportError(Way w, String msg, int type) { 53 errors.add(new TestError(this, Severity.WARNING, msg, type, Collections.singletonList(w))); 51 errors.add(TestError.builder(this, Severity.WARNING, type) 52 .message(msg) 53 .primitives(w) 54 .build()); 54 55 } 55 56 } -
trunk/test/unit/org/openstreetmap/josm/gui/dialogs/validator/ValidatorTreePanelTest.java
r10962 r11129 42 42 43 43 ValidatorTreePanel vtp = new ValidatorTreePanel(new ArrayList<>(Arrays.asList( 44 new TestError(null, Severity.ERROR, "err", 0, new Node(1)), 45 new TestError(null, Severity.WARNING, "warn", 0, new Node(2))))); 44 TestError.builder(null, Severity.ERROR, 0) 45 .message("err") 46 .primitives(new Node(1)) 47 .build(), 48 TestError.builder(null, Severity.WARNING, 0) 49 .message("warn") 50 .primitives(new Node(2)) 51 .build()))); 46 52 assertNotNull(vtp); 47 53 assertEquals(2, vtp.getErrors().size()); … … 49 55 vtp.setVisible(false); 50 56 Node n = new Node(10); 51 vtp.setErrors(Arrays.asList(new TestError(null, Severity.ERROR, "", 0, n))); 57 vtp.setErrors(Arrays.asList(TestError.builder(null, Severity.ERROR, 0) 58 .message("") 59 .primitives(n) 60 .build())); 52 61 assertEquals(1, vtp.getErrors().size()); 53 62 vtp.selectRelatedErrors(Collections.<OsmPrimitive>singleton(n));
Note:
See TracChangeset
for help on using the changeset viewer.