Changeset 12778 in osm for applications/editors/josm/plugins/validator/src/org
- Timestamp:
- 2009-01-01T18:28:53+01:00 (17 years ago)
- Location:
- applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator
- Files:
-
- 26 edited
-
ErrorTreeRenderer.java (modified) (1 diff)
-
GridLayer.java (modified) (4 diffs)
-
PreferenceEditor.java (modified) (1 diff)
-
Severity.java (modified) (3 diffs)
-
Test.java (modified) (4 diffs)
-
TestError.java (modified) (1 diff)
-
ValidateUploadHook.java (modified) (1 diff)
-
tests/ChangePropertyKeyCommand.java (modified) (1 diff)
-
tests/Coastlines.java (modified) (1 diff)
-
tests/CrossingWays.java (modified) (1 diff)
-
tests/DuplicateNode.java (modified) (3 diffs)
-
tests/DuplicatedWayNodes.java (modified) (1 diff)
-
tests/NodesWithSameName.java (modified) (1 diff)
-
tests/OverlappingWays.java (modified) (1 diff)
-
tests/SelfIntersectingWay.java (modified) (1 diff)
-
tests/SimilarNamedWays.java (modified) (1 diff)
-
tests/TagChecker.java (modified) (1 diff)
-
tests/UnconnectedWays.java (modified) (1 diff)
-
tests/UntaggedNode.java (modified) (1 diff)
-
tests/UntaggedWay.java (modified) (1 diff)
-
tests/WronglyOrderedWays.java (modified) (1 diff)
-
util/AgregatePrimitivesVisitor.java (modified) (1 diff)
-
util/Bag.java (modified) (3 diffs)
-
util/Entities.java (modified) (1 diff)
-
util/MultipleNameVisitor.java (modified) (1 diff)
-
util/Util.java (modified) (1 diff)
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 /** Serializable ID */19 private static final long serialVersionUID = 5567632718124640198L;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 * Constructor32 * @param name33 */34 public GridLayer(String name)30 /** 31 * Constructor 32 * @param name 33 */ 34 public GridLayer(String name) 35 35 { 36 super(name);37 }36 super(name); 37 } 38 38 39 /**40 * Return a static icon.41 */42 @Override public Icon getIcon() {43 return ImageProvider.get("layer", "validator");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 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();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 EastNorth origin = mv.getEastNorth(0, 0);60 EastNorth border = mv.getEastNorth(width, height);59 EastNorth origin = mv.getEastNorth(0, 0); 60 EastNorth border = mv.getEastNorth(width, height); 61 61 62 if( border.east() * gridWidth > 50 )63 return;62 if( border.east() * gridWidth > 50 ) 63 return; 64 64 65 65 g.setColor(Color.RED.darker().darker()); 66 HighlightCellVisitor visitor = new HighlightCellVisitor(g, mv, gridWidth);67 for(OsmPrimitive p : Main.ds.getSelected() )68 p.visit(visitor);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 long x1 = (long)Math.floor(border.east() * gridWidth);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 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 }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 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 }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 @Override92 @Override 93 93 public String getToolTipText() 94 94 { 95 return null;96 }95 return null; 96 } 97 97 98 @Override99 public void mergeFrom(Layer from) {}98 @Override 99 public void mergeFrom(Layer from) {} 100 100 101 @Override102 public boolean isMergable(Layer other) {103 return false;104 }101 @Override 102 public boolean isMergable(Layer other) { 103 return false; 104 } 105 105 106 @Override107 public void visitBoundingBox(BoundingXYVisitor v) {}106 @Override 107 public void visitBoundingBox(BoundingXYVisitor v) {} 108 108 109 @Override110 public Object getInfoComponent()109 @Override 110 public Object getInfoComponent() 111 111 { 112 return getToolTipText();113 }112 return getToolTipText(); 113 } 114 114 115 @Override116 public Component[] getMenuEntries()115 @Override 116 public Component[] getMenuEntries() 117 117 { 118 118 return new Component[]{ … … 125 125 } 126 126 127 @Override public void destroy() { }128 129 /**130 * Visitor that highlights all cells the selected primitives go through131 */132 class HighlightCellVisitor implements Visitor133 {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;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 * Constructor145 * @param g the graphics146 * @param mv The MapView147 * @param gridDetail The grid detail148 */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 }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 public void visit(Node n)161 {162 double x = n.eastNorth.east() * gridDetail;163 double y = n.eastNorth.north()* gridDetail + 1;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 drawCell( Math.floor(x), Math.floor(y) );166 }165 drawCell( Math.floor(x), Math.floor(y) ); 166 } 167 167 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 }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 public void visit(Relation r) {}184 185 /**186 * Draws a solid cell at the (x,y) location187 * @param x188 * @param y189 */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 }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 private OSMValidatorPlugin plugin;28 private OSMValidatorPlugin plugin; 29 29 30 /** The preferences prefix */31 public static final String PREFIX = "validator";30 /** The preferences prefix */ 31 public static final String PREFIX = "validator"; 32 32 33 /** The preferences key for debug preferences */34 public static final String PREF_DEBUG = PREFIX + ".debug";33 /** The preferences key for debug preferences */ 34 public static final String PREF_DEBUG = PREFIX + ".debug"; 35 35 36 /** The preferences key for debug preferences */37 public static final String PREF_LAYER = PREFIX + ".layer";36 /** The preferences key for debug preferences */ 37 public static final String PREF_LAYER = PREFIX + ".layer"; 38 38 39 /** The preferences key for enabled tests */40 public static final String PREF_TESTS = PREFIX + ".tests";39 /** The preferences key for enabled tests */ 40 public static final String PREF_TESTS = PREFIX + ".tests"; 41 41 42 /** The preferences key for enabled tests */43 public static final String PREF_USE_IGNORE = PREFIX + ".ignore";42 /** The preferences key for enabled tests */ 43 public static final String PREF_USE_IGNORE = PREFIX + ".ignore"; 44 44 45 /** The preferences key for enabled tests before upload*/46 public static final String PREF_TESTS_BEFORE_UPLOAD = PREFIX + ".testsBeforeUpload";45 /** The preferences key for enabled tests before upload*/ 46 public static final String PREF_TESTS_BEFORE_UPLOAD = PREFIX + ".testsBeforeUpload"; 47 47 48 /**49 * The preferences key for enabling the permanent filtering50 * of the displayed errors in the tree regarding the current selection51 */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 private JCheckBox prefUseIgnore;55 private JCheckBox prefUseLayer;54 private JCheckBox prefUseIgnore; 55 private JCheckBox prefUseLayer; 56 56 57 /** The list of all tests */58 private Collection<Test> allTests;57 /** The list of all tests */ 58 private Collection<Test> allTests; 59 59 60 public PreferenceEditor(OSMValidatorPlugin plugin) {61 this.plugin = plugin;62 }60 public PreferenceEditor(OSMValidatorPlugin plugin) { 61 this.plugin = plugin; 62 } 63 63 64 public void addGui(PreferenceDialog gui)65 {66 JPanel testPanel = new JPanel(new GridBagLayout());67 testPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));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 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());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 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());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 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 );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 allTests = OSMValidatorPlugin.getTests();83 for(Test test: allTests)84 {85 test.addGui(testPanel);86 }82 allTests = OSMValidatorPlugin.getTests(); 83 for(Test test: allTests) 84 { 85 test.addGui(testPanel); 86 } 87 87 88 JScrollPane testPane = new JScrollPane(testPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);89 testPane.setBorder(null);88 JScrollPane testPane = new JScrollPane(testPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 89 testPane.setBorder(null); 90 90 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 }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 public boolean ok()101 {102 StringBuilder tests = new StringBuilder();103 StringBuilder testsBeforeUpload = new StringBuilder();104 Boolean res = false;100 public boolean ok() 101 { 102 StringBuilder tests = new StringBuilder(); 103 StringBuilder testsBeforeUpload = new StringBuilder(); 104 Boolean res = false; 105 105 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 }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 if (tests.length() > 0 ) tests = tests.deleteCharAt(0);116 if (testsBeforeUpload.length() > 0 ) testsBeforeUpload = testsBeforeUpload.deleteCharAt(0);115 if (tests.length() > 0 ) tests = tests.deleteCharAt(0); 116 if (testsBeforeUpload.length() > 0 ) testsBeforeUpload = testsBeforeUpload.deleteCharAt(0); 117 117 118 plugin.initializeTests( allTests );118 plugin.initializeTests( allTests ); 119 119 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 }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 /** 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 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 * Constructor30 * 31 * @param message Description32 * @param icon Associated icon33 * @param color The color of this severity34 */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 this.icon = icon;38 this.icon = icon; 39 39 this.color = color; 40 40 } 41 41 42 @Override43 public String toString()44 {45 return message;46 }42 @Override 43 public String toString() 44 { 45 return message; 46 } 47 47 48 /** 49 * Gets the associated icon50 * @return the associated icon51 */52 public String getIcon()53 {54 return icon;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 /** Name of the test */30 protected String name;31 32 /** Description of the test */33 protected String description;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 /** 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 * Constructor58 * @param name Name of the test59 * @param description Description of the test60 */61 public Test(String name, String description)62 {63 this.name = name;64 this.description = description;65 }66 67 /**68 * Constructor69 * @param name Name of the test70 */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 plugin79 * @throws Exception When cannot initialize the test80 */81 public static void initialize(OSMValidatorPlugin plugin) throws Exception {}82 83 /**84 * Notification of the start of the test. The tester can initialize the85 * structures it may need for this test86 */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 selection94 * @param partialSelection Whether the test is on a partial selection data95 */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 errors104 */105 public List<TestError> getErrors()106 {107 return errors;108 }109 110 /**111 * Notification of the end of the test. The tester may perform additional112 * actions and destroy the used structures113 */114 public void endTest() {}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 if( !p.deleted && !p.incomplete )127 p.visit(this);126 if( !p.deleted && !p.incomplete ) 127 p.visit(this); 128 128 } 129 129 } … … 131 131 public void visit(Node n) {} 132 132 133 public void visit(Way w) {}134 135 public void visit(Relation r) {}136 137 /**138 * Allow the tester to manage its own preferences139 * @param testPanel The panel to add any preferences component140 */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 preferences156 */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 command166 *167 * @param testError168 * @return The command to fix the error169 */170 public Command fixError(TestError testError)171 {172 return null;173 }174 175 /**176 * Returns true if the given error can be fixed automatically177 *178 * @param testError The error to check if can be fixed179 * @return true if the error can be fixed180 */181 public boolean isFixable(TestError testError)182 {183 return false;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 * segments.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 /** Serializable ID */32 private static final long serialVersionUID = -2304521273582574603L;31 /** Serializable ID */ 32 private static final long serialVersionUID = -2304521273582574603L; 33 33 34 private OSMValidatorPlugin plugin;34 private OSMValidatorPlugin plugin; 35 35 36 public ValidateUploadHook(OSMValidatorPlugin plugin)37 {38 this.plugin = plugin;39 }36 public ValidateUploadHook(OSMValidatorPlugin plugin) 37 { 38 this.plugin = plugin; 39 } 40 40 41 /**42 * Validate the modified data before uploading43 */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;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 AgregatePrimitivesVisitor v = new AgregatePrimitivesVisitor();51 v.visit(add);52 Collection<OsmPrimitive> selection = v.visit(update);50 AgregatePrimitivesVisitor v = new AgregatePrimitivesVisitor(); 51 v.visit(add); 52 Collection<OsmPrimitive> selection = v.visit(update); 53 53 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;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 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 }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 * Displays a screen where the actions that would be taken are displayed and95 * give the user the possibility to cancel the upload.96 * @param errors The errors displayed in the screen97 * @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());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 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 }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 * 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 * Constructor39 *40 * @param objects all objects subject to change replacement41 * @param key The key to replace42 * @param newKey the new value of the key43 */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 old52 for (OsmPrimitive osm : objects) {53 if(osm.keys != null)54 {55 osm.modified = true;56 osm.put(newKey, osm.keys.remove(key) );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 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {63 modified.addAll(objects);64 }62 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 63 modified.addAll(objects); 64 } 65 65 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 } else73 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;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 protected static int UNORDERED_COASTLINES = 901;23 protected static int UNORDERED_COASTLINES = 901; 24 24 25 /** All ways, grouped by cells */26 Map<Point2D,List<Way>> _cellWays;27 /** The already detected errors */28 Bag<Way, Way> _errorWays;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 * Constructor32 */33 public Coastlines()34 {35 super(tr("Coastlines."),36 tr("This test checks that coastlines are correct."));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 @Override40 public void startTest()41 {42 _cellWays = new HashMap<Point2D,List<Way>>(1000);43 _errorWays = new Bag<Way, Way>();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 @Override47 public void endTest()48 {49 _cellWays = null;50 _errorWays = null;51 }46 @Override 47 public void endTest() 48 { 49 _cellWays = null; 50 _errorWays = null; 51 } 52 52 53 @Override54 public void visit(Way w)55 {56 if( w.deleted || w.incomplete )57 return;53 @Override 54 public void visit(Way w) 55 { 56 if( w.deleted || w.incomplete ) 57 return; 58 58 59 String natural = w.get("natural");60 if( natural == null || !natural.equals("coastline") )61 return;59 String natural = w.get("natural"); 60 if( natural == null || !natural.equals("coastline") ) 61 return; 62 62 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;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 String natural2 = w.get("natural");72 if( natural2 == null || !natural2.equals("coastline") )73 continue;71 String natural2 = w.get("natural"); 72 if( natural2 == null || !natural2.equals("coastline") ) 73 continue; 74 74 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 }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 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 * Constructor42 */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 @Override51 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 @Override59 public void endTest()60 {61 cellSegments = null;62 errorSegments = null;63 ways_seen = null;64 }65 66 @Override67 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 else120 {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 list132 * of segments already processed133 *134 * @param n1 The first node135 * @param n2 The second node136 * @return A list with all the cells the segment crosses137 */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 information157 * @author frsantos158 */159 private class ExtendedSegment160 {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 * Constructor176 * @param ws The way segment177 * @param layer The layer of the way this segment is in178 * @param railway The railway type of the way this segment is in179 * @param coastline The coastlyne typo of the way the segment is in180 */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 segment193 * @param s2 The other segment194 * @return true if both segements crosses195 */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 }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 protected static int DUPLICATE_NODE = 1;22 protected static int DUPLICATE_NODE = 1; 23 23 24 /** Bag of all nodes */25 Bag<LatLon, OsmPrimitive> nodes;24 /** Bag of all nodes */ 25 Bag<LatLon, OsmPrimitive> nodes; 26 26 27 /**28 * Constructor29 */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 }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 @Override38 public void startTest()39 {40 nodes = new Bag<LatLon, OsmPrimitive>(1000);41 }37 @Override 38 public void startTest() 39 { 40 nodes = new Bag<LatLon, OsmPrimitive>(1000); 41 } 42 42 43 @Override44 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 }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 @Override58 public void visit(Node n)59 {60 if(!n.deleted && !n.incomplete)61 nodes.add(n.coor, n);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 * Merge the nodes into one.66 * Copied from UtilsPlugin.MergePointsAction67 */68 @Override69 public Command fixError(TestError testError)70 {71 Collection<? extends OsmPrimitive> sel = testError.getPrimitives();72 LinkedList<Node> nodes = new LinkedList<Node>();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 // select the target node in the same way as in the core action MergeNodesAction, rev.108482 // 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 @Override98 public boolean isFixable(TestError testError)99 {100 return (testError.getTester() instanceof DuplicateNode);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 protected static int DUPLICATE_WAY_NODE = 501;18 protected static int DUPLICATE_WAY_NODE = 501; 19 19 20 public DuplicatedWayNodes() {21 super(tr("Duplicated way nodes."),22 tr("Checks for ways with identical consecutive nodes."));23 }20 public DuplicatedWayNodes() { 21 super(tr("Duplicated way nodes."), 22 tr("Checks for ways with identical consecutive nodes.")); 23 } 24 24 25 @Override public void visit(Way w) {26 if (w.deleted || w.incomplete) return;25 @Override public void visit(Way w) { 26 if (w.deleted || w.incomplete) return; 27 27 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 }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 @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 node53 } else {54 wnew.nodes.add(n);55 }56 lastN = n;57 }58 if (wnew.nodes.size() < 2) {59 // Empty way, delete60 return DeleteCommand.delete(Collections.singleton(w));61 } else {62 return new ChangeCommand(w, wnew);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 @Override public boolean isFixable(TestError testError) {67 return testError.getTester() instanceof DuplicatedWayNodes;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 protected static int SAME_NAME = 801;16 protected static int SAME_NAME = 801; 17 17 18 private Map<String, List<Node>> namesToNodes;18 private Map<String, List<Node>> namesToNodes; 19 19 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 }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 @Override public void startTest() {26 namesToNodes = new HashMap<String, List<Node>>();27 }25 @Override public void startTest() { 26 namesToNodes = new HashMap<String, List<Node>>(); 27 } 28 28 29 @Override public void visit(Node n) {30 if (n.deleted || n.incomplete) return;29 @Override public void visit(Node n) { 30 if (n.deleted || n.incomplete) return; 31 31 32 String name = n.get("name");33 String sign = n.get("traffic_sign");34 if (name == null || (sign != null && sign.equals("city_limit"))) return;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 List<Node> nodes = namesToNodes.get(name);37 if (nodes == null)38 namesToNodes.put(name, nodes = new ArrayList<Node>());36 List<Node> nodes = namesToNodes.get(name); 37 if (nodes == null) 38 namesToNodes.put(name, nodes = new ArrayList<Node>()); 39 39 40 nodes.add(n);41 }40 nodes.add(n); 41 } 42 42 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 }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 namesToNodes = null;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 /** Bag of all way segments */29 Bag<Pair<Node,Node>, WaySegment> nodePairs;28 /** Bag of all way segments */ 29 Bag<Pair<Node,Node>, WaySegment> nodePairs; 30 30 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;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 /** 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 }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 @Override50 public void startTest()51 {52 nodePairs = new Bag<Pair<Node,Node>, WaySegment>(1000);53 }49 @Override 50 public void startTest() 51 { 52 nodePairs = new Bag<Pair<Node,Node>, WaySegment>(1000); 53 } 54 54 55 @Override56 public void endTest()57 {58 Map<List<Way>, List<WaySegment>> ways_seen = new HashMap<List<Way>, List<WaySegment>>(500);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 for (List<WaySegment> duplicated : nodePairs.values())61 {62 int ways = duplicated.size();60 for (List<WaySegment> duplicated : nodePairs.values()) 61 { 62 int ways = duplicated.size(); 63 63 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;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 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") != null83 || ws.way.get("amenity") != null || ws.way.get("leisure") != null84 || ws.way.get("building") != null)85 {86 area++; ways--;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 prims.add(ws.way);90 current_ways.add(ws.way);91 }92 /* These ways not seen before93 * If two or more of the overlapping ways are94 * highways or railways mark a seperate error95 */96 if ((highlight = ways_seen.get(current_ways)) == null)97 {98 String errortype;99 int type;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 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 else119 {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 else135 {136 errortype = tr("Overlapping ways");137 type = OVERLAPPING_WAY;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 errors.add(new TestError(this, type < OVERLAPPING_HIGHWAY_AREA141 ? 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 }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 @Override155 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 }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 protected static int SELF_INTERSECT = 401;18 protected static int SELF_INTERSECT = 401; 19 19 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 }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 @Override public void visit(Way w) {27 HashSet<Node> nodes = new HashSet<Node>();26 @Override public void visit(Way w) { 27 HashSet<Node> nodes = new HashSet<Node>(); 28 28 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 }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 protected static int SIMILAR_NAMED = 701;24 protected static int SIMILAR_NAMED = 701; 25 25 26 /** All ways, grouped by cells */27 Map<Point2D,List<Way>> cellWays;28 /** The already detected errors */29 Bag<Way, Way> errorWays;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 * Constructor33 */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 }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 @Override41 public void startTest()42 {43 cellWays = new HashMap<Point2D,List<Way>>(1000);44 errorWays = new Bag<Way, Way>();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 @Override48 public void endTest()49 {50 cellWays = null;51 errorWays = null;52 }47 @Override 48 public void endTest() 49 { 50 cellWays = null; 51 errorWays = null; 52 } 53 53 54 @Override55 public void visit(Way w)56 {57 if( w.deleted || w.incomplete )58 return;54 @Override 55 public void visit(Way w) 56 { 57 if( w.deleted || w.incomplete ) 58 return; 59 59 60 String name = w.get("name");61 if( name == null || name.length() < 6 )62 return;60 String name = w.get("name"); 61 if( name == null || name.length() < 6 ) 62 return; 63 63 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;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 String name2 = w2.get("name");73 if( name2 == null || name2.length() < 6 )74 continue;72 String name2 = w2.get("name"); 73 if( name2 == null || name2.length() < 6 ) 74 continue; 75 75 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 }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 * Compute Levenshtein distance92 *93 * @param s First word94 * @param t Second word95 * @return The distance between words96 */97 public int getLevenshteinDistance(String s, String t)98 {99 int d[][]; // matrix100 int n; // length of s101 int m; // length of t102 int i; // iterates through s103 int j; // iterates through t104 char s_i; // ith character of s105 char t_j; // jth character of t106 int cost; // cost90 /** 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 // Step 1108 // Step 1 109 109 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];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 // Step 2117 for (i = 0; i <= n; i++) d[i][0] = i;118 for (j = 0; j <= m; j++) d[0][j] = j;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 // Step 3121 for (i = 1; i <= n; i++)122 {123 s_i = s.charAt(i - 1);120 // Step 3 121 for (i = 1; i <= n; i++) 122 { 123 s_i = s.charAt(i - 1); 124 124 125 // Step 4126 for (j = 1; j <= m; j++)127 {128 t_j = t.charAt(j - 1);125 // Step 4 126 for (j = 1; j <= m; j++) 127 { 128 t_j = t.charAt(j - 1); 129 129 130 // Step 5131 if (s_i == t_j)132 {133 cost = 0;134 }135 else136 {137 cost = 1;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 // Step 6141 d[i][j] = Minimum(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);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 // Step 7146 return d[n][m];147 }145 // Step 7 146 return d[n][m]; 147 } 148 148 149 /**150 * Get minimum of three values151 * @param a First value152 * @param b Second value153 * @param c Third value154 * @return The minimum of the tre values155 */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 }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 /** 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 * Constructor137 */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 Exception145 {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 replaced154 * by the nearest + word before this.155 *156 * @throws FileNotFoundException157 * @throws IOException158 */159 private static void initializeData() throws IOException160 {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 else168 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 else175 sources = SPELL_FILE + ";" + sources;176 }177 178 String errorSources = "";179 if(sources.length() == 0)180 return;181 for(String source: sources.split(";"))182 {183 try184 {185 MirroredInputStream s = new MirroredInputStream(source, Util.getPluginDir(), -1);186 InputStreamReader r;187 try188 {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 else217 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 else229 {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 Exception248 */249 public static void initializePresets() throws Exception250 {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 @Override279 public void visit(Node n)280 {281 checkPrimitive(n);282 }283 284 285 @Override286 public void visit(Relation n)287 {288 checkPrimitive(n);289 }290 291 292 @Override293 public void visit(Way w)294 {295 checkPrimitive(w);296 }297 298 /**299 * Checks the primitive properties300 * @param p The primitive to check301 */302 private void checkPrimitive(OsmPrimitive p)303 {304 // Just a collection to know if a primitive has been already marked with error305 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 already325 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 @Override392 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 @Override416 public void visit(Collection<OsmPrimitive> selection)417 {418 if( checkKeys || checkValues || checkComplex)419 super.visit(selection);420 }421 422 @Override423 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 else483 {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 @Override578 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 @Override610 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 else634 {635 String evalue = entities.unescape(value);636 if(!evalue.equals(value))637 commands.add( new ChangePropertyCommand(Collections.singleton(primitives.get(i)), key, evalue) );638 else639 {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 else656 return new SequenceCommand(tr("Fix properties"), commands);657 }658 659 @Override660 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, PatternSyntaxException693 {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, PatternSyntaxException701 {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 else709 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 else725 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 try746 {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 else782 return tr("Could not find warning level");783 for(String exp: n[2].split(" *&& *"))784 {785 try786 {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 }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 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 way32 Set<Node> endnodes_highway; // nodes at end of way33 Set<Node> middlenodes; // nodes in middle of way34 Set<Node> othernodes; // nodes appearing at least twice35 36 double mindist;37 double minmiddledist;38 /**39 * Constructor40 */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 @Override48 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 @Override60 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 MyWaySegment151 {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 @Override172 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 else207 middlenodes.remove(n);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 protected static int UNTAGGED_NODE = 201;24 protected static int UNTAGGED_NODE = 201; 25 25 26 /** Bag of all nodes */27 Set<Node> emptyNodes;26 /** Bag of all nodes */ 27 Set<Node> emptyNodes; 28 28 29 /**30 * Constructor31 */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 }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 @Override39 public void startTest()40 {41 emptyNodes = new HashSet<Node>(100);42 }38 @Override 39 public void startTest() 40 { 41 emptyNodes = new HashSet<Node>(100); 42 } 43 43 44 @Override45 public void visit(Collection<OsmPrimitive> selection)46 {47 // If there is a partial selection, it may be false positives if a48 // node is selected, but not the container way. So, in this49 // 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 }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 @Override69 public void visit(Node n)70 {71 if(!n.incomplete && !n.deleted && !n.tagged)72 emptyNodes.add(n);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 @Override76 public void visit(Way w)77 {78 for (Node n : w.nodes) {79 emptyNodes.remove(n);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 @Override84 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 }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 @Override94 public Command fixError(TestError testError)95 {96 return DeleteCommand.delete(testError.getPrimitives());97 }93 @Override 94 public Command fixError(TestError testError) 95 { 96 return DeleteCommand.delete(testError.getPrimitives()); 97 } 98 98 99 @Override100 public boolean isFixable(TestError testError)101 {102 return (testError.getTester() instanceof UntaggedNode);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 /** 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;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 /** Ways that must have a name */33 public static final Set<String> NAMED_WAYS = new HashSet<String>();34 static35 {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 }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 * Constructor47 */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 }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 @Override55 public void visit(Way w)56 {57 if (w.deleted || w.incomplete) return;54 @Override 55 public void visit(Way w) 56 { 57 if (w.deleted || w.incomplete) return; 58 58 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 }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 if( !hasName)76 errors.add( new TestError(this, Severity.WARNING, tr("Unnamed ways"), UNNAMED_WAY, w) );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 if(!w.tagged)82 {83 errors.add( new TestError(this, Severity.WARNING, tr("Untagged ways"), UNTAGGED_WAY, w) );84 }81 if(!w.tagged) 82 { 83 errors.add( new TestError(this, Severity.WARNING, tr("Untagged ways"), UNTAGGED_WAY, w) ); 84 } 85 85 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 }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 @Override98 public boolean isFixable(TestError testError)99 {100 if( testError.getTester() instanceof UntaggedWay )101 {102 return testError.getCode() == EMPTY_WAY103 || testError.getCode() == ONE_NODE_WAY;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 return false;107 }106 return false; 107 } 108 108 109 @Override110 public Command fixError(TestError testError)111 {112 return DeleteCommand.delete(testError.getPrimitives());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 protected static int WRONGLY_ORDERED_COAST = 1001;22 protected static int WRONGLY_ORDERED_WATER = 1002;23 protected static int WRONGLY_ORDERED_LAND = 1003;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 /** The already detected errors */26 Bag<Way, Way> _errorWays;25 /** The already detected errors */ 26 Bag<Way, Way> _errorWays; 27 27 28 /**29 * Constructor30 */31 public WronglyOrderedWays()32 {33 super(tr("Wrongly Ordered Ways."),34 tr("This test checks the direction of water, land and coastline ways."));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 @Override38 public void startTest()39 {40 _errorWays = new Bag<Way, Way>();41 }37 @Override 38 public void startTest() 39 { 40 _errorWays = new Bag<Way, Way>(); 41 } 42 42 43 @Override44 public void endTest()45 {46 _errorWays = null;47 }43 @Override 44 public void endTest() 45 { 46 _errorWays = null; 47 } 48 48 49 @Override50 public void visit(Way w)51 {52 String errortype = "";53 int type;49 @Override 50 public void visit(Way w) 51 { 52 String errortype = ""; 53 int type; 54 54 55 if( w.deleted || w.incomplete )56 return;55 if( w.deleted || w.incomplete ) 56 return; 57 57 58 String natural = w.get("natural");59 if( natural == null)60 return;58 String natural = w.get("natural"); 59 if( natural == null) 60 return; 61 61 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 else78 return;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 * Test the directionality of the way83 *84 * Assuming a closed non-looping way, compute twice the area85 * 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 direction87 *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 if(w.nodes.get(0) == w.nodes.get(w.nodes.size()-1))91 {92 double area2 = 0;90 if(w.nodes.get(0) == w.nodes.get(w.nodes.size()-1)) 91 { 92 double area2 = 0; 93 93 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 }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 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 }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 /** Aggregated data */20 Collection<OsmPrimitive> aggregatedData;19 /** Aggregated data */ 20 Collection<OsmPrimitive> aggregatedData; 21 21 22 /**23 * Constructor24 */25 public AgregatePrimitivesVisitor()26 {27 aggregatedData = new LinkedList<OsmPrimitive>();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 * Returns the list of elements with the same key25 * @param key The key to obtain the elements26 * @return the list of elements with the same key27 */28 public List<V> get(K key)29 {30 return super.get(key);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 * Adds an element to the bag35 * @param key The key of the element36 * @param value The element to add37 */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 }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 * Constructor51 */52 public Bag()53 {54 super();55 }49 /** 50 * Constructor 51 */ 52 public Bag() 53 { 54 super(); 55 } 56 56 57 /**58 * Constructor59 * 60 * @param initialCapacity The initial capacity61 */62 public Bag(int initialCapacity)63 {64 super(initialCapacity);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 * Returns true if the bag contains a value for a key69 * @param key The key70 * @param value The value71 * @return true if the key contains the value72 */73 public boolean contains(K key, V value)74 {75 List<V> values = get(key);76 return (values == null) ? false : values.contains(value);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 * Returns the plugin's directory of the plugin26 *27 * @return The directory of the plugin28 */29 public static String getPluginDir()30 {31 return Main.pref.getPreferencesDir() + "plugins/validator/";32 }33 34 /**35 * Returns the version36 * @return The version of the application37 */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 versions49 *50 * @author frsantos51 */52 public static class Version53 {54 /** The revision */55 public String revision;56 /** The build time */57 public String time;58 59 /**60 * Constructor61 * @param revision62 * @param time63 */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 way74 * @param cellWays The map with all cells75 * @return A list with all the cells the way starts or ends76 */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 coordinates90 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 way96 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 way107 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 way127 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 way141 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 2159 * 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 smaller164 * cells, but a bigger number of them.165 * @return A list with the coordinates of all cells166 */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 cuadrants178 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)+y1198 // Note: if dy < 0, must use *bottom* line. If dy > 0, must use upper line199 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 else208 gridY0 += stepY;209 }210 211 return cells;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.
