source: josm/trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java@ 6370

Last change on this file since 6370 was 6370, checked in by simon04, 10 years ago

fix #9157 - add opening_hours validation test

This test utilizes https://github.com/ypid/opening_hours.js which is licensed
under the New (2-clause) BSD license.

  • Property svn:eol-style set to native
File size: 11.9 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.io.BufferedReader;
7import java.io.File;
8import java.io.FileNotFoundException;
9import java.io.FileReader;
10import java.io.FileWriter;
11import java.io.IOException;
12import java.io.PrintWriter;
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.Collection;
16import java.util.HashMap;
17import java.util.Map;
18import java.util.TreeSet;
19import java.util.regex.Matcher;
20import java.util.regex.Pattern;
21
22import javax.swing.JOptionPane;
23
24import org.openstreetmap.josm.Main;
25import org.openstreetmap.josm.actions.ValidateAction;
26import org.openstreetmap.josm.data.validation.tests.Addresses;
27import org.openstreetmap.josm.data.validation.tests.BarriersEntrances;
28import org.openstreetmap.josm.data.validation.tests.BuildingInBuilding;
29import org.openstreetmap.josm.data.validation.tests.Coastlines;
30import org.openstreetmap.josm.data.validation.tests.CrossingWays;
31import org.openstreetmap.josm.data.validation.tests.DeprecatedTags;
32import org.openstreetmap.josm.data.validation.tests.DuplicateNode;
33import org.openstreetmap.josm.data.validation.tests.DuplicateRelation;
34import org.openstreetmap.josm.data.validation.tests.DuplicateWay;
35import org.openstreetmap.josm.data.validation.tests.DuplicatedWayNodes;
36import org.openstreetmap.josm.data.validation.tests.Highways;
37import org.openstreetmap.josm.data.validation.tests.MultipolygonTest;
38import org.openstreetmap.josm.data.validation.tests.NameMismatch;
39import org.openstreetmap.josm.data.validation.tests.NodesDuplicatingWayTags;
40import org.openstreetmap.josm.data.validation.tests.NodesWithSameName;
41import org.openstreetmap.josm.data.validation.tests.OpeningHourTest;
42import org.openstreetmap.josm.data.validation.tests.OverlappingAreas;
43import org.openstreetmap.josm.data.validation.tests.OverlappingWays;
44import org.openstreetmap.josm.data.validation.tests.PowerLines;
45import org.openstreetmap.josm.data.validation.tests.RelationChecker;
46import org.openstreetmap.josm.data.validation.tests.SelfIntersectingWay;
47import org.openstreetmap.josm.data.validation.tests.SimilarNamedWays;
48import org.openstreetmap.josm.data.validation.tests.TagChecker;
49import org.openstreetmap.josm.data.validation.tests.TurnrestrictionTest;
50import org.openstreetmap.josm.data.validation.tests.UnclosedWays;
51import org.openstreetmap.josm.data.validation.tests.UnconnectedWays;
52import org.openstreetmap.josm.data.validation.tests.UntaggedNode;
53import org.openstreetmap.josm.data.validation.tests.UntaggedWay;
54import org.openstreetmap.josm.data.validation.tests.WayConnectedToArea;
55import org.openstreetmap.josm.data.validation.tests.WronglyOrderedWays;
56import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
57import org.openstreetmap.josm.gui.layer.Layer;
58import org.openstreetmap.josm.gui.layer.OsmDataLayer;
59import org.openstreetmap.josm.gui.layer.ValidatorLayer;
60import org.openstreetmap.josm.gui.preferences.ValidatorPreference;
61import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
62import org.openstreetmap.josm.tools.Utils;
63
64/**
65 *
66 * A OSM data validator
67 *
68 * @author Francisco R. Santos <frsantos@gmail.com>
69 */
70public class OsmValidator implements LayerChangeListener {
71
72 public static ValidatorLayer errorLayer = null;
73
74 /** The validate action */
75 public ValidateAction validateAction = new ValidateAction();
76
77 /** Grid detail, multiplier of east,north values for valuable cell sizing */
78 public static double griddetail;
79
80 public static final Collection<String> ignoredErrors = new TreeSet<String>();
81
82 /**
83 * All available tests
84 * TODO: is there any way to find out automatically all available tests?
85 */
86 @SuppressWarnings("unchecked")
87 private static final Class<Test>[] allAvailableTests = new Class[] {
88 DuplicateNode.class, // ID 1 .. 99
89 OverlappingWays.class, // ID 101 .. 199
90 UntaggedNode.class, // ID 201 .. 299
91 UntaggedWay.class, // ID 301 .. 399
92 SelfIntersectingWay.class, // ID 401 .. 499
93 DuplicatedWayNodes.class, // ID 501 .. 599
94 CrossingWays.class, // ID 601 .. 699
95 SimilarNamedWays.class, // ID 701 .. 799
96 NodesWithSameName.class, // ID 801 .. 899
97 Coastlines.class, // ID 901 .. 999
98 WronglyOrderedWays.class, // ID 1001 .. 1099
99 UnclosedWays.class, // ID 1101 .. 1199
100 TagChecker.class, // ID 1201 .. 1299
101 UnconnectedWays.class, // ID 1301 .. 1399
102 DuplicateWay.class, // ID 1401 .. 1499
103 NameMismatch.class, // ID 1501 .. 1599
104 MultipolygonTest.class, // ID 1601 .. 1699
105 RelationChecker.class, // ID 1701 .. 1799
106 TurnrestrictionTest.class, // ID 1801 .. 1899
107 DuplicateRelation.class, // ID 1901 .. 1999
108 BuildingInBuilding.class, // ID 2001 .. 2099
109 DeprecatedTags.class, // ID 2101 .. 2199
110 OverlappingAreas.class, // ID 2201 .. 2299
111 WayConnectedToArea.class, // ID 2301 .. 2399
112 NodesDuplicatingWayTags.class, // ID 2401 .. 2499
113 PowerLines.class, // ID 2501 .. 2599
114 Addresses.class, // ID 2601 .. 2699
115 Highways.class, // ID 2701 .. 2799
116 BarriersEntrances.class, // ID 2801 .. 2899
117 OpeningHourTest.class // 2901 .. 2999
118 };
119
120 /**
121 * Constructs a new {@code OsmValidator}.
122 */
123 public OsmValidator() {
124 checkValidatorDir();
125 initializeGridDetail();
126 initializeTests(getTests());
127 loadIgnoredErrors(); //FIXME: load only when needed
128 }
129
130 /**
131 * Returns the plugin's directory of the plugin
132 *
133 * @return The directory of the plugin
134 */
135 public static String getValidatorDir()
136 {
137 return Main.pref.getPreferencesDir() + "validator/";
138 }
139
140 /**
141 * Check if plugin directory exists (store ignored errors file)
142 */
143 private void checkValidatorDir() {
144 try {
145 File pathDir = new File(getValidatorDir());
146 if (!pathDir.exists()) {
147 pathDir.mkdirs();
148 }
149 } catch (Exception e){
150 e.printStackTrace();
151 }
152 }
153
154 private void loadIgnoredErrors() {
155 ignoredErrors.clear();
156 if (Main.pref.getBoolean(ValidatorPreference.PREF_USE_IGNORE, true)) {
157 BufferedReader in = null;
158 try {
159 in = new BufferedReader(new FileReader(getValidatorDir() + "ignorederrors"));
160 for (String line = in.readLine(); line != null; line = in.readLine()) {
161 ignoredErrors.add(line);
162 }
163 } catch (final FileNotFoundException e) {
164 // Ignore
165 } catch (final IOException e) {
166 e.printStackTrace();
167 } finally {
168 Utils.close(in);
169 }
170 }
171 }
172
173 public static void addIgnoredError(String s) {
174 ignoredErrors.add(s);
175 }
176
177 public static boolean hasIgnoredError(String s) {
178 return ignoredErrors.contains(s);
179 }
180
181 public static void saveIgnoredErrors() {
182 PrintWriter out = null;
183 try {
184 out = new PrintWriter(new FileWriter(getValidatorDir() + "ignorederrors"), false);
185 for (String e : ignoredErrors) {
186 out.println(e);
187 }
188 } catch (IOException e) {
189 e.printStackTrace();
190 } finally {
191 Utils.close(out);
192 }
193 }
194
195 public static void initializeErrorLayer() {
196 if (!Main.pref.getBoolean(ValidatorPreference.PREF_LAYER, true))
197 return;
198 if (errorLayer == null) {
199 errorLayer = new ValidatorLayer();
200 Main.main.addLayer(errorLayer);
201 }
202 }
203
204 /** Gets a map from simple names to all tests. */
205 public static Map<String, Test> getAllTestsMap() {
206 Map<String, Test> tests = new HashMap<String, Test>();
207 for (Class<Test> testClass : allAvailableTests) {
208 try {
209 Test test = testClass.newInstance();
210 tests.put(testClass.getSimpleName(), test);
211 } catch (Exception e) {
212 e.printStackTrace();
213 continue;
214 }
215 }
216 applyPrefs(tests, false);
217 applyPrefs(tests, true);
218 return tests;
219 }
220
221 private static void applyPrefs(Map<String, Test> tests, boolean beforeUpload) {
222 Pattern regexp = Pattern.compile("(\\w+)=(true|false),?");
223 Matcher m = regexp.matcher(Main.pref.get(beforeUpload ? ValidatorPreference.PREF_TESTS_BEFORE_UPLOAD
224 : ValidatorPreference.PREF_TESTS));
225 int pos = 0;
226 while (m.find(pos)) {
227 String testName = m.group(1);
228 Test test = tests.get(testName);
229 if (test != null) {
230 boolean enabled = Boolean.valueOf(m.group(2));
231 if (beforeUpload) {
232 test.testBeforeUpload = enabled;
233 } else {
234 test.enabled = enabled;
235 }
236 }
237 pos = m.end();
238 }
239 }
240
241 public static Collection<Test> getTests() {
242 return getAllTestsMap().values();
243 }
244
245 public static Collection<Test> getEnabledTests(boolean beforeUpload) {
246 Collection<Test> enabledTests = getTests();
247 for (Test t : new ArrayList<Test>(enabledTests)) {
248 if (beforeUpload ? t.testBeforeUpload : t.enabled) {
249 continue;
250 }
251 enabledTests.remove(t);
252 }
253 return enabledTests;
254 }
255
256 /**
257 * Gets the list of all available test classes
258 *
259 * @return An array of the test classes
260 */
261 public static Class<Test>[] getAllAvailableTests() {
262 return Arrays.copyOf(allAvailableTests, allAvailableTests.length);
263 }
264
265 /**
266 * Initialize grid details based on current projection system. Values based on
267 * the original value fixed for EPSG:4326 (10000) using heuristics (that is, test&error
268 * until most bugs were discovered while keeping the processing time reasonable)
269 */
270 public void initializeGridDetail() {
271 String code = Main.getProjection().toCode();
272 if (Arrays.asList(ProjectionPreference.wgs84.allCodes()).contains(code)) {
273 OsmValidator.griddetail = 10000;
274 } else if (Arrays.asList(ProjectionPreference.mercator.allCodes()).contains(code)) {
275 OsmValidator.griddetail = 0.01;
276 } else if (Arrays.asList(ProjectionPreference.lambert.allCodes()).contains(code)) {
277 OsmValidator.griddetail = 0.1;
278 } else {
279 OsmValidator.griddetail = 1.0;
280 }
281 }
282
283 /**
284 * Initializes all tests
285 * @param allTests The tests to initialize
286 */
287 public static void initializeTests(Collection<Test> allTests) {
288 for (Test test : allTests) {
289 try {
290 if (test.enabled) {
291 test.initialize();
292 }
293 } catch (Exception e) {
294 e.printStackTrace();
295 JOptionPane.showMessageDialog(Main.parent,
296 tr("Error initializing test {0}:\n {1}", test.getClass()
297 .getSimpleName(), e),
298 tr("Error"),
299 JOptionPane.ERROR_MESSAGE);
300 }
301 }
302 }
303
304 /* -------------------------------------------------------------------------- */
305 /* interface LayerChangeListener */
306 /* -------------------------------------------------------------------------- */
307 @Override
308 public void activeLayerChange(Layer oldLayer, Layer newLayer) {
309 }
310
311 @Override
312 public void layerAdded(Layer newLayer) {
313 }
314
315 @Override
316 public void layerRemoved(Layer oldLayer) {
317 if (oldLayer == errorLayer) {
318 errorLayer = null;
319 return;
320 }
321 if (Main.map.mapView.getLayersOfType(OsmDataLayer.class).isEmpty()) {
322 if (errorLayer != null) {
323 Main.main.removeLayer(errorLayer);
324 }
325 }
326 }
327}
Note: See TracBrowser for help on using the repository browser.