Ticket #17268: clear_ignored_errors_v24.2.patch

File clear_ignored_errors_v24.2.patch, 26.4 KB (added by taylor.smock, 5 years ago)

Fixes for ant pmd checkstyle (I forgot to run it before uploading the patch)

  • 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
  • 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;
     
    1817import java.util.Collections;
    1918import java.util.EnumMap;
    2019import java.util.HashMap;
     20import java.util.Iterator;
    2121import java.util.List;
    2222import java.util.Map;
     23import java.util.Map.Entry;
    2324import java.util.SortedMap;
    2425import java.util.TreeMap;
    2526import java.util.TreeSet;
     
    8889    /** Grid detail, multiplier of east,north values for valuable cell sizing */
    8990    private static double griddetail;
    9091
    91     private static final Collection<String> ignoredErrors = new TreeSet<>();
    92 
     92    private static final SortedMap<String, String> ignoredErrors = new TreeMap<>();
    9393    /**
    9494     * All registered tests
    9595     */
     
    169169    public static void initialize() {
    170170        checkValidatorDir();
    171171        initializeGridDetail();
    172         loadIgnoredErrors(); //FIXME: load only when needed
     172        loadIgnoredErrors();
    173173    }
    174174
    175175    /**
     
    204204    private static void loadIgnoredErrors() {
    205205        ignoredErrors.clear();
    206206        if (ValidatorPrefHelper.PREF_USE_IGNORE.get()) {
     207            Config.getPref().getListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST).forEach(ignoredErrors::putAll);
    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 -> ignoredErrors.putIfAbsent(ignore, ""));
     215
     216                        saveIgnoredErrors();
     217                        Files.deleteIfExists(path);
     218
     219                        cleanupIgnoredErrors();
    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        if (description == null) description = "";
     251
     252        ignoredErrors.put(s, description);
     253        if (s.split(":(r|w|n)_[0-9]+($|:)").length == 1) {
     254            cleanupIgnoredErrors();
     255        }
     256    }
     257
     258    /**
     259     *  make sure that we don't keep single entries for a "group ignore"
     260     */
     261    private static void cleanupIgnoredErrors() {
     262        if (ignoredErrors.size() > 1) {
     263            List<String> toRemove = new ArrayList<>();
     264
     265            Iterator<Entry<String, String>> iter = ignoredErrors.entrySet().iterator();
     266            Entry<String, String> last = iter.next();
     267            while (iter.hasNext()) {
     268                Entry<String, String> entry = iter.next();
     269                if (entry.getKey().startsWith(last.getKey())) {
     270                    toRemove.add(entry.getKey());
     271                } else {
     272                    last = entry;
     273                }
     274            }
     275            toRemove.forEach(ignoredErrors::remove);
     276        }
     277    }
     278
     279    /**
    235280     * Check if a error should be ignored
    236281     * @param s The ignore group / sub group name
    237282     * @return <code>true</code> to ignore that error
    238283     */
    239284    public static boolean hasIgnoredError(String s) {
    240         return ignoredErrors.contains(s);
     285        return ignoredErrors.containsKey(s);
    241286    }
    242287
    243288    /**
    244      * Saves the names of the ignored errors to a file
     289     * Get the list of all ignored errors
     290     * @return The <code>Collection&ltString&gt</code> of errors that are ignored
    245291     */
     292    public static SortedMap<String, String> getIgnoredErrors() {
     293        return ignoredErrors;
     294    }
     295
     296    /**
     297     * Reset the error list by deleting {@code validator.ignorelist}
     298     */
     299    public static void resetErrorList() {
     300        saveIgnoredErrors();
     301        backupErrorList();
     302        Config.getPref().putListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST, null);
     303        OsmValidator.initialize();
     304    }
     305
     306    /**
     307     * Restore the error list by copying {@code validator.ignorelist.bak} to
     308     * {@code validator.ignorelist}
     309     */
     310    public static void restoreErrorList() {
     311        saveIgnoredErrors();
     312        List<Map<String, String>> tlist = Config.getPref().getListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST_BACKUP);
     313        backupErrorList();
     314        Config.getPref().putListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST, tlist);
     315        OsmValidator.initialize();
     316    }
     317
     318    private static void backupErrorList() {
     319        List<Map<String, String>> tlist = Config.getPref().getListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST, null);
     320        Config.getPref().putListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST_BACKUP, tlist);
     321    }
     322
     323    /**
     324     * Saves the names of the ignored errors to a preference
     325     */
    246326    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);
     327        cleanupIgnoredErrors();
     328        List<Map<String, String>> list = new ArrayList<>();
     329        list.add(ignoredErrors);
     330        int i = 0;
     331        while (i < list.size()) {
     332            if (list.get(i) == null || list.get(i).isEmpty()) {
     333                list.remove(i);
     334                continue;
    250335            }
    251         } catch (IOException e) {
    252             Logging.error(e);
     336            i++;
    253337        }
     338        if (list.isEmpty()) list = null;
     339        Config.getPref().putListOfMaps(ValidatorPrefHelper.PREF_IGNORELIST, list);
    254340    }
    255341
    256342    /**
  • 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)
  • 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.Rectangle;
     8import java.awt.event.ActionEvent;
     9import java.awt.event.KeyEvent;
     10import java.awt.event.KeyListener;
     11import java.awt.event.MouseAdapter;
     12import java.awt.event.MouseEvent;
     13import java.util.Enumeration;
     14import java.util.HashMap;
     15import java.util.List;
     16import java.util.Locale;
     17import java.util.Map;
     18import java.util.Map.Entry;
     19import java.util.TreeMap;
     20
     21import javax.swing.AbstractAction;
     22import javax.swing.ImageIcon;
     23import javax.swing.JMenuItem;
     24import javax.swing.JOptionPane;
     25import javax.swing.JPanel;
     26import javax.swing.JPopupMenu;
     27import javax.swing.JScrollPane;
     28import javax.swing.JTree;
     29import javax.swing.tree.DefaultMutableTreeNode;
     30import javax.swing.tree.TreeModel;
     31import javax.swing.tree.TreeNode;
     32import javax.swing.tree.TreePath;
     33
     34import org.openstreetmap.josm.actions.ValidateAction;
     35import org.openstreetmap.josm.data.validation.OsmValidator;
     36import org.openstreetmap.josm.data.validation.TestError;
     37import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
     38import org.openstreetmap.josm.gui.ExtendedDialog;
     39import org.openstreetmap.josm.gui.MainApplication;
     40import org.openstreetmap.josm.gui.MapFrame;
     41import org.openstreetmap.josm.gui.util.GuiHelper;
     42import org.openstreetmap.josm.tools.GBC;
     43import org.openstreetmap.josm.tools.ImageProvider;
     44import org.openstreetmap.josm.tools.Logging;
     45
     46
     47/**
     48 * A management window for the validator's ignorelist
     49 * @author Taylor Smock
     50 * @since xxx
     51 */
     52public class ValidatorListManagementDialog extends ExtendedDialog {
     53    enum BUTTONS {
     54        OK(0, tr("OK"), new ImageProvider("ok")),
     55        CLEAR(1, tr("Clear All"), new ImageProvider("dialogs", "fix")),
     56        RESTORE(2, tr("Restore"), new ImageProvider("copy")),
     57        CANCEL(3, tr("Cancel"), new ImageProvider("cancel"));
     58
     59        private int index;
     60        private String name;
     61        private ImageIcon icon;
     62
     63        BUTTONS(int index, String name, ImageProvider image) {
     64            this.index = index;
     65            this.name = name;
     66            this.icon = image.getResource().getImageIcon();
     67        }
     68
     69        public ImageIcon getImageIcon() {
     70            return icon;
     71        }
     72
     73        public int getIndex() {
     74            return index;
     75        }
     76
     77        public String getName() {
     78            return name;
     79        }
     80    }
     81
     82    private static final String[] BUTTON_TEXTS = {BUTTONS.OK.getName(), BUTTONS.CLEAR.getName(),
     83            BUTTONS.RESTORE.getName(), BUTTONS.CANCEL.getName()
     84    };
     85
     86    private static final ImageIcon[] BUTTON_IMAGES = {BUTTONS.OK.getImageIcon(), BUTTONS.CLEAR.getImageIcon(),
     87            BUTTONS.RESTORE.getImageIcon(), BUTTONS.CANCEL.getImageIcon()
     88    };
     89
     90    private final JPanel panel = new JPanel(new GridBagLayout());
     91
     92    private final JTree ignoreErrors;
     93
     94    private final String type;
     95
     96    /**
     97     * Create a new {@link ValidatorListManagementDialog}
     98     * @param type The type of list to create (first letter may or may not be
     99     * capitalized, it is put into all lowercase after building the title)
     100     */
     101    public ValidatorListManagementDialog(String type) {
     102        super(MainApplication.getMainFrame(), tr("Validator {0} List Management", type), BUTTON_TEXTS, false);
     103        this.type = type.toLowerCase(Locale.ENGLISH);
     104        setButtonIcons(BUTTON_IMAGES);
     105
     106        ignoreErrors = buildList();
     107        JScrollPane scroll = GuiHelper.embedInVerticalScrollPane(ignoreErrors);
     108
     109        panel.add(scroll, GBC.eol().fill(GBC.BOTH).anchor(GBC.CENTER));
     110        setContent(panel);
     111        setDefaultButton(1);
     112        setupDialog();
     113        showDialog();
     114    }
     115
     116    @Override
     117    public void buttonAction(int buttonIndex, ActionEvent evt) {
     118        // Currently OK/Cancel buttons do nothing
     119        final int answer;
     120        if (buttonIndex == BUTTONS.RESTORE.getIndex()) {
     121            dispose();
     122            answer = rerunValidatorPrompt();
     123            if (answer == JOptionPane.YES_OPTION || answer == JOptionPane.NO_OPTION) {
     124                OsmValidator.restoreErrorList();
     125            }
     126        } else if (buttonIndex == BUTTONS.CLEAR.getIndex()) {
     127            dispose();
     128            answer = rerunValidatorPrompt();
     129            if (answer == JOptionPane.YES_OPTION || answer == JOptionPane.NO_OPTION) {
     130                OsmValidator.resetErrorList();
     131            }
     132        } else if (buttonIndex == BUTTONS.OK.getIndex()) {
     133            Map<String, String> errors = OsmValidator.getIgnoredErrors();
     134            Map<String, String> tree = buildIgnore(ignoreErrors);
     135            if (!errors.equals(tree)) {
     136                answer = rerunValidatorPrompt();
     137                if (answer == JOptionPane.YES_OPTION || answer == JOptionPane.NO_OPTION) {
     138                    OsmValidator.resetErrorList();
     139                    Logging.setLogLevel(Logging.LEVEL_DEBUG);
     140                    Logging.debug("Starting to rebuild the error list of size {0}", tree.size());
     141                    tree.forEach((ignore, description) -> {
     142                        Logging.debug("Adding {0} with description {1}", ignore, description);
     143                        OsmValidator.addIgnoredError(ignore, description);
     144                    });
     145                    OsmValidator.saveIgnoredErrors();
     146                    OsmValidator.initialize();
     147                }
     148            }
     149            dispose();
     150        } else {
     151            super.buttonAction(buttonIndex, evt);
     152        }
     153    }
     154
     155    /**
     156     * Build a {@code HashMap} from a tree of ignored errors
     157     * @param tree The JTree of ignored errors
     158     * @return A {@code HashMap} of the ignored errors for comparison
     159     */
     160    public Map<String, String> buildIgnore(JTree tree) {
     161        TreeModel model = tree.getModel();
     162        DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
     163        return buildIgnore(model, root);
     164    }
     165
     166    private static Map<String, String> buildIgnore(TreeModel model, DefaultMutableTreeNode node) {
     167        Logging.setLogLevel(Logging.LEVEL_DEBUG);
     168        HashMap<String, String> rHashMap = new HashMap<>();
     169
     170        String osmids = node.getUserObject().toString();
     171        String description = "";
     172
     173        if (!model.getRoot().equals(node)) description = ((DefaultMutableTreeNode) node.getParent()).getUserObject().toString();
     174        if (!osmids.matches("^[0-9]+_.*")) osmids = "";
     175
     176        for (int i = 0; i < model.getChildCount(node); i++) {
     177            DefaultMutableTreeNode child = (DefaultMutableTreeNode) model.getChild(node, i);
     178            if (model.getChildCount(child) == 0) {
     179                String ignoreName = child.getUserObject().toString();
     180                if (ignoreName.matches("^(r|w|n)_.*")) {
     181                    osmids += ":" + child.getUserObject().toString();
     182                } else if (ignoreName.matches("^[0-9]+_.*")) {
     183                    rHashMap.put(ignoreName, description);
     184                }
     185            } else {
     186                rHashMap.putAll(buildIgnore(model, child));
     187            }
     188        }
     189        if (!osmids.isEmpty() && osmids.indexOf(':') != 0) rHashMap.put(osmids, description);
     190        return rHashMap;
     191    }
     192
     193    private static DefaultMutableTreeNode inTree(DefaultMutableTreeNode root, String name) {
     194        @SuppressWarnings("unchecked")
     195        Enumeration<TreeNode> trunks = root.children();
     196        while (trunks.hasMoreElements()) {
     197            TreeNode ttrunk = trunks.nextElement();
     198            if (ttrunk instanceof DefaultMutableTreeNode) {
     199                DefaultMutableTreeNode trunk = (DefaultMutableTreeNode) ttrunk;
     200                if (name.equals(trunk.getUserObject())) {
     201                    return trunk;
     202                }
     203            }
     204        }
     205        return new DefaultMutableTreeNode(name);
     206    }
     207
     208    /**
     209     * Build a JTree with a list
     210     * @return &lttype&gtlist as a {@code JTree}
     211     */
     212    public JTree buildList() {
     213        TreeMap<String, String> map = new TreeMap<>();
     214        if ("ignore".equals(type)) {
     215            Map<String, String> tmap;
     216            tmap = OsmValidator.getIgnoredErrors();
     217            if (tmap.isEmpty()) {
     218                OsmValidator.initialize();
     219                tmap = OsmValidator.getIgnoredErrors();
     220            }
     221            map.putAll(tmap);
     222        } else {
     223            Logging.error(tr("Cannot understand the following type: {0}", type));
     224            return null;
     225        }
     226        DefaultMutableTreeNode root = new DefaultMutableTreeNode(tr("{0} list", type));
     227
     228        for (Entry<String, String> e: map.entrySet()) {
     229            String key = e.getKey();
     230            String value = e.getValue();
     231            String[] osmobjects = key.split(":(r|w|n)_");
     232            DefaultMutableTreeNode trunk;
     233            DefaultMutableTreeNode branch;
     234
     235            if (value != null && !value.isEmpty()) {
     236                trunk = inTree(root, value);
     237                branch = inTree(trunk, osmobjects[0]);
     238                trunk.add(branch);
     239            } else {
     240                trunk = inTree(root, osmobjects[0]);
     241                branch = trunk;
     242            }
     243            for (int i = 1; i < osmobjects.length; i++) {
     244                String osmid = osmobjects[i];
     245                int index = key.indexOf(osmid);
     246                char type = key.charAt(index - 2);
     247                DefaultMutableTreeNode leaf = new DefaultMutableTreeNode(type + "_" + osmid);
     248                branch.add(leaf);
     249            }
     250            root.add(trunk);
     251        }
     252        JTree tree = new JTree(root);
     253        tree.setRootVisible(false);
     254        tree.setShowsRootHandles(true);
     255        tree.addMouseListener(new MouseAdapter() {
     256            @Override
     257            public void mousePressed(MouseEvent e) {
     258                process(e);
     259            }
     260
     261            @Override
     262            public void mouseReleased(MouseEvent e) {
     263                process(e);
     264            }
     265
     266            private void process(MouseEvent e) {
     267                if (e.isPopupTrigger()) {
     268                    TreePath[] paths = tree.getSelectionPaths();
     269                    if (paths == null) return;
     270                    Rectangle bounds = tree.getUI().getPathBounds(tree, paths[0]);
     271                    if (bounds != null) {
     272                        JPopupMenu menu = new JPopupMenu();
     273                        JMenuItem delete = new JMenuItem(new AbstractAction(tr("Delete")) {
     274                            @Override
     275                            public void actionPerformed(ActionEvent e1) {
     276                                deleteAction(tree, paths);
     277                            }
     278                        });
     279                        menu.add(delete);
     280                        menu.show(e.getComponent(), e.getX(), e.getY());
     281                    }
     282                }
     283            }
     284        });
     285
     286        tree.addKeyListener(new KeyListener() {
     287
     288            @Override
     289            public void keyTyped(KeyEvent e) {
     290                // Do nothing
     291            }
     292
     293            @Override
     294            public void keyPressed(KeyEvent e) {
     295                // Do nothing
     296            }
     297
     298            @Override
     299            public void keyReleased(KeyEvent e) {
     300                TreePath[] paths = tree.getSelectionPaths();
     301                if (e.getKeyCode() == KeyEvent.VK_DELETE && paths != null) {
     302                    deleteAction(tree, paths);
     303                }
     304            }
     305        });
     306        return tree;
     307    }
     308
     309    private void deleteAction(JTree tree, TreePath[] paths) {
     310        for (TreePath path : paths) {
     311            tree.clearSelection();
     312            tree.addSelectionPath(path);
     313            DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
     314            DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
     315            node.removeAllChildren();
     316            while (node.getChildCount() == 0) {
     317                node.removeFromParent();
     318                node = parent;
     319                if (parent.isRoot()) break;
     320                parent = (DefaultMutableTreeNode) node.getParent();
     321            }
     322        }
     323        tree.updateUI();
     324    }
     325
     326
     327    /**
     328     * Prompt to rerun the validator when the ignore list changes
     329     * @return {@code JOptionPane.YES_OPTION}, {@code JOptionPane.NO_OPTION},
     330     *  or {@code JOptionPane.CANCEL_OPTION}
     331     */
     332    public int rerunValidatorPrompt() {
     333        MapFrame map = MainApplication.getMap();
     334        List<TestError> errors = map.validatorDialog.tree.getErrors();
     335        ValidateAction validateAction = ValidatorDialog.validateAction;
     336        if (!validateAction.isEnabled() || errors == null || errors.isEmpty()) return JOptionPane.NO_OPTION;
     337        final int answer = ConditionalOptionPaneUtil.showOptionDialog(
     338                "rerun_validation_when_ignorelist_changed",
     339                MainApplication.getMainFrame(),
     340                tr("{0}Should the validation be rerun?{1}", "<hmtl><h3>", "</h3></html>"),
     341                tr("Ignored error filter changed"),
     342                JOptionPane.YES_NO_CANCEL_OPTION,
     343                JOptionPane.QUESTION_MESSAGE,
     344                null,
     345                null);
     346        if (answer == JOptionPane.YES_OPTION) {
     347            validateAction.doValidate(true);
     348        }
     349        return answer;
     350    }
     351}
  • src/org/openstreetmap/josm/spi/preferences/MapListSetting.java

     
    66import java.util.LinkedHashMap;
    77import java.util.List;
    88import java.util.Map;
     9import java.util.SortedMap;
    910
    1011/**
    1112 * Setting containing a {@link List} of {@link Map}s of {@link String} values.
     
    4041        if (value.contains(null))
    4142            throw new IllegalArgumentException("Error: Null as list element in preference setting");
    4243        for (Map<String, String> map : value) {
    43             if (map.containsKey(null))
     44            if (!(map instanceof SortedMap) && map.containsKey(null))
    4445                throw new IllegalArgumentException("Error: Null as map key in preference setting");
    4546            if (map.containsValue(null))
    4647                throw new IllegalArgumentException("Error: Null as map value in preference setting");