source: josm/trunk/src/org/openstreetmap/josm/data/validation/Test.java@ 16553

Last change on this file since 16553 was 16553, checked in by Don-vip, 4 years ago

see #19334 - javadoc fixes + protected constructors for abstract classes

  • Property svn:eol-style set to native
File size: 11.8 KB
RevLine 
[8378]1// License: GPL. For details, see LICENSE file.
[3669]2package org.openstreetmap.josm.data.validation;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.GridBagConstraints;
7import java.util.ArrayList;
8import java.util.Collection;
9import java.util.List;
[11553]10import java.util.Optional;
[10657]11import java.util.function.Predicate;
[16332]12import java.util.stream.Collectors;
[3669]13
14import javax.swing.JCheckBox;
15import javax.swing.JPanel;
16
17import org.openstreetmap.josm.command.Command;
[5287]18import org.openstreetmap.josm.command.DeleteCommand;
[3669]19import org.openstreetmap.josm.data.osm.Node;
20import org.openstreetmap.josm.data.osm.OsmPrimitive;
21import org.openstreetmap.josm.data.osm.Relation;
22import org.openstreetmap.josm.data.osm.Way;
[12864]23import org.openstreetmap.josm.data.osm.search.SearchCompiler.InDataSourceArea;
[12656]24import org.openstreetmap.josm.data.osm.search.SearchCompiler.NotOutsideDataSourceArea;
[12809]25import org.openstreetmap.josm.data.osm.visitor.OsmPrimitiveVisitor;
[15682]26import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
[3669]27import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
28import org.openstreetmap.josm.gui.progress.ProgressMonitor;
29import org.openstreetmap.josm.tools.GBC;
[12620]30import org.openstreetmap.josm.tools.Logging;
[15755]31import org.openstreetmap.josm.tools.Stopwatch;
[3669]32
33/**
34 * Parent class for all validation tests.
35 * <p>
36 * A test is a primitive visitor, so that it can access to all data to be
37 * validated. These primitives are always visited in the same order: nodes
38 * first, then ways.
39 *
40 * @author frsantos
41 */
[15463]42public class Test implements OsmPrimitiveVisitor {
[6623]43
[9397]44 protected static final Predicate<OsmPrimitive> IN_DOWNLOADED_AREA = new NotOutsideDataSourceArea();
[12864]45 protected static final Predicate<OsmPrimitive> IN_DOWNLOADED_AREA_STRICT = new InDataSourceArea(true);
[9381]46
[3669]47 /** Name of the test */
48 protected final String name;
49
50 /** Description of the test */
51 protected final String description;
52
53 /** Whether this test is enabled. Enabled by default */
54 public boolean enabled = true;
55
56 /** The preferences check for validation */
57 protected JCheckBox checkEnabled;
58
59 /** The preferences check for validation on upload */
60 protected JCheckBox checkBeforeUpload;
61
62 /** Whether this test must check before upload. Enabled by default */
63 public boolean testBeforeUpload = true;
64
65 /** Whether this test is performing just before an upload */
66 protected boolean isBeforeUpload;
67
68 /** The list of errors */
[16031]69 protected List<TestError> errors = new ArrayList<>();
[3669]70
71 /** Whether the test is run on a partial selection data */
72 protected boolean partialSelection;
73
74 /** the progress monitor to use */
75 protected ProgressMonitor progressMonitor;
[7140]76
[6354]77 /** the start time to compute elapsed time when test finishes */
[15755]78 protected Stopwatch stopwatch;
[7140]79
[14599]80 private boolean showElementCount;
81
[3669]82 /**
83 * Constructor
84 * @param name Name of the test
85 * @param description Description of the test
86 */
[3671]87 public Test(String name, String description) {
[3669]88 this.name = name;
89 this.description = description;
90 }
91
92 /**
93 * Constructor
94 * @param name Name of the test
95 */
[3671]96 public Test(String name) {
[3669]97 this(name, null);
98 }
99
100 /**
[6591]101 * A test that forwards all primitives to {@link #check(OsmPrimitive)}.
102 */
[6623]103 public abstract static class TagTest extends Test {
104 /**
105 * Constructs a new {@code TagTest} with given name and description.
106 * @param name The test name
107 * @param description The test description
108 */
[16553]109 protected TagTest(String name, String description) {
[6591]110 super(name, description);
111 }
112
[6623]113 /**
114 * Constructs a new {@code TagTest} with given name.
115 * @param name The test name
116 */
[16553]117 protected TagTest(String name) {
[6591]118 super(name);
119 }
120
[6623]121 /**
122 * Checks the tags of the given primitive.
123 * @param p The primitive to test
124 */
[11023]125 public abstract void check(OsmPrimitive p);
[6591]126
127 @Override
128 public void visit(Node n) {
129 check(n);
130 }
131
132 @Override
133 public void visit(Way w) {
134 check(w);
135 }
136
137 @Override
138 public void visit(Relation r) {
139 check(r);
140 }
[15682]141
[15683]142 protected boolean includeOtherSeverityChecks() {
[15682]143 return isBeforeUpload ? ValidatorPrefHelper.PREF_OTHER_UPLOAD.get() : ValidatorPrefHelper.PREF_OTHER.get();
144 }
[6591]145 }
146
147 /**
[3669]148 * Initializes any global data used this tester.
149 * @throws Exception When cannot initialize the test
150 */
[3671]151 public void initialize() throws Exception {
[15755]152 this.stopwatch = Stopwatch.createStarted();
[3671]153 }
[3669]154
155 /**
156 * Start the test using a given progress monitor
157 *
158 * @param progressMonitor the progress monitor
159 */
160 public void startTest(ProgressMonitor progressMonitor) {
[11553]161 this.progressMonitor = Optional.ofNullable(progressMonitor).orElse(NullProgressMonitor.INSTANCE);
[6354]162 String startMessage = tr("Running test {0}", name);
163 this.progressMonitor.beginTask(startMessage);
[12620]164 Logging.debug(startMessage);
[7005]165 this.errors = new ArrayList<>(30);
[15755]166 this.stopwatch = Stopwatch.createStarted();
[3669]167 }
168
169 /**
170 * Flag notifying that this test is run over a partial data selection
171 * @param partialSelection Whether the test is on a partial selection data
172 */
[3671]173 public void setPartialSelection(boolean partialSelection) {
[3669]174 this.partialSelection = partialSelection;
175 }
176
177 /**
178 * Gets the validation errors accumulated until this moment.
179 * @return The list of errors
180 */
[3671]181 public List<TestError> getErrors() {
[3669]182 return errors;
183 }
184
185 /**
186 * Notification of the end of the test. The tester may perform additional
[5269]187 * actions and destroy the used structures.
188 * <p>
[6623]189 * If you override this method, don't forget to cleanup {@code progressMonitor}
[5269]190 * (most overrides call {@code super.endTest()} to do this).
[3669]191 */
192 public void endTest() {
193 progressMonitor.finishTask();
194 progressMonitor = null;
[15755]195 if (stopwatch.elapsed() > 0) {
[16069]196 Logging.debug(stopwatch.toString(getName()));
[6354]197 }
[3669]198 }
199
200 /**
201 * Visits all primitives to be tested. These primitives are always visited
202 * in the same order: nodes first, then ways.
203 *
204 * @param selection The primitives to be tested
205 */
[3671]206 public void visit(Collection<OsmPrimitive> selection) {
[8724]207 if (progressMonitor != null) {
208 progressMonitor.setTicksCount(selection.size());
209 }
[14599]210 long cnt = 0;
[3669]211 for (OsmPrimitive p : selection) {
[8829]212 if (isCanceled()) {
213 break;
214 }
[6400]215 if (isPrimitiveUsable(p)) {
[6009]216 p.accept(this);
[3671]217 }
[8724]218 if (progressMonitor != null) {
219 progressMonitor.worked(1);
[14599]220 cnt++;
221 // add frequently changing info to progress monitor so that it
222 // doesn't seem to hang when test takes long
223 if (showElementCount && cnt % 1000 == 0) {
224 progressMonitor.setExtraText(tr("{0} of {1} elements done", cnt, selection.size()));
225 }
[8724]226 }
[3669]227 }
228 }
229
[6623]230 /**
231 * Determines if the primitive is usable for tests.
232 * @param p The primitive
233 * @return {@code true} if the primitive can be tested, {@code false} otherwise
234 */
[6400]235 public boolean isPrimitiveUsable(OsmPrimitive p) {
236 return p.isUsable() && (!(p instanceof Way) || (((Way) p).getNodesCount() > 1)); // test only Ways with at least 2 nodes
237 }
238
[3671]239 @Override
[9989]240 public void visit(Node n) {
241 // To be overridden in subclasses
242 }
[3669]243
[3671]244 @Override
[9989]245 public void visit(Way w) {
246 // To be overridden in subclasses
247 }
[3669]248
[3671]249 @Override
[9989]250 public void visit(Relation r) {
251 // To be overridden in subclasses
252 }
[3669]253
254 /**
255 * Allow the tester to manage its own preferences
256 * @param testPanel The panel to add any preferences component
257 */
[3671]258 public void addGui(JPanel testPanel) {
[3669]259 checkEnabled = new JCheckBox(name, enabled);
260 checkEnabled.setToolTipText(description);
261 testPanel.add(checkEnabled, GBC.std());
262
263 GBC a = GBC.eol();
264 a.anchor = GridBagConstraints.EAST;
265 checkBeforeUpload = new JCheckBox();
266 checkBeforeUpload.setSelected(testBeforeUpload);
267 testPanel.add(checkBeforeUpload, a);
268 }
269
270 /**
271 * Called when the used submits the preferences
[6623]272 * @return {@code true} if restart is required, {@code false} otherwise
[3669]273 */
[3671]274 public boolean ok() {
[3669]275 enabled = checkEnabled.isSelected();
276 testBeforeUpload = checkBeforeUpload.isSelected();
277 return false;
278 }
279
280 /**
[3671]281 * Fixes the error with the appropriate command
[3669]282 *
[8470]283 * @param testError error to fix
[3669]284 * @return The command to fix the error
285 */
[3671]286 public Command fixError(TestError testError) {
[3669]287 return null;
288 }
289
290 /**
291 * Returns true if the given error can be fixed automatically
292 *
293 * @param testError The error to check if can be fixed
294 * @return true if the error can be fixed
295 */
[3671]296 public boolean isFixable(TestError testError) {
[3669]297 return false;
298 }
299
300 /**
301 * Returns true if this plugin must check the uploaded data before uploading
302 * @return true if this plugin must check the uploaded data before uploading
303 */
[3671]304 public boolean testBeforeUpload() {
[3669]305 return testBeforeUpload;
306 }
307
308 /**
309 * Sets the flag that marks an upload check
310 * @param isUpload if true, the test is before upload
311 */
[3671]312 public void setBeforeUpload(boolean isUpload) {
[3669]313 this.isBeforeUpload = isUpload;
314 }
315
[6623]316 /**
317 * Returns the test name.
318 * @return The test name
319 */
[3669]320 public String getName() {
321 return name;
322 }
[4059]323
[6623]324 /**
325 * Determines if the test has been canceled.
326 * @return {@code true} if the test has been canceled, {@code false} otherwise
327 */
[4310]328 public boolean isCanceled() {
[15121]329 return progressMonitor != null && progressMonitor.isCanceled();
[4059]330 }
[6069]331
[5287]332 /**
333 * Build a Delete command on all primitives that have not yet been deleted manually by user, or by another error fix.
334 * If all primitives have already been deleted, null is returned.
335 * @param primitives The primitives wanted for deletion
336 * @return a Delete command on all primitives that have not yet been deleted, or null otherwise
337 */
338 protected final Command deletePrimitivesIfNeeded(Collection<? extends OsmPrimitive> primitives) {
[16332]339 Collection<OsmPrimitive> primitivesToDelete = primitives.stream()
340 .filter(p -> !p.isDeleted())
341 .collect(Collectors.toList());
[5287]342 if (!primitivesToDelete.isEmpty()) {
[12718]343 return DeleteCommand.delete(primitivesToDelete);
[5287]344 } else {
345 return null;
346 }
347 }
[5293]348
349 /**
350 * Determines if the specified primitive denotes a building.
351 * @param p The primitive to be tested
352 * @return True if building key is set and different from no,entrance
353 */
354 protected static final boolean isBuilding(OsmPrimitive p) {
[11608]355 return p.hasTagDifferent("building", "no", "entrance");
[5293]356 }
[7140]357
[13671]358 /**
359 * Determines if the specified primitive denotes a residential area.
360 * @param p The primitive to be tested
361 * @return True if landuse key is equal to residential
362 */
363 protected static final boolean isResidentialArea(OsmPrimitive p) {
364 return p.hasTag("landuse", "residential");
365 }
366
[14473]367 /**
368 * Free resources.
369 */
370 public void clear() {
371 errors.clear();
372 }
[14599]373
374 protected void setShowElements(boolean b) {
375 showElementCount = b;
376 }
[15972]377
378 /**
[16553]379 * Returns the name of this class.
[15972]380 * @return the name of this class (for ToolTip)
[16553]381 * @since 15972
[15972]382 */
383 public Object getSource() {
384 return "Java: " + this.getClass().getName();
385 }
[3669]386}
Note: See TracBrowser for help on using the repository browser.