Ticket #12438: HideItemsFromRecentlyAddedTags.patch
| File HideItemsFromRecentlyAddedTags.patch, 17.8 KB (added by , 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. 2 package org.openstreetmap.josm.data.preferences; 3 4 import org.openstreetmap.josm.Main; 5 6 /** 7 * A property containing an {@code Enum} value. 8 * @author András Kolesár 9 * @param <T> 10 */ 11 public 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; 5 5 6 6 public abstract class ParametrizedEnumProperty<T extends Enum<T>> { 7 7 8 pr ivatefinal T defaultValue;9 pr ivatefinal Class<T> enumClass;8 protected final T defaultValue; 9 protected final Class<T> enumClass; 10 10 11 11 public ParametrizedEnumProperty(Class<T> enumClass, T defaultValue) { 12 12 this.defaultValue = defaultValue; 13 13 this.enumClass = enumClass; 14 if (Main.pref != null) {15 get();16 }17 14 } 18 15 19 16 protected abstract String getKey(String... params); … … public abstract class ParametrizedEnumProperty<T extends Enum<T>> { 27 24 } 28 25 29 26 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 } 31 32 } 32 33 } -
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; 38 38 import java.util.LinkedList; 39 39 import java.util.List; 40 40 import java.util.Map; 41 import java.util.TreeMap; 41 42 42 43 import javax.swing.AbstractAction; 43 44 import javax.swing.Action; 44 45 import javax.swing.Box; 46 import javax.swing.ButtonGroup; 45 47 import javax.swing.DefaultListCellRenderer; 46 48 import javax.swing.ImageIcon; 47 49 import javax.swing.JCheckBoxMenuItem; 48 50 import javax.swing.JComponent; 49 51 import javax.swing.JLabel; 50 52 import javax.swing.JList; 53 import javax.swing.JMenu; 51 54 import javax.swing.JOptionPane; 52 55 import javax.swing.JPanel; 53 56 import javax.swing.JPopupMenu; 57 import javax.swing.JRadioButtonMenuItem; 54 58 import javax.swing.JTable; 55 59 import javax.swing.KeyStroke; 56 60 import javax.swing.ListCellRenderer; … … import org.openstreetmap.josm.command.SequenceCommand; 65 69 import org.openstreetmap.josm.data.osm.OsmPrimitive; 66 70 import org.openstreetmap.josm.data.osm.Tag; 67 71 import org.openstreetmap.josm.data.preferences.BooleanProperty; 72 import org.openstreetmap.josm.data.preferences.EnumProperty; 68 73 import org.openstreetmap.josm.data.preferences.IntegerProperty; 69 74 import org.openstreetmap.josm.gui.ExtendedDialog; 70 75 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles; … … public class TagEditHelper { 119 124 /** Number of recent tags */ 120 125 public static final IntegerProperty PROPERTY_RECENT_TAGS_NUMBER = new IntegerProperty("properties.recently-added-tags", 121 126 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); 122 153 123 154 // LRU cache for recently added tags (http://java-planet.blogspot.com/2005/08/how-to-set-up-simple-lru-cache-using.html) 124 155 private final Map<Tag, Void> recentTags = new LinkedHashMap<Tag, Void>(MAX_LRU_TAGS_NUMBER+1, 1.1f, true) { … … public class TagEditHelper { 128 159 } 129 160 }; 130 161 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 */ 131 171 public TagEditHelper(JTable tagTable, DefaultTableModel propertyData, Map<String, Map<String, Integer>> valueCount) { 132 172 this.tagTable = tagTable; 133 173 this.tagData = propertyData; 134 174 this.valueCount = valueCount; 135 175 } 136 176 177 /** 178 * Finds the key from given row of tag editor 179 * @param viewRow index of row 180 * @return key of tag 181 */ 137 182 public final String getDataKey(int viewRow) { 138 183 return tagData.getValueAt(tagTable.convertRowIndexToModel(viewRow), 0).toString(); 139 184 } 140 185 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 */ 141 191 @SuppressWarnings("unchecked") 142 192 public final Map<String, Integer> getDataValues(int viewRow) { 143 193 return (Map<String, Integer>) tagData.getValueAt(tagTable.convertRowIndexToModel(viewRow), 1); … … public class TagEditHelper { 211 261 return changedKey; 212 262 } 213 263 264 /** 265 * Reset last changed key 266 */ 214 267 public void resetChangedKey() { 215 268 changedKey = null; 216 269 } … … public class TagEditHelper { 259 312 } 260 313 261 314 /** 315 * Update cache of recent tags used for displaying tags 316 */ 317 private void cacheRecentTags() { 318 tags = new LinkedList<>(recentTags.keySet()); 319 } 320 321 /** 262 322 * Warns user about a key being overwritten. 263 323 * @param action The action done by the user. Must state what key is changed 264 324 * @param togglePref The preference to save the checkbox state to … … public class TagEditHelper { 572 632 protected class AddTagsDialog extends AbstractTagsDialog { 573 633 private final List<JosmAction> recentTagsActions = new ArrayList<>(); 574 634 protected final transient FocusAdapter focus; 635 private JPanel mainPanel; 575 636 private JPanel recentTagsPanel; 576 637 577 638 // Counter of added commands for possible undo … … public class TagEditHelper { 583 644 setCancelButton(2); 584 645 configureContextsensitiveHelp("/Dialog/AddValue", true /* show help button */); 585 646 586 final JPanelmainPanel = new JPanel(new GridBagLayout());647 mainPanel = new JPanel(new GridBagLayout()); 587 648 keys = new AutoCompletingComboBox(); 588 649 values = new AutoCompletingComboBox(); 589 650 … … public class TagEditHelper { 640 701 @Override 641 702 public void actionPerformed(ActionEvent e) { 642 703 performTagAdding(); 704 refreshRecentTags(); 643 705 selectKeysComboBox(); 644 706 } 645 707 }); 646 708 647 suggestRecentlyAddedTags(mainPanel); 709 cacheRecentTags(); 710 suggestRecentlyAddedTags(); 648 711 649 712 mainPanel.add(Box.createVerticalGlue(), GBC.eop().fill()); 650 713 setContent(mainPanel, false); … … public class TagEditHelper { 655 718 @Override 656 719 public void actionPerformed(ActionEvent e) { 657 720 selectNumberOfTags(); 658 suggestRecentlyAddedTags( mainPanel);721 suggestRecentlyAddedTags(); 659 722 } 660 723 }); 724 725 popupMenu.add(buildMenuRecentExisting()); 726 popupMenu.add(buildMenuRefreshRecent()); 727 661 728 JCheckBoxMenuItem rememberLastTags = new JCheckBoxMenuItem( 662 729 new AbstractAction(tr("Remember last used tags after a restart")) { 663 730 @Override … … public class TagEditHelper { 672 739 popupMenu.add(rememberLastTags); 673 740 } 674 741 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 675 785 @Override 676 786 public void setContentPane(Container contentPane) { 677 787 final int commandDownMask = GuiHelper.getMenuShortcutKeyMaskEx(); … … public class TagEditHelper { 712 822 } 713 823 } 714 824 715 protected void suggestRecentlyAddedTags(JPanel mainPanel) { 716 825 protected void suggestRecentlyAddedTags() { 717 826 if (recentTagsPanel == null) { 718 827 recentTagsPanel = new JPanel(new GridBagLayout()); 719 suggestRecentlyAddedTags();828 buildRecentTagsPanel(); 720 829 mainPanel.add(recentTagsPanel, GBC.eol().fill(GBC.HORIZONTAL)); 721 830 } else { 722 831 Dimension panelOldSize = recentTagsPanel.getPreferredSize(); 723 832 recentTagsPanel.removeAll(); 724 suggestRecentlyAddedTags();833 buildRecentTagsPanel(); 725 834 Dimension panelNewSize = recentTagsPanel.getPreferredSize(); 726 835 Dimension dialogOldSize = getMinimumSize(); 727 836 Dimension dialogNewSize = new Dimension(dialogOldSize.width, dialogOldSize.height-panelOldSize.height+panelNewSize.height); … … public class TagEditHelper { 733 842 } 734 843 } 735 844 736 protected void suggestRecentlyAddedTags() {845 protected void buildRecentTagsPanel() { 737 846 final int tagsToShow = Math.min(PROPERTY_RECENT_TAGS_NUMBER.get(), MAX_LRU_TAGS_NUMBER); 738 847 if (!(tagsToShow > 0 && !recentTags.isEmpty())) 739 848 return; 740 849 recentTagsPanel.add(new JLabel(tr("Recently added tags")), GBC.eol()); 741 850 742 int count = 1; 851 int count = 0; 852 destroyActions(); 743 853 // We store the maximum number of recent tags to allow dynamic change of number of tags shown in the preferences. 744 854 // This implies to iterate in descending order, as the oldest elements will only be removed after we reach the maximum 745 855 // number and not the number of tags to show. 746 856 // However, as Set does not allow to iterate in descending order, we need to copy its elements into a List we can access 747 857 // 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--) { 750 859 final Tag t = tags.get(i); 860 boolean keyExists = keyExists(t); 861 if (keyExists && PROPERTY_RECENT_EXISTING.get() == RecentExisting.HIDE) 862 continue; 863 count++; 751 864 // Create action for reusing the tag, with keyboard shortcut 752 865 /* POSSIBLE SHORTCUTS: 1,2,3,4,5,6,7,8,9,0=10 */ 753 866 final Shortcut sc = count > 10 ? null : Shortcut.registerShortcut("properties:recent:" + count, … … public class TagEditHelper { 772 885 public void actionPerformed(ActionEvent e) { 773 886 action.actionPerformed(null); 774 887 performTagAdding(); 888 refreshRecentTags(); 775 889 selectKeysComboBox(); 776 890 } 777 891 }; 778 892 recentTagsActions.add(action); 779 893 recentTagsActions.add(actionShift); 780 disableTagIfNeeded(t, action); 894 if (keyExists && PROPERTY_RECENT_EXISTING.get() == RecentExisting.DISABLE) { 895 action.setEnabled(false); 896 } 781 897 // Find and display icon 782 898 ImageIcon icon = MapPaintStyles.getNodeIcon(t, false); // Filters deprecated icon 783 899 if (icon == null) { … … public class TagEditHelper { 822 938 @Override 823 939 public void mouseClicked(MouseEvent e) { 824 940 action.actionPerformed(null); 825 // add tags and close window on double-click826 if (e.getClickCount() > 1) {827 buttonAction(0, null); // emulate OK click and close the dialog828 }829 // add tags on Shift-Click830 941 if (e.isShiftDown()) { 942 // add tags on Shift-Click 831 943 performTagAdding(); 944 refreshRecentTags(); 832 945 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 833 949 } 834 950 } 835 951 }); … … public class TagEditHelper { 844 960 tagPanel.add(tagLabel); 845 961 recentTagsPanel.add(tagPanel, GBC.eol().fill(GBC.HORIZONTAL)); 846 962 } 963 // Clear label if no tags were added 964 if (count == 0) recentTagsPanel.removeAll(); 847 965 } 848 966 849 967 public void destroyActions() { … … public class TagEditHelper { 872 990 lastAddKey = key; 873 991 lastAddValue = value; 874 992 recentTags.put(new Tag(key, value), null); 993 valueCount.put(key, new TreeMap<String, Integer>()); 875 994 AutoCompletionManager.rememberUserInput(key, value, false); 876 995 commandCount++; 877 996 Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, value)); … … public class TagEditHelper { 888 1007 Main.main.undoRedo.undo(commandCount); 889 1008 } 890 1009 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 reason893 // 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(); 899 1018 } 900 1019 } 901 1020 }
