Ticket #17268: clear_ignored_errors_v19.patch

File clear_ignored_errors_v19.patch, 18.2 KB (added by taylor.smock, 5 years ago)

No longer using string concanation with tr, logging, etc., fixes the bug where not all errors were populated in the dialog (I forgot to increment the index), and fixes a possible NPE found by SonarLint (GerdP), and use "Cannot" in error messages.

  • src/org/openstreetmap/josm/data/preferences/sources/ValidatorPrefHelper.java

     
    4444    /** The preferences for ignored severity other */
    4545    public static final BooleanProperty PREF_OTHER = new BooleanProperty(PREFIX + ".other", false);
    4646
     47    /** The preferences key for the ignorelist */
     48    public static final String PREF_IGNORELIST = PREFIX + ".ignorelist";
     49
     50    /** The preferences key for the ignorelist backup */
     51    public static final String PREF_IGNORELIST_BACKUP = PREFIX + ".ignorelist.bak";
     52
     53    /** The preferences key for whether or not the ignorelist backup should be cleared on start */
     54    public static final BooleanProperty PREF_IGNORELIST_KEEP_BACKUP = new BooleanProperty(PREFIX + ".ignorelist.bak.keep", false);
     55
    4756    /**
    4857     * The preferences key for enabling the permanent filtering
    4958     * of the displayed errors in the tree regarding the current selection
     
    5059     */
    5160    public static final String PREF_FILTER_BY_SELECTION = PREFIX + ".selectionFilter";
    5261
    53     /**
    54      * Constructs a new {@code PresetPrefHelper}.
    55      */
    5662    public ValidatorPrefHelper() {
    5763        super(MapCSSTagChecker.ENTRIES_PREF_KEY, SourceType.TAGCHECKER_RULE);
    5864    }
  • src/org/openstreetmap/josm/data/validation/OsmValidator.java

     
    77import java.io.File;
    88import java.io.FileNotFoundException;
    99import java.io.IOException;
    10 import java.io.PrintWriter;
    1110import java.nio.charset.StandardCharsets;
    1211import java.nio.file.Files;
    1312import java.nio.file.Path;
     
    8887    /** Grid detail, multiplier of east,north values for valuable cell sizing */
    8988    private static double griddetail;
    9089
    91     private static final Collection<String> ignoredErrors = new TreeSet<>();
    92 
     90    private static final HashMap<String, String> ignoredErrors = new HashMap<>();
    9391    /**
    9492     * All registered tests
    9593     */
     
    204202    private static void loadIgnoredErrors() {
    205203        ignoredErrors.clear();
    206204        if (ValidatorPrefHelper.PREF_USE_IGNORE.get()) {
     205            Config.getPref().getListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST).forEach(map -> {
     206                ignoredErrors.putAll(map);
     207            });
    207208            Path path = Paths.get(getValidatorDir()).resolve("ignorederrors");
    208209            try {
    209210                if (path.toFile().exists()) {
    210211                    try {
    211                         ignoredErrors.addAll(Files.readAllLines(path, StandardCharsets.UTF_8));
     212                        TreeSet<String> treeSet = new TreeSet<>();
     213                        treeSet.addAll(Files.readAllLines(path, StandardCharsets.UTF_8));
     214                        treeSet.forEach(ignore -> {
     215                            ignoredErrors.putIfAbsent(ignore, "");
     216                        });
     217
     218                        saveIgnoredErrors();
     219                        Files.deleteIfExists(path);
    212220                    } catch (FileNotFoundException e) {
    213221                        Logging.debug(Logging.getErrorMessage(e));
    214222                    } catch (IOException e) {
     
    228236     * @see TestError#getIgnoreSubGroup()
    229237     */
    230238    public static void addIgnoredError(String s) {
    231         ignoredErrors.add(s);
     239        addIgnoredError(s, "");
    232240    }
    233241
    234242    /**
     243     * Adds an ignored error
     244     * @param s The ignore group / sub group name
     245     * @param description What the error actually is
     246     * @see TestError#getIgnoreGroup()
     247     * @see TestError#getIgnoreSubGroup()
     248     */
     249    public static void addIgnoredError(String s, String description) {
     250        ignoredErrors.put(s, description);
     251    }
     252
     253    /**
    235254     * Check if a error should be ignored
    236255     * @param s The ignore group / sub group name
    237256     * @return <code>true</code> to ignore that error
    238257     */
    239258    public static boolean hasIgnoredError(String s) {
    240         return ignoredErrors.contains(s);
     259        return ignoredErrors.containsKey(s);
    241260    }
    242261
    243262    /**
    244      * Saves the names of the ignored errors to a file
     263     * Get the list of all ignored errors
     264     * @return The <code>Collection&ltString&gt</code> of errors that are ignored
    245265     */
     266    public static HashMap<String, String> getIgnoredErrors() {
     267        return ignoredErrors;
     268    }
     269
     270    /**
     271     * Reset the error list by deleting {@code validator.ignorelist}
     272     */
     273    public static void resetErrorList() {
     274        saveIgnoredErrors();
     275        backupErrorList();
     276        Config.getPref().putListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST, null);
     277        OsmValidator.initialize();
     278    }
     279
     280    /**
     281     * Restore the error list by copying {@code validator.ignorelist.bak} to
     282     * {@code validator.ignorelist}
     283     */
     284    public static void restoreErrorList() {
     285        saveIgnoredErrors();
     286        List<Map<String, String>> tlist = Config.getPref().getListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST_BACKUP);
     287        backupErrorList();
     288        Config.getPref().putListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST, tlist);
     289        OsmValidator.initialize();
     290    }
     291
     292    private static void backupErrorList() {
     293        List<Map<String, String>> tlist = Config.getPref().getListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST, null);
     294        Config.getPref().putListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST_BACKUP, tlist);
     295    }
     296
     297    /**
     298     * Saves the names of the ignored errors to a preference
     299     */
    246300    public static void saveIgnoredErrors() {
    247         try (PrintWriter out = new PrintWriter(new File(getValidatorDir(), "ignorederrors"), StandardCharsets.UTF_8.name())) {
    248             for (String e : ignoredErrors) {
    249                 out.println(e);
     301        List<Map<String, String>> list = new ArrayList<>();
     302        list.add(ignoredErrors);
     303        int i = 0;
     304        while (i < list.size()) {
     305            if (list.get(i) == null || list.get(i).isEmpty()) {
     306                list.remove(i);
     307                continue;
    250308            }
    251         } catch (IOException e) {
    252             Logging.error(e);
     309            i++;
    253310        }
     311        if (list.isEmpty()) list = null;
     312        Config.getPref().putListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST, list);
    254313    }
    255314
    256315    /**
  • src/org/openstreetmap/josm/gui/dialogs/ValidatorListManagementDialog.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.dialogs;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.awt.GridBagLayout;
     7import java.awt.event.ActionEvent;
     8import java.util.HashMap;
     9import java.util.List;
     10import java.util.Locale;
     11
     12import javax.swing.ImageIcon;
     13import javax.swing.JOptionPane;
     14import javax.swing.JPanel;
     15import javax.swing.JScrollPane;
     16import javax.swing.JTable;
     17import javax.swing.table.TableModel;
     18
     19import org.openstreetmap.josm.actions.ValidateAction;
     20import org.openstreetmap.josm.data.validation.OsmValidator;
     21import org.openstreetmap.josm.data.validation.TestError;
     22import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
     23import org.openstreetmap.josm.gui.ExtendedDialog;
     24import org.openstreetmap.josm.gui.MainApplication;
     25import org.openstreetmap.josm.gui.MapFrame;
     26import org.openstreetmap.josm.gui.util.GuiHelper;
     27import org.openstreetmap.josm.tools.GBC;
     28import org.openstreetmap.josm.tools.ImageProvider;
     29import org.openstreetmap.josm.tools.Logging;
     30
     31
     32/**
     33 * A management window for the validator's ignorelist
     34 * @author Taylor Smock
     35 * @since xxx
     36 */
     37public class ValidatorListManagementDialog extends ExtendedDialog {
     38    enum BUTTONS {
     39        OK(0, tr("OK"), new ImageProvider("ok")),
     40        CLEAR(1, tr("Clear"), new ImageProvider("dialogs", "fix")),
     41        RESTORE(2, tr("Restore"), new ImageProvider("copy")),
     42        CANCEL(3, tr("Cancel"), new ImageProvider("cancel"));
     43
     44        private int index;
     45        private String name;
     46        private ImageIcon icon;
     47
     48        BUTTONS(int index, String name, ImageProvider image) {
     49            this.index = index;
     50            this.name = name;
     51            this.icon = image.getResource().getImageIcon();
     52        }
     53
     54        public ImageIcon getImageIcon() {
     55            return icon;
     56        }
     57
     58        public int getIndex() {
     59            return index;
     60        }
     61
     62        public String getName() {
     63            return name;
     64        }
     65    }
     66
     67    private static final String[] BUTTON_TEXTS = {BUTTONS.OK.getName(), BUTTONS.CLEAR.getName(),
     68            BUTTONS.RESTORE.getName(), BUTTONS.CANCEL.getName()
     69    };
     70
     71    private static final ImageIcon[] BUTTON_IMAGES = {BUTTONS.OK.getImageIcon(), BUTTONS.CLEAR.getImageIcon(),
     72            BUTTONS.RESTORE.getImageIcon(), BUTTONS.CANCEL.getImageIcon()
     73    };
     74
     75    private final JPanel panel = new JPanel(new GridBagLayout());
     76
     77    private final JTable ignoreErrors;
     78
     79    private final String type;
     80
     81    /**
     82     * Create a new {@link ValidatorListManagementDialog}
     83     * @param type The type of list to create (first letter may or may not be
     84     * capitalized, it is put into all lowercase after building the title)
     85     */
     86    public ValidatorListManagementDialog(String type) {
     87        super(MainApplication.getMainFrame(), tr("Validator {0} List Management", type), BUTTON_TEXTS, false);
     88        this.type = type.toLowerCase(Locale.ENGLISH);
     89        setButtonIcons(BUTTON_IMAGES);
     90
     91        ignoreErrors = buildList();
     92        JScrollPane scroll = GuiHelper.embedInVerticalScrollPane(ignoreErrors);
     93
     94        panel.add(scroll, GBC.eol().fill(GBC.BOTH).anchor(GBC.CENTER));
     95        setContent(panel);
     96        setDefaultButton(1);
     97        setupDialog();
     98        showDialog();
     99    }
     100
     101    @Override
     102    public void buttonAction(int buttonIndex, ActionEvent evt) {
     103        // Currently OK/Cancel buttons do nothing
     104        final int answer;
     105        if (buttonIndex == BUTTONS.RESTORE.getIndex()) {
     106            dispose();
     107            answer = rerunValidatorPrompt();
     108            if (answer == JOptionPane.YES_OPTION || answer == JOptionPane.NO_OPTION) {
     109                OsmValidator.restoreErrorList();
     110            }
     111        } else if (buttonIndex == BUTTONS.CLEAR.getIndex()) {
     112            dispose();
     113            answer = rerunValidatorPrompt();
     114            if (answer == JOptionPane.YES_OPTION || answer == JOptionPane.NO_OPTION) {
     115                OsmValidator.resetErrorList();
     116            }
     117        } else if (buttonIndex == BUTTONS.OK.getIndex()) {
     118            dispose();
     119            answer = rerunValidatorPrompt();
     120            if (answer == JOptionPane.YES_OPTION || answer == JOptionPane.NO_OPTION) {
     121                TableModel model = ignoreErrors.getModel();
     122                if (model.getColumnCount() != 2) {
     123                    Logging.error("We only expect two columns for ignoreErrors.getModel(): actual = {0}",
     124                                  model.getColumnCount());
     125                }
     126                OsmValidator.resetErrorList();
     127                for (int i = 0; i < model.getRowCount(); i++) {
     128                    OsmValidator.addIgnoredError((String) model.getValueAt(i, 0),
     129                            (String) model.getValueAt(i, 1));
     130                }
     131                OsmValidator.saveIgnoredErrors();
     132                OsmValidator.initialize();
     133            }
     134        } else {
     135            super.buttonAction(buttonIndex, evt);
     136        }
     137    }
     138
     139    /**
     140     * Build a JTextArea with a list
     141     * @return &lttype&gtlist as a JTextArea
     142     */
     143    public JTable buildList() {
     144        HashMap<String, String> map;
     145        if ("ignore".equals(type)) {
     146            map = OsmValidator.getIgnoredErrors();
     147            if (map.isEmpty()) {
     148                OsmValidator.initialize();
     149                map = OsmValidator.getIgnoredErrors();
     150            }
     151        } else {
     152            Logging.error(tr("Cannot understand the following type: {0}", type));
     153            return null;
     154        }
     155
     156        String[][] content = new String[map.size()][2];
     157        int i = 0;
     158        for (String key : map.keySet()) {
     159            String value = map.get(key);
     160            content[i][0] = key;
     161            if (value != null && !value.isEmpty()) {
     162                content[i][1] = value;
     163            } else {
     164                content[i][1] = "";
     165            }
     166            i++;
     167            // This is needed, since otherwise there may be a NPE
     168            if (i >= map.size()) break;
     169        }
     170
     171        String[] header = new String[] {tr("Errors"), tr("Description") };
     172        return new JTable(content, header);
     173    }
     174
     175    /**
     176     * Prompt to rerun the validator when the ignore list changes
     177     * @return {@code JOptionPane.YES_OPTION}, {@code JOptionPane.NO_OPTION},
     178     *  or {@code JOptionPane.CANCEL_OPTION}
     179     */
     180    public int rerunValidatorPrompt() {
     181        MapFrame map = MainApplication.getMap();
     182        List<TestError> errors = map.validatorDialog.tree.getErrors();
     183        ValidateAction validateAction = ValidatorDialog.validateAction;
     184        if (!validateAction.isEnabled() || errors == null || errors.isEmpty()) return JOptionPane.NO_OPTION;
     185        final int answer = ConditionalOptionPaneUtil.showOptionDialog(
     186                "rerun_validation_when_ignorelist_changed",
     187                MainApplication.getMainFrame(),
     188                tr("{0}Should the validation be rerun?{1}", "<hmtl><h3>", "</h3></html>"),
     189                tr("Ignored error filter changed"),
     190                JOptionPane.YES_NO_CANCEL_OPTION,
     191                JOptionPane.QUESTION_MESSAGE,
     192                null,
     193                null);
     194        if (answer == JOptionPane.YES_OPTION) {
     195            validateAction.doValidate(true);
     196        }
     197        return answer;
     198    }
     199}
  • src/org/openstreetmap/josm/gui/dialogs/ValidatorDialog.java

     
    6363import org.openstreetmap.josm.tools.ImageProvider;
    6464import org.openstreetmap.josm.tools.InputMapUtils;
    6565import org.openstreetmap.josm.tools.JosmRuntimeException;
     66import org.openstreetmap.josm.tools.Pair;
    6667import org.openstreetmap.josm.tools.Shortcut;
    6768import org.xml.sax.SAXException;
    6869
     
    8586    private final SideButton fixButton;
    8687    /** The ignore button */
    8788    private final SideButton ignoreButton;
     89    /** The reset ignorelist button */
     90    private final SideButton ignorelistManagement;
    8891    /** The select button */
    8992    private final SideButton selectButton;
    9093    /** The lookup button */
     
    174177            });
    175178            ignoreButton.setEnabled(false);
    176179            buttons.add(ignoreButton);
     180
     181            if (!ValidatorPrefHelper.PREF_IGNORELIST_KEEP_BACKUP.get()) {
     182                // Clear the backup ignore list
     183                Config.getPref().putListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST_BACKUP, null);
     184            }
     185            ignorelistManagement = new SideButton(new AbstractAction() {
     186                {
     187                    putValue(NAME, tr("Manage Ignore"));
     188                    putValue(SHORT_DESCRIPTION, tr("Manage the ignore list"));
     189                    new ImageProvider("dialogs", "fix").getResource().attachImageIcon(this, true);
     190                }
     191
     192                @Override
     193                public void actionPerformed(ActionEvent e) {
     194                    ValidatorListManagementDialog dialog = new ValidatorListManagementDialog("Ignore");
     195                    if (dialog.getValue() == 1) {
     196                        // TODO save
     197                    }
     198                }
     199            });
     200            buttons.add(ignorelistManagement);
    177201        } else {
    178202            ignoreButton = null;
     203            ignorelistManagement = null;
    179204        }
     205
    180206        createLayout(tree, true, buttons);
    181207    }
    182208
     
    245271
    246272            Object mainNodeInfo = node.getUserObject();
    247273            if (!(mainNodeInfo instanceof TestError)) {
    248                 Set<String> state = new HashSet<>();
     274                Set<Pair<String, String>> state = new HashSet<>();
    249275                // ask if the whole set should be ignored
    250276                if (asked == JOptionPane.DEFAULT_OPTION) {
    251277                    String[] a = new String[] {tr("Whole group"), tr("Single elements"), tr("Nothing")};
     
    257283                    ValidatorTreePanel.visitTestErrors(node, err -> {
    258284                        err.setIgnored(true);
    259285                        changed.set(true);
    260                         state.add(node.getDepth() == 1 ? err.getIgnoreSubGroup() : err.getIgnoreGroup());
     286                        state.add(new Pair<>(node.getDepth() == 1 ? err.getIgnoreSubGroup() : err.getIgnoreGroup(), err.getMessage()));
    261287                    }, processedNodes);
    262                     for (String s : state) {
    263                         OsmValidator.addIgnoredError(s);
     288                    for (Pair<String, String> s : state) {
     289                        OsmValidator.addIgnoredError(s.a, s.b);
    264290                    }
    265291                    continue;
    266292                } else if (asked == JOptionPane.CANCEL_OPTION || asked == JOptionPane.CLOSED_OPTION) {
     
    271297            ValidatorTreePanel.visitTestErrors(node, error -> {
    272298                String state = error.getIgnoreState();
    273299                if (state != null) {
    274                     OsmValidator.addIgnoredError(state);
     300                    OsmValidator.addIgnoredError(state, error.getMessage());
    275301                }
    276302                changed.set(true);
    277303                error.setIgnored(true);
     
    287313    /**
    288314     * Sets the selection of the map to the current selected items.
    289315     */
    290     @SuppressWarnings("unchecked")
    291316    private void setSelectedItems() {
    292317        DataSet ds = MainApplication.getLayerManager().getActiveDataSet();
    293318        if (tree == null || ds == null)