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

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

fix #2746 - add validation: Way connected to Area

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