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

Last change on this file since 4409 was 4409, checked in by simon04, 13 years ago

fix #4656 - new validator test: building inside building

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