Ticket #12438: HideItemsFromRecentlyAddedTags.patch

File HideItemsFromRecentlyAddedTags.patch, 17.8 KB (added by kolesar, 10 years ago)
  • new file src/org/openstreetmap/josm/data/preferences/EnumProperty.java

    diff --git a/src/org/openstreetmap/josm/data/preferences/EnumProperty.java b/src/org/openstreetmap/josm/data/preferences/EnumProperty.java
    new file mode 100644
    index 0000000..d72c94c
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.preferences;
     3
     4import org.openstreetmap.josm.Main;
     5
     6/**
     7 * A property containing an {@code Enum} value.
     8 * @author András Kolesár
     9 * @param <T>
     10 */
     11public class EnumProperty<T extends Enum<T>> extends ParametrizedEnumProperty<T> {
     12
     13    protected final String key;
     14
     15    /**
     16     * Constructs a new {@code EnumProperty}.
     17     * @param key The property key
     18     * @param enumClass The {@code Enum} class
     19     * @param defaultValue The default value
     20     */
     21    public EnumProperty(String key, Class<T> enumClass, T defaultValue) {
     22        super(enumClass, defaultValue);
     23        this.key = key;
     24        if (Main.pref != null) {
     25            get();
     26        }
     27    }
     28
     29    @Override
     30    protected String getKey(String... params) {
     31        return key;
     32    }
     33}
  • src/org/openstreetmap/josm/data/preferences/ParametrizedEnumProperty.java

    diff --git a/src/org/openstreetmap/josm/data/preferences/ParametrizedEnumProperty.java b/src/org/openstreetmap/josm/data/preferences/ParametrizedEnumProperty.java
    index 84dc7ba..66726c8 100644
    a b import org.openstreetmap.josm.Main;  
    55
    66public abstract class ParametrizedEnumProperty<T extends Enum<T>> {
    77
    8     private final T defaultValue;
    9     private final Class<T> enumClass;
     8    protected final T defaultValue;
     9    protected final Class<T> enumClass;
    1010
    1111    public ParametrizedEnumProperty(Class<T> enumClass, T defaultValue) {
    1212        this.defaultValue = defaultValue;
    1313        this.enumClass = enumClass;
    14         if (Main.pref != null) {
    15             get();
    16         }
    1714    }
    1815
    1916    protected abstract String getKey(String... params);
    public abstract class ParametrizedEnumProperty<T extends Enum<T>> {  
    2724    }
    2825
    2926    protected T parse(String s) {
    30         return Enum.valueOf(enumClass, s);
     27        try {
     28            return Enum.valueOf(enumClass, s);
     29        } catch (IllegalArgumentException e) {
     30            return defaultValue;
     31        }
    3132    }
    3233}
  • src/org/openstreetmap/josm/gui/dialogs/properties/TagEditHelper.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/properties/TagEditHelper.java b/src/org/openstreetmap/josm/gui/dialogs/properties/TagEditHelper.java
    index 3445763..3d0ab53 100644
    a b import java.util.LinkedHashMap;  
    3838import java.util.LinkedList;
    3939import java.util.List;
    4040import java.util.Map;
     41import java.util.TreeMap;
    4142
    4243import javax.swing.AbstractAction;
    4344import javax.swing.Action;
    4445import javax.swing.Box;
     46import javax.swing.ButtonGroup;
    4547import javax.swing.DefaultListCellRenderer;
    4648import javax.swing.ImageIcon;
    4749import javax.swing.JCheckBoxMenuItem;
    4850import javax.swing.JComponent;
    4951import javax.swing.JLabel;
    5052import javax.swing.JList;
     53import javax.swing.JMenu;
    5154import javax.swing.JOptionPane;
    5255import javax.swing.JPanel;
    5356import javax.swing.JPopupMenu;
     57import javax.swing.JRadioButtonMenuItem;
    5458import javax.swing.JTable;
    5559import javax.swing.KeyStroke;
    5660import javax.swing.ListCellRenderer;
    import org.openstreetmap.josm.command.SequenceCommand;  
    6569import org.openstreetmap.josm.data.osm.OsmPrimitive;
    6670import org.openstreetmap.josm.data.osm.Tag;
    6771import org.openstreetmap.josm.data.preferences.BooleanProperty;
     72import org.openstreetmap.josm.data.preferences.EnumProperty;
    6873import org.openstreetmap.josm.data.preferences.IntegerProperty;
    6974import org.openstreetmap.josm.gui.ExtendedDialog;
    7075import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
    public class TagEditHelper {  
    119124    /** Number of recent tags */
    120125    public static final IntegerProperty PROPERTY_RECENT_TAGS_NUMBER = new IntegerProperty("properties.recently-added-tags",
    121126            DEFAULT_LRU_TAGS_NUMBER);
     127    /**
     128     * What to do with recent tags where keys already exist
     129     */
     130    private enum RecentExisting {
     131        ENABLE,
     132        DISABLE,
     133        HIDE
     134    }
     135    /**
     136     * Preference setting for popup menu item "Recent tags with existing key"
     137     */
     138    public static final EnumProperty<RecentExisting> PROPERTY_RECENT_EXISTING = new EnumProperty<>(
     139        "properties.recently-added-tags-existing-key", RecentExisting.class, RecentExisting.DISABLE);
     140    /**
     141     * What to do after applying tag
     142     */
     143    private enum RefreshRecent {
     144        REFRESH,
     145        STATUS,
     146        NO
     147    }
     148    /**
     149     * Preference setting for popup menu item "Refresh recent tags list after applying tag"
     150     */
     151    public static final EnumProperty<RefreshRecent> PROPERTY_REFRESH_RECENT = new EnumProperty<>(
     152        "properties.refresh-recently-added-tags", RefreshRecent.class, RefreshRecent.STATUS);
    122153
    123154    // LRU cache for recently added tags (http://java-planet.blogspot.com/2005/08/how-to-set-up-simple-lru-cache-using.html)
    124155    private final Map<Tag, Void> recentTags = new LinkedHashMap<Tag, Void>(MAX_LRU_TAGS_NUMBER+1, 1.1f, true) {
    public class TagEditHelper {  
    128159        }
    129160    };
    130161
     162    // Copy of recently added tags, used to cache initial status
     163    private List<Tag> tags;
     164
     165    /**
     166     * Constructs a new {@code TagEditHelper}.
     167     * @param tagTable
     168     * @param propertyData
     169     * @param valueCount
     170     */
    131171    public TagEditHelper(JTable tagTable, DefaultTableModel propertyData, Map<String, Map<String, Integer>> valueCount) {
    132172        this.tagTable = tagTable;
    133173        this.tagData = propertyData;
    134174        this.valueCount = valueCount;
    135175    }
    136176
     177    /**
     178     * Finds the key from given row of tag editor
     179     * @param viewRow index of row
     180     * @return key of tag
     181     */
    137182    public final String getDataKey(int viewRow) {
    138183        return tagData.getValueAt(tagTable.convertRowIndexToModel(viewRow), 0).toString();
    139184    }
    140185
     186    /**
     187     * Finds the values from given row of tag editor
     188     * @param viewRow index of row
     189     * @return map of values and number of occurrences
     190     */
    141191    @SuppressWarnings("unchecked")
    142192    public final Map<String, Integer> getDataValues(int viewRow) {
    143193        return (Map<String, Integer>) tagData.getValueAt(tagTable.convertRowIndexToModel(viewRow), 1);
    public class TagEditHelper {  
    211261        return changedKey;
    212262    }
    213263
     264    /**
     265     * Reset last changed key
     266     */
    214267    public void resetChangedKey() {
    215268        changedKey = null;
    216269    }
    public class TagEditHelper {  
    259312    }
    260313
    261314    /**
     315     * Update cache of recent tags used for displaying tags
     316     */
     317    private void cacheRecentTags() {
     318        tags = new LinkedList<>(recentTags.keySet());
     319    }
     320
     321    /**
    262322     * Warns user about a key being overwritten.
    263323     * @param action The action done by the user. Must state what key is changed
    264324     * @param togglePref  The preference to save the checkbox state to
    public class TagEditHelper {  
    572632    protected class AddTagsDialog extends AbstractTagsDialog {
    573633        private final List<JosmAction> recentTagsActions = new ArrayList<>();
    574634        protected final transient FocusAdapter focus;
     635        private JPanel mainPanel;
    575636        private JPanel recentTagsPanel;
    576637
    577638        // Counter of added commands for possible undo
    public class TagEditHelper {  
    583644            setCancelButton(2);
    584645            configureContextsensitiveHelp("/Dialog/AddValue", true /* show help button */);
    585646
    586             final JPanel mainPanel = new JPanel(new GridBagLayout());
     647            mainPanel = new JPanel(new GridBagLayout());
    587648            keys = new AutoCompletingComboBox();
    588649            values = new AutoCompletingComboBox();
    589650
    public class TagEditHelper {  
    640701                    @Override
    641702                    public void actionPerformed(ActionEvent e) {
    642703                        performTagAdding();
     704                        refreshRecentTags();
    643705                        selectKeysComboBox();
    644706                    }
    645707                });
    646708
    647             suggestRecentlyAddedTags(mainPanel);
     709            cacheRecentTags();
     710            suggestRecentlyAddedTags();
    648711
    649712            mainPanel.add(Box.createVerticalGlue(), GBC.eop().fill());
    650713            setContent(mainPanel, false);
    public class TagEditHelper {  
    655718                @Override
    656719                public void actionPerformed(ActionEvent e) {
    657720                    selectNumberOfTags();
    658                     suggestRecentlyAddedTags(mainPanel);
     721                    suggestRecentlyAddedTags();
    659722                }
    660723            });
     724
     725            popupMenu.add(buildMenuRecentExisting());
     726            popupMenu.add(buildMenuRefreshRecent());
     727
    661728            JCheckBoxMenuItem rememberLastTags = new JCheckBoxMenuItem(
    662729                new AbstractAction(tr("Remember last used tags after a restart")) {
    663730                @Override
    public class TagEditHelper {  
    672739            popupMenu.add(rememberLastTags);
    673740        }
    674741
     742        private JMenu buildMenuRecentExisting() {
     743            JMenu menu = new JMenu(tr("Recent tags with existing key"));
     744            TreeMap<RecentExisting, String> radios = new TreeMap<>();
     745            radios.put(RecentExisting.ENABLE, tr("Enable"));
     746            radios.put(RecentExisting.DISABLE, tr("Disable"));
     747            radios.put(RecentExisting.HIDE, tr("Hide"));
     748            ButtonGroup buttonGroup = new ButtonGroup();
     749            for (final Map.Entry<RecentExisting, String> entry : radios.entrySet()) {
     750                JRadioButtonMenuItem radio = new JRadioButtonMenuItem(new AbstractAction(entry.getValue()) {
     751                    @Override
     752                    public void actionPerformed(ActionEvent e) {
     753                        PROPERTY_RECENT_EXISTING.put(entry.getKey());
     754                        suggestRecentlyAddedTags();
     755                    }
     756                });
     757                buttonGroup.add(radio);
     758                radio.setSelected(PROPERTY_RECENT_EXISTING.get() == entry.getKey());
     759                menu.add(radio);
     760            }
     761            return menu;
     762        }
     763
     764        private JMenu buildMenuRefreshRecent() {
     765            JMenu menu = new JMenu(tr("Refresh recent tags list after applying tag"));
     766            TreeMap<RefreshRecent, String> radios = new TreeMap<>();
     767            radios.put(RefreshRecent.REFRESH, tr("Refresh tag status and list of recently added tags"));
     768            radios.put(RefreshRecent.STATUS, tr("Refresh tag status only"));
     769            radios.put(RefreshRecent.NO, tr("No refresh"));
     770            ButtonGroup buttonGroup = new ButtonGroup();
     771            for (final Map.Entry<RefreshRecent, String> entry : radios.entrySet()) {
     772                JRadioButtonMenuItem radio = new JRadioButtonMenuItem(new AbstractAction(entry.getValue()) {
     773                    @Override
     774                    public void actionPerformed(ActionEvent e) {
     775                        PROPERTY_REFRESH_RECENT.put(entry.getKey());
     776                    }
     777                });
     778                buttonGroup.add(radio);
     779                radio.setSelected(PROPERTY_REFRESH_RECENT.get() == entry.getKey());
     780                menu.add(radio);
     781            }
     782            return menu;
     783        }
     784
    675785        @Override
    676786        public void setContentPane(Container contentPane) {
    677787            final int commandDownMask = GuiHelper.getMenuShortcutKeyMaskEx();
    public class TagEditHelper {  
    712822            }
    713823        }
    714824
    715         protected void suggestRecentlyAddedTags(JPanel mainPanel) {
    716 
     825        protected void suggestRecentlyAddedTags() {
    717826            if (recentTagsPanel == null) {
    718827                recentTagsPanel = new JPanel(new GridBagLayout());
    719                 suggestRecentlyAddedTags();
     828                buildRecentTagsPanel();
    720829                mainPanel.add(recentTagsPanel, GBC.eol().fill(GBC.HORIZONTAL));
    721830            } else {
    722831                Dimension panelOldSize = recentTagsPanel.getPreferredSize();
    723832                recentTagsPanel.removeAll();
    724                 suggestRecentlyAddedTags();
     833                buildRecentTagsPanel();
    725834                Dimension panelNewSize = recentTagsPanel.getPreferredSize();
    726835                Dimension dialogOldSize = getMinimumSize();
    727836                Dimension dialogNewSize = new Dimension(dialogOldSize.width, dialogOldSize.height-panelOldSize.height+panelNewSize.height);
    public class TagEditHelper {  
    733842            }
    734843        }
    735844
    736         protected void suggestRecentlyAddedTags() {
     845        protected void buildRecentTagsPanel() {
    737846            final int tagsToShow = Math.min(PROPERTY_RECENT_TAGS_NUMBER.get(), MAX_LRU_TAGS_NUMBER);
    738847            if (!(tagsToShow > 0 && !recentTags.isEmpty()))
    739848                return;
    740849            recentTagsPanel.add(new JLabel(tr("Recently added tags")), GBC.eol());
    741850
    742             int count = 1;
     851            int count = 0;
     852            destroyActions();
    743853            // We store the maximum number of recent tags to allow dynamic change of number of tags shown in the preferences.
    744854            // This implies to iterate in descending order, as the oldest elements will only be removed after we reach the maximum
    745855            // number and not the number of tags to show.
    746856            // However, as Set does not allow to iterate in descending order, we need to copy its elements into a List we can access
    747857            // in reverse order.
    748             List<Tag> tags = new LinkedList<>(recentTags.keySet());
    749             for (int i = tags.size()-1; i >= 0 && count <= tagsToShow; i--, count++) {
     858            for (int i = tags.size()-1; i >= 0 && count < tagsToShow; i--) {
    750859                final Tag t = tags.get(i);
     860                boolean keyExists = keyExists(t);
     861                if (keyExists && PROPERTY_RECENT_EXISTING.get() == RecentExisting.HIDE)
     862                    continue;
     863                count++;
    751864                // Create action for reusing the tag, with keyboard shortcut
    752865                /* POSSIBLE SHORTCUTS: 1,2,3,4,5,6,7,8,9,0=10 */
    753866                final Shortcut sc = count > 10 ? null : Shortcut.registerShortcut("properties:recent:" + count,
    public class TagEditHelper {  
    772885                    public void actionPerformed(ActionEvent e) {
    773886                        action.actionPerformed(null);
    774887                        performTagAdding();
     888                        refreshRecentTags();
    775889                        selectKeysComboBox();
    776890                    }
    777891                };
    778892                recentTagsActions.add(action);
    779893                recentTagsActions.add(actionShift);
    780                 disableTagIfNeeded(t, action);
     894                if (keyExists && PROPERTY_RECENT_EXISTING.get() == RecentExisting.DISABLE) {
     895                    action.setEnabled(false);
     896                }
    781897                // Find and display icon
    782898                ImageIcon icon = MapPaintStyles.getNodeIcon(t, false); // Filters deprecated icon
    783899                if (icon == null) {
    public class TagEditHelper {  
    822938                        @Override
    823939                        public void mouseClicked(MouseEvent e) {
    824940                            action.actionPerformed(null);
    825                             // add tags and close window on double-click
    826                             if (e.getClickCount() > 1) {
    827                                 buttonAction(0, null); // emulate OK click and close the dialog
    828                             }
    829                             // add tags on Shift-Click
    830941                            if (e.isShiftDown()) {
     942                                // add tags on Shift-Click
    831943                                performTagAdding();
     944                                refreshRecentTags();
    832945                                selectKeysComboBox();
     946                            } else if (e.getClickCount() > 1) {
     947                                // add tags and close window on double-click
     948                                buttonAction(0, null); // emulate OK click and close the dialog
    833949                            }
    834950                        }
    835951                    });
    public class TagEditHelper {  
    844960                tagPanel.add(tagLabel);
    845961                recentTagsPanel.add(tagPanel, GBC.eol().fill(GBC.HORIZONTAL));
    846962            }
     963            // Clear label if no tags were added
     964            if (count == 0) recentTagsPanel.removeAll();
    847965        }
    848966
    849967        public void destroyActions() {
    public class TagEditHelper {  
    872990            lastAddKey = key;
    873991            lastAddValue = value;
    874992            recentTags.put(new Tag(key, value), null);
     993            valueCount.put(key, new TreeMap<String, Integer>());
    875994            AutoCompletionManager.rememberUserInput(key, value, false);
    876995            commandCount++;
    877996            Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, value));
    public class TagEditHelper {  
    8881007            Main.main.undoRedo.undo(commandCount);
    8891008        }
    8901009
    891         private void disableTagIfNeeded(final Tag t, final JosmAction action) {
    892             // Disable action if its key is already set on the object (the key being absent from the keys list for this reason
    893             // performing this action leads to autocomplete to the next key (see #7671 comments)
    894             for (int j = 0; j < tagData.getRowCount(); ++j) {
    895                 if (t.getKey().equals(getDataKey(j))) {
    896                     action.setEnabled(false);
    897                     break;
    898                 }
     1010        private boolean keyExists(final Tag t) {
     1011            return valueCount.containsKey(t.getKey());
     1012        }
     1013
     1014        private void refreshRecentTags() {
     1015            switch (PROPERTY_REFRESH_RECENT.get()) {
     1016                case REFRESH: cacheRecentTags(); // break missing intentionally
     1017                case STATUS: suggestRecentlyAddedTags();
    8991018            }
    9001019        }
    9011020    }