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

Last change on this file since 7489 was 7197, checked in by bastiK, 10 years ago

fixed #10085 - give warning for fixme=yes

  • Property svn:eol-style set to native
File size: 10.8 KB
Line 
1// License: GPL. See LICENSE file for details.
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;
10
11import javax.swing.JCheckBox;
12import javax.swing.JPanel;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.command.Command;
16import org.openstreetmap.josm.command.DeleteCommand;
17import org.openstreetmap.josm.data.osm.Node;
18import org.openstreetmap.josm.data.osm.OsmPrimitive;
19import org.openstreetmap.josm.data.osm.Relation;
20import org.openstreetmap.josm.data.osm.Way;
21import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
22import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
23import org.openstreetmap.josm.gui.progress.ProgressMonitor;
24import org.openstreetmap.josm.tools.GBC;
25import org.openstreetmap.josm.tools.Utils;
26
27/**
28 * Parent class for all validation tests.
29 * <p>
30 * A test is a primitive visitor, so that it can access to all data to be
31 * validated. These primitives are always visited in the same order: nodes
32 * first, then ways.
33 *
34 * @author frsantos
35 */
36public class Test extends AbstractVisitor {
37
38 /** Name of the test */
39 protected final String name;
40
41 /** Description of the test */
42 protected final String description;
43
44 /** Whether this test is enabled. Enabled by default */
45 public boolean enabled = true;
46
47 /** The preferences check for validation */
48 protected JCheckBox checkEnabled;
49
50 /** The preferences check for validation on upload */
51 protected JCheckBox checkBeforeUpload;
52
53 /** Whether this test must check before upload. Enabled by default */
54 public boolean testBeforeUpload = true;
55
56 /** Whether this test is performing just before an upload */
57 protected boolean isBeforeUpload;
58
59 /** The list of errors */
60 protected List<TestError> errors = new ArrayList<>(30);
61
62 /** Whether the test is run on a partial selection data */
63 protected boolean partialSelection;
64
65 /** the progress monitor to use */
66 protected ProgressMonitor progressMonitor;
67
68 /** the start time to compute elapsed time when test finishes */
69 protected long startTime;
70
71 /**
72 * Constructor
73 * @param name Name of the test
74 * @param description Description of the test
75 */
76 public Test(String name, String description) {
77 this.name = name;
78 this.description = description;
79 }
80
81 /**
82 * Constructor
83 * @param name Name of the test
84 */
85 public Test(String name) {
86 this(name, null);
87 }
88
89 /**
90 * A test that forwards all primitives to {@link #check(OsmPrimitive)}.
91 */
92 public abstract static class TagTest extends Test {
93 /**
94 * Constructs a new {@code TagTest} with given name and description.
95 * @param name The test name
96 * @param description The test description
97 */
98 public TagTest(String name, String description) {
99 super(name, description);
100 }
101
102 /**
103 * Constructs a new {@code TagTest} with given name.
104 * @param name The test name
105 */
106 public TagTest(String name) {
107 super(name);
108 }
109
110 /**
111 * Checks the tags of the given primitive.
112 * @param p The primitive to test
113 */
114 public abstract void check(final OsmPrimitive p);
115
116 @Override
117 public void visit(Node n) {
118 check(n);
119 }
120
121 @Override
122 public void visit(Way w) {
123 check(w);
124 }
125
126 @Override
127 public void visit(Relation r) {
128 check(r);
129 }
130 }
131
132 /**
133 * Initializes any global data used this tester.
134 * @throws Exception When cannot initialize the test
135 */
136 public void initialize() throws Exception {
137 this.startTime = -1;
138 }
139
140 /**
141 * Start the test using a given progress monitor
142 *
143 * @param progressMonitor the progress monitor
144 */
145 public void startTest(ProgressMonitor progressMonitor) {
146 if (progressMonitor == null) {
147 this.progressMonitor = NullProgressMonitor.INSTANCE;
148 } else {
149 this.progressMonitor = progressMonitor;
150 }
151 String startMessage = tr("Running test {0}", name);
152 this.progressMonitor.beginTask(startMessage);
153 Main.debug(startMessage);
154 this.errors = new ArrayList<>(30);
155 this.startTime = System.currentTimeMillis();
156 }
157
158 /**
159 * Flag notifying that this test is run over a partial data selection
160 * @param partialSelection Whether the test is on a partial selection data
161 */
162 public void setPartialSelection(boolean partialSelection) {
163 this.partialSelection = partialSelection;
164 }
165
166 /**
167 * Gets the validation errors accumulated until this moment.
168 * @return The list of errors
169 */
170 public List<TestError> getErrors() {
171 return errors;
172 }
173
174 /**
175 * Notification of the end of the test. The tester may perform additional
176 * actions and destroy the used structures.
177 * <p>
178 * If you override this method, don't forget to cleanup {@code progressMonitor}
179 * (most overrides call {@code super.endTest()} to do this).
180 */
181 public void endTest() {
182 progressMonitor.finishTask();
183 progressMonitor = null;
184 if (startTime > 0) {
185 long elapsedTime = System.currentTimeMillis() - startTime;
186 Main.debug(tr("Test ''{0}'' completed in {1}", getName(), Utils.getDurationString(elapsedTime)));
187 }
188 }
189
190 /**
191 * Visits all primitives to be tested. These primitives are always visited
192 * in the same order: nodes first, then ways.
193 *
194 * @param selection The primitives to be tested
195 */
196 public void visit(Collection<OsmPrimitive> selection) {
197 progressMonitor.setTicksCount(selection.size());
198 for (OsmPrimitive p : selection) {
199 if (isPrimitiveUsable(p)) {
200 p.accept(this);
201 }
202 progressMonitor.worked(1);
203 }
204 }
205
206 /**
207 * Determines if the primitive is usable for tests.
208 * @param p The primitive
209 * @return {@code true} if the primitive can be tested, {@code false} otherwise
210 */
211 public boolean isPrimitiveUsable(OsmPrimitive p) {
212 return p.isUsable() && (!(p instanceof Way) || (((Way) p).getNodesCount() > 1)); // test only Ways with at least 2 nodes
213 }
214
215 @Override
216 public void visit(Node n) {}
217
218 @Override
219 public void visit(Way w) {}
220
221 @Override
222 public void visit(Relation r) {}
223
224 /**
225 * Allow the tester to manage its own preferences
226 * @param testPanel The panel to add any preferences component
227 */
228 public void addGui(JPanel testPanel) {
229 checkEnabled = new JCheckBox(name, enabled);
230 checkEnabled.setToolTipText(description);
231 testPanel.add(checkEnabled, GBC.std());
232
233 GBC a = GBC.eol();
234 a.anchor = GridBagConstraints.EAST;
235 checkBeforeUpload = new JCheckBox();
236 checkBeforeUpload.setSelected(testBeforeUpload);
237 testPanel.add(checkBeforeUpload, a);
238 }
239
240 /**
241 * Called when the used submits the preferences
242 * @return {@code true} if restart is required, {@code false} otherwise
243 */
244 public boolean ok() {
245 enabled = checkEnabled.isSelected();
246 testBeforeUpload = checkBeforeUpload.isSelected();
247 return false;
248 }
249
250 /**
251 * Fixes the error with the appropriate command
252 *
253 * @param testError
254 * @return The command to fix the error
255 */
256 public Command fixError(TestError testError) {
257 return null;
258 }
259
260 /**
261 * Returns true if the given error can be fixed automatically
262 *
263 * @param testError The error to check if can be fixed
264 * @return true if the error can be fixed
265 */
266 public boolean isFixable(TestError testError) {
267 return false;
268 }
269
270 /**
271 * Returns true if this plugin must check the uploaded data before uploading
272 * @return true if this plugin must check the uploaded data before uploading
273 */
274 public boolean testBeforeUpload() {
275 return testBeforeUpload;
276 }
277
278 /**
279 * Sets the flag that marks an upload check
280 * @param isUpload if true, the test is before upload
281 */
282 public void setBeforeUpload(boolean isUpload) {
283 this.isBeforeUpload = isUpload;
284 }
285
286 /**
287 * Returns the test name.
288 * @return The test name
289 */
290 public String getName() {
291 return name;
292 }
293
294 /**
295 * Determines if the test has been canceled.
296 * @return {@code true} if the test has been canceled, {@code false} otherwise
297 */
298 public boolean isCanceled() {
299 return progressMonitor.isCanceled();
300 }
301
302 /**
303 * Build a Delete command on all primitives that have not yet been deleted manually by user, or by another error fix.
304 * If all primitives have already been deleted, null is returned.
305 * @param primitives The primitives wanted for deletion
306 * @return a Delete command on all primitives that have not yet been deleted, or null otherwise
307 */
308 protected final Command deletePrimitivesIfNeeded(Collection<? extends OsmPrimitive> primitives) {
309 Collection<OsmPrimitive> primitivesToDelete = new ArrayList<>();
310 for (OsmPrimitive p : primitives) {
311 if (!p.isDeleted()) {
312 primitivesToDelete.add(p);
313 }
314 }
315 if (!primitivesToDelete.isEmpty()) {
316 return DeleteCommand.delete(Main.main.getEditLayer(), primitivesToDelete);
317 } else {
318 return null;
319 }
320 }
321
322 /**
323 * Determines if the specified primitive denotes a building.
324 * @param p The primitive to be tested
325 * @return True if building key is set and different from no,entrance
326 */
327 protected static final boolean isBuilding(OsmPrimitive p) {
328 String v = p.get("building");
329 return v != null && !"no".equals(v) && !"entrance".equals(v);
330 }
331
332 @Override
333 public int hashCode() {
334 final int prime = 31;
335 int result = 1;
336 result = prime * result + ((description == null) ? 0 : description.hashCode());
337 result = prime * result + ((name == null) ? 0 : name.hashCode());
338 return result;
339 }
340
341 @Override
342 public boolean equals(Object obj) {
343 if (this == obj)
344 return true;
345 if (obj == null)
346 return false;
347 if (!(obj instanceof Test))
348 return false;
349 Test other = (Test) obj;
350 if (description == null) {
351 if (other.description != null)
352 return false;
353 } else if (!description.equals(other.description))
354 return false;
355 if (name == null) {
356 if (other.name != null)
357 return false;
358 } else if (!name.equals(other.name))
359 return false;
360 return true;
361 }
362}
Note: See TracBrowser for help on using the repository browser.