Changeset 12778 in osm for applications/editors/josm/plugins/validator/src/org
- Timestamp:
- 2009-01-01T18:28:53+01:00 (16 years ago)
- Location:
- applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator
- Files:
-
- 26 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ErrorTreeRenderer.java
r9598 r12778 16 16 public class ErrorTreeRenderer extends DefaultTreeCellRenderer 17 17 { 18 19 18 /** Serializable ID */ 19 private static final long serialVersionUID = 5567632718124640198L; 20 20 21 @Override 22 public Component getTreeCellRendererComponent(JTree tree, Object value, 23 boolean selected, boolean expanded, boolean leaf, int row, 24 boolean hasFocus) 25 { 26 super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); 27 28 DefaultMutableTreeNode node = (DefaultMutableTreeNode)value; 29 Object nodeInfo = node.getUserObject(); 21 @Override 22 public Component getTreeCellRendererComponent(JTree tree, Object value, 23 boolean selected, boolean expanded, boolean leaf, int row, 24 boolean hasFocus) 25 { 26 super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); 30 27 31 if (nodeInfo instanceof Severity) 32 { 33 Severity s = (Severity)nodeInfo; 34 setIcon(ImageProvider.get("data", s.getIcon())); 35 } 36 else if (nodeInfo instanceof TestError) 37 { 38 TestError error = (TestError)nodeInfo; 39 MultipleNameVisitor v = new MultipleNameVisitor(); 40 v.visit(error.getPrimitives()); 41 setText(v.getText()); 42 setIcon(v.getIcon()); 43 } 28 DefaultMutableTreeNode node = (DefaultMutableTreeNode)value; 29 Object nodeInfo = node.getUserObject(); 44 30 45 return this; 46 } 31 if (nodeInfo instanceof Severity) 32 { 33 Severity s = (Severity)nodeInfo; 34 setIcon(ImageProvider.get("data", s.getIcon())); 35 } 36 else if (nodeInfo instanceof TestError) 37 { 38 TestError error = (TestError)nodeInfo; 39 MultipleNameVisitor v = new MultipleNameVisitor(); 40 v.visit(error.getPrimitives()); 41 setText(v.getText()); 42 setIcon(v.getIcon()); 43 } 44 45 return this; 46 } 47 47 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/GridLayer.java
r4844 r12778 28 28 public class GridLayer extends Layer 29 29 { 30 31 32 33 34 30 /** 31 * Constructor 32 * @param name 33 */ 34 public GridLayer(String name) 35 35 { 36 37 36 super(name); 37 } 38 38 39 40 41 42 43 44 39 /** 40 * Return a static icon. 41 */ 42 @Override public Icon getIcon() { 43 return ImageProvider.get("layer", "validator"); 44 } 45 45 46 46 /** … … 50 50 public void paint(final Graphics g, final MapView mv) 51 51 { 52 53 54 55 56 57 52 if( !Main.pref.hasKey(PreferenceEditor.PREF_DEBUG + ".grid") ) 53 return; 54 55 int gridWidth = Integer.parseInt(Main.pref.get(PreferenceEditor.PREF_DEBUG + ".grid") ); 56 int width = mv.getWidth(); 57 int height = mv.getHeight(); 58 58 59 60 59 EastNorth origin = mv.getEastNorth(0, 0); 60 EastNorth border = mv.getEastNorth(width, height); 61 61 62 63 62 if( border.east() * gridWidth > 50 ) 63 return; 64 64 65 65 g.setColor(Color.RED.darker().darker()); 66 67 68 66 HighlightCellVisitor visitor = new HighlightCellVisitor(g, mv, gridWidth); 67 for(OsmPrimitive p : Main.ds.getSelected() ) 68 p.visit(visitor); 69 69 70 70 long x0 = (long)Math.floor(origin.east() * gridWidth); 71 71 long x1 = (long)Math.floor(border.east() * gridWidth); 72 72 long y0 = (long)Math.floor(origin.north() * gridWidth) + 1; 73 73 long y1 = (long)Math.floor(border.north() * gridWidth) + 1; … … 77 77 78 78 g.setColor(Color.RED.brighter().brighter()); 79 80 81 82 83 79 for( double x = x0; x <= x1; x++) 80 { 81 Point point = mv.getPoint( new EastNorth(x/gridWidth, 0)); 82 g.drawLine(point.x, 0, point.x, height); 83 } 84 84 85 86 87 88 89 85 for( double y = y0; y <= y1; y++) 86 { 87 Point point = mv.getPoint( new EastNorth(0, y/gridWidth)); 88 g.drawLine(0, point.y, width, point.y); 89 } 90 90 } 91 91 92 92 @Override 93 93 public String getToolTipText() 94 94 { 95 96 95 return null; 96 } 97 97 98 99 98 @Override 99 public void mergeFrom(Layer from) {} 100 100 101 102 103 104 101 @Override 102 public boolean isMergable(Layer other) { 103 return false; 104 } 105 105 106 107 106 @Override 107 public void visitBoundingBox(BoundingXYVisitor v) {} 108 108 109 110 109 @Override 110 public Object getInfoComponent() 111 111 { 112 113 112 return getToolTipText(); 113 } 114 114 115 116 115 @Override 116 public Component[] getMenuEntries() 117 117 { 118 118 return new Component[]{ … … 125 125 } 126 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 127 @Override public void destroy() { } 128 129 /** 130 * Visitor that highlights all cells the selected primitives go through 131 */ 132 class HighlightCellVisitor implements Visitor 133 { 134 /** The MapView */ 135 private final MapView mv; 136 /** The graphics */ 137 private final Graphics g; 138 /** The grid width */ 139 private final int gridDetail; 140 /** The width of a cell */ 141 private int cellWidth; 142 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 143 /** 144 * Constructor 145 * @param g the graphics 146 * @param mv The MapView 147 * @param gridDetail The grid detail 148 */ 149 public HighlightCellVisitor(final Graphics g, final MapView mv, int gridDetail) 150 { 151 this.g = g; 152 this.mv = mv; 153 this.gridDetail = gridDetail; 154 155 Point p = mv.getPoint( new EastNorth(0, 0) ); 156 Point p2 = mv.getPoint( new EastNorth(1d/gridDetail, 1d/gridDetail) ); 157 cellWidth = Math.abs(p2.x - p.x); 158 } 159 159 160 161 162 163 160 public void visit(Node n) 161 { 162 double x = n.eastNorth.east() * gridDetail; 163 double y = n.eastNorth.north()* gridDetail + 1; 164 164 165 166 165 drawCell( Math.floor(x), Math.floor(y) ); 166 } 167 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 168 public void visit(Way w) 169 { 170 Node lastN = null; 171 for (Node n : w.nodes) { 172 if (lastN == null) { 173 lastN = n; 174 continue; 175 } 176 for (Point2D p : Util.getSegmentCells(lastN, n, gridDetail)) { 177 drawCell( p.getX(), p.getY() ); 178 } 179 lastN = n; 180 } 181 } 182 182 183 184 185 186 187 188 189 190 191 192 193 194 195 183 public void visit(Relation r) {} 184 185 /** 186 * Draws a solid cell at the (x,y) location 187 * @param x 188 * @param y 189 */ 190 protected void drawCell(double x, double y) 191 { 192 Point p = mv.getPoint( new EastNorth(x/gridDetail, y/gridDetail) ); 193 g.fillRect(p.x, p.y, cellWidth, cellWidth); 194 } 195 } 196 196 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/PreferenceEditor.java
r12777 r12778 26 26 public class PreferenceEditor implements PreferenceSetting 27 27 { 28 28 private OSMValidatorPlugin plugin; 29 29 30 31 30 /** The preferences prefix */ 31 public static final String PREFIX = "validator"; 32 32 33 34 33 /** The preferences key for debug preferences */ 34 public static final String PREF_DEBUG = PREFIX + ".debug"; 35 35 36 37 36 /** The preferences key for debug preferences */ 37 public static final String PREF_LAYER = PREFIX + ".layer"; 38 38 39 40 39 /** The preferences key for enabled tests */ 40 public static final String PREF_TESTS = PREFIX + ".tests"; 41 41 42 43 42 /** The preferences key for enabled tests */ 43 public static final String PREF_USE_IGNORE = PREFIX + ".ignore"; 44 44 45 46 45 /** The preferences key for enabled tests before upload*/ 46 public static final String PREF_TESTS_BEFORE_UPLOAD = PREFIX + ".testsBeforeUpload"; 47 47 48 49 50 51 48 /** 49 * The preferences key for enabling the permanent filtering 50 * of the displayed errors in the tree regarding the current selection 51 */ 52 52 public static final String PREF_FILTER_BY_SELECTION = PREFIX + ".selectionFilter"; 53 53 54 55 54 private JCheckBox prefUseIgnore; 55 private JCheckBox prefUseLayer; 56 56 57 58 57 /** The list of all tests */ 58 private Collection<Test> allTests; 59 59 60 61 62 60 public PreferenceEditor(OSMValidatorPlugin plugin) { 61 this.plugin = plugin; 62 } 63 63 64 65 66 67 64 public void addGui(PreferenceDialog gui) 65 { 66 JPanel testPanel = new JPanel(new GridBagLayout()); 67 testPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 68 68 69 70 71 69 prefUseIgnore = new JCheckBox(tr("Use ignore list."), Main.pref.getBoolean(PREF_USE_IGNORE, true)); 70 prefUseIgnore.setToolTipText(tr("Use the ignore list to suppress warnings.")); 71 testPanel.add(prefUseIgnore, GBC.eol()); 72 72 73 74 75 73 prefUseLayer = new JCheckBox(tr("Use error layer."), Main.pref.getBoolean(PREF_LAYER, true)); 74 prefUseLayer.setToolTipText(tr("Use the error layer to display problematic elements.")); 75 testPanel.add(prefUseLayer, GBC.eol()); 76 76 77 78 79 80 77 GBC a = GBC.eol().insets(-5,0,0,0); 78 a.anchor = GBC.EAST; 79 testPanel.add( new JLabel(tr("On demand")), GBC.std() ); 80 testPanel.add( new JLabel(tr("On upload")), a ); 81 81 82 83 84 85 86 82 allTests = OSMValidatorPlugin.getTests(); 83 for(Test test: allTests) 84 { 85 test.addGui(testPanel); 86 } 87 87 88 89 88 JScrollPane testPane = new JScrollPane(testPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 89 testPane.setBorder(null); 90 90 91 92 93 94 95 96 97 98 91 Version ver = Util.getVersion(); 92 String description = tr("A OSM data validator that checks for common errors made by users and editor programs."); 93 if( ver != null ) 94 description += "<br>" + tr("Version {0} - Last change at {1}", ver.revision, ver.time); 95 JPanel tab = gui.createPreferenceTab("validator", tr("Data validator"), description); 96 tab.add(testPane, GBC.eol().fill(GBC.BOTH)); 97 tab.add(GBC.glue(0,10), a); 98 } 99 99 100 101 102 103 104 100 public boolean ok() 101 { 102 StringBuilder tests = new StringBuilder(); 103 StringBuilder testsBeforeUpload = new StringBuilder(); 104 Boolean res = false; 105 105 106 107 108 109 110 111 112 113 106 for (Test test : allTests) 107 { 108 if(test.ok()) 109 res = false; 110 String name = test.getClass().getSimpleName(); 111 tests.append( ',' ).append( name ).append( '=' ).append( test.enabled ); 112 testsBeforeUpload.append( ',' ).append( name ).append( '=' ).append( test.testBeforeUpload ); 113 } 114 114 115 116 115 if (tests.length() > 0 ) tests = tests.deleteCharAt(0); 116 if (testsBeforeUpload.length() > 0 ) testsBeforeUpload = testsBeforeUpload.deleteCharAt(0); 117 117 118 118 plugin.initializeTests( allTests ); 119 119 120 121 122 123 124 125 120 Main.pref.put( PREF_TESTS, tests.toString()); 121 Main.pref.put( PREF_TESTS_BEFORE_UPLOAD, testsBeforeUpload.toString()); 122 Main.pref.put( PREF_USE_IGNORE, prefUseIgnore.isSelected()); 123 Main.pref.put( PREF_LAYER, prefUseLayer.isSelected()); 124 return false; 125 } 126 126 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/Severity.java
r9913 r12778 10 10 /** The error severity */ 11 11 public enum Severity { 12 13 14 15 16 17 18 19 20 21 12 /** Error messages */ 13 ERROR(tr("Errors"), "error.gif", Main.pref.getColor(marktr("validation error"), Color.RED)), 14 /** Warning messages */ 15 WARNING(tr("Warnings"), "warning.gif", Main.pref.getColor(marktr("validation warning"), Color.YELLOW)), 16 /** Other messages */ 17 OTHER(tr("Other"), "other.gif", Main.pref.getColor(marktr("validation other"), Color.CYAN)); 18 19 /** Description of the severity code */ 20 private final String message; 21 22 22 /** Associated icon */ 23 23 private final String icon; … … 26 26 private final Color color; 27 27 28 29 30 * 31 32 33 34 35 Severity(String message, String icon, Color color) 28 /** 29 * Constructor 30 * 31 * @param message Description 32 * @param icon Associated icon 33 * @param color The color of this severity 34 */ 35 Severity(String message, String icon, Color color) 36 36 { 37 37 this.message = message; 38 38 this.icon = icon; 39 39 this.color = color; 40 40 } 41 41 42 43 44 45 46 42 @Override 43 public String toString() 44 { 45 return message; 46 } 47 47 48 /** 49 50 51 52 53 54 55 48 /** 49 * Gets the associated icon 50 * @return the associated icon 51 */ 52 public String getIcon() 53 { 54 return icon; 55 } 56 56 57 57 /** … … 63 63 return color; 64 64 } 65 66 65 66 67 67 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/Test.java
r12777 r12778 27 27 public class Test implements Visitor 28 28 { 29 30 31 32 33 34 29 /** Name of the test */ 30 protected String name; 31 32 /** Description of the test */ 33 protected String description; 34 35 35 /** Whether this test is enabled. Enabled by default */ 36 36 protected boolean enabled = true; … … 48 48 protected boolean isBeforeUpload; 49 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 50 /** The list of errors */ 51 protected List<TestError> errors = new ArrayList<TestError>(30); 52 53 /** Whether the test is run on a partial selection data */ 54 protected boolean partialSelection; 55 56 /** 57 * Constructor 58 * @param name Name of the test 59 * @param description Description of the test 60 */ 61 public Test(String name, String description) 62 { 63 this.name = name; 64 this.description = description; 65 } 66 67 /** 68 * Constructor 69 * @param name Name of the test 70 */ 71 public Test(String name) 72 { 73 this.name = name; 74 } 75 76 /** 77 * Initializes any global data used this tester. 78 * @param plugin The plugin 79 * @throws Exception When cannot initialize the test 80 */ 81 public static void initialize(OSMValidatorPlugin plugin) throws Exception {} 82 83 /** 84 * Notification of the start of the test. The tester can initialize the 85 * structures it may need for this test 86 */ 87 public void startTest() 88 { 89 errors = new ArrayList<TestError>(30); 90 } 91 92 /** 93 * Flag notifying that this test is run over a partial data selection 94 * @param partialSelection Whether the test is on a partial selection data 95 */ 96 public void setPartialSelection(boolean partialSelection) 97 { 98 this.partialSelection = partialSelection; 99 } 100 101 /** 102 * Gets the validation errors accumulated until this moment. 103 * @return The list of errors 104 */ 105 public List<TestError> getErrors() 106 { 107 return errors; 108 } 109 110 /** 111 * Notification of the end of the test. The tester may perform additional 112 * actions and destroy the used structures 113 */ 114 public void endTest() {} 115 115 116 116 /** … … 124 124 for (OsmPrimitive p : selection) 125 125 { 126 127 126 if( !p.deleted && !p.incomplete ) 127 p.visit(this); 128 128 } 129 129 } … … 131 131 public void visit(Node n) {} 132 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 133 public void visit(Way w) {} 134 135 public void visit(Relation r) {} 136 137 /** 138 * Allow the tester to manage its own preferences 139 * @param testPanel The panel to add any preferences component 140 */ 141 public void addGui(JPanel testPanel) 142 { 143 checkEnabled = new JCheckBox(name, enabled); 144 checkEnabled.setToolTipText(description); 145 testPanel.add(checkEnabled, GBC.std()); 146 147 GBC a = GBC.eol(); 148 a.anchor = GBC.EAST; 149 checkBeforeUpload = new JCheckBox(); 150 checkBeforeUpload.setSelected(testBeforeUpload); 151 testPanel.add(checkBeforeUpload, a); 152 } 153 154 /** 155 * Called when the used submits the preferences 156 */ 157 public boolean ok() 158 { 159 enabled = checkEnabled.isSelected(); 160 testBeforeUpload = checkBeforeUpload.isSelected(); 161 return false; 162 } 163 164 /** 165 * Fixes the error with the appropiate command 166 * 167 * @param testError 168 * @return The command to fix the error 169 */ 170 public Command fixError(TestError testError) 171 { 172 return null; 173 } 174 175 /** 176 * Returns true if the given error can be fixed automatically 177 * 178 * @param testError The error to check if can be fixed 179 * @return true if the error can be fixed 180 */ 181 public boolean isFixable(TestError testError) 182 { 183 return false; 184 } 185 185 186 186 /** -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/TestError.java
r10540 r12778 372 372 * Checks if the given segment is in the visible area. 373 373 * NOTE: This will return true for a small number of non-visible 374 * 374 * segments. 375 375 * @param ls The segment to check 376 376 * @return true if the segment is visible -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidateUploadHook.java
r11530 r12778 29 29 public class ValidateUploadHook implements UploadHook 30 30 { 31 32 31 /** Serializable ID */ 32 private static final long serialVersionUID = -2304521273582574603L; 33 33 34 34 private OSMValidatorPlugin plugin; 35 35 36 37 38 39 36 public ValidateUploadHook(OSMValidatorPlugin plugin) 37 { 38 this.plugin = plugin; 39 } 40 40 41 42 43 44 45 46 47 48 41 /** 42 * Validate the modified data before uploading 43 */ 44 public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete) 45 { 46 Collection<Test> tests = OSMValidatorPlugin.getEnabledTests(true); 47 if( tests.isEmpty() ) 48 return true; 49 49 50 51 52 50 AgregatePrimitivesVisitor v = new AgregatePrimitivesVisitor(); 51 v.visit(add); 52 Collection<OsmPrimitive> selection = v.visit(update); 53 53 54 55 56 57 58 59 60 61 62 63 64 65 66 54 List<TestError> errors = new ArrayList<TestError>(30); 55 for(Test test : tests) 56 { 57 test.setBeforeUpload(true); 58 test.setPartialSelection(true); 59 test.startTest(); 60 test.visit(selection); 61 test.endTest(); 62 errors.addAll( test.getErrors() ); 63 } 64 tests = null; 65 if(errors == null || errors.isEmpty()) 66 return true; 67 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 68 if(Main.pref.getBoolean(PreferenceEditor.PREF_USE_IGNORE, true)) 69 { 70 int nume = 0; 71 for(TestError error : errors) 72 { 73 List<String> s = new ArrayList<String>(); 74 s.add(error.getIgnoreState()); 75 s.add(error.getIgnoreGroup()); 76 s.add(error.getIgnoreSubGroup()); 77 for(String state : s) 78 { 79 if(state != null && plugin.ignoredErrors.contains(state)) 80 { 81 error.setIgnored(true); 82 } 83 } 84 if(!error.getIgnored()) 85 ++nume; 86 } 87 if(nume == 0) 88 return true; 89 } 90 return displayErrorScreen(errors); 91 } 92 92 93 94 95 96 97 98 99 100 101 102 103 104 105 93 /** 94 * Displays a screen where the actions that would be taken are displayed and 95 * give the user the possibility to cancel the upload. 96 * @param errors The errors displayed in the screen 97 * @return <code>true</code>, if the upload should continue. <code>false</code> 98 * if the user requested cancel. 99 */ 100 private boolean displayErrorScreen(List<TestError> errors) 101 { 102 JPanel p = new JPanel(new GridBagLayout()); 103 ErrorTreePanel errorPanel = new ErrorTreePanel(errors); 104 errorPanel.expandAll(); 105 p.add(new JScrollPane(errorPanel), GBC.eol()); 106 106 107 108 109 110 111 112 113 114 115 116 107 int res = JOptionPane.showConfirmDialog(Main.parent, p, 108 tr("Data with errors. Upload anyway?"), JOptionPane.YES_NO_OPTION); 109 if(res == JOptionPane.NO_OPTION) 110 { 111 plugin.validationDialog.tree.setErrors(errors); 112 plugin.validationDialog.setVisible(true); 113 DataSet.fireSelectionChanged(Main.ds.getSelected()); 114 } 115 return res == JOptionPane.YES_OPTION; 116 } 117 117 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/ChangePropertyKeyCommand.java
r7804 r12778 22 22 */ 23 23 public class ChangePropertyKeyCommand extends Command { 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 24 /** 25 * All primitives, that are affected with this command. 26 */ 27 private final List<OsmPrimitive> objects; 28 /** 29 * The key that is subject to change. 30 */ 31 private final String key; 32 /** 33 * The mew key. 34 */ 35 private final String newKey; 36 37 /** 38 * Constructor 39 * 40 * @param objects all objects subject to change replacement 41 * @param key The key to replace 42 * @param newKey the new value of the key 43 */ 44 public ChangePropertyKeyCommand(Collection<? extends OsmPrimitive> objects, String key, String newKey) { 45 this.objects = new LinkedList<OsmPrimitive>(objects); 46 this.key = key; 47 this.newKey = newKey; 48 } 49 50 @Override public boolean executeCommand() { 51 if (!super.executeCommand()) return false; // save old 52 for (OsmPrimitive osm : objects) { 53 if(osm.keys != null) 54 { 55 osm.modified = true; 56 osm.put(newKey, osm.keys.remove(key) ); 57 } 58 } 59 59 return true; 60 60 } 61 61 62 63 64 62 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 63 modified.addAll(objects); 64 } 65 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 66 @Override public MutableTreeNode description() { 67 String text = tr( "Replace \"{0}\" by \"{1}\" for", key, newKey); 68 if (objects.size() == 1) { 69 NameVisitor v = new NameVisitor(); 70 objects.iterator().next().visit(v); 71 text += " "+tr(v.className)+" "+v.name; 72 } else 73 text += " "+objects.size()+" "+trn("object","objects",objects.size()); 74 DefaultMutableTreeNode root = new DefaultMutableTreeNode(new JLabel(text, ImageProvider.get("data", "key"), JLabel.HORIZONTAL)); 75 if (objects.size() == 1) 76 return root; 77 NameVisitor v = new NameVisitor(); 78 for (OsmPrimitive osm : objects) { 79 osm.visit(v); 80 root.add(new DefaultMutableTreeNode(v.toLabel())); 81 } 82 return root; 83 83 } 84 84 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/Coastlines.java
r9684 r12778 21 21 public class Coastlines extends Test 22 22 { 23 23 protected static int UNORDERED_COASTLINES = 901; 24 24 25 26 27 28 25 /** All ways, grouped by cells */ 26 Map<Point2D,List<Way>> _cellWays; 27 /** The already detected errors */ 28 Bag<Way, Way> _errorWays; 29 29 30 31 32 33 34 35 36 37 30 /** 31 * Constructor 32 */ 33 public Coastlines() 34 { 35 super(tr("Coastlines."), 36 tr("This test checks that coastlines are correct.")); 37 } 38 38 39 40 41 42 43 44 39 @Override 40 public void startTest() 41 { 42 _cellWays = new HashMap<Point2D,List<Way>>(1000); 43 _errorWays = new Bag<Way, Way>(); 44 } 45 45 46 47 48 49 50 51 46 @Override 47 public void endTest() 48 { 49 _cellWays = null; 50 _errorWays = null; 51 } 52 52 53 54 55 56 57 53 @Override 54 public void visit(Way w) 55 { 56 if( w.deleted || w.incomplete ) 57 return; 58 58 59 60 61 59 String natural = w.get("natural"); 60 if( natural == null || !natural.equals("coastline") ) 61 return; 62 62 63 64 65 66 67 68 69 63 List<List<Way>> cellWays = Util.getWaysInCell(w, _cellWays); 64 for( List<Way> ways : cellWays) 65 { 66 for( Way w2 : ways) 67 { 68 if( _errorWays.contains(w, w2) || _errorWays.contains(w2, w) ) 69 continue; 70 70 71 72 73 71 String natural2 = w.get("natural"); 72 if( natural2 == null || !natural2.equals("coastline") ) 73 continue; 74 74 75 76 77 78 79 80 81 82 83 84 85 86 75 if( w.nodes.get(0).equals(w2.nodes.get(0)) || w.nodes.get(w.nodes.size() - 1).equals(w2.nodes.get(w2.nodes.size() - 1))) 76 { 77 List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>(); 78 primitives.add(w); 79 primitives.add(w2); 80 errors.add( new TestError(this, Severity.ERROR, tr("Unordered coastline"), UNORDERED_COASTLINES, primitives) ); 81 _errorWays.add(w, w2); 82 } 83 } 84 ways.add(w); 85 } 86 } 87 87 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/CrossingWays.java
r12257 r12778 28 28 public class CrossingWays extends Test 29 29 { 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 30 protected static int CROSSING_WAYS = 601; 31 32 /** All way segments, grouped by cells */ 33 Map<Point2D,List<ExtendedSegment>> cellSegments; 34 /** The already detected errors */ 35 HashSet<WaySegment> errorSegments; 36 /** The already detected ways in error */ 37 Map<List<Way>, List<WaySegment>> ways_seen; 38 39 40 /** 41 * Constructor 42 */ 43 public CrossingWays() 44 { 45 super(tr("Crossing ways."), 46 tr("This test checks if two roads, railways or waterways crosses in the same layer, but are not connected by a node.")); 47 } 48 49 50 @Override 51 public void startTest() 52 { 53 cellSegments = new HashMap<Point2D,List<ExtendedSegment>>(1000); 54 errorSegments = new HashSet<WaySegment>(); 55 ways_seen = new HashMap<List<Way>, List<WaySegment>>(50); 56 } 57 58 @Override 59 public void endTest() 60 { 61 cellSegments = null; 62 errorSegments = null; 63 ways_seen = null; 64 } 65 66 @Override 67 public void visit(Way w) 68 { 69 if( w.deleted || w.incomplete ) 70 return; 71 72 String coastline1 = w.get("natural"); 73 boolean isCoastline1 = coastline1 != null && (coastline1.equals("water") || coastline1.equals("coastline")); 74 String railway1 = w.get("railway"); 75 boolean isSubway1 = railway1 != null && railway1.equals("subway"); 76 if( w.get("highway") == null && w.get("waterway") == null && (railway1 == null || isSubway1) && !isCoastline1) 77 return; 78 79 String layer1 = w.get("layer"); 80 81 int nodesSize = w.nodes.size(); 82 for (int i = 0; i < nodesSize - 1; i++) { 83 WaySegment ws = new WaySegment(w, i); 84 ExtendedSegment es1 = new ExtendedSegment(ws, layer1, railway1, coastline1); 85 List<List<ExtendedSegment>> cellSegments = getSegments(es1.n1, es1.n2); 86 for( List<ExtendedSegment> segments : cellSegments) 87 { 88 for( ExtendedSegment es2 : segments) 89 { 90 List<Way> prims; 91 List<WaySegment> highlight; 92 93 if (errorSegments.contains(ws) && errorSegments.contains(es2.ws)) 94 continue; 95 96 String layer2 = es2.layer; 97 String railway2 = es2.railway; 98 String coastline2 = es2.coastline; 99 if (layer1 == null ? layer2 != null : !layer1.equals(layer2)) 100 continue; 101 102 if( !es1.intersects(es2) ) continue; 103 if( isSubway1 && "subway".equals(railway2)) continue; 104 105 boolean isCoastline2 = coastline2 != null && (coastline2.equals("water") || coastline2.equals("coastline")); 106 if( isCoastline1 != isCoastline2 ) continue; 107 108 prims = Arrays.asList(es1.ws.way, es2.ws.way); 109 if ((highlight = ways_seen.get(prims)) == null) 110 { 111 highlight = new ArrayList<WaySegment>(); 112 highlight.add(es1.ws); 113 highlight.add(es2.ws); 114 115 errors.add(new TestError(this, Severity.WARNING, 116 tr("Crossing ways"), CROSSING_WAYS, prims, highlight)); 117 ways_seen.put(prims, highlight); 118 } 119 else 120 { 121 highlight.add(es1.ws); 122 highlight.add(es2.ws); 123 } 124 } 125 segments.add(es1); 126 } 127 } 128 } 129 130 /** 131 * Returns all the cells this segment crosses. Each cell contains the list 132 * of segments already processed 133 * 134 * @param n1 The first node 135 * @param n2 The second node 136 * @return A list with all the cells the segment crosses 137 */ 138 public List<List<ExtendedSegment>> getSegments(Node n1, Node n2) 139 { 140 List<List<ExtendedSegment>> cells = new ArrayList<List<ExtendedSegment>>(); 141 for( Point2D cell : Util.getSegmentCells(n1, n2, OSMValidatorPlugin.griddetail) ) 142 { 143 List<ExtendedSegment> segments = cellSegments.get( cell ); 144 if( segments == null ) 145 { 146 segments = new ArrayList<ExtendedSegment>(); 147 cellSegments.put(cell, segments); 148 } 149 cells.add(segments); 150 } 151 152 return cells; 153 } 154 155 /** 156 * A way segment with some additional information 157 * @author frsantos 158 */ 159 private class ExtendedSegment 160 { 161 public Node n1, n2; 162 163 public WaySegment ws; 164 165 /** The layer */ 166 public String layer; 167 168 /** The railway type */ 169 public String railway; 170 171 /** The coastline type */ 172 public String coastline; 173 174 /** 175 * Constructor 176 * @param ws The way segment 177 * @param layer The layer of the way this segment is in 178 * @param railway The railway type of the way this segment is in 179 * @param coastline The coastlyne typo of the way the segment is in 180 */ 181 public ExtendedSegment(WaySegment ws, String layer, String railway, String coastline) 182 { 183 this.ws = ws; 184 this.n1 = ws.way.nodes.get(ws.lowerIndex); 185 this.n2 = ws.way.nodes.get(ws.lowerIndex + 1); 186 this.layer = layer; 187 this.railway = railway; 188 this.coastline = coastline; 189 } 190 191 /** 192 * Checks whether this segment crosses other segment 193 * @param s2 The other segment 194 * @return true if both segements crosses 195 */ 196 public boolean intersects(ExtendedSegment s2) 197 { 198 if( n1.equals(s2.n1) || n2.equals(s2.n2) || 199 n1.equals(s2.n2) || n2.equals(s2.n1) ) 200 { 201 return false; 202 } 203 204 return Line2D.linesIntersect( 205 n1.eastNorth.east(), n1.eastNorth.north(), 206 n2.eastNorth.east(), n2.eastNorth.north(), 207 s2.n1.eastNorth.east(), s2.n1.eastNorth.north(), 208 s2.n2.eastNorth.east(), s2.n2.eastNorth.north()); 209 } 210 } 211 211 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicateNode.java
r12279 r12778 20 20 public class DuplicateNode extends Test 21 21 { 22 22 protected static int DUPLICATE_NODE = 1; 23 23 24 25 24 /** Bag of all nodes */ 25 Bag<LatLon, OsmPrimitive> nodes; 26 26 27 28 29 30 31 32 33 34 27 /** 28 * Constructor 29 */ 30 public DuplicateNode() 31 { 32 super(tr("Duplicated nodes."), 33 tr("This test checks that there are no nodes at the very same location.")); 34 } 35 35 36 36 37 38 39 40 41 37 @Override 38 public void startTest() 39 { 40 nodes = new Bag<LatLon, OsmPrimitive>(1000); 41 } 42 42 43 44 45 46 47 48 49 50 51 52 53 54 55 43 @Override 44 public void endTest() 45 { 46 for(List<OsmPrimitive> duplicated : nodes.values() ) 47 { 48 if( duplicated.size() > 1) 49 { 50 TestError testError = new TestError(this, Severity.ERROR, tr("Duplicated nodes"), DUPLICATE_NODE, duplicated); 51 errors.add( testError ); 52 } 53 } 54 nodes = null; 55 } 56 56 57 58 59 60 61 62 57 @Override 58 public void visit(Node n) 59 { 60 if(!n.deleted && !n.incomplete) 61 nodes.add(n.coor, n); 62 } 63 63 64 65 66 67 68 69 70 71 72 64 /** 65 * Merge the nodes into one. 66 * Copied from UtilsPlugin.MergePointsAction 67 */ 68 @Override 69 public Command fixError(TestError testError) 70 { 71 Collection<? extends OsmPrimitive> sel = testError.getPrimitives(); 72 LinkedList<Node> nodes = new LinkedList<Node>(); 73 73 74 74 for (OsmPrimitive osm : sel) … … 80 80 81 81 Node target = null; 82 82 // select the target node in the same way as in the core action MergeNodesAction, rev.1084 83 83 for (Node n: nodes) { 84 84 if (n.id > 0) { … … 93 93 94 94 return null; // undoRedo handling done in mergeNodes 95 95 } 96 96 97 98 99 100 101 97 @Override 98 public boolean isFixable(TestError testError) 99 { 100 return (testError.getTester() instanceof DuplicateNode); 101 } 102 102 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicatedWayNodes.java
r11530 r12778 16 16 17 17 public class DuplicatedWayNodes extends Test { 18 18 protected static int DUPLICATE_WAY_NODE = 501; 19 19 20 21 22 23 20 public DuplicatedWayNodes() { 21 super(tr("Duplicated way nodes."), 22 tr("Checks for ways with identical consecutive nodes.")); 23 } 24 24 25 26 25 @Override public void visit(Way w) { 26 if (w.deleted || w.incomplete) return; 27 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 28 Node lastN = null; 29 for (Node n : w.nodes) { 30 if (lastN == null) { 31 lastN = n; 32 continue; 33 } 34 if (lastN == n) { 35 errors.add(new TestError(this, Severity.ERROR, tr("Duplicated way nodes"), DUPLICATE_WAY_NODE, 36 Arrays.asList(w), Arrays.asList(n))); 37 break; 38 } 39 lastN = n; 40 } 41 } 42 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 43 @Override public Command fixError(TestError testError) { 44 Way w = (Way) testError.getPrimitives().iterator().next(); 45 Way wnew = new Way(w); 46 wnew.nodes.clear(); 47 Node lastN = null; 48 for (Node n : w.nodes) { 49 if (lastN == null) { 50 wnew.nodes.add(n); 51 } else if (n == lastN) { 52 // Skip this node 53 } else { 54 wnew.nodes.add(n); 55 } 56 lastN = n; 57 } 58 if (wnew.nodes.size() < 2) { 59 // Empty way, delete 60 return DeleteCommand.delete(Collections.singleton(w)); 61 } else { 62 return new ChangeCommand(w, wnew); 63 } 64 } 65 65 66 67 68 } 66 @Override public boolean isFixable(TestError testError) { 67 return testError.getTester() instanceof DuplicatedWayNodes; 68 } 69 69 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/NodesWithSameName.java
r10520 r12778 14 14 15 15 public class NodesWithSameName extends Test { 16 16 protected static int SAME_NAME = 801; 17 17 18 18 private Map<String, List<Node>> namesToNodes; 19 19 20 21 22 23 20 public NodesWithSameName() { 21 super(tr("Nodes with same name"), 22 tr("This test finds nodes that have the same name (might be duplicates).")); 23 } 24 24 25 26 27 25 @Override public void startTest() { 26 namesToNodes = new HashMap<String, List<Node>>(); 27 } 28 28 29 30 29 @Override public void visit(Node n) { 30 if (n.deleted || n.incomplete) return; 31 31 32 33 34 32 String name = n.get("name"); 33 String sign = n.get("traffic_sign"); 34 if (name == null || (sign != null && sign.equals("city_limit"))) return; 35 35 36 37 38 36 List<Node> nodes = namesToNodes.get(name); 37 if (nodes == null) 38 namesToNodes.put(name, nodes = new ArrayList<Node>()); 39 39 40 41 40 nodes.add(n); 41 } 42 42 43 44 45 46 47 48 49 43 @Override public void endTest() { 44 for (List<Node> nodes : namesToNodes.values()) { 45 if (nodes.size() > 1) { 46 errors.add(new TestError(this, Severity.OTHER, 47 tr("Nodes with same name"), SAME_NAME, nodes)); 48 } 49 } 50 50 51 52 51 namesToNodes = null; 52 } 53 53 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/OverlappingWays.java
r11530 r12778 21 21 /** 22 22 * Tests if there are overlapping ways 23 * 23 * 24 24 * @author frsantos 25 25 */ 26 26 public class OverlappingWays extends Test 27 27 { 28 29 28 /** Bag of all way segments */ 29 Bag<Pair<Node,Node>, WaySegment> nodePairs; 30 30 31 32 33 34 35 36 37 31 protected static int OVERLAPPING_HIGHWAY = 101; 32 protected static int OVERLAPPING_RAILWAY = 102; 33 protected static int OVERLAPPING_WAY = 103; 34 protected static int OVERLAPPING_HIGHWAY_AREA = 111; 35 protected static int OVERLAPPING_RAILWAY_AREA = 112; 36 protected static int OVERLAPPING_WAY_AREA = 113; 37 protected static int OVERLAPPING_AREA = 120; 38 38 39 40 41 42 43 44 45 46 39 /** Constructor */ 40 public OverlappingWays() 41 { 42 super(tr("Overlapping ways."), 43 tr("This test checks that a connection between two nodes " 44 + "is not used by more than one way.")); 45 46 } 47 47 48 48 49 50 51 52 53 49 @Override 50 public void startTest() 51 { 52 nodePairs = new Bag<Pair<Node,Node>, WaySegment>(1000); 53 } 54 54 55 56 57 58 55 @Override 56 public void endTest() 57 { 58 Map<List<Way>, List<WaySegment>> ways_seen = new HashMap<List<Way>, List<WaySegment>>(500); 59 59 60 61 62 60 for (List<WaySegment> duplicated : nodePairs.values()) 61 { 62 int ways = duplicated.size(); 63 63 64 65 66 67 68 69 70 71 64 if (ways > 1) 65 { 66 List<OsmPrimitive> prims = new ArrayList<OsmPrimitive>(); 67 List<Way> current_ways = new ArrayList<Way>(); 68 List<WaySegment> highlight; 69 int highway = 0; 70 int railway = 0; 71 int area = 0; 72 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 73 for (WaySegment ws : duplicated) 74 { 75 if (ws.way.get("highway") != null) 76 highway++; 77 else if (ws.way.get("railway") != null) 78 railway++; 79 Boolean ar = OsmUtils.getOsmBoolean(ws.way.get("area")); 80 if (ar != null && ar) 81 area++; 82 if (ws.way.get("landuse") != null || ws.way.get("natural") != null 83 || ws.way.get("amenity") != null || ws.way.get("leisure") != null 84 || ws.way.get("building") != null) 85 { 86 area++; ways--; 87 } 88 88 89 90 91 92 93 94 95 96 97 98 99 89 prims.add(ws.way); 90 current_ways.add(ws.way); 91 } 92 /* These ways not seen before 93 * If two or more of the overlapping ways are 94 * highways or railways mark a seperate error 95 */ 96 if ((highlight = ways_seen.get(current_ways)) == null) 97 { 98 String errortype; 99 int type; 100 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 101 if(area > 0) 102 { 103 if (ways == 0 || duplicated.size() == area) 104 { 105 errortype = tr("Overlapping areas"); 106 type = OVERLAPPING_AREA; 107 } 108 else if (highway == ways) 109 { 110 errortype = tr("Overlapping highways (with area)"); 111 type = OVERLAPPING_HIGHWAY_AREA; 112 } 113 else if (railway == ways) 114 { 115 errortype = tr("Overlapping railways (with area)"); 116 type = OVERLAPPING_RAILWAY_AREA; 117 } 118 else 119 { 120 errortype = tr("Overlapping ways (with area)"); 121 type = OVERLAPPING_WAY_AREA; 122 } 123 } 124 else if (highway == ways) 125 { 126 errortype = tr("Overlapping highways"); 127 type = OVERLAPPING_HIGHWAY; 128 } 129 else if (railway == ways) 130 { 131 errortype = tr("Overlapping railways"); 132 type = OVERLAPPING_RAILWAY; 133 } 134 else 135 { 136 errortype = tr("Overlapping ways"); 137 type = OVERLAPPING_WAY; 138 } 139 139 140 141 142 143 144 else/* way seen, mark highlight layer only */145 146 147 148 149 150 151 152 140 errors.add(new TestError(this, type < OVERLAPPING_HIGHWAY_AREA 141 ? Severity.WARNING : Severity.OTHER, tr(errortype), type, prims, duplicated)); 142 ways_seen.put(current_ways, duplicated); 143 } 144 else /* way seen, mark highlight layer only */ 145 { 146 for (WaySegment ws : duplicated) 147 highlight.add(ws); 148 } 149 } 150 } 151 nodePairs = null; 152 } 153 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 154 @Override 155 public void visit(Way w) 156 { 157 Node lastN = null; 158 int i = -2; 159 for (Node n : w.nodes) { 160 i++; 161 if (lastN == null) { 162 lastN = n; 163 continue; 164 } 165 nodePairs.add(Pair.sort(new Pair<Node,Node>(lastN, n)), 166 new WaySegment(w, i)); 167 lastN = n; 168 } 169 } 170 170 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SelfIntersectingWay.java
r10520 r12778 16 16 */ 17 17 public class SelfIntersectingWay extends Test { 18 18 protected static int SELF_INTERSECT = 401; 19 19 20 21 22 23 24 20 public SelfIntersectingWay() { 21 super(tr("Self-intersecting ways"), 22 tr("This test checks for ways " + 23 "that contain some of their nodes more than once.")); 24 } 25 25 26 27 26 @Override public void visit(Way w) { 27 HashSet<Node> nodes = new HashSet<Node>(); 28 28 29 30 31 32 33 34 35 36 37 38 39 40 29 for (int i = 1; i < w.nodes.size() - 1; i++) { 30 Node n = w.nodes.get(i); 31 if (nodes.contains(n)) { 32 errors.add(new TestError(this, 33 Severity.WARNING, tr("Self-intersecting ways"), SELF_INTERSECT, 34 Arrays.asList(w), Arrays.asList(n))); 35 break; 36 } else { 37 nodes.add(n); 38 } 39 } 40 } 41 41 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SimilarNamedWays.java
r9684 r12778 22 22 public class SimilarNamedWays extends Test 23 23 { 24 24 protected static int SIMILAR_NAMED = 701; 25 25 26 27 28 29 26 /** All ways, grouped by cells */ 27 Map<Point2D,List<Way>> cellWays; 28 /** The already detected errors */ 29 Bag<Way, Way> errorWays; 30 30 31 32 33 34 35 36 37 38 31 /** 32 * Constructor 33 */ 34 public SimilarNamedWays() 35 { 36 super(tr("Similar named ways."), 37 tr("This test checks for ways with similar names that may have been misspelled.")); 38 } 39 39 40 41 42 43 44 45 40 @Override 41 public void startTest() 42 { 43 cellWays = new HashMap<Point2D,List<Way>>(1000); 44 errorWays = new Bag<Way, Way>(); 45 } 46 46 47 48 49 50 51 52 47 @Override 48 public void endTest() 49 { 50 cellWays = null; 51 errorWays = null; 52 } 53 53 54 55 56 57 58 54 @Override 55 public void visit(Way w) 56 { 57 if( w.deleted || w.incomplete ) 58 return; 59 59 60 61 62 60 String name = w.get("name"); 61 if( name == null || name.length() < 6 ) 62 return; 63 63 64 65 66 67 68 69 70 64 List<List<Way>> theCellWays = Util.getWaysInCell(w, cellWays); 65 for( List<Way> ways : theCellWays) 66 { 67 for( Way w2 : ways) 68 { 69 if( errorWays.contains(w, w2) || errorWays.contains(w2, w) ) 70 continue; 71 71 72 73 74 72 String name2 = w2.get("name"); 73 if( name2 == null || name2.length() < 6 ) 74 continue; 75 75 76 77 78 79 80 81 82 83 84 85 86 87 88 76 int levenshteinDistance = getLevenshteinDistance(name, name2); 77 if( 0 < levenshteinDistance && levenshteinDistance <= 2 ) 78 { 79 List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>(); 80 primitives.add(w); 81 primitives.add(w2); 82 errors.add( new TestError(this, Severity.WARNING, tr("Similar named ways"), SIMILAR_NAMED, primitives) ); 83 errorWays.add(w, w2); 84 } 85 } 86 ways.add(w); 87 } 88 } 89 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 90 /** 91 * Compute Levenshtein distance 92 * 93 * @param s First word 94 * @param t Second word 95 * @return The distance between words 96 */ 97 public int getLevenshteinDistance(String s, String t) 98 { 99 int d[][]; // matrix 100 int n; // length of s 101 int m; // length of t 102 int i; // iterates through s 103 int j; // iterates through t 104 char s_i; // ith character of s 105 char t_j; // jth character of t 106 int cost; // cost 107 107 108 108 // Step 1 109 109 110 111 112 113 114 110 n = s.length(); 111 m = t.length(); 112 if (n == 0) return m; 113 if (m == 0) return n; 114 d = new int[n + 1][m + 1]; 115 115 116 117 118 116 // Step 2 117 for (i = 0; i <= n; i++) d[i][0] = i; 118 for (j = 0; j <= m; j++) d[0][j] = j; 119 119 120 121 122 123 120 // Step 3 121 for (i = 1; i <= n; i++) 122 { 123 s_i = s.charAt(i - 1); 124 124 125 126 127 128 125 // Step 4 126 for (j = 1; j <= m; j++) 127 { 128 t_j = t.charAt(j - 1); 129 129 130 131 132 133 134 135 136 137 138 130 // Step 5 131 if (s_i == t_j) 132 { 133 cost = 0; 134 } 135 else 136 { 137 cost = 1; 138 } 139 139 140 141 142 143 140 // Step 6 141 d[i][j] = Minimum(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost); 142 } 143 } 144 144 145 146 147 145 // Step 7 146 return d[n][m]; 147 } 148 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 149 /** 150 * Get minimum of three values 151 * @param a First value 152 * @param b Second value 153 * @param c Third value 154 * @return The minimum of the tre values 155 */ 156 private static int Minimum(int a, int b, int c) 157 { 158 int mi = a; 159 if (b < mi) 160 { 161 mi = b; 162 } 163 if (c < mi) 164 { 165 mi = c; 166 } 167 return mi; 168 } 169 169 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/TagChecker.java
r12777 r12778 63 63 public class TagChecker extends Test 64 64 { 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 65 /** The default data files */ 66 public static final String DATA_FILE = "http://svn.openstreetmap.org/applications/editors/josm/plugins/validator/tagchecker.cfg"; 67 public static final String SPELL_FILE = "http://svn.openstreetmap.org/applications/utils/planet.osm/java/speller/words.cfg"; 68 69 /** The spell check key substitutions: the key should be substituted by the value */ 70 protected static Map<String, String> spellCheckKeyData; 71 /** The spell check preset values */ 72 protected static Bag<String, String> presetsValueData; 73 /** The TagChecker data */ 74 protected static List<CheckerData> checkerData = new ArrayList<CheckerData>(); 75 76 /** The preferences prefix */ 77 protected static final String PREFIX = PreferenceEditor.PREFIX + "." + TagChecker.class.getSimpleName(); 78 79 public static final String PREF_CHECK_VALUES = PREFIX + ".checkValues"; 80 public static final String PREF_CHECK_KEYS = PREFIX + ".checkKeys"; 81 public static final String PREF_CHECK_COMPLEX = PREFIX + ".checkComplex"; 82 public static final String PREF_CHECK_FIXMES = PREFIX + ".checkFixmes"; 83 public static final String PREF_CHECK_PAINT = PREFIX + ".paint"; 84 85 public static final String PREF_SOURCES = PREFIX + ".sources"; 86 public static final String PREF_USE_DATA_FILE = PREFIX + ".usedatafile"; 87 public static final String PREF_USE_SPELL_FILE = PREFIX + ".usespellfile"; 88 89 public static final String PREF_CHECK_KEYS_BEFORE_UPLOAD = PREF_CHECK_KEYS + "BeforeUpload"; 90 public static final String PREF_CHECK_VALUES_BEFORE_UPLOAD = PREF_CHECK_VALUES + "BeforeUpload"; 91 public static final String PREF_CHECK_COMPLEX_BEFORE_UPLOAD = PREF_CHECK_COMPLEX + "BeforeUpload"; 92 public static final String PREF_CHECK_FIXMES_BEFORE_UPLOAD = PREF_CHECK_FIXMES + "BeforeUpload"; 93 public static final String PREF_CHECK_PAINT_BEFORE_UPLOAD = PREF_CHECK_PAINT + "BeforeUpload"; 94 95 protected boolean checkKeys = false; 96 protected boolean checkValues = false; 97 protected boolean checkComplex = false; 98 protected boolean checkFixmes = false; 99 protected boolean checkPaint = false; 100 101 protected JCheckBox prefCheckKeys; 102 protected JCheckBox prefCheckValues; 103 protected JCheckBox prefCheckComplex; 104 protected JCheckBox prefCheckFixmes; 105 protected JCheckBox prefCheckPaint; 106 107 protected JCheckBox prefCheckKeysBeforeUpload; 108 protected JCheckBox prefCheckValuesBeforeUpload; 109 protected JCheckBox prefCheckComplexBeforeUpload; 110 protected JCheckBox prefCheckFixmesBeforeUpload; 111 protected JCheckBox prefCheckPaintBeforeUpload; 112 113 protected JCheckBox prefUseDataFile; 114 protected JCheckBox prefUseSpellFile; 115 116 protected JButton addSrcButton; 117 protected JButton editSrcButton; 118 protected JButton deleteSrcButton; 119 120 protected static int EMPTY_VALUES = 1200; 121 protected static int INVALID_KEY = 1201; 122 protected static int INVALID_VALUE = 1202; 123 protected static int FIXME = 1203; 124 protected static int INVALID_SPACE = 1204; 125 protected static int INVALID_KEY_SPACE = 1205; 126 protected static int INVALID_HTML = 1206; 127 protected static int PAINT = 1207; 128 /** 1250 and up is used by tagcheck */ 129 130 /** List of sources for spellcheck data */ 131 protected JList Sources; 132 133 134 protected static Entities entities = new Entities(); 135 /** 136 * Constructor 137 */ 138 public TagChecker() 139 { 140 super(tr("Properties checker :"), 141 tr("This plugin checks for errors in property keys and values.")); 142 } 143 144 public static void initialize(OSMValidatorPlugin plugin) throws Exception 145 { 146 initializeData(); 147 initializePresets(); 148 } 149 150 /** 151 * Reads the spellcheck file into a HashMap. 152 * The data file is a list of words, beginning with +/-. If it starts with +, 153 * the word is valid, but if it starts with -, the word should be replaced 154 * by the nearest + word before this. 155 * 156 * @throws FileNotFoundException 157 * @throws IOException 158 */ 159 private static void initializeData() throws IOException 160 { 161 spellCheckKeyData = new HashMap<String, String>(); 162 String sources = Main.pref.get( PREF_SOURCES, ""); 163 if(Main.pref.getBoolean(PREF_USE_DATA_FILE, true)) 164 { 165 if( sources == null || sources.length() == 0) 166 sources = DATA_FILE; 167 else 168 sources = DATA_FILE + ";" + sources; 169 } 170 if(Main.pref.getBoolean(PREF_USE_SPELL_FILE, true)) 171 { 172 if( sources == null || sources.length() == 0) 173 sources = SPELL_FILE; 174 else 175 sources = SPELL_FILE + ";" + sources; 176 } 177 178 String errorSources = ""; 179 if(sources.length() == 0) 180 return; 181 for(String source: sources.split(";")) 182 { 183 try 184 { 185 MirroredInputStream s = new MirroredInputStream(source, Util.getPluginDir(), -1); 186 InputStreamReader r; 187 try 188 { 189 r = new InputStreamReader(s, "UTF-8"); 190 } 191 catch (UnsupportedEncodingException e) 192 { 193 r = new InputStreamReader(s); 194 } 195 BufferedReader reader = new BufferedReader(r); 196 197 String okValue = null; 198 Boolean tagcheckerfile = false; 199 String line; 200 while((line = reader.readLine()) != null && (tagcheckerfile || line.length() != 0)) 201 { 202 if(line.startsWith("#")) 203 { 204 if(line.startsWith("# JOSM TagChecker")) 205 tagcheckerfile = true; 206 } 207 else if(tagcheckerfile) 208 { 209 if(line.length() > 0) 210 { 211 CheckerData d = new CheckerData(); 212 String err = d.getData(line); 213 214 if(err == null) 215 checkerData.add(d); 216 else 217 System.err.println(tr("Invalid tagchecker line - {0}: {1}", err, line)); 218 } 219 } 220 else if(line.charAt(0) == '+') 221 { 222 okValue = line.substring(1); 223 } 224 else if(line.charAt(0) == '-' && okValue != null) 225 { 226 spellCheckKeyData.put(line.substring(1), okValue); 227 } 228 else 229 { 230 System.err.println(tr("Invalid spellcheck line: {0}", line)); 231 } 232 } 233 } 234 catch (IOException e) 235 { 236 errorSources += source + "\n"; 237 } 238 } 239 240 if( errorSources.length() > 0 ) 241 throw new IOException( tr("Could not access data file(s):\n{0}", errorSources) ); 242 } 243 244 /** 245 * Reads the presets data. 246 * 247 * @throws Exception 248 */ 249 public static void initializePresets() throws Exception 250 { 251 if( !Main.pref.getBoolean(PREF_CHECK_VALUES, true) ) 252 return; 253 254 Collection<TaggingPreset> presets = TaggingPresetPreference.taggingPresets; 255 if(presets != null) 256 { 257 presetsValueData = new Bag<String, String>(); 258 for(TaggingPreset p : presets) 259 { 260 for(TaggingPreset.Item i : p.data) 261 { 262 if(i instanceof TaggingPreset.Combo) 263 { 264 TaggingPreset.Combo combo = (TaggingPreset.Combo) i; 265 for(String value : combo.values.split(",")) 266 presetsValueData.add(combo.key, value); 267 } 268 else if(i instanceof TaggingPreset.Key) 269 { 270 TaggingPreset.Key k = (TaggingPreset.Key) i; 271 presetsValueData.add(k.key, k.value); 272 } 273 } 274 } 275 } 276 } 277 278 @Override 279 public void visit(Node n) 280 { 281 checkPrimitive(n); 282 } 283 284 285 @Override 286 public void visit(Relation n) 287 { 288 checkPrimitive(n); 289 } 290 291 292 @Override 293 public void visit(Way w) 294 { 295 checkPrimitive(w); 296 } 297 298 /** 299 * Checks the primitive properties 300 * @param p The primitive to check 301 */ 302 private void checkPrimitive(OsmPrimitive p) 303 { 304 // Just a collection to know if a primitive has been already marked with error 305 Bag<OsmPrimitive, String> withErrors = new Bag<OsmPrimitive, String>(); 306 307 if(checkComplex) 308 { 309 for(CheckerData d : checkerData) 310 { 311 if(d.match(p)) 312 { 313 errors.add( new TestError(this, d.getSeverity(), tr("Illegal tag/value combinations"), 314 d.getDescription(), d.getDescriptionOrig(), d.getCode(), p) ); 315 withErrors.add(p, "TC"); 316 break; 317 } 318 } 319 } 320 if(checkPaint && p.errors != null) 321 { 322 for(String s: p.errors) 323 { 324 /* passing translated text also to original string, as we already 325 translated the stuff before. Makes the ignore file language dependend. */ 326 errors.add( new TestError(this, Severity.WARNING, tr("Painting problem"), 327 s, s, PAINT, p) ); 328 withErrors.add(p, "P"); 329 } 330 } 331 332 Map<String, String> props = (p.keys == null) ? Collections.<String, String>emptyMap() : p.keys; 333 for(Entry<String, String> prop: props.entrySet() ) 334 { 335 String s = marktr("Key ''{0}'' invalid."); 336 String key = prop.getKey(); 337 String value = prop.getValue(); 338 if( checkValues && (value==null || value.trim().length() == 0) && !withErrors.contains(p, "EV")) 339 { 340 errors.add( new TestError(this, Severity.WARNING, tr("Tags with empty values"), 341 tr(s, key), MessageFormat.format(s, key), EMPTY_VALUES, p) ); 342 withErrors.add(p, "EV"); 343 } 344 if( checkKeys && spellCheckKeyData.containsKey(key) && !withErrors.contains(p, "IPK")) 345 { 346 errors.add( new TestError(this, Severity.WARNING, tr("Invalid property key"), 347 tr(s, key), MessageFormat.format(s, key), INVALID_KEY, p) ); 348 withErrors.add(p, "IPK"); 349 } 350 if( checkKeys && key.indexOf(" ") >= 0 && !withErrors.contains(p, "IPK")) 351 { 352 errors.add( new TestError(this, Severity.WARNING, tr("Invalid white space in property key"), 353 tr(s, key), MessageFormat.format(s, key), INVALID_KEY_SPACE, p) ); 354 withErrors.add(p, "IPK"); 355 } 356 if( checkValues && value != null && (value.startsWith(" ") || value.endsWith(" ")) && !withErrors.contains(p, "SPACE")) 357 { 358 errors.add( new TestError(this, Severity.OTHER, tr("Property values start or end with white space"), 359 tr(s, key), MessageFormat.format(s, key), INVALID_SPACE, p) ); 360 withErrors.add(p, "SPACE"); 361 } 362 if( checkValues && value != null && !value.equals(entities.unescape(value)) && !withErrors.contains(p, "HTML")) 363 { 364 errors.add( new TestError(this, Severity.OTHER, tr("Property values contain HTML entity"), 365 tr(s, key), MessageFormat.format(s, key), INVALID_HTML, p) ); 366 withErrors.add(p, "HTML"); 367 } 368 if( checkValues && value != null && value.length() > 0 && presetsValueData != null) 369 { 370 List<String> values = presetsValueData.get(key); 371 if( values != null && !values.contains(prop.getValue()) && !withErrors.contains(p, "UPV")) 372 { 373 String i = marktr("Key ''{0}'' unknown."); 374 errors.add( new TestError(this, Severity.OTHER, tr("Unknown property values"), 375 tr(i, key), MessageFormat.format(i, key), INVALID_VALUE, p) ); 376 withErrors.add(p, "UPV"); 377 } 378 } 379 if( checkFixmes && value != null && value.length() > 0 ) 380 { 381 if( (value.contains("FIXME") || value.contains("check and delete") || key.contains("todo") || key.contains("fixme")) 382 && !withErrors.contains(p, "FIXME")) 383 { 384 errors.add( new TestError(this, Severity.OTHER, tr("FIXMES"), FIXME, p) ); 385 withErrors.add(p, "FIXME"); 386 } 387 } 388 } 389 } 390 391 @Override 392 public void startTest() 393 { 394 checkKeys = Main.pref.getBoolean(PREF_CHECK_KEYS, true); 395 if( isBeforeUpload ) 396 checkKeys = checkKeys && Main.pref.getBoolean(PREF_CHECK_KEYS_BEFORE_UPLOAD, true); 397 398 checkValues = Main.pref.getBoolean(PREF_CHECK_VALUES, true); 399 if( isBeforeUpload ) 400 checkValues = checkValues && Main.pref.getBoolean(PREF_CHECK_VALUES_BEFORE_UPLOAD, true); 401 402 checkComplex = Main.pref.getBoolean(PREF_CHECK_COMPLEX, true); 403 if( isBeforeUpload ) 404 checkComplex = checkValues && Main.pref.getBoolean(PREF_CHECK_COMPLEX_BEFORE_UPLOAD, true); 405 406 checkFixmes = Main.pref.getBoolean(PREF_CHECK_FIXMES, true); 407 if( isBeforeUpload ) 408 checkFixmes = checkFixmes && Main.pref.getBoolean(PREF_CHECK_FIXMES_BEFORE_UPLOAD, true); 409 410 checkPaint = Main.pref.getBoolean(PREF_CHECK_PAINT, true); 411 if( isBeforeUpload ) 412 checkPaint = checkPaint && Main.pref.getBoolean(PREF_CHECK_PAINT_BEFORE_UPLOAD, true); 413 } 414 415 @Override 416 public void visit(Collection<OsmPrimitive> selection) 417 { 418 if( checkKeys || checkValues || checkComplex) 419 super.visit(selection); 420 } 421 422 @Override 423 public void addGui(JPanel testPanel) 424 { 425 GBC a = GBC.eol(); 426 a.anchor = GBC.EAST; 427 428 testPanel.add( new JLabel(name), GBC.eol().insets(3,0,0,0) ); 429 430 prefCheckKeys = new JCheckBox(tr("Check property keys."), Main.pref.getBoolean(PREF_CHECK_KEYS, true)); 431 prefCheckKeys.setToolTipText(tr("Validate that property keys are valid checking against list of words.")); 432 testPanel.add(prefCheckKeys, GBC.std().insets(20,0,0,0)); 433 434 prefCheckKeysBeforeUpload = new JCheckBox(); 435 prefCheckKeysBeforeUpload.setSelected(Main.pref.getBoolean(PREF_CHECK_KEYS_BEFORE_UPLOAD, true)); 436 testPanel.add(prefCheckKeysBeforeUpload, a); 437 438 prefCheckComplex = new JCheckBox(tr("Use complex property checker."), Main.pref.getBoolean(PREF_CHECK_COMPLEX, true)); 439 prefCheckComplex.setToolTipText(tr("Validate property values and tags using complex rules.")); 440 testPanel.add(prefCheckComplex, GBC.std().insets(20,0,0,0)); 441 442 prefCheckComplexBeforeUpload = new JCheckBox(); 443 prefCheckComplexBeforeUpload.setSelected(Main.pref.getBoolean(PREF_CHECK_COMPLEX_BEFORE_UPLOAD, true)); 444 testPanel.add(prefCheckComplexBeforeUpload, a); 445 446 Sources = new JList(new DefaultListModel()); 447 448 String sources = Main.pref.get( PREF_SOURCES ); 449 if(sources != null && sources.length() > 0) 450 { 451 for(String source : sources.split(";")) 452 ((DefaultListModel)Sources.getModel()).addElement(source); 453 } 454 455 addSrcButton = new JButton(tr("Add")); 456 addSrcButton.addActionListener(new ActionListener(){ 457 public void actionPerformed(ActionEvent e) { 458 String source = JOptionPane.showInputDialog(Main.parent, tr("TagChecker source")); 459 if (source != null) 460 ((DefaultListModel)Sources.getModel()).addElement(source); 461 Sources.clearSelection(); 462 } 463 }); 464 465 editSrcButton = new JButton(tr("Edit")); 466 editSrcButton.addActionListener(new ActionListener(){ 467 public void actionPerformed(ActionEvent e) { 468 int row = Sources.getSelectedIndex(); 469 if(row == -1 && Sources.getModel().getSize() == 1) 470 { 471 Sources.setSelectedIndex(0); 472 row = 0; 473 } 474 if (row == -1) 475 { 476 if(Sources.getModel().getSize() == 0) 477 { 478 String source = JOptionPane.showInputDialog(Main.parent, tr("TagChecker source")); 479 if (source != null) 480 ((DefaultListModel)Sources.getModel()).addElement(source); 481 } 482 else 483 { 484 JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to edit.")); 485 } 486 } 487 else { 488 String source = JOptionPane.showInputDialog(Main.parent, tr("TagChecker source"), Sources.getSelectedValue()); 489 if (source != null) 490 ((DefaultListModel)Sources.getModel()).setElementAt(source, row); 491 } 492 Sources.clearSelection(); 493 } 494 }); 495 496 deleteSrcButton = new JButton(tr("Delete")); 497 deleteSrcButton.addActionListener(new ActionListener(){ 498 public void actionPerformed(ActionEvent e) { 499 if (Sources.getSelectedIndex() == -1) 500 JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to delete.")); 501 else { 502 ((DefaultListModel)Sources.getModel()).remove(Sources.getSelectedIndex()); 503 } 504 } 505 }); 506 Sources.setMinimumSize(new Dimension(300,50)); 507 Sources.setVisibleRowCount(3); 508 509 Sources.setToolTipText(tr("The sources (URL or filename) of spell check (see http://wiki.openstreetmap.org/index.php/User:JLS/speller) or tag checking data files.")); 510 addSrcButton.setToolTipText(tr("Add a new source to the list.")); 511 editSrcButton.setToolTipText(tr("Edit the selected source.")); 512 deleteSrcButton.setToolTipText(tr("Delete the selected source from the list.")); 513 514 testPanel.add(new JLabel(tr("Data sources")), GBC.eol().insets(23,0,0,0)); 515 testPanel.add(new JScrollPane(Sources), GBC.eol().insets(23,0,0,0).fill(GBC.HORIZONTAL)); 516 final JPanel buttonPanel = new JPanel(new GridBagLayout()); 517 testPanel.add(buttonPanel, GBC.eol().fill(GBC.HORIZONTAL)); 518 buttonPanel.add(addSrcButton, GBC.std().insets(0,5,0,0)); 519 buttonPanel.add(editSrcButton, GBC.std().insets(5,5,5,0)); 520 buttonPanel.add(deleteSrcButton, GBC.std().insets(0,5,0,0)); 521 522 ActionListener disableCheckActionListener = new ActionListener(){ 523 public void actionPerformed(ActionEvent e) { 524 handlePrefEnable(); 525 } 526 }; 527 prefCheckKeys.addActionListener(disableCheckActionListener); 528 prefCheckKeysBeforeUpload.addActionListener(disableCheckActionListener); 529 prefCheckComplex.addActionListener(disableCheckActionListener); 530 prefCheckComplexBeforeUpload.addActionListener(disableCheckActionListener); 531 532 handlePrefEnable(); 533 534 prefCheckValues = new JCheckBox(tr("Check property values."), Main.pref.getBoolean(PREF_CHECK_VALUES, true)); 535 prefCheckValues.setToolTipText(tr("Validate that property values are valid checking against presets.")); 536 testPanel.add(prefCheckValues, GBC.std().insets(20,0,0,0)); 537 538 prefCheckValuesBeforeUpload = new JCheckBox(); 539 prefCheckValuesBeforeUpload.setSelected(Main.pref.getBoolean(PREF_CHECK_VALUES_BEFORE_UPLOAD, true)); 540 testPanel.add(prefCheckValuesBeforeUpload, a); 541 542 prefCheckFixmes = new JCheckBox(tr("Check for FIXMES."), Main.pref.getBoolean(PREF_CHECK_FIXMES, true)); 543 prefCheckFixmes.setToolTipText(tr("Looks for nodes or ways with FIXME in any property value.")); 544 testPanel.add(prefCheckFixmes, GBC.std().insets(20,0,0,0)); 545 546 prefCheckFixmesBeforeUpload = new JCheckBox(); 547 prefCheckFixmesBeforeUpload.setSelected(Main.pref.getBoolean(PREF_CHECK_FIXMES_BEFORE_UPLOAD, true)); 548 testPanel.add(prefCheckFixmesBeforeUpload, a); 549 550 prefCheckPaint = new JCheckBox(tr("Check for paint notes."), Main.pref.getBoolean(PREF_CHECK_PAINT, true)); 551 prefCheckPaint.setToolTipText(tr("Check if map paining found data errors.")); 552 testPanel.add(prefCheckPaint, GBC.std().insets(20,0,0,0)); 553 554 prefCheckPaintBeforeUpload = new JCheckBox(); 555 prefCheckPaintBeforeUpload.setSelected(Main.pref.getBoolean(PREF_CHECK_PAINT_BEFORE_UPLOAD, true)); 556 testPanel.add(prefCheckPaintBeforeUpload, a); 557 558 prefUseDataFile = new JCheckBox(tr("Use default data file."), Main.pref.getBoolean(PREF_USE_DATA_FILE, true)); 559 prefUseDataFile.setToolTipText(tr("Use the default data file (recommended).")); 560 testPanel.add(prefUseDataFile, GBC.eol().insets(20,0,0,0)); 561 562 prefUseSpellFile = new JCheckBox(tr("Use default spellcheck file."), Main.pref.getBoolean(PREF_USE_SPELL_FILE, true)); 563 prefUseSpellFile.setToolTipText(tr("Use the default spellcheck file (recommended).")); 564 testPanel.add(prefUseSpellFile, GBC.eol().insets(20,0,0,0)); 565 } 566 567 public void handlePrefEnable() 568 { 569 boolean selected = prefCheckKeys.isSelected() || prefCheckKeysBeforeUpload.isSelected() 570 || prefCheckComplex.isSelected() || prefCheckComplexBeforeUpload.isSelected(); 571 Sources.setEnabled( selected ); 572 addSrcButton.setEnabled(selected); 573 editSrcButton.setEnabled(selected); 574 deleteSrcButton.setEnabled(selected); 575 } 576 577 @Override 578 public boolean ok() 579 { 580 enabled = prefCheckKeys.isSelected() || prefCheckValues.isSelected() || prefCheckComplex.isSelected() || prefCheckFixmes.isSelected(); 581 testBeforeUpload = prefCheckKeysBeforeUpload.isSelected() || prefCheckValuesBeforeUpload.isSelected() 582 || prefCheckFixmesBeforeUpload.isSelected() || prefCheckComplexBeforeUpload.isSelected(); 583 584 Main.pref.put(PREF_CHECK_VALUES, prefCheckValues.isSelected()); 585 Main.pref.put(PREF_CHECK_COMPLEX, prefCheckComplex.isSelected()); 586 Main.pref.put(PREF_CHECK_KEYS, prefCheckKeys.isSelected()); 587 Main.pref.put(PREF_CHECK_FIXMES, prefCheckFixmes.isSelected()); 588 Main.pref.put(PREF_CHECK_PAINT, prefCheckPaint.isSelected()); 589 Main.pref.put(PREF_CHECK_VALUES_BEFORE_UPLOAD, prefCheckValuesBeforeUpload.isSelected()); 590 Main.pref.put(PREF_CHECK_COMPLEX_BEFORE_UPLOAD, prefCheckComplexBeforeUpload.isSelected()); 591 Main.pref.put(PREF_CHECK_KEYS_BEFORE_UPLOAD, prefCheckKeysBeforeUpload.isSelected()); 592 Main.pref.put(PREF_CHECK_FIXMES_BEFORE_UPLOAD, prefCheckFixmesBeforeUpload.isSelected()); 593 Main.pref.put(PREF_CHECK_PAINT_BEFORE_UPLOAD, prefCheckPaintBeforeUpload.isSelected()); 594 Main.pref.put(PREF_USE_DATA_FILE, prefUseDataFile.isSelected()); 595 Main.pref.put(PREF_USE_SPELL_FILE, prefUseSpellFile.isSelected()); 596 String sources = ""; 597 if( Sources.getModel().getSize() > 0 ) 598 { 599 String sb = ""; 600 for (int i = 0; i < Sources.getModel().getSize(); ++i) 601 sb += ";"+Sources.getModel().getElementAt(i); 602 sources = sb.substring(1); 603 } 604 if(sources.length() == 0) 605 sources = null; 606 return Main.pref.put(PREF_SOURCES, sources); 607 } 608 609 @Override 610 public Command fixError(TestError testError) 611 { 612 List<Command> commands = new ArrayList<Command>(50); 613 614 int i = -1; 615 List<? extends OsmPrimitive> primitives = testError.getPrimitives(); 616 for(OsmPrimitive p : primitives ) 617 { 618 i++; 619 Map<String, String> tags = p.keys; 620 if( tags == null || tags.size() == 0 ) 621 continue; 622 623 for(Entry<String, String> prop: tags.entrySet() ) 624 { 625 String key = prop.getKey(); 626 String value = prop.getValue(); 627 if( value == null || value.trim().length() == 0 ) 628 commands.add( new ChangePropertyCommand(Collections.singleton(primitives.get(i)), key, null) ); 629 else if(value.startsWith(" ") || value.endsWith(" ")) 630 commands.add( new ChangePropertyCommand(Collections.singleton(primitives.get(i)), key, value.trim()) ); 631 else if(key.startsWith(" ") || key.endsWith(" ")) 632 commands.add( new ChangePropertyKeyCommand(Collections.singleton(primitives.get(i)), key, key.trim()) ); 633 else 634 { 635 String evalue = entities.unescape(value); 636 if(!evalue.equals(value)) 637 commands.add( new ChangePropertyCommand(Collections.singleton(primitives.get(i)), key, evalue) ); 638 else 639 { 640 String replacementKey = spellCheckKeyData.get(key); 641 if( replacementKey != null ) 642 { 643 commands.add( new ChangePropertyKeyCommand(Collections.singleton(primitives.get(i)), 644 key, replacementKey) ); 645 } 646 } 647 } 648 } 649 } 650 651 if( commands.size() == 0 ) 652 return null; 653 else if( commands.size() == 1 ) 654 return commands.get(0); 655 else 656 return new SequenceCommand(tr("Fix properties"), commands); 657 } 658 659 @Override 660 public boolean isFixable(TestError testError) 661 { 662 if( testError.getTester() instanceof TagChecker) 663 { 664 int code = testError.getCode(); 665 return code == INVALID_KEY || code == EMPTY_VALUES || code == INVALID_SPACE || code == INVALID_KEY_SPACE || code == INVALID_HTML; 666 } 667 668 return false; 669 } 670 671 private static class CheckerData { 672 private String description; 673 private List<CheckerElement> data = new ArrayList<CheckerElement>(); 674 private Integer type = 0; 675 private Integer code; 676 protected Severity severity; 677 protected static int NODE = 1; 678 protected static int WAY = 2; 679 protected static int RELATION = 3; 680 protected static int ALL = 4; 681 protected static int TAG_CHECK_ERROR = 1250; 682 protected static int TAG_CHECK_WARN = 1260; 683 protected static int TAG_CHECK_INFO = 1270; 684 685 private class CheckerElement { 686 public Object tag; 687 public Object value; 688 public Boolean noMatch; 689 public Boolean tagAll = false; 690 public Boolean valueAll = false; 691 public Boolean valueBool = false; 692 private Pattern getPattern(String str) throws IllegalStateException, PatternSyntaxException 693 { 694 if(str.endsWith("/i")) 695 return Pattern.compile(str.substring(1,str.length()-2), Pattern.CASE_INSENSITIVE); 696 else if(str.endsWith("/")) 697 return Pattern.compile(str.substring(1,str.length()-1)); 698 throw new IllegalStateException(); 699 } 700 public CheckerElement(String exp) throws IllegalStateException, PatternSyntaxException 701 { 702 Matcher m = Pattern.compile("(.+)([!=]=)(.+)").matcher(exp); 703 m.matches(); 704 705 String n = m.group(1).trim(); 706 if(n.equals("*")) 707 tagAll = true; 708 else 709 tag = n.startsWith("/") ? getPattern(n) : n; 710 noMatch = m.group(2).equals("!="); 711 n = m.group(3).trim(); 712 if(n.equals("*")) 713 valueAll = true; 714 else if(n.equals("BOOLEAN_TRUE")) 715 { 716 valueBool = true; 717 value = OsmUtils.trueval; 718 } 719 else if(n.equals("BOOLEAN_FALSE")) 720 { 721 valueBool = true; 722 value = OsmUtils.falseval; 723 } 724 else 725 value = n.startsWith("/") ? getPattern(n) : n; 726 } 727 public Boolean match(OsmPrimitive osm) 728 { 729 for(Entry<String, String> prop: osm.keys.entrySet()) 730 { 731 String key = prop.getKey(); 732 String val = valueBool ? OsmUtils.getNamedOsmBoolean(prop.getValue()) : prop.getValue(); 733 if((tagAll || (tag instanceof Pattern ? ((Pattern)tag).matcher(key).matches() : key.equals(tag))) 734 && (valueAll || (value instanceof Pattern ? ((Pattern)value).matcher(val).matches() : val.equals(value)))) 735 return !noMatch; 736 } 737 return noMatch; 738 } 739 }; 740 741 public String getData(String str) 742 { 743 Matcher m = Pattern.compile(" *# *([^#]+) *$").matcher(str); 744 str = m.replaceFirst("").trim(); 745 try 746 { 747 description = m.group(1); 748 if(description != null && description.length() == 0) 749 description = null; 750 } 751 catch (IllegalStateException e) 752 { 753 description = null; 754 } 755 String[] n = str.split(" *: *", 3); 756 if(n[0].equals("way")) 757 type = WAY; 758 else if(n[0].equals("node")) 759 type = NODE; 760 else if(n[0].equals("relation")) 761 type = RELATION; 762 else if(n[0].equals("*")) 763 type = ALL; 764 if(type == 0 || n.length != 3) 765 return tr("Could not find element type"); 766 if(n[1].equals("W")) 767 { 768 severity = Severity.WARNING; 769 code = TAG_CHECK_WARN; 770 } 771 else if(n[1].equals("E")) 772 { 773 severity = Severity.ERROR; 774 code = TAG_CHECK_ERROR; 775 } 776 else if(n[1].equals("I")) 777 { 778 severity = Severity.OTHER; 779 code = TAG_CHECK_INFO; 780 } 781 else 782 return tr("Could not find warning level"); 783 for(String exp: n[2].split(" *&& *")) 784 { 785 try 786 { 787 data.add(new CheckerElement(exp)); 788 } 789 catch(IllegalStateException e) 790 { 791 return tr("Illegal expression ''{0}''", exp); 792 } 793 catch(PatternSyntaxException e) 794 { 795 return tr("Illegal regular expression ''{0}''", exp); 796 } 797 } 798 return null; 799 } 800 public Boolean match(OsmPrimitive osm) 801 { 802 if(osm.keys == null || (type == NODE && !(osm instanceof Node)) 803 || (type == RELATION && !(osm instanceof Relation)) || (type == WAY && !(osm instanceof Way))) 804 return false; 805 for(CheckerElement ce : data) 806 { 807 if(!ce.match(osm)) 808 return false; 809 } 810 return true; 811 } 812 public String getDescription() 813 { 814 return tr(description); 815 } 816 public String getDescriptionOrig() 817 { 818 return description; 819 } 820 public Severity getSeverity() 821 { 822 return severity; 823 } 824 public int getCode() 825 { 826 return code + type; 827 } 828 } 829 829 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UnconnectedWays.java
r10774 r12778 25 25 public class UnconnectedWays extends Test 26 26 { 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 27 protected static int UNCONNECTED_WAYS = 1301; 28 protected static final String PREFIX = PreferenceEditor.PREFIX + "." + UnconnectedWays.class.getSimpleName(); 29 30 Set<MyWaySegment> ways; 31 Set<Node> endnodes; // nodes at end of way 32 Set<Node> endnodes_highway; // nodes at end of way 33 Set<Node> middlenodes; // nodes in middle of way 34 Set<Node> othernodes; // nodes appearing at least twice 35 36 double mindist; 37 double minmiddledist; 38 /** 39 * Constructor 40 */ 41 public UnconnectedWays() 42 { 43 super(tr("Unconnected ways."), 44 tr("This test checks if a way has an endpoint very near to another way.")); 45 } 46 47 @Override 48 public void startTest() 49 { 50 ways = new HashSet<MyWaySegment>(); 51 endnodes = new HashSet<Node>(); 52 endnodes_highway = new HashSet<Node>(); 53 middlenodes = new HashSet<Node>(); 54 othernodes = new HashSet<Node>(); 55 mindist = Main.pref.getDouble(PREFIX + ".node_way_distance", 10.0)/6378135.0; 56 minmiddledist = Main.pref.getDouble(PREFIX + ".way_way_distance", 0.0)/6378135.0; 57 } 58 59 @Override 60 public void endTest() 61 { 62 Map<Node, Way> map = new HashMap<Node, Way>(); 63 for(Node en : endnodes_highway) 64 { 65 for(MyWaySegment s : ways) 66 { 67 if(s.highway && s.nearby(en, mindist)) 68 map.put(en, s.w); 69 } 70 } 71 if(map.size() > 0) 72 { 73 for(Map.Entry<Node, Way> error : map.entrySet()) 74 { 75 errors.add(new TestError(this, Severity.WARNING, 76 tr("Way end node near other highway"), UNCONNECTED_WAYS, 77 Arrays.asList(error.getKey(), error.getValue()))); 78 } 79 } 80 map.clear(); 81 for(Node en : endnodes_highway) 82 { 83 for(MyWaySegment s : ways) 84 { 85 if(!s.highway && s.nearby(en, mindist)) 86 map.put(en, s.w); 87 } 88 } 89 for(Node en : endnodes) 90 { 91 for(MyWaySegment s : ways) 92 { 93 if(s.nearby(en, mindist)) 94 map.put(en, s.w); 95 } 96 } 97 if(map.size() > 0) 98 { 99 for(Map.Entry<Node, Way> error : map.entrySet()) 100 { 101 errors.add(new TestError(this, Severity.WARNING, 102 tr("Way end node near other way"), UNCONNECTED_WAYS, 103 Arrays.asList(error.getKey(), error.getValue()))); 104 } 105 } 106 /* the following two use a shorter distance */ 107 if(minmiddledist > 0.0) 108 { 109 map.clear(); 110 for(Node en : middlenodes) 111 { 112 for(MyWaySegment s : ways) 113 { 114 if(s.nearby(en, minmiddledist)) 115 map.put(en, s.w); 116 } 117 } 118 if(map.size() > 0) 119 { 120 for(Map.Entry<Node, Way> error : map.entrySet()) 121 { 122 errors.add(new TestError(this, Severity.OTHER, 123 tr("Way node near other way"), UNCONNECTED_WAYS, 124 Arrays.asList(error.getKey(), error.getValue()))); 125 } 126 } 127 map.clear(); 128 for(Node en : othernodes) 129 { 130 for(MyWaySegment s : ways) 131 { 132 if(s.nearby(en, minmiddledist)) 133 map.put(en, s.w); 134 } 135 } 136 if(map.size() > 0) 137 { 138 for(Map.Entry<Node, Way> error : map.entrySet()) 139 { 140 errors.add(new TestError(this, Severity.OTHER, 141 tr("Connected way end node near other way"), UNCONNECTED_WAYS, 142 Arrays.asList(error.getKey(), error.getValue()))); 143 } 144 } 145 } 146 ways = null; 147 endnodes = null; 148 } 149 150 private class MyWaySegment 151 { 152 private Line2D line; 153 public Way w; 154 public Boolean highway; 155 156 public MyWaySegment(Way w, Node n1, Node n2) 157 { 158 this.w = w; 159 this.highway = w.get("highway") != null || w.get("railway") != null; 160 line = new Line2D.Double(n1.eastNorth.east(), n1.eastNorth.north(), 161 n2.eastNorth.east(), n2.eastNorth.north()); 162 } 163 164 public boolean nearby(Node n, double dist) 165 { 166 return !w.nodes.contains(n) 167 && line.ptSegDist(n.eastNorth.east(), n.eastNorth.north()) < dist; 168 } 169 } 170 171 @Override 172 public void visit(Way w) 173 { 174 if( w.deleted || w.incomplete ) 175 return; 176 int size = w.nodes.size(); 177 if(size < 2) 178 return; 179 for(int i = 1; i < size; ++i) 180 { 181 if(i < size-1) 182 addNode(w.nodes.get(i), middlenodes); 183 ways.add(new MyWaySegment(w, w.nodes.get(i-1), w.nodes.get(i))); 184 } 185 Set<Node> set = endnodes; 186 if(w.get("highway") != null || w.get("railway") != null) 187 set = endnodes_highway; 188 addNode(w.nodes.get(0), set); 189 addNode(w.nodes.get(size-1), set); 190 } 191 private void addNode(Node n, Set<Node> s) 192 { 193 Boolean m = middlenodes.contains(n); 194 Boolean e = endnodes.contains(n); 195 Boolean eh = endnodes_highway.contains(n); 196 Boolean o = othernodes.contains(n); 197 if(!m && !e && !o && !eh) 198 s.add(n); 199 else if(!o) 200 { 201 othernodes.add(n); 202 if(e) 203 endnodes.remove(n); 204 else if(eh) 205 endnodes_highway.remove(n); 206 else 207 middlenodes.remove(n); 208 } 209 } 210 210 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UntaggedNode.java
r10774 r12778 22 22 public class UntaggedNode extends Test 23 23 { 24 24 protected static int UNTAGGED_NODE = 201; 25 25 26 27 26 /** Bag of all nodes */ 27 Set<Node> emptyNodes; 28 28 29 30 31 32 33 34 35 36 29 /** 30 * Constructor 31 */ 32 public UntaggedNode() 33 { 34 super(tr("Untagged nodes."), 35 tr("This test checks for untagged nodes that are not part of any way.")); 36 } 37 37 38 39 40 41 42 38 @Override 39 public void startTest() 40 { 41 emptyNodes = new HashSet<Node>(100); 42 } 43 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 44 @Override 45 public void visit(Collection<OsmPrimitive> selection) 46 { 47 // If there is a partial selection, it may be false positives if a 48 // node is selected, but not the container way. So, in this 49 // case, we must visit all ways, selected or not. 50 if (partialSelection) { 51 for (OsmPrimitive p : selection) { 52 if (!p.deleted && !p.incomplete && p instanceof Node) { 53 p.visit(this); 54 } 55 } 56 for (Way w : Main.ds.ways) { 57 visit(w); 58 } 59 } else { 60 for (OsmPrimitive p : selection) { 61 if (!p.deleted && !p.incomplete) { 62 p.visit(this); 63 } 64 } 65 } 66 } 67 67 68 69 70 71 72 73 68 @Override 69 public void visit(Node n) 70 { 71 if(!n.incomplete && !n.deleted && !n.tagged) 72 emptyNodes.add(n); 73 } 74 74 75 76 77 78 79 80 81 75 @Override 76 public void visit(Way w) 77 { 78 for (Node n : w.nodes) { 79 emptyNodes.remove(n); 80 } 81 } 82 82 83 84 85 86 87 88 89 90 91 83 @Override 84 public void endTest() 85 { 86 for(Node node : emptyNodes) 87 { 88 errors.add( new TestError(this, Severity.OTHER, tr("Untagged and unconnected nodes"), UNTAGGED_NODE, node) ); 89 } 90 emptyNodes = null; 91 } 92 92 93 94 95 96 97 93 @Override 94 public Command fixError(TestError testError) 95 { 96 return DeleteCommand.delete(testError.getPrimitives()); 97 } 98 98 99 100 101 102 103 99 @Override 100 public boolean isFixable(TestError testError) 101 { 102 return (testError.getTester() instanceof UntaggedNode); 103 } 104 104 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UntaggedWay.java
r10774 r12778 21 21 public class UntaggedWay extends Test 22 22 { 23 24 25 26 27 28 29 30 23 /** Empty way error */ 24 protected static final int EMPTY_WAY = 301; 25 /** Untagged way error */ 26 protected static final int UNTAGGED_WAY = 302; 27 /** Unnamed way error */ 28 protected static final int UNNAMED_WAY = 303; 29 /** One node way error */ 30 protected static final int ONE_NODE_WAY = 304; 31 31 32 33 34 35 36 37 38 39 40 41 42 43 32 /** Ways that must have a name */ 33 public static final Set<String> NAMED_WAYS = new HashSet<String>(); 34 static 35 { 36 NAMED_WAYS.add( "motorway" ); 37 NAMED_WAYS.add( "trunk" ); 38 NAMED_WAYS.add( "primary" ); 39 NAMED_WAYS.add( "secondary" ); 40 NAMED_WAYS.add( "tertiary" ); 41 NAMED_WAYS.add( "residential" ); 42 NAMED_WAYS.add( "pedestrian" ); ; 43 } 44 44 45 46 47 48 49 50 51 52 45 /** 46 * Constructor 47 */ 48 public UntaggedWay() 49 { 50 super(tr("Untagged, empty, and one node ways."), 51 tr("This test checks for untagged, empty and one node ways.")); 52 } 53 53 54 55 56 57 54 @Override 55 public void visit(Way w) 56 { 57 if (w.deleted || w.incomplete) return; 58 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 59 Map<String, String> tags = w.keys; 60 if( tags != null ) 61 { 62 String highway = tags.get("highway"); 63 if(highway != null && NAMED_WAYS.contains(highway)) 64 { 65 if( !tags.containsKey("name") && !tags.containsKey("ref") ) 66 { 67 boolean hasName = false; 68 for( String key : w.keySet()) 69 { 70 hasName = key.startsWith("name:") || key.endsWith("_name") || key.endsWith("_ref"); 71 if( hasName ) 72 break; 73 } 74 74 75 76 77 78 79 75 if( !hasName) 76 errors.add( new TestError(this, Severity.WARNING, tr("Unnamed ways"), UNNAMED_WAY, w) ); 77 } 78 } 79 } 80 80 81 82 83 84 81 if(!w.tagged) 82 { 83 errors.add( new TestError(this, Severity.WARNING, tr("Untagged ways"), UNTAGGED_WAY, w) ); 84 } 85 85 86 87 88 89 90 91 92 93 86 if( w.nodes.size() == 0 ) 87 { 88 errors.add( new TestError(this, Severity.ERROR, tr("Empty ways"), EMPTY_WAY, w) ); 89 } 90 else if( w.nodes.size() == 1 ) 91 { 92 errors.add( new TestError(this, Severity.ERROR, tr("One node ways"), ONE_NODE_WAY, w) ); 93 } 94 94 95 95 } 96 96 97 98 99 100 101 102 103 104 97 @Override 98 public boolean isFixable(TestError testError) 99 { 100 if( testError.getTester() instanceof UntaggedWay ) 101 { 102 return testError.getCode() == EMPTY_WAY 103 || testError.getCode() == ONE_NODE_WAY; 104 } 105 105 106 107 106 return false; 107 } 108 108 109 110 111 112 113 109 @Override 110 public Command fixError(TestError testError) 111 { 112 return DeleteCommand.delete(testError.getPrimitives()); 113 } 114 114 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/WronglyOrderedWays.java
r11530 r12778 19 19 */ 20 20 public class WronglyOrderedWays extends Test { 21 22 23 21 protected static int WRONGLY_ORDERED_COAST = 1001; 22 protected static int WRONGLY_ORDERED_WATER = 1002; 23 protected static int WRONGLY_ORDERED_LAND = 1003; 24 24 25 26 25 /** The already detected errors */ 26 Bag<Way, Way> _errorWays; 27 27 28 29 30 31 32 33 34 35 28 /** 29 * Constructor 30 */ 31 public WronglyOrderedWays() 32 { 33 super(tr("Wrongly Ordered Ways."), 34 tr("This test checks the direction of water, land and coastline ways.")); 35 } 36 36 37 38 39 40 41 37 @Override 38 public void startTest() 39 { 40 _errorWays = new Bag<Way, Way>(); 41 } 42 42 43 44 45 46 47 43 @Override 44 public void endTest() 45 { 46 _errorWays = null; 47 } 48 48 49 50 51 52 53 49 @Override 50 public void visit(Way w) 51 { 52 String errortype = ""; 53 int type; 54 54 55 56 55 if( w.deleted || w.incomplete ) 56 return; 57 57 58 59 60 58 String natural = w.get("natural"); 59 if( natural == null) 60 return; 61 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 62 if( natural.equals("coastline") ) 63 { 64 errortype = tr("Reversed coastline: land not on left side"); 65 type= WRONGLY_ORDERED_COAST; 66 } 67 else if(natural.equals("water") ) 68 { 69 errortype = tr("Reversed water: land not on left side"); 70 type= WRONGLY_ORDERED_WATER; 71 } 72 else if( natural.equals("land") ) 73 { 74 errortype = tr("Reversed land: land not on left side"); 75 type= WRONGLY_ORDERED_LAND; 76 } 77 else 78 return; 79 79 80 80 81 82 83 84 85 86 87 88 81 /** 82 * Test the directionality of the way 83 * 84 * Assuming a closed non-looping way, compute twice the area 85 * of the polygon using the formula 2*a = sum (Xn * Yn+1 - Xn+1 * Yn) 86 * If the area is negative the way is ordered in a clockwise direction 87 * 88 */ 89 89 90 91 92 90 if(w.nodes.get(0) == w.nodes.get(w.nodes.size()-1)) 91 { 92 double area2 = 0; 93 93 94 95 96 97 98 94 for (int node = 1; node < w.nodes.size(); node++) 95 { 96 area2 += (w.nodes.get(node-1).coor.lon() * w.nodes.get(node).coor.lat() 97 - w.nodes.get(node).coor.lon() * w.nodes.get(node-1).coor.lat()); 98 } 99 99 100 101 102 103 104 105 106 107 108 109 100 if(((natural.equals("coastline") || natural.equals("land")) && area2 < 0.) 101 || (natural.equals("water") && area2 > 0.)) 102 { 103 List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>(); 104 primitives.add(w); 105 errors.add( new TestError(this, Severity.WARNING, errortype, type, primitives) ); 106 _errorWays.add(w,w); 107 } 108 } 109 } 110 110 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/util/AgregatePrimitivesVisitor.java
r12777 r12778 12 12 * <p> 13 13 * The primitives are sorted according to their type: first nodes, then ways. 14 * 14 * 15 15 * @author frsantos 16 16 */ 17 17 public class AgregatePrimitivesVisitor implements Visitor 18 18 { 19 20 19 /** Aggregated data */ 20 Collection<OsmPrimitive> aggregatedData; 21 21 22 23 24 25 26 27 28 22 /** 23 * Constructor 24 */ 25 public AgregatePrimitivesVisitor() 26 { 27 aggregatedData = new LinkedList<OsmPrimitive>(); 28 } 29 29 30 /** 31 * Visits a collection of primitives 32 * @param data The collection of primitives 33 * @return The aggregated primitives 34 */ 35 public Collection<OsmPrimitive> visit(Collection<OsmPrimitive> data) 36 { 37 for (OsmPrimitive osm : data) 38 { 39 osm.visit(this); 40 } 41 42 return aggregatedData; 43 } 30 /** 31 * Visits a collection of primitives 32 * @param data The collection of primitives 33 * @return The aggregated primitives 34 */ 35 public Collection<OsmPrimitive> visit(Collection<OsmPrimitive> data) 36 { 37 for (OsmPrimitive osm : data) 38 { 39 osm.visit(this); 40 } 44 41 45 public void visit(Node n) 46 { 47 if(!aggregatedData.contains(n)) 48 aggregatedData.add(n); 49 } 42 return aggregatedData; 43 } 50 44 51 public void visit(Way w) 52 { 53 if(!aggregatedData.contains(w)) 54 { 55 aggregatedData.add(w); 56 for (Node n : w.nodes) 57 visit(n); 58 } 59 } 45 public void visit(Node n) 46 { 47 if(!aggregatedData.contains(n)) 48 aggregatedData.add(n); 49 } 60 50 61 public void visit(Relation r) { 62 if (!aggregatedData.contains(r)) { 63 aggregatedData.add(r); 64 for (RelationMember m : r.members) { 65 m.member.visit(this); 66 } 67 } 68 } 51 public void visit(Way w) 52 { 53 if(!aggregatedData.contains(w)) 54 { 55 aggregatedData.add(w); 56 for (Node n : w.nodes) 57 visit(n); 58 } 59 } 60 61 public void visit(Relation r) { 62 if (!aggregatedData.contains(r)) { 63 aggregatedData.add(r); 64 for (RelationMember m : r.members) { 65 m.member.visit(this); 66 } 67 } 68 } 69 69 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/util/Bag.java
r2453 r12778 6 6 7 7 /** 8 * 8 * 9 9 * A very simple bag to store multiple occurences of a same key. 10 10 * <p> 11 11 * The bag will keep, for each key, a list of values. 12 * 12 * 13 13 * @author frsantos 14 14 * … … 16 16 * @param <V> The value class 17 17 */ 18 public class Bag<K,V> extends HashMap<K, List<V>> 18 public class Bag<K,V> extends HashMap<K, List<V>> 19 19 { 20 20 /** Serializable ID */ … … 22 22 23 23 /** 24 25 26 27 28 29 30 31 24 * Returns the list of elements with the same key 25 * @param key The key to obtain the elements 26 * @return the list of elements with the same key 27 */ 28 public List<V> get(K key) 29 { 30 return super.get(key); 31 } 32 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 33 /** 34 * Adds an element to the bag 35 * @param key The key of the element 36 * @param value The element to add 37 */ 38 public void add(K key, V value) 39 { 40 List<V> values = get(key); 41 if( values == null ) 42 { 43 values = new ArrayList<V>(); 44 put(key, values); 45 } 46 values.add(value); 47 } 48 48 49 50 51 52 53 54 55 49 /** 50 * Constructor 51 */ 52 public Bag() 53 { 54 super(); 55 } 56 56 57 58 59 * 60 61 62 63 64 65 57 /** 58 * Constructor 59 * 60 * @param initialCapacity The initial capacity 61 */ 62 public Bag(int initialCapacity) 63 { 64 super(initialCapacity); 65 } 66 66 67 68 69 70 71 72 73 74 75 76 77 67 /** 68 * Returns true if the bag contains a value for a key 69 * @param key The key 70 * @param value The value 71 * @return true if the key contains the value 72 */ 73 public boolean contains(K key, V value) 74 { 75 List<V> values = get(key); 76 return (values == null) ? false : values.contains(value); 77 } 78 78 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/util/Entities.java
r10532 r12778 6 6 * (the "License"); you may not use this file except in compliance with 7 7 * the License. You may obtain a copy of the License at 8 * 8 * 9 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 10 * 11 11 * Unless required by applicable law or agreed to in writing, software 12 12 * distributed under the License is distributed on an "AS IS" BASIS, -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/util/MultipleNameVisitor.java
r9598 r12778 15 15 /** 16 16 * Able to create a name and an icon for a collection of elements. 17 * 17 * 18 18 * @author frsantos 19 19 */ 20 public class MultipleNameVisitor extends NameVisitor 20 public class MultipleNameVisitor extends NameVisitor 21 21 { 22 /** The class name of the combined primitives */ 23 String multipleClassname; 24 /* name to be displayed */ 25 String displayName; 26 /** Size of the collection */ 27 int size; 28 29 /** 30 * Visits a collection of primitives 31 * @param data The collection of primitives 32 */ 33 public void visit(Collection<? extends OsmPrimitive> data) 34 { 35 String multipleName = null; 36 String multiplePluralClassname = null; 37 String firstName = null; 38 boolean initializedname = false; 39 size = data.size(); 22 /** The class name of the combined primitives */ 23 String multipleClassname; 24 /* name to be displayed */ 25 String displayName; 26 /** Size of the collection */ 27 int size; 40 28 41 multipleClassname = null; 42 for (OsmPrimitive osm : data) 43 { 44 String name = osm.get("name"); 45 if(name == null) name = osm.get("ref"); 46 if(!initializedname) 47 { 48 multipleName = name; initializedname = true; 49 } 50 else if(multipleName != null && (name == null || !name.equals(multipleName))) 51 { 52 multipleName = null; 53 } 29 /** 30 * Visits a collection of primitives 31 * @param data The collection of primitives 32 */ 33 public void visit(Collection<? extends OsmPrimitive> data) 34 { 35 String multipleName = null; 36 String multiplePluralClassname = null; 37 String firstName = null; 38 boolean initializedname = false; 39 size = data.size(); 54 40 55 if(firstName == null && name != null) 56 firstName = name; 57 osm.visit(this); 58 if (multipleClassname == null) 59 { 60 multipleClassname = className; 61 multiplePluralClassname = classNamePlural; 62 } 63 else if (!multipleClassname.equals(className)) 64 { 65 multipleClassname = "object"; 66 multiplePluralClassname = trn("object", "objects", 2); 67 } 68 } 41 multipleClassname = null; 42 for (OsmPrimitive osm : data) 43 { 44 String name = osm.get("name"); 45 if(name == null) name = osm.get("ref"); 46 if(!initializedname) 47 { 48 multipleName = name; initializedname = true; 49 } 50 else if(multipleName != null && (name == null || !name.equals(multipleName))) 51 { 52 multipleName = null; 53 } 69 54 70 if( size == 1 ) 71 displayName = name; 72 else if(multipleName != null) 73 displayName = size + " " + trn(multipleClassname, multiplePluralClassname, size) + ": " + multipleName; 74 else if(firstName != null) 75 displayName = size + " " + trn(multipleClassname, multiplePluralClassname, size) + ": " + tr("{0}, ...", firstName); 76 else 77 displayName = size + " " + trn(multipleClassname, multiplePluralClassname, size); 78 } 55 if(firstName == null && name != null) 56 firstName = name; 57 osm.visit(this); 58 if (multipleClassname == null) 59 { 60 multipleClassname = className; 61 multiplePluralClassname = classNamePlural; 62 } 63 else if (!multipleClassname.equals(className)) 64 { 65 multipleClassname = "object"; 66 multiplePluralClassname = trn("object", "objects", 2); 67 } 68 } 79 69 80 @Override 81 public JLabel toLabel() 82 { 83 return new JLabel(getText(), getIcon(), JLabel.HORIZONTAL); 84 } 70 if( size == 1 ) 71 displayName = name; 72 else if(multipleName != null) 73 displayName = size + " " + trn(multipleClassname, multiplePluralClassname, size) + ": " + multipleName; 74 else if(firstName != null) 75 displayName = size + " " + trn(multipleClassname, multiplePluralClassname, size) + ": " + tr("{0}, ...", firstName); 76 else 77 displayName = size + " " + trn(multipleClassname, multiplePluralClassname, size); 78 } 85 79 86 /** 87 * Gets the name of the items 88 * @return the name of the items 89 */ 90 public String getText() 91 { 92 return displayName; 93 } 80 @Override 81 public JLabel toLabel() 82 { 83 return new JLabel(getText(), getIcon(), JLabel.HORIZONTAL); 84 } 94 85 95 /** 96 * Gets the icon of the items 97 * @return the icon of the items 98 */ 99 public Icon getIcon() 100 { 101 if( size == 1 ) 102 return icon; 103 else 104 return ImageProvider.get("data", multipleClassname); 105 } 86 /** 87 * Gets the name of the items 88 * @return the name of the items 89 */ 90 public String getText() 91 { 92 return displayName; 93 } 94 95 /** 96 * Gets the icon of the items 97 * @return the icon of the items 98 */ 99 public Icon getIcon() 100 { 101 if( size == 1 ) 102 return icon; 103 else 104 return ImageProvider.get("data", multipleClassname); 105 } 106 106 } -
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/util/Util.java
r12257 r12778 22 22 public class Util 23 23 { 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 24 /** 25 * Returns the plugin's directory of the plugin 26 * 27 * @return The directory of the plugin 28 */ 29 public static String getPluginDir() 30 { 31 return Main.pref.getPreferencesDir() + "plugins/validator/"; 32 } 33 34 /** 35 * Returns the version 36 * @return The version of the application 37 */ 38 public static Version getVersion() 39 { 40 PluginInformation info = PluginInformation.getLoaded("validator"); 41 if( info == null ) 42 return null; 43 44 return new Version(info.version, info.attr.get("Plugin-Date")); 45 } 46 47 /** 48 * Utility class for displaying versions 49 * 50 * @author frsantos 51 */ 52 public static class Version 53 { 54 /** The revision */ 55 public String revision; 56 /** The build time */ 57 public String time; 58 59 /** 60 * Constructor 61 * @param revision 62 * @param time 63 */ 64 public Version(String revision, String time) 65 { 66 this.revision = revision; 67 this.time = time; 68 } 69 } 70 71 /** 72 * Returns the start and end cells of a way. 73 * @param w The way 74 * @param cellWays The map with all cells 75 * @return A list with all the cells the way starts or ends 76 */ 77 public static List<List<Way>> getWaysInCell(Way w, Map<Point2D,List<Way>> cellWays) 78 { 79 if (w.nodes.size() == 0) 80 return Collections.emptyList(); 81 82 Node n1 = w.nodes.get(0); 83 Node n2 = w.nodes.get(w.nodes.size() - 1); 84 85 List<List<Way>> cells = new ArrayList<List<Way>>(2); 86 Set<Point2D> cellNodes = new HashSet<Point2D>(); 87 Point2D cell; 88 89 // First, round coordinates 90 long x0 = Math.round(n1.eastNorth.east() * OSMValidatorPlugin.griddetail); 91 long y0 = Math.round(n1.eastNorth.north() * OSMValidatorPlugin.griddetail); 92 long x1 = Math.round(n2.eastNorth.east() * OSMValidatorPlugin.griddetail); 93 long y1 = Math.round(n2.eastNorth.north() * OSMValidatorPlugin.griddetail); 94 95 // Start of the way 96 cell = new Point2D.Double(x0, y0); 97 cellNodes.add(cell); 98 List<Way> ways = cellWays.get( cell ); 99 if( ways == null ) 100 { 101 ways = new ArrayList<Way>(); 102 cellWays.put(cell, ways); 103 } 104 cells.add(ways); 105 106 // End of the way 107 cell = new Point2D.Double(x1, y1); 108 if( !cellNodes.contains(cell) ) 109 { 110 cellNodes.add(cell); 111 ways = cellWays.get( cell ); 112 if( ways == null ) 113 { 114 ways = new ArrayList<Way>(); 115 cellWays.put(cell, ways); 116 } 117 cells.add(ways); 118 } 119 120 // Then floor coordinates, in case the way is in the border of the cell. 121 x0 = (long)Math.floor(n1.eastNorth.east() * OSMValidatorPlugin.griddetail); 122 y0 = (long)Math.floor(n1.eastNorth.north() * OSMValidatorPlugin.griddetail); 123 x1 = (long)Math.floor(n2.eastNorth.east() * OSMValidatorPlugin.griddetail); 124 y1 = (long)Math.floor(n2.eastNorth.north() * OSMValidatorPlugin.griddetail); 125 126 // Start of the way 127 cell = new Point2D.Double(x0, y0); 128 if( !cellNodes.contains(cell) ) 129 { 130 cellNodes.add(cell); 131 ways = cellWays.get( cell ); 132 if( ways == null ) 133 { 134 ways = new ArrayList<Way>(); 135 cellWays.put(cell, ways); 136 } 137 cells.add(ways); 138 } 139 140 // End of the way 141 cell = new Point2D.Double(x1, y1); 142 if( !cellNodes.contains(cell) ) 143 { 144 cellNodes.add(cell); 145 ways = cellWays.get( cell ); 146 if( ways == null ) 147 { 148 ways = new ArrayList<Way>(); 149 cellWays.put(cell, ways); 150 } 151 cells.add(ways); 152 } 153 154 return cells; 155 } 156 157 /** 158 * Returns the coordinates of all cells in a grid that a line between 2 159 * nodes intersects with. 160 * 161 * @param n1 The first node. 162 * @param n2 The second node. 163 * @param gridDetail The detail of the grid. Bigger values give smaller 164 * cells, but a bigger number of them. 165 * @return A list with the coordinates of all cells 166 */ 167 public static List<Point2D> getSegmentCells(Node n1, Node n2, double gridDetail) 168 { 169 List<Point2D> cells = new ArrayList<Point2D>(); 170 double x0 = n1.eastNorth.east() * gridDetail; 171 double x1 = n2.eastNorth.east() * gridDetail; 172 double y0 = n1.eastNorth.north() * gridDetail + 1; 173 double y1 = n2.eastNorth.north() * gridDetail + 1; 174 175 if( x0 > x1 ) 176 { 177 // Move to 1st-4th cuadrants 178 double aux; 179 aux = x0; x0 = x1; x1 = aux; 180 aux = y0; y0 = y1; y1 = aux; 181 } 182 183 double dx = x1 - x0; 184 double dy = y1 - y0; 185 long stepY = y0 <= y1 ? 1 : -1; 186 long gridX0 = (long)Math.floor(x0); 187 long gridX1 = (long)Math.floor(x1); 188 long gridY0 = (long)Math.floor(y0); 189 long gridY1 = (long)Math.floor(y1); 190 191 long maxSteps = (gridX1 - gridX0) + Math.abs(gridY1 - gridY0) + 1; 192 while( (gridX0 <= gridX1 && (gridY0 - gridY1)*stepY <= 0) && maxSteps-- > 0) 193 { 194 cells.add( new Point2D.Double(gridX0, gridY0) ); 195 196 // Is the cross between the segment and next vertical line nearer than the cross with next horizontal line? 197 // Note: segment line formula: y=dy/dx(x-x1)+y1 198 // Note: if dy < 0, must use *bottom* line. If dy > 0, must use upper line 199 double scanY = dy/dx * (gridX0 + 1 - x1) + y1 + (dy < 0 ? -1 : 0); 200 double scanX = dx/dy * (gridY0 + (dy < 0 ? 0 : 1)*stepY - y1) + x1; 201 202 double distX = Math.pow(gridX0 + 1 - x0, 2) + Math.pow(scanY - y0, 2); 203 double distY = Math.pow(scanX - x0, 2) + Math.pow(gridY0 + stepY - y0, 2); 204 205 if( distX < distY) 206 gridX0 += 1; 207 else 208 gridY0 += stepY; 209 } 210 211 return cells; 212 } 213 213 }
Note:
See TracChangeset
for help on using the changeset viewer.