Ignore:
Timestamp:
2008-07-24T08:57:07+02:00 (16 years ago)
Author:
stoecker
Message:

added first parts of new TagChecker and ignore warnings possibility

Location:
applications/editors/josm/plugins/validator
Files:
1 added
1 deleted
9 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ErrorTreePanel.java

    r4023 r9269  
    160160    }
    161161
    162     /**
    163      * Clears the current error list and adds thiese errors to it
    164      * @param errors The validation errors
    165      */
    166     public void setErrors(List<TestError> errors)
    167     {
    168         this.errors.clear();
    169         this.errors.addAll(errors);
    170         if( isVisible() )
    171                 buildTree();
    172     }
    173 
    174     /**
    175      * Returns the errors of the tree
    176      * @return  the errors of the tree
    177      */
    178     public List<TestError> getErrors()
    179     {
    180         return errors != null ? errors : Collections.<TestError>emptyList();
    181     }
     162        /**
     163         * Clears the current error list and adds these errors to it
     164         * @param errors The validation errors
     165         */
     166        public void setErrors(List<TestError> newerrors)
     167        {
     168                errors.clear();
     169                for(TestError error : newerrors)
     170                {
     171                        if(!error.getIgnored())
     172                                errors.add(error);
     173                }
     174                if( isVisible() )
     175                        buildTree();
     176        }
     177
     178        /**
     179         * Returns the errors of the tree
     180         * @return  the errors of the tree
     181         */
     182        public List<TestError> getErrors()
     183        {
     184                return errors != null ? errors : Collections.<TestError>emptyList();
     185        }
     186
     187        /**
     188         * Updates the current errors list
     189         * @param errors The validation errors
     190         */
     191        public void resetErrors()
     192        {
     193                List<TestError> e = new ArrayList<TestError>(errors);
     194                setErrors(e);
     195        }
    182196
    183197    /**
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/OSMValidatorPlugin.java

    r9111 r9269  
    5050                UntaggedWay.class,
    5151                SelfIntersectingWay.class,
    52                 SpellCheck.class,
    5352                DuplicatedWayNodes.class,
    5453                CrossingWays.class,
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/PreferenceEditor.java

    r6389 r9269  
    3535        public static final String PREF_TESTS = PREFIX + ".tests";
    3636
     37        /** The preferences key for enabled tests */
     38        public static final String PREF_USE_IGNORE = PREFIX + ".ignore";
     39
    3740        /** The preferences key for enabled tests before upload*/
    3841        public static final String PREF_TESTS_BEFORE_UPLOAD = PREFIX + ".testsBeforeUpload";
     42
     43        private JCheckBox prefUseIgnore;
    3944
    4045        /** The list of all tests */
     
    4550        }
    4651
    47     public void addGui(PreferenceDialog gui)
    48     {
     52        public void addGui(PreferenceDialog gui)
     53        {
    4954                JPanel testPanel = new JPanel(new GridBagLayout());
    5055                testPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    51                
    52         testPanel.add( new JLabel(), GBC.std() );
    53         testPanel.add( new JLabel("On upload"), GBC.eop() );
     56
     57                prefUseIgnore = new JCheckBox(tr("Use ignore list."), Main.pref.getBoolean(PREF_USE_IGNORE, true));
     58                prefUseIgnore.setToolTipText(tr("Use the use ignore list to suppress warnings."));
     59                testPanel.add(prefUseIgnore, GBC.eol());
     60
     61                GBC a = GBC.eol().insets(-5,0,0,0);
     62                a.anchor = GBC.EAST;
     63                testPanel.add( new JLabel(tr("On demand")), GBC.std() );
     64                testPanel.add( new JLabel(tr("On upload")), a );
    5465
    5566                allTests = OSMValidatorPlugin.getTests();
    56                 for(Test test: allTests) 
     67                for(Test test: allTests)
    5768                {
    58             test.addGui(testPanel);
     69                        test.addGui(testPanel);
    5970                }
    60                
     71
    6172                JScrollPane testPane = new JScrollPane(testPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    6273                testPane.setBorder(null);
     
    6677                if( ver != null )
    6778                        description += "<br><br>" + tr("Version: {0}<br>Last change at {1}", ver.revision, ver.time);
    68         JPanel tab = gui.createPreferenceTab("validator", tr("Data validator"), description);
     79                JPanel tab = gui.createPreferenceTab("validator", tr("Data validator"), description);
    6980                tab.add(testPane, GBC.eol().fill(GBC.BOTH));
    70                 tab.add(GBC.glue(0,10), GBC.eol());
    71     }
     81                tab.add(GBC.glue(0,10), a);
     82        }
    7283
    73         public void ok() 
     84        public void ok()
    7485        {
    7586                StringBuilder tests = new StringBuilder();
    7687                StringBuilder testsBeforeUpload = new StringBuilder();
    77                
     88
    7889                for (Test test : allTests)
    7990                {
     
    8394                        testsBeforeUpload.append( ',' ).append( name ).append( '=' ).append( test.testBeforeUpload );
    8495                }
    85                
     96
    8697                if (tests.length() > 0 ) tests = tests.deleteCharAt(0);
    8798                if (testsBeforeUpload.length() > 0 ) testsBeforeUpload = testsBeforeUpload.deleteCharAt(0);
    88                
     99
    89100                plugin.initializeTests( allTests );
    90                
     101
    91102                Main.pref.put( PREF_TESTS, tests.toString());
    92103                Main.pref.put( PREF_TESTS_BEFORE_UPLOAD, testsBeforeUpload.toString());
     104                Main.pref.put( PREF_USE_IGNORE, prefUseIgnore.isSelected());
    93105        }
    94106       
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/Severity.java

    r7404 r9269  
    11package org.openstreetmap.josm.plugins.validator;
     2
     3import static org.openstreetmap.josm.tools.I18n.tr;
    24
    35import java.awt.Color;
     
    810public enum Severity {
    911        /** Error messages */
    10         ERROR("Errors", "error.gif",       Preferences.getPreferencesColor("validation error", Color.RED)),
     12        ERROR(tr("Errors"), "error.gif",       Preferences.getPreferencesColor("validation error", Color.RED)),
    1113        /** Warning messages */
    12         WARNING("Warnings", "warning.gif", Preferences.getPreferencesColor("validation warning", Color.YELLOW)),
     14        WARNING(tr("Warnings"), "warning.gif", Preferences.getPreferencesColor("validation warning", Color.YELLOW)),
    1315        /** Other messages */
    14         OTHER("Other", "other.gif",        Preferences.getPreferencesColor("validation other", Color.CYAN));
     16        OTHER(tr("Other"), "other.gif",        Preferences.getPreferencesColor("validation other", Color.CYAN));
    1517       
    1618        /** Description of the severity code */
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/Test.java

    r6388 r9269  
    142142                checkEnabled = new JCheckBox(name, enabled);
    143143                checkEnabled.setToolTipText(description);
    144                 testPanel.add(checkEnabled, GBC.std().insets(20,0,0,0));
    145                
    146         checkBeforeUpload = new JCheckBox();
    147         checkBeforeUpload.setSelected(testBeforeUpload);
    148         testPanel.add(checkBeforeUpload, GBC.eop().insets(20,0,0,0));
     144                testPanel.add(checkEnabled, GBC.std());
     145
     146                GBC a = GBC.eol();
     147                a.anchor = GBC.EAST;
     148                checkBeforeUpload = new JCheckBox();
     149                checkBeforeUpload.setSelected(testBeforeUpload);
     150                testPanel.add(checkBeforeUpload, a);
    149151        }
    150152
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/TestError.java

    r9111 r9269  
    22
    33import java.awt.*;
     4import java.util.Collection;
    45import java.util.Collections;
    56import java.util.List;
     7import java.util.TreeSet;
    68
    79import org.openstreetmap.josm.command.Command;
     
    1618public class TestError
    1719{
     20        /** is this error on the ignore list */
     21        private Boolean ignored = false;
    1822        /** Severity */
    1923        private Severity severity;
     
    2832        /** Internal code used by testers to classify errors */
    2933        private int internalCode = -1;
    30     /** If this error is selected */
    31     private boolean selected;
     34        /** If this error is selected */
     35        private boolean selected;
    3236       
    3337        public TestError(Test tester, Severity severity, String message,
     
    136140         * Sets the ignore state for this error
    137141         */
    138         public void getIgnoreState()
    139         {
    140                 System.out.println("Ignore " + message);
     142        public String getIgnoreState()
     143        {
     144                Collection<String> strings = new TreeSet<String>();
     145                String ignorestring = message;
    141146                for (OsmPrimitive o : primitives)
    142147                {
    143                         System.out.println(o.id + " - " + o.getClass());
    144                 }
    145         }
    146 
    147         /**
    148          * Gets the tester that raised this error
     148                        String type = "u";
     149                        if (o instanceof Way) type = "w";
     150                        else if (o instanceof Relation) type = "r";
     151                        else if (o instanceof Node) type = "n";
     152                        strings.add(type + "_" + o.id);
     153                }
     154                for (String o : strings)
     155                {
     156                        ignorestring += ":" + o;
     157                }
     158                return ignorestring;
     159        }
     160
     161        public void setIgnored(boolean state)
     162        {
     163                ignored = state;
     164        }
     165
     166        public Boolean getIgnored()
     167        {
     168                return ignored;
     169        }
     170
     171        /**
     172         * Gets the tester that raised this error
    149173         * @return the tester that raised this error
    150174         */
    151         public Test getTester() 
     175        public Test getTester()
    152176        {
    153177                return tester;
     
    158182         * @return the internal code
    159183         */
    160         public int getInternalCode() 
     184        public int getInternalCode()
    161185        {
    162186                return internalCode;
    163187        }
    164188
    165        
    166189        /**
    167190         * Sets the internal code
     
    175198        /**
    176199         * Returns true if the error can be fixed automatically
    177          * 
     200         *
    178201         * @return true if the error can be fixed
    179202         */
     
    182205                return tester != null && tester.isFixable(this);
    183206        }
    184        
     207
    185208        /**
    186209         * Fixes the error with the appropiate command
    187          * 
     210         *
    188211         * @return The command to fix the error
    189212         */
     
    192215                if( tester == null )
    193216                        return null;
    194                
     217
    195218                return tester.fixError(this);
    196219        }
    197220
    198     /**
    199      * Paints the error on affected primitives
    200      *
    201      * @param g The graphics
    202      * @param mv The MapView
    203      */
    204     public void paint(Graphics g, MapView mv)
    205     {
    206         PaintVisitor v = new PaintVisitor(g, mv);
    207         for (Object o : highlighted) {
    208                         if (o instanceof OsmPrimitive) {
    209                                 v.visit((OsmPrimitive) o);
    210                         } else if (o instanceof WaySegment) {
    211                                 v.visit((WaySegment) o);
     221        /**
     222         * Paints the error on affected primitives
     223         *
     224         * @param g The graphics
     225         * @param mv The MapView
     226         */
     227        public void paint(Graphics g, MapView mv)
     228        {
     229                if(!ignored)
     230                {
     231                        PaintVisitor v = new PaintVisitor(g, mv);
     232                        for (Object o : highlighted) {
     233                                if (o instanceof OsmPrimitive)
     234                                        v.visit((OsmPrimitive) o);
     235                                else if (o instanceof WaySegment)
     236                                        v.visit((WaySegment) o);
    212237                        }
    213         }
    214     }   
    215    
     238                }
     239        }
     240
    216241    /**
    217242     * Visitor that highlights the primitives affected by this error
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidateAction.java

    r6389 r9269  
    11package org.openstreetmap.josm.plugins.validator;
     2
     3import static org.openstreetmap.josm.tools.I18n.tr;
    24
    35import java.awt.event.ActionEvent;
     
    3537         */
    3638        public ValidateAction(OSMValidatorPlugin plugin) {
    37                 super("Validation", "validator", "Performs the data validation", KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK + KeyEvent.ALT_MASK, true);
     39                super(tr("Validation"), "validator", tr("Performs the data validation"), KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK + KeyEvent.ALT_MASK, true);
    3840                this.plugin = plugin;
    3941        }
     
    8890
    8991                List<TestError> errors = new ArrayList<TestError>();
    90                 for(Test test : tests) 
    91         {
     92                for(Test test : tests)
     93                {
    9294                        test.setPartialSelection(lastSelection != null);
    93                     test.startTest();
    94                     test.visit(selection);
     95                        test.startTest();
     96                        test.visit(selection);
    9597                        test.endTest();
    9698                        errors.addAll( test.getErrors() );
    9799                }
    98100                tests = null;
    99                
     101                if(Main.pref.getBoolean(PreferenceEditor.PREF_USE_IGNORE, true))
     102                {
     103                        for(TestError error : errors)
     104                        {
     105                                if(plugin.validationDialog.ignoredErrors.contains(error.getIgnoreState()))
     106                                {
     107                                        error.setIgnored(true);
     108                                }
     109                        }
     110                }
     111
    100112                plugin.validationDialog.tree.setErrors(errors);
    101         plugin.validationDialog.setVisible(true);
    102         DataSet.fireSelectionChanged(Main.ds.getSelected());
     113                plugin.validationDialog.setVisible(true);
     114                DataSet.fireSelectionChanged(Main.ds.getSelected());
    103115        }
    104116}
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidatorDialog.java

    r9111 r9269  
    66import java.awt.GridLayout;
    77import java.awt.event.*;
     8import java.io.BufferedReader;
     9import java.io.FileNotFoundException;
     10import java.io.FileReader;
     11import java.io.FileWriter;
     12import java.io.IOException;
     13import java.io.PrintWriter;
    814import java.util.*;
    915import java.util.Map.Entry;
     
    4046        protected ErrorTreePanel tree;
    4147
     48        public Collection<String> ignoredErrors = new TreeSet<String>();
     49
    4250        /** The fix button */
    4351        private JButton fixButton;
     
    7684                fixButton.setEnabled(false);
    7785                buttonPanel.add(fixButton);
    78                 ignoreButton = Util.createButton(tr("Ignore"), "ignore", "dialogs/delete", tr("Ignore the selected errors next time."), this);
    79                 ignoreButton.setEnabled(false);
    80                 buttonPanel.add(ignoreButton);
     86                if(Main.pref.getBoolean(PreferenceEditor.PREF_USE_IGNORE, true))
     87                {
     88                        ignoreButton = Util.createButton(tr("Ignore"), "ignore", "dialogs/delete", tr("Ignore the selected errors next time."), this);
     89                        ignoreButton.setEnabled(false);
     90                        buttonPanel.add(ignoreButton);
     91                }
     92                else
     93                {
     94                        ignoreButton = null;
     95                }
    8196                add(buttonPanel, BorderLayout.SOUTH);
    82         }
    83 
    84     @Override
    85     public void setVisible(boolean v)
    86     {
    87         if( tree != null )
    88             tree.setVisible(v);
     97                loadIgnoredErrors();
     98        }
     99
     100        private void loadIgnoredErrors() {
     101                ignoredErrors.clear();
     102                if(Main.pref.getBoolean(PreferenceEditor.PREF_USE_IGNORE, true))
     103                {
     104                        try {
     105                                final BufferedReader in = new BufferedReader(new FileReader(Util.getPluginDir() + "ignorederrors"));
     106                                for (String line = in.readLine(); line != null; line = in.readLine()) {
     107                                        ignoredErrors.add(line);
     108                                }
     109                        }
     110                        catch (final FileNotFoundException e) {}
     111                        catch (final IOException e) {
     112                                e.printStackTrace();
     113                        }
     114                }
     115        }
     116
     117        private void saveIgnoredErrors() {
     118                try {
     119                        final PrintWriter out = new PrintWriter(new FileWriter(Util.getPluginDir() + "ignorederrors"), false);
     120                        for (String e : ignoredErrors)
     121                                out.println(e);
     122                        out.close();
     123                } catch (final IOException e) {
     124                        e.printStackTrace();
     125                }
     126        }
     127
     128        @Override
     129        public void setVisible(boolean v)
     130        {
     131                if( tree != null )
     132                        tree.setVisible(v);
    89133                if( action != null && action.button != null )
    90134                        action.button.setSelected(v);
     
    92136                Main.map.repaint();
    93137        }
    94    
    95    
     138
     139
    96140        /**
    97141         * Fix selected errors
    98          * @param e 
     142         * @param e
    99143         */
    100144        @SuppressWarnings("unchecked")
    101         private void fixErrors(ActionEvent e)
    102         {
    103         TreePath[] selectionPaths = tree.getSelectionPaths();
    104         if( selectionPaths == null )
    105             return;
    106        
    107         Set<DefaultMutableTreeNode> processedNodes = new HashSet<DefaultMutableTreeNode>();
    108         for( TreePath path : selectionPaths )
    109         {
    110             DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
    111                 if( node == null )
    112                         continue;
    113            
    114                 Enumeration<DefaultMutableTreeNode> children = node.breadthFirstEnumeration();
    115                 while( children.hasMoreElements() )
    116                 {
    117                         DefaultMutableTreeNode childNode = children.nextElement();
    118                 if( processedNodes.contains(childNode) )
    119                     continue;
    120                
    121                 processedNodes.add(childNode);
    122                         Object nodeInfo = childNode.getUserObject();
    123                         if( nodeInfo instanceof TestError)
    124                         {
    125                                 TestError error = (TestError)nodeInfo;
    126                                 Command fixCommand = error.getFix();
    127                                 if( fixCommand != null )
    128                                 {
    129                                         Main.main.undoRedo.add(fixCommand);
    130                                 }
    131                         }
    132                 }
    133         }
    134                
    135                 Main.map.repaint();
    136                 DataSet.fireSelectionChanged(Main.ds.getSelected());
    137                        
    138         plugin.validateAction.doValidate(e, false);
    139         }       
    140 
    141         /**
    142          * Set selected errors to ignore state
    143          * @param e
    144          */
    145         @SuppressWarnings("unchecked")
    146         private void ignoreErrors(ActionEvent e)
     145        private void fixErrors(ActionEvent e)
    147146        {
    148147                TreePath[] selectionPaths = tree.getSelectionPaths();
     
    169168                                {
    170169                                        TestError error = (TestError)nodeInfo;
    171                                         String error.getIgnoreState();
    172 /* ignore */
     170                                        Command fixCommand = error.getFix();
     171                                        if( fixCommand != null )
     172                                        {
     173                                                Main.main.undoRedo.add(fixCommand);
     174                                                error.setIgnored(true);
     175                                        }
    173176                                }
    174177                        }
     
    176179
    177180                Main.map.repaint();
     181                tree.resetErrors();
    178182                DataSet.fireSelectionChanged(Main.ds.getSelected());
    179 
    180                 plugin.validateAction.doValidate(e, false);
     183        }
     184
     185        /**
     186         * Set selected errors to ignore state
     187         * @param e
     188         */
     189        @SuppressWarnings("unchecked")
     190        private void ignoreErrors(ActionEvent e)
     191        {
     192                boolean changed = false;
     193                TreePath[] selectionPaths = tree.getSelectionPaths();
     194                if( selectionPaths == null )
     195                        return;
     196
     197                Set<DefaultMutableTreeNode> processedNodes = new HashSet<DefaultMutableTreeNode>();
     198                for( TreePath path : selectionPaths )
     199                {
     200                        DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
     201                        if( node == null )
     202                                continue;
     203
     204                        Enumeration<DefaultMutableTreeNode> children = node.breadthFirstEnumeration();
     205                        while( children.hasMoreElements() )
     206                        {
     207                                DefaultMutableTreeNode childNode = children.nextElement();
     208                                if( processedNodes.contains(childNode) )
     209                                        continue;
     210
     211                                processedNodes.add(childNode);
     212                                Object nodeInfo = childNode.getUserObject();
     213                                if( nodeInfo instanceof TestError)
     214                                {
     215                                        TestError error = (TestError)nodeInfo;
     216                                        String state = error.getIgnoreState();
     217                                        ignoredErrors.add(state);
     218                                        changed = true;
     219                                        error.setIgnored(true);
     220                                }
     221                        }
     222                }
     223                if(changed)
     224                {
     225                        tree.resetErrors();
     226                        saveIgnoredErrors();
     227                        Main.map.repaint();
     228                }
    181229        }
    182230
     
    277325                }
    278326                selectButton.setEnabled(true);
    279                 ignoreButton.setEnabled(true);
     327                if(ignoreButton != null)
     328                        ignoreButton.setEnabled(true);
    280329               
    281330                return hasFixes;
     
    291340                {
    292341                        fixButton.setEnabled(false);
    293                         ignoreButton.setEnabled(false);
     342                        if(ignoreButton != null)
     343                                ignoreButton.setEnabled(false);
    294344                        selectButton.setEnabled(false);
    295345
     
    316366                {
    317367                        fixButton.setEnabled(false);
    318                         ignoreButton.setEnabled(false);
     368                        if(ignoreButton != null)
     369                                ignoreButton.setEnabled(false);
    319370                        selectButton.setEnabled(false);
    320371
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/TagChecker.java

    r9111 r9269  
    33import static org.openstreetmap.josm.tools.I18n.tr;
    44
     5import java.awt.GridBagLayout;
     6import java.awt.event.ActionEvent;
     7import java.awt.event.ActionListener;
     8import java.io.*;
     9import java.net.URL;
    510import java.util.*;
    6 
    7 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    8 import org.openstreetmap.josm.data.osm.Way;
    9 import org.openstreetmap.josm.data.osm.Node;
    10 import org.openstreetmap.josm.plugins.validator.Severity;
    11 import org.openstreetmap.josm.plugins.validator.Test;
    12 import org.openstreetmap.josm.plugins.validator.TestError;
     11import java.util.Map.Entry;
     12
     13import javax.swing.*;
     14
     15import org.openstreetmap.josm.Main;
     16import org.openstreetmap.josm.command.*;
     17import org.openstreetmap.josm.data.osm.*;
     18import org.openstreetmap.josm.gui.tagging.TaggingPreset;
     19import org.openstreetmap.josm.gui.tagging.TaggingPreset.*;
     20import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference;
     21import org.openstreetmap.josm.plugins.validator.*;
    1322import org.openstreetmap.josm.plugins.validator.util.Bag;
     23import org.openstreetmap.josm.plugins.validator.util.Util;
     24import org.openstreetmap.josm.tools.GBC;
     25import org.openstreetmap.josm.tools.XmlObjectParser;
     26import org.xml.sax.SAXException;
    1427
    1528/**
    16  * Check area type ways for errors
     29 * Check for mispelled or wrong properties
    1730 *
    18  * @author stoecker
     31 * @author frsantos
    1932 */
    20 public class TagChecker extends Test  {
    21         /** The already detected errors */
    22         Bag<Way, Way> _errorWays;
     33public class TagChecker extends Test
     34{
     35        /** The default data files */
     36        public static final String DATA_FILE = "http://svn.openstreetmap.org/applications/editors/josm/plugins/validator/tagchecker.cfg";
     37        public static final String SPELL_FILE = "http://svn.openstreetmap.org/applications/utils/planet.osm/java/speller/words.cfg";
     38
     39        /** The spell check key substitutions: the key should be substituted by the value */
     40        protected static Map<String, String> spellCheckKeyData;
     41        /** The spell check preset values */
     42        protected static Bag<String, String> presetsValueData;
     43
     44        /** The preferences prefix */
     45        protected static final String PREFIX = PreferenceEditor.PREFIX + "." + TagChecker.class.getSimpleName();
     46
     47        /** Preference name for checking values */
     48        public static final String PREF_CHECK_VALUES = PREFIX + ".checkValues";
     49        /** Preference name for checking values */
     50        public static final String PREF_CHECK_KEYS = PREFIX + ".checkKeys";
     51        /** Preference name for checking FIXMES */
     52        public static final String PREF_CHECK_FIXMES = PREFIX + ".checkFixmes";
     53        /** Preference name for sources */
     54        public static final String PREF_SOURCES = PREFIX + ".sources";
     55        /** Preference name for sources */
     56        public static final String PREF_USE_DATA_FILE = PREFIX + ".usedatafile";
     57        /** Preference name for sources */
     58        public static final String PREF_USE_SPELL_FILE = PREFIX + ".usespellfile";
     59        /** Preference name for keys upload check */
     60        public static final String PREF_CHECK_KEYS_BEFORE_UPLOAD = PREFIX + ".checkKeysBeforeUpload";
     61        /** Preference name for values upload check */
     62        public static final String PREF_CHECK_VALUES_BEFORE_UPLOAD = PREFIX + ".checkValuesBeforeUpload";
     63        /** Preference name for fixmes upload check */
     64        public static final String PREF_CHECK_FIXMES_BEFORE_UPLOAD = PREFIX + ".checkFixmesBeforeUpload";
     65
     66        /** Whether to check keys */
     67        protected boolean checkKeys = false;
     68        /** Whether to check values */
     69        protected boolean checkValues = false;
     70        /** Whether to check for fixmes in values */
     71        protected boolean checkFixmes = false;
     72
     73        /** Preferences checkbox for keys */
     74        protected JCheckBox prefCheckKeys;
     75        /** Preferences checkbox for values */
     76        protected JCheckBox prefCheckValues;
     77        /** Preferences checkbox for FIXMES */
     78        protected JCheckBox prefCheckFixmes;
     79        /** The preferences checkbox for validation of keys on upload */
     80        protected JCheckBox prefCheckKeysBeforeUpload;
     81        /** The preferences checkbox for validation of values on upload */
     82        protected JCheckBox prefCheckValuesBeforeUpload;
     83        /** The preferences checkbox for validation of fixmes on upload */
     84        protected JCheckBox prefCheckFixmesBeforeUpload;
     85        /** The add button */
     86        protected JButton addSrcButton;
     87        /** The edit button */
     88        protected JButton editSrcButton;
     89        /** The delete button */
     90        protected JButton deleteSrcButton;
     91
     92        /** Empty values error */
     93        protected static int EMPTY_VALUES = 0;
     94        /** Invalid key error */
     95        protected static int INVALID_KEY = 1;
     96        /** Invalid value error */
     97        protected static int INVALID_VALUE = 2;
     98        /** fixme error */
     99        protected static int FIXME = 3;
     100       
     101        /** List of sources for spellcheck data */
     102        protected JList Sources;
     103
     104        /** Whether this test must check the keys before upload. Used by peferences */
     105        protected boolean testKeysBeforeUpload;
     106        /** Whether this test must check the values before upload. Used by peferences */
     107        protected boolean testValuesBeforeUpload;
     108        /** Whether this test must check form fixmes in values before upload. Used by peferences */
     109        protected boolean testFixmesBeforeUpload;
    23110
    24111        /**
     
    27114        public TagChecker()
    28115        {
    29                 super(tr("Tag Checker."),
    30                           tr("This tests if major tags are used as expected."));
     116                super(tr("Properties checker :"),
     117                          tr("This plugin checks for errors in property keys and values."));
     118        }
     119
     120        public static void initialize(OSMValidatorPlugin plugin) throws Exception
     121        {
     122                initializeData();
     123                initializePresets();
     124        }
     125
     126        /**
     127         * Reads the spellcheck file into a HashMap.
     128         * <p>
     129         * The data file is a list of words, beginning with +/-. If it starts with +,
     130         * the word is valid, but if it starts with -, the word should be replaced
     131         * by the nearest + word before this.
     132         *
     133         * @throws FileNotFoundException
     134         * @throws IOException
     135         */
     136        private static void initializeData() throws FileNotFoundException, IOException
     137        {
     138                spellCheckKeyData = new HashMap<String, String>();
     139                String sources = Main.pref.get( PREF_SOURCES );
     140//              if(Main.pref.getBoolean(PREF_USE_DATA_FILE))
     141//              {
     142//                      if( sources == null || sources.length() == 0)
     143//                              sources = DATA_FILE;
     144//                      else
     145//                              sources = DATA_FILE + ";" + sources;
     146//              }
     147                if(Main.pref.getBoolean(PREF_USE_SPELL_FILE))
     148                {
     149                        if( sources == null || sources.length() == 0)
     150                                sources = SPELL_FILE;
     151                        else
     152                                sources = SPELL_FILE + ";" + sources;
     153                }
     154               
     155                StringTokenizer st = new StringTokenizer(sources, ";");
     156                StringBuilder errorSources = new StringBuilder();
     157                while (st.hasMoreTokens())
     158                {
     159                        String source = st.nextToken();
     160                        File sourceFile = Util.mirror(new URL(source), Util.getPluginDir(), -1);
     161                        if( sourceFile == null || !sourceFile.exists() )
     162                        {
     163                                errorSources.append(source).append("\n");
     164                                continue;
     165                        }
     166
     167                        BufferedReader reader = new BufferedReader(new FileReader(sourceFile));
     168
     169                        String okValue = null;
     170                        do
     171                        {
     172                                String line = reader.readLine();
     173                                if( line == null || line.length() == 0 )
     174                                        break;
     175                                if( line.startsWith("#") )
     176                                        continue;
     177       
     178                                if( line.charAt(0) == '+' )
     179                                {
     180                                        okValue = line.substring(1);
     181                                }
     182                                else if( line.charAt(0) == '-' && okValue != null )
     183                                {
     184                                        spellCheckKeyData.put(line.substring(1), okValue);
     185                                }
     186                                else
     187                                {
     188                                        System.err.println("Invalid spellcheck line:" + line);
     189                                }
     190                        }
     191                        while( true );
     192                }
     193
     194                if( errorSources.length() > 0 )
     195                        throw new IOException( tr("Could not download data file(s):\n{0}", errorSources) );
     196        }
     197       
     198        /**
     199         * Reads the presets data.
     200         *
     201         * @throws Exception
     202         */
     203        public static void initializePresets() throws Exception
     204        {
     205                if( !Main.pref.getBoolean(PREF_CHECK_VALUES) )
     206                        return;
     207
     208                Collection<TaggingPreset> presets = TaggingPresetPreference.taggingPresets;
     209                if( presets == null || presets.isEmpty() )
     210                {
     211                        // Skip re-reading presets if there are none available
     212                        return;
     213                }
     214
     215                presetsValueData = new Bag<String, String>();
     216                readPresetFromPreferences();
     217        }
     218       
     219       
     220        @Override
     221        public void visit(Node n)
     222        {
     223                checkPrimitive(n);
     224        }
     225
     226
     227        @Override
     228        public void visit(Way w)
     229        {
     230                checkPrimitive(w);
     231        }
     232
     233        /**
     234         * Checks the primitive properties
     235         * @param p The primitive to check
     236         */
     237        private void checkPrimitive(OsmPrimitive p)
     238        {
     239                // Just a collection to know if a primitive has been already marked with error
     240                Bag<OsmPrimitive, String> withErrors = new Bag<OsmPrimitive, String>();
     241
     242                Map<String, String> props = (p.keys == null) ? Collections.<String, String>emptyMap() : p.keys;
     243                for(Entry<String, String> prop: props.entrySet() )
     244                {
     245                        String key = prop.getKey();
     246                        String value = prop.getValue();
     247                        if( checkValues && (value==null || value.trim().length() == 0) && !withErrors.contains(p, "EV"))
     248                        {
     249                                errors.add( new TestError(this, Severity.WARNING, tr("Tags with empty values"), p, EMPTY_VALUES) );
     250                                withErrors.add(p, "EV");
     251                        }
     252                        if( checkKeys && spellCheckKeyData.containsKey(key) && !withErrors.contains(p, "IPK"))
     253                        {
     254                                errors.add( new TestError(this, Severity.WARNING, tr("Invalid property key ''{0}''", key), p, INVALID_KEY) );
     255                                withErrors.add(p, "IPK");
     256                        }
     257                        if( checkKeys && key.indexOf(" ") >= 0 && !withErrors.contains(p, "IPK"))
     258                        {
     259                                errors.add( new TestError(this, Severity.WARNING, tr("Invalid white space in property key ''{0}''", key), p, INVALID_KEY) );
     260                                withErrors.add(p, "IPK");
     261                        }
     262                        if( checkValues && value != null && (value.startsWith(" ") || value.endsWith(" ")) && !withErrors.contains(p, "SPACE"))
     263                        {
     264                                errors.add( new TestError(this, Severity.OTHER, tr("Property values start or end with white space"), p, INVALID_VALUE) );
     265                                withErrors.add(p, "SPACE");
     266                        }
     267                        if( checkValues && value != null && value.length() > 0 && presetsValueData != null)
     268                        {
     269                                List<String> values = presetsValueData.get(key);
     270                                if( values != null && !values.contains(prop.getValue()) && !withErrors.contains(p, "UPV"))
     271                                {
     272                                        errors.add( new TestError(this, Severity.OTHER, tr("Unknown property values"), p, INVALID_VALUE) );
     273                                        withErrors.add(p, "UPV");
     274                                }
     275                        }
     276                        if( checkFixmes && value != null && value.length() > 0 )
     277                        {
     278                                if( (value.contains("FIXME") || value.contains("check and delete") || key.contains("todo") || key.contains("fixme"))
     279                                && !withErrors.contains(p, "FIXME"))
     280                                {
     281                                        errors.add( new TestError(this, Severity.OTHER, tr("FIXMES"), p, FIXME) );
     282                                        withErrors.add(p, "FIXME");
     283                                }
     284                        }
     285                }
     286        }
     287
     288        /**
     289         * Parse an anotation preset from a stream
     290         *
     291         * @param inStream The stream of the anotstion preset
     292         * @throws SAXException
     293         */
     294        public static void readPresets(InputStream inStream) throws SAXException
     295        {
     296                BufferedReader in = null;
     297                try
     298                {
     299                        in = new BufferedReader(new InputStreamReader(inStream, "UTF-8"));
     300                }
     301                catch (UnsupportedEncodingException e)
     302                {
     303                        e.printStackTrace();
     304                        in = new BufferedReader(new InputStreamReader(inStream));
     305                }
     306               
     307                XmlObjectParser parser = new XmlObjectParser();
     308                parser.mapOnStart("item", TaggingPreset.class);
     309                parser.map("text", Text.class);
     310                parser.map("check", Check.class);
     311                parser.map("combo", Combo.class);
     312                parser.map("label", Label.class);
     313                parser.map("key", Key.class);
     314                parser.start(in);
     315               
     316                while(parser.hasNext())
     317                {
     318                        Object obj = parser.next();
     319                        if (obj instanceof Combo) {
     320                                Combo combo = (Combo)obj;
     321                                for(String value : combo.values.split(",") )
     322                                        presetsValueData.add(combo.key, value);
     323                        }
     324                }
     325        }
     326
     327        /**
     328         * Reads the tagging presets
     329         */
     330        public static void readPresetFromPreferences()
     331        {
     332                String allAnnotations = Main.pref.get("taggingpreset.sources");
     333                StringTokenizer st = new StringTokenizer(allAnnotations, ";");
     334                while (st.hasMoreTokens())
     335                {
     336                        InputStream in = null;
     337                        String source = st.nextToken();
     338                        try
     339                        {
     340                                if (source.startsWith("http") || source.startsWith("ftp") || source.startsWith("file"))
     341                                        in = new URL(source).openStream();
     342                                else if (source.startsWith("resource://"))
     343                                        in = Main.class.getResourceAsStream(source.substring("resource:/".length()));
     344                                else
     345                                        in = new FileInputStream(source);
     346                                readPresets(in);
     347                                in.close();
     348                        }
     349                        catch (IOException e)
     350                        {
     351                                // Error already reported by JOSM
     352                        }
     353                        catch (SAXException e)
     354                        {
     355                                // Error already reported by JOSM
     356                        }
     357                }
    31358        }
    32359
     
    34361        public void startTest()
    35362        {
    36                 _errorWays = new Bag<Way, Way>();
    37         }
    38 
    39         @Override
    40         public void endTest()
    41         {
    42                 _errorWays = null;
     363                checkKeys = Main.pref.getBoolean(PREF_CHECK_KEYS);
     364                if( isBeforeUpload )
     365                        checkKeys = checkKeys && Main.pref.getBoolean(PREF_CHECK_KEYS_BEFORE_UPLOAD, true);
     366
     367                checkValues = Main.pref.getBoolean(PREF_CHECK_VALUES);
     368                if( isBeforeUpload )
     369                        checkValues = checkValues && Main.pref.getBoolean(PREF_CHECK_VALUES_BEFORE_UPLOAD, true);
     370
     371                checkFixmes = Main.pref.getBoolean(PREF_CHECK_FIXMES);
     372                if( isBeforeUpload )
     373                        checkFixmes = checkFixmes && Main.pref.getBoolean(PREF_CHECK_FIXMES_BEFORE_UPLOAD, true);
     374        }
     375
     376        @Override
     377        public void visit(Collection<OsmPrimitive> selection)
     378        {
     379                if( checkKeys || checkValues)
     380                        super.visit(selection);
    43381        }
    44382       
    45383        @Override
    46         public void visit(Node n)
    47         {
    48 /* ... */
    49         }
    50 
    51         @Override
    52         public void visit(Way w)
    53         {
    54 /* ... */
     384        public void addGui(JPanel testPanel)
     385        {
     386                GBC a = GBC.eol();
     387                a.anchor = GBC.EAST;
     388
     389                testPanel.add( new JLabel(name), GBC.eol().insets(3,0,0,0) );
     390               
     391                boolean checkKeys = Main.pref.getBoolean(PREF_CHECK_KEYS, true);
     392                prefCheckKeys = new JCheckBox(tr("Check property keys."), checkKeys);
     393                prefCheckKeys.setToolTipText(tr("Validate that property keys are valid checking against list of words."));
     394                testPanel.add(prefCheckKeys, GBC.std().insets(20,0,0,0));
     395
     396                prefCheckKeysBeforeUpload = new JCheckBox();
     397                prefCheckKeysBeforeUpload.setSelected(Main.pref.getBoolean(PREF_CHECK_KEYS_BEFORE_UPLOAD, true));
     398                testPanel.add(prefCheckKeysBeforeUpload, a);
     399
     400                Sources = new JList(new DefaultListModel());
     401
     402                String sources = Main.pref.get( PREF_SOURCES );
     403                StringTokenizer st = new StringTokenizer(sources, ";");
     404                while (st.hasMoreTokens())
     405                        ((DefaultListModel)Sources.getModel()).addElement(st.nextToken());
     406
     407                addSrcButton = new JButton(tr("Add"));
     408                addSrcButton.addActionListener(new ActionListener(){
     409                        public void actionPerformed(ActionEvent e) {
     410                                String source = JOptionPane.showInputDialog(Main.parent, tr("TagChecker source"));
     411                                if (source != null)
     412                                        ((DefaultListModel)Sources.getModel()).addElement(source);
     413                                Sources.clearSelection();
     414                        }
     415                });
     416
     417                editSrcButton = new JButton(tr("Edit"));
     418                editSrcButton.addActionListener(new ActionListener(){
     419                        public void actionPerformed(ActionEvent e) {
     420                                int row = Sources.getSelectedIndex();
     421                                if(row == -1 && Sources.getModel().getSize() == 1)
     422                                {
     423                                        Sources.setSelectedIndex(0);
     424                                        row = 0;
     425                                }
     426                                if (row == -1)
     427                                {
     428                                        if(Sources.getModel().getSize() == 0)
     429                                        {
     430                                                String source = JOptionPane.showInputDialog(Main.parent, tr("TagChecker source"));
     431                                                if (source != null)
     432                                                        ((DefaultListModel)Sources.getModel()).addElement(source);
     433                                        }
     434                                        else
     435                                        {
     436                                                JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to edit."));
     437                                        }
     438                                }
     439                                else {
     440                                        String source = JOptionPane.showInputDialog(Main.parent, tr("TagChecker source"), Sources.getSelectedValue());
     441                                        if (source != null)
     442                                                ((DefaultListModel)Sources.getModel()).setElementAt(source, row);
     443                                }
     444                                Sources.clearSelection();
     445                        }
     446                });
     447
     448                deleteSrcButton = new JButton(tr("Delete"));
     449                deleteSrcButton.addActionListener(new ActionListener(){
     450                        public void actionPerformed(ActionEvent e) {
     451                                if (Sources.getSelectedIndex() == -1)
     452                                        JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to delete."));
     453                                else {
     454                                        ((DefaultListModel)Sources.getModel()).remove(Sources.getSelectedIndex());
     455                                }
     456                        }
     457                });
     458                Sources.setVisibleRowCount(3);
     459
     460                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."));
     461                addSrcButton.setToolTipText(tr("Add a new source to the list."));
     462                editSrcButton.setToolTipText(tr("Edit the selected source."));
     463                deleteSrcButton.setToolTipText(tr("Delete the selected source from the list."));
     464
     465                testPanel.add(new JLabel(tr("Data sources")), GBC.eol().insets(23,0,0,0));
     466                testPanel.add(new JScrollPane(Sources), GBC.eol().insets(23,0,0,0).fill(GBC.HORIZONTAL));
     467                final JPanel buttonPanel = new JPanel(new GridBagLayout());
     468                testPanel.add(buttonPanel, GBC.eol().fill(GBC.HORIZONTAL));
     469                buttonPanel.add(addSrcButton, GBC.std().insets(0,5,0,0));
     470                buttonPanel.add(editSrcButton, GBC.std().insets(5,5,5,0));
     471                buttonPanel.add(deleteSrcButton, GBC.std().insets(0,5,0,0));
     472
     473                ActionListener disableCheckKeysActionListener = new ActionListener(){
     474                        public void actionPerformed(ActionEvent e) {
     475                                boolean selected = prefCheckKeys.isSelected() || prefCheckKeysBeforeUpload.isSelected();
     476                                Sources.setEnabled( selected );
     477                                addSrcButton.setEnabled(selected);
     478                                editSrcButton.setEnabled(selected);
     479                                deleteSrcButton.setEnabled(selected);
     480                        }
     481                };
     482                prefCheckKeys.addActionListener(disableCheckKeysActionListener);
     483                prefCheckKeysBeforeUpload.addActionListener(disableCheckKeysActionListener);
     484
     485                Sources.setEnabled( checkKeys );
     486                buttonPanel.setEnabled( checkKeys );
     487
     488                boolean checkValues = Main.pref.getBoolean(PREF_CHECK_VALUES, true);
     489                prefCheckValues = new JCheckBox(tr("Check property values."), checkValues);
     490                prefCheckValues.setToolTipText(tr("Validate that property values are valid checking against presets."));
     491                testPanel.add(prefCheckValues, GBC.std().insets(20,0,0,0));
     492
     493                prefCheckValuesBeforeUpload = new JCheckBox();
     494                prefCheckValuesBeforeUpload.setSelected(Main.pref.getBoolean(PREF_CHECK_VALUES_BEFORE_UPLOAD, true));
     495                testPanel.add(prefCheckValuesBeforeUpload, a);
     496
     497                boolean checkFixmes = Main.pref.getBoolean(PREF_CHECK_FIXMES, true);
     498                prefCheckFixmes = new JCheckBox(tr("Check for FIXMES."), checkFixmes);
     499                prefCheckFixmes.setToolTipText(tr("Looks for nodes or ways with FIXME in any property value."));
     500                testPanel.add(prefCheckFixmes, GBC.std().insets(20,0,0,0));
     501
     502                prefCheckFixmesBeforeUpload = new JCheckBox();
     503                prefCheckFixmesBeforeUpload.setSelected(Main.pref.getBoolean(PREF_CHECK_FIXMES_BEFORE_UPLOAD, true));
     504                testPanel.add(prefCheckFixmesBeforeUpload, a);
     505
     506                boolean useDataFile = Main.pref.getBoolean(PREF_USE_DATA_FILE, true);
     507                JCheckBox prefUseDataFile = new JCheckBox(tr("Use default data file."), checkValues);
     508                prefUseDataFile.setToolTipText(tr("Use the default data file (recommended)."));
     509                testPanel.add(prefUseDataFile, GBC.eol().insets(20,0,0,0));
     510
     511                boolean useSpellFile = Main.pref.getBoolean(PREF_USE_DATA_FILE, true);
     512                JCheckBox prefUseSpellFile = new JCheckBox(tr("Use default spellcheck file."), checkValues);
     513                prefUseSpellFile.setToolTipText(tr("Use the default spellcheck file (recommended)."));
     514                testPanel.add(prefUseSpellFile, GBC.eol().insets(20,0,0,0));
     515        }
     516
     517        @Override
     518        public void ok()
     519        {
     520                enabled = prefCheckKeys.isSelected() || prefCheckValues.isSelected() || prefCheckFixmes.isSelected();
     521                testBeforeUpload = prefCheckKeysBeforeUpload.isSelected() || prefCheckValuesBeforeUpload.isSelected() || prefCheckFixmesBeforeUpload.isSelected();
     522
     523                Main.pref.put(PREF_CHECK_VALUES, prefCheckValues.isSelected());
     524                Main.pref.put(PREF_CHECK_KEYS, prefCheckKeys.isSelected());
     525                Main.pref.put(PREF_CHECK_FIXMES, prefCheckFixmes.isSelected());
     526                Main.pref.put(PREF_CHECK_VALUES_BEFORE_UPLOAD, prefCheckValuesBeforeUpload.isSelected());
     527                Main.pref.put(PREF_CHECK_KEYS_BEFORE_UPLOAD, prefCheckKeysBeforeUpload.isSelected());
     528                Main.pref.put(PREF_CHECK_FIXMES_BEFORE_UPLOAD, prefCheckFixmesBeforeUpload.isSelected());
     529                String sources = "";
     530                if( Sources.getModel().getSize() > 0 )
     531                {
     532                        StringBuilder sb = new StringBuilder();
     533                        for (int i = 0; i < Sources.getModel().getSize(); ++i)
     534                                sb.append(";"+Sources.getModel().getElementAt(i));
     535                        sources = sb.substring(1);
     536                }
     537                Main.pref.put(PREF_SOURCES, sources );
     538        }
     539
     540        @Override
     541        public Command fixError(TestError testError)
     542        {
     543                List<Command> commands = new ArrayList<Command>(50);
     544
     545                int i = -1;
     546                List<? extends OsmPrimitive> primitives = testError.getPrimitives();
     547                for(OsmPrimitive p : primitives )
     548                {
     549                        i++;
     550                        Map<String, String> tags = p.keys;
     551                        if( tags == null || tags.size() == 0 )
     552                                continue;
     553
     554                        for(Entry<String, String> prop: tags.entrySet() )
     555                        {
     556                                String key = prop.getKey();
     557                                String value = prop.getValue();
     558                                if( value == null || value.trim().length() == 0 )
     559                                        commands.add( new ChangePropertyCommand(Collections.singleton(primitives.get(i)), key, null) );
     560                                else
     561                                {
     562                                        String replacementKey = spellCheckKeyData.get(key);
     563                                        if( replacementKey != null )
     564                                                commands.add( new ChangePropertyKeyCommand(Collections.singleton(primitives.get(i)), key, replacementKey) );   
     565                                }
     566                        }
     567                }
     568
     569                if( commands.size() == 0 )
     570                        return null;
     571                else if( commands.size() == 1 )
     572                        return commands.get(0);
     573                else
     574                        return new SequenceCommand(tr("Fix properties"), commands);
     575        }
     576
     577        @Override
     578        public boolean isFixable(TestError testError)
     579        {
     580                if( testError.getTester() instanceof TagChecker)
     581                {
     582                        int code = testError.getInternalCode();
     583                        return code == INVALID_KEY || code == EMPTY_VALUES;
     584                }
     585
     586                return false;
    55587        }
    56588}
Note: See TracChangeset for help on using the changeset viewer.