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

Last change on this file since 11266 was 11023, checked in by Don-vip, 8 years ago

checkstyle

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