Ticket #23397: 23397-beta2.patch
File 23397-beta2.patch, 17.0 KB (added by , 13 months ago) |
---|
-
src/org/openstreetmap/josm/actions/ValidateAction.java
12 12 import org.openstreetmap.josm.data.validation.OsmValidator; 13 13 import org.openstreetmap.josm.data.validation.Test; 14 14 import org.openstreetmap.josm.data.validation.ValidationTask; 15 import org.openstreetmap.josm.data.validation.util.AggregatePrimitivesVisitor;16 15 import org.openstreetmap.josm.gui.MainApplication; 17 16 import org.openstreetmap.josm.gui.MapFrame; 18 17 import org.openstreetmap.josm.tools.Shortcut; … … 70 69 selection = getLayerManager().getActiveDataSet().allNonDeletedPrimitives(); 71 70 lastSelection = null; 72 71 } else { 73 AggregatePrimitivesVisitor v = new AggregatePrimitivesVisitor();74 selection = v.visit(selection);75 72 lastSelection = selection; 76 73 } 77 74 } else { -
src/org/openstreetmap/josm/actions/upload/ValidateUploadHook.java
6 6 import java.awt.Dimension; 7 7 import java.awt.GridBagLayout; 8 8 import java.util.Collection; 9 import java.util.HashSet; 9 10 import java.util.List; 10 11 import java.util.concurrent.atomic.AtomicBoolean; 11 12 … … 17 18 import org.openstreetmap.josm.data.validation.OsmValidator; 18 19 import org.openstreetmap.josm.data.validation.TestError; 19 20 import org.openstreetmap.josm.data.validation.ValidationTask; 20 import org.openstreetmap.josm.data.validation.util.AggregatePrimitivesVisitor;21 21 import org.openstreetmap.josm.gui.ExtendedDialog; 22 22 import org.openstreetmap.josm.gui.MainApplication; 23 23 import org.openstreetmap.josm.gui.dialogs.validator.ValidatorTreePanel; … … 45 45 @Override 46 46 public boolean checkUpload(APIDataSet apiDataSet) { 47 47 AtomicBoolean returnCode = new AtomicBoolean(); 48 AggregatePrimitivesVisitor v = new AggregatePrimitivesVisitor();49 v.visit(apiDataSet.getPrimitivesToAdd());50 Collection<OsmPrimitive> visited = v.visit(apiDataSet.getPrimitivesToUpdate());48 Collection<OsmPrimitive> toCheck = new HashSet<>(); 49 toCheck.addAll(apiDataSet.getPrimitivesToAdd()); 50 toCheck.addAll(apiDataSet.getPrimitivesToUpdate()); 51 51 OsmValidator.initializeTests(); 52 52 new ValidationTask(errors -> { 53 53 if (errors.stream().allMatch(TestError::isIgnored)) { … … 58 58 // of the progress monitor. 59 59 GuiHelper.runInEDTAndWait(() -> returnCode.set(displayErrorScreen(errors))); 60 60 } 61 }, null, OsmValidator.getEnabledTests(true), visited, null, true).run();61 }, null, OsmValidator.getEnabledTests(true), toCheck, null, true).run(); 62 62 63 63 return returnCode.get(); 64 64 } -
src/org/openstreetmap/josm/data/validation/Test.java
6 6 import java.awt.GridBagConstraints; 7 7 import java.util.ArrayList; 8 8 import java.util.Collection; 9 import java.util.HashSet; 9 10 import java.util.List; 10 11 import java.util.Optional; 12 import java.util.Set; 11 13 import java.util.function.Predicate; 12 14 import java.util.stream.Collectors; 13 15 … … 383 385 public Object getSource() { 384 386 return "Java: " + this.getClass().getName(); 385 387 } 388 389 /** 390 * Filter the list of errors, remove all which do not concern the given list of primitives 391 * @param given the list of primitives 392 * @since xxx 393 */ 394 public void removeIrrelevantErrors(Collection<? extends OsmPrimitive> given) { 395 if (errors == null || errors.isEmpty()) 396 return; 397 // filter errors for those which are needed, don't show errors for objects which were not in the selection 398 final Set<? extends OsmPrimitive> relevant; 399 if (given instanceof Set) { 400 relevant = (Set<? extends OsmPrimitive>) given; 401 } else { 402 relevant = new HashSet<>(given); 403 } 404 errors.removeIf(e -> !e.isConcerned(relevant)); 405 } 386 406 } -
src/org/openstreetmap/josm/data/validation/TestError.java
12 12 import java.util.List; 13 13 import java.util.Locale; 14 14 import java.util.Map; 15 import java.util.Set; 15 16 import java.util.TreeSet; 16 17 import java.util.function.Supplier; 17 18 import java.util.stream.Collectors; … … 666 667 ", code=" + code + ", message=" + message + ']'; 667 668 } 668 669 670 /** 671 * Check if any of the primitives in this error occurs in the given set of primitives. 672 * @param given the set of primitives 673 * @return true if any of the primitives in this error occurs in the given set of primitives, else false 674 * @since xxx 675 */ 676 public boolean isConcerned(Set<? extends OsmPrimitive> given) { 677 for (OsmPrimitive p : getPrimitives()) { 678 if (given.contains(p)) { 679 return true; 680 } 681 } 682 return false; 683 } 669 684 } -
src/org/openstreetmap/josm/data/validation/ValidationTask.java
6 6 import java.awt.GraphicsEnvironment; 7 7 import java.util.ArrayList; 8 8 import java.util.Collection; 9 import java.util.HashSet; 9 10 import java.util.List; 10 11 import java.util.function.BiConsumer; 11 12 import java.util.function.Consumer; … … 12 13 13 14 import javax.swing.JOptionPane; 14 15 16 import org.openstreetmap.josm.data.osm.Node; 15 17 import org.openstreetmap.josm.data.osm.OsmPrimitive; 16 18 import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper; 19 import org.openstreetmap.josm.data.validation.util.AggregatePrimitivesVisitor; 17 20 import org.openstreetmap.josm.gui.MainApplication; 18 21 import org.openstreetmap.josm.gui.MapFrame; 19 22 import org.openstreetmap.josm.gui.Notification; … … 30 33 public class ValidationTask extends PleaseWaitRunnable { 31 34 private final Consumer<List<TestError>> onFinish; 32 35 private Collection<Test> tests; 33 private final Collection<OsmPrimitive> validatedPrimitives;36 private final Collection<OsmPrimitive> initialPrimitives; 34 37 private final Collection<OsmPrimitive> formerValidatedPrimitives; 35 38 private final boolean beforeUpload; 36 39 private boolean canceled; … … 71 74 progressMonitor != null ? progressMonitor : new PleaseWaitProgressMonitor(tr("Validating")), 72 75 false /*don't ignore exceptions */); 73 76 this.onFinish = onFinish; 74 this. validatedPrimitives = validatedPrimitives;77 this.initialPrimitives = validatedPrimitives; 75 78 this.formerValidatedPrimitives = formerValidatedPrimitives; 76 79 this.tests = tests; 77 80 this.beforeUpload = beforeUpload; 78 81 } 79 82 83 /** 84 * Create extended list 85 * - add child objects because MapCss tests may need them to work properly 86 * - add parent objects of modified nodes as they may mean a geometry change 87 * @param primitives the primitives 88 * @return extended list of primitives 89 */ 90 private static Collection<OsmPrimitive> extendList(Collection<OsmPrimitive> primitives) { 91 Collection<OsmPrimitive> extendedList = new HashSet<>(primitives); 92 for (OsmPrimitive p : primitives) { 93 if (p instanceof Node && p.isModified() && !p.isNew()) { 94 for (OsmPrimitive parent : p.getReferrers()) { 95 if (!parent.isDeleted()) { 96 extendedList.add(parent); 97 } 98 } 99 } 100 } 101 AggregatePrimitivesVisitor v = new AggregatePrimitivesVisitor(); 102 return v.visit(extendedList); 103 } 104 80 105 protected ValidationTask(ProgressMonitor progressMonitor, 81 106 Collection<Test> tests, 82 107 Collection<OsmPrimitive> validatedPrimitives, … … 122 147 protected void realRun() { 123 148 if (Utils.isEmpty(tests)) 124 149 return; 150 int testCounter = 0; 151 final boolean isPartial = this.beforeUpload || formerValidatedPrimitives != null; 152 153 Collection<OsmPrimitive> validatedPrimitives = isPartial ? extendList(initialPrimitives) : initialPrimitives; 125 154 getProgressMonitor().setTicksCount(tests.size() * validatedPrimitives.size()); 126 int testCounter = 0; 155 127 156 for (Test test : tests) { 128 157 if (canceled) 129 158 return; … … 131 160 getProgressMonitor().setCustomText(tr("Test {0}/{1}: Starting {2}", testCounter, tests.size(), test.getName())); 132 161 test.setBeforeUpload(this.beforeUpload); 133 162 // Pre-upload checks only run on a partial selection. 134 test.setPartialSelection( this.beforeUpload || formerValidatedPrimitives != null);163 test.setPartialSelection(isPartial); 135 164 test.startTest(getProgressMonitor().createSubTaskMonitor(validatedPrimitives.size(), false)); 136 165 test.visit(validatedPrimitives); 137 166 test.endTest(); 167 if (isPartial) { 168 // #23397: remove errors for objects which were not in the initial list of primitives 169 test.removeIrrelevantErrors(initialPrimitives); 170 } 138 171 errors.addAll(test.getErrors()); 139 172 if (this.testConsumer != null) { 140 173 this.testConsumer.accept(this, test); -
src/org/openstreetmap/josm/data/validation/tests/CrossingWays.java
6 6 import java.awt.geom.Point2D; 7 7 import java.util.ArrayList; 8 8 import java.util.Arrays; 9 import java.util.Collection; 9 10 import java.util.HashMap; 10 11 import java.util.HashSet; 11 12 import java.util.List; … … 16 17 17 18 import org.openstreetmap.josm.data.coor.EastNorth; 18 19 import org.openstreetmap.josm.data.coor.ILatLon; 20 import org.openstreetmap.josm.data.osm.DataSet; 21 import org.openstreetmap.josm.data.osm.OsmDataManager; 19 22 import org.openstreetmap.josm.data.osm.OsmPrimitive; 20 23 import org.openstreetmap.josm.data.osm.OsmUtils; 21 24 import org.openstreetmap.josm.data.osm.Relation; … … 81 84 private final Map<Point2D, List<WaySegment>> cellSegments = new HashMap<>(1000); 82 85 /** The already detected ways in error */ 83 86 private final Map<List<Way>, List<WaySegment>> seenWays = new HashMap<>(50); 87 private final Set<Way> waysToTest = new HashSet<>(); 84 88 85 89 protected final int code; 86 90 … … 305 309 306 310 @Override 307 311 public void endTest() { 308 super.endTest(); 312 final Collection<Way> selection; 313 if (this instanceof SelfCrossing || !partialSelection) { 314 selection = waysToTest; 315 } else { 316 selection = new HashSet<>(); 317 DataSet ds = OsmDataManager.getInstance().getActiveDataSet(); 318 if (ds != null) { 319 for (Way w: waysToTest) { 320 selection.addAll(ds.searchWays(w.getBBox())); 321 } 322 } 323 } 324 for (Way w : selection) { 325 if (!w.isDeleted() && isPrimitiveUsable(w)) { 326 testWay(w); 327 } 328 } 329 // free storage 309 330 cellSegments.clear(); 310 331 seenWays.clear(); 332 waysToTest.clear(); 333 super.endTest(); 311 334 } 312 335 313 336 static boolean isCoastline(OsmPrimitive w) { … … 344 367 345 368 @Override 346 369 public void visit(Way w) { 370 waysToTest.add(w); 371 } 372 373 private void testWay(Way w) { 347 374 boolean findSelfCrossingOnly = this instanceof SelfCrossing; 348 375 if (findSelfCrossingOnly) { 349 376 // free memory, we are not interested in previous ways … … 482 509 CheckParameterUtil.ensureParameterNotNull(way, "way"); 483 510 SelfCrossing test = new SelfCrossing(); 484 511 test.visit(way); 512 test.endTest(); 485 513 return !test.getErrors().isEmpty(); 486 514 } 487 515 } -
src/org/openstreetmap/josm/data/validation/tests/DuplicateWay.java
7 7 import java.util.Collection; 8 8 import java.util.Collections; 9 9 import java.util.HashSet; 10 import java.util.LinkedHashSet; 10 11 import java.util.LinkedList; 11 12 import java.util.List; 12 13 import java.util.Map; … … 103 104 104 105 /** Set of known hashcodes for list of coordinates **/ 105 106 private Set<Integer> knownHashCodes; 107 private List<Way> waysToCheck; 106 108 107 109 /** 108 110 * Constructor … … 115 117 @Override 116 118 public void startTest(ProgressMonitor monitor) { 117 119 super.startTest(monitor); 120 waysToCheck = new ArrayList<>(); 118 121 ways = new MultiMap<>(1000); 119 122 waysNoTags = new MultiMap<>(1000); 120 123 knownHashCodes = new HashSet<>(1000); … … 122 125 123 126 @Override 124 127 public void endTest() { 125 super.endTest(); 128 if (partialSelection && !waysToCheck.isEmpty()) { 129 // make sure that we have the error candidates even if not selected 130 Set<Way> extended = new LinkedHashSet<>(waysToCheck); 131 for (Way w : waysToCheck) { 132 // select a node, anyone can be used but a middle node is less likely to have many parent ways 133 final Node n = w.getNode(w.getNodesCount()/2); 134 // check the ways which might be in the same position 135 for (Way other : n.getParentWays()) { 136 if (other != w && !other.isDeleted() && other.isUsable() 137 && other.getNodesCount() == w.getNodesCount()) 138 extended.add(other); 139 } 140 } 141 extended.forEach(this::checkWay); 142 } 143 126 144 for (Set<OsmPrimitive> duplicated : ways.values()) { 127 145 if (duplicated.size() > 1) { 128 146 TestError testError = TestError.builder(this, Severity.ERROR, DUPLICATE_WAY) … … 162 180 errors.add(testError); 163 181 } 164 182 } 183 165 184 ways = null; 166 185 waysNoTags = null; 167 186 knownHashCodes = null; 187 waysToCheck = null; 188 super.endTest(); 168 189 } 169 190 170 191 /** … … 181 202 public void visit(Way w) { 182 203 if (!w.isUsable()) 183 204 return; 205 if (partialSelection) 206 waysToCheck.add(w); 207 else 208 checkWay(w); 209 } 210 211 private void checkWay(Way w) { 184 212 List<LatLon> wLat = getOrderedNodes(w); 185 213 // If this way has not direction-dependant keys, make sure the list is ordered the same for all ways (fix #8015) 186 214 if (!w.hasDirectionKeys()) { -
src/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerRule.java
377 377 res.add(errorBuilder.primitives(p, (OsmPrimitive) c).build()); 378 378 } 379 379 } 380 } else if (env.parent != null) { 381 res.add(errorBuilder.primitives(p, (OsmPrimitive) env.parent).highlight(p).build()); 380 382 } else { 381 383 res.add(errorBuilder.primitives(p).build()); 382 384 } -
src/org/openstreetmap/josm/data/validation/util/AggregatePrimitivesVisitor.java
14 14 /** 15 15 * A visitor that aggregates all primitives it visits. 16 16 * <p> 17 * The primitives are sorted according to their type: first nodes, then ways.18 17 * 19 18 * @author frsantos 20 19 */ … … 24 23 25 24 /** 26 25 * Visits a collection of primitives 27 * @param data The collection of primitives 26 * @param data The collection of primitives in no specific order. 28 27 * @return The aggregated primitives 29 28 */ 30 29 public Collection<OsmPrimitive> visit(Collection<OsmPrimitive> data) {