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

Last change on this file since 5272 was 5272, checked in by simon04, 12 years ago

fix #7639 - Validator should warn about nodes tagged with their way's tags (patch by mrwojo)

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