Changeset 5383 in josm


Ignore:
Timestamp:
2012-07-30T19:53:01+02:00 (12 years ago)
Author:
Don-vip
Message:

fix #7671 - Show last N used tags in "Add key/value" dialog for selecting with a single click

LRU tags are shown in reverse order (most recent first).

This can be customized by setting the property properties.recently-added-tags to an integer between 1 and 9.
This can be disabled by setting the same property to a number lesser or equal to 0.

Keyboard shortcuts Ctrl+1 to Ctrl+9 are available in the context of the "Add property" dialog only.

Location:
trunk/src/org/openstreetmap/josm/gui
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java

    r5378 r5383  
    77import java.awt.BorderLayout;
    88import java.awt.Component;
     9import java.awt.Cursor;
     10import java.awt.Dialog.ModalityType;
    911import java.awt.Dimension;
    1012import java.awt.Font;
     13import java.awt.GridBagConstraints;
    1114import java.awt.GridBagLayout;
    1215import java.awt.Point;
    1316import java.awt.Toolkit;
    14 import java.awt.Dialog.ModalityType;
    1517import java.awt.datatransfer.Clipboard;
    1618import java.awt.datatransfer.Transferable;
     
    1921import java.awt.event.FocusAdapter;
    2022import java.awt.event.FocusEvent;
    21 import java.awt.event.InputEvent;
    2223import java.awt.event.KeyEvent;
    2324import java.awt.event.MouseAdapter;
    2425import java.awt.event.MouseEvent;
     26import java.awt.image.BufferedImage;
    2527import java.net.HttpURLConnection;
    2628import java.net.URI;
     
    3537import java.util.HashSet;
    3638import java.util.Iterator;
     39import java.util.LinkedHashMap;
    3740import java.util.LinkedList;
    3841import java.util.List;
    3942import java.util.Map;
     43import java.util.Map.Entry;
    4044import java.util.Set;
    4145import java.util.TreeMap;
    4246import java.util.TreeSet;
    4347import java.util.Vector;
    44 import java.util.Map.Entry;
    4548
    4649import javax.swing.AbstractAction;
     
    4851import javax.swing.Box;
    4952import javax.swing.DefaultListCellRenderer;
    50 import javax.swing.InputMap;
     53import javax.swing.ImageIcon;
    5154import javax.swing.JComboBox;
    5255import javax.swing.JComponent;
     
    6265import javax.swing.KeyStroke;
    6366import javax.swing.ListSelectionModel;
    64 import javax.swing.SwingUtilities;
    6567import javax.swing.event.ListSelectionEvent;
    6668import javax.swing.event.ListSelectionListener;
     
    9395import org.openstreetmap.josm.data.osm.event.DataSetListenerAdapter;
    9496import org.openstreetmap.josm.data.osm.event.DatasetEventManager;
     97import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
    9598import org.openstreetmap.josm.data.osm.event.SelectionEventManager;
    96 import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
    9799import org.openstreetmap.josm.gui.DefaultNameFormatter;
    98100import org.openstreetmap.josm.gui.ExtendedDialog;
     
    105107import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
    106108import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     109import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
    107110import org.openstreetmap.josm.gui.tagging.TaggingPreset;
    108111import org.openstreetmap.josm.gui.tagging.TaggingPreset.PresetType;
     
    157160                int row = propertyTable.rowAtPoint(e.getPoint());
    158161                if (row > -1) {
    159                     propertyEdit(row);
     162                    editProperty(row);
    160163                } else {
    161                     add();
     164                    addProperty();
    162165                }
    163166            } else if (e.getSource() == membershipTable) {
    164167                int row = membershipTable.rowAtPoint(e.getPoint());
    165168                if (row > -1) {
    166                     membershipEdit(row);
     169                    editMembership(row);
    167170                }
    168171            }
    169172            else
    170173            {
    171                 add();
     174                addProperty();
    172175            }
    173176        }
     
    233236     */
    234237    @SuppressWarnings("unchecked")
    235     void propertyEdit(int row) {
     238    private void editProperty(int row) {
    236239        Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected();
    237240        if (sel.isEmpty()) return;
     
    434437     * @return a list of keys
    435438     */
    436     static List<String> getAutocompletionKeys(String key) {
     439    private static List<String> getAutocompletionKeys(String key) {
    437440        if ("name".equals(key) || "addr:street".equals(key))
    438441            return Arrays.asList("addr:street", "name");
     
    447450     * @param row
    448451     */
    449     void membershipEdit(int row) {
     452    private void editMembership(int row) {
    450453        Relation relation = (Relation)membershipData.getValueAt(row, 0);
    451454        Main.map.relationListDialog.selectRelation(relation);
     
    458461    private static String lastAddKey = null;
    459462    private static String lastAddValue = null;
     463   
     464    public static final int DEFAULT_LRU_TAGS_NUMBER = 5;
     465    public static final int MAX_LRU_TAGS_NUMBER = 9;
     466   
     467    // LRU cache for recently added tags (http://java-planet.blogspot.com/2005/08/how-to-set-up-simple-lru-cache-using.html)
     468    private static final Map<Tag, Void> recentTags = new LinkedHashMap<Tag, Void>(MAX_LRU_TAGS_NUMBER+1, 1.1f, true) {
     469        @Override
     470        protected boolean removeEldestEntry(Entry<Tag, Void> eldest) {
     471            return size() > MAX_LRU_TAGS_NUMBER;
     472        }
     473    };
     474   
    460475    /**
    461476     * Open the add selection dialog and add a new key/value to the table (and
    462477     * to the dataset, of course).
    463478     */
    464     void add() {
     479    private void addProperty() {
    465480        Collection<OsmPrimitive> sel;
    466481        if (Main.map.mapMode instanceof DrawAction) {
     
    473488        if (sel.isEmpty()) return;
    474489
    475         JPanel p = new JPanel(new BorderLayout());
     490        JPanel p = new JPanel(new GridBagLayout());
    476491        p.add(new JLabel("<html>"+trn("This will change up to {0} object.",
    477492                "This will change up to {0} objects.", sel.size(),sel.size())
    478                 +"<br><br>"+tr("Please select a key")), BorderLayout.NORTH);
     493                +"<br><br>"+tr("Please select a key")), GBC.eol());
    479494        final AutoCompletingComboBox keys = new AutoCompletingComboBox();
    480495        AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager();
     
    504519        keys.setEditable(true);
    505520
    506         p.add(keys, BorderLayout.CENTER);
    507 
    508         JPanel p2 = new JPanel(new BorderLayout());
    509         p.add(p2, BorderLayout.SOUTH);
    510         p2.add(new JLabel(tr("Please select a value")), BorderLayout.NORTH);
     521        p.add(keys, GBC.eop().fill());
     522
     523        p.add(new JLabel(tr("Please select a value")), GBC.eol());
    511524        final AutoCompletingComboBox values = new AutoCompletingComboBox();
    512525        values.setEditable(true);
    513         p2.add(values, BorderLayout.CENTER);
     526        p.add(values, GBC.eop().fill());
    514527        if (itemToSelect != null) {
    515528            keys.setSelectedItem(itemToSelect);
     
    519532            }
    520533        }
     534       
     535        int recentTagsToShow = Main.pref.getInteger("properties.recently-added-tags", DEFAULT_LRU_TAGS_NUMBER);
     536        if (recentTagsToShow > MAX_LRU_TAGS_NUMBER) {
     537            recentTagsToShow = MAX_LRU_TAGS_NUMBER;
     538        }
     539        List<JosmAction> recentTagsActions = new ArrayList<JosmAction>();
     540        suggestRecentlyAddedTags(p, keys, values, recentTagsActions, recentTagsToShow);
    521541
    522542        FocusAdapter focus = addFocusAdapter(-1, keys, values, autocomplete, defaultACItemComparator);
     
    542562        dialog.setModalityType(ModalityType.DOCUMENT_MODAL);
    543563        dialog.setVisible(true);
     564       
     565        for (JosmAction action : recentTagsActions) {
     566            action.destroy();
     567        }
    544568
    545569        if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
     
    551575        lastAddKey = key;
    552576        lastAddValue = value;
     577        recentTags.put(new Tag(key, value), null);
    553578        Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, value));
    554579        btnAdd.requestFocusInWindow();
     580    }
     581   
     582    private void suggestRecentlyAddedTags(JPanel p, final AutoCompletingComboBox keys, final AutoCompletingComboBox values, List<JosmAction> tagsActions, int tagsToShow) {
     583        if (tagsToShow > 0 && !recentTags.isEmpty()) {
     584            p.add(new JLabel(tr("Recently added tags")), GBC.eol());
     585           
     586            int count = 1;
     587            // We store the maximum number (9) of recent tags to allow dynamic change of number of tags shown in the preferences.
     588            // This implies to iterate in descending order, as the oldest elements will only be removed after we reach the maximum numbern and not the number of tags to show.
     589            // However, as Set does not allow to iterate in descending order, we need to copy its elements into a List we can access in reverse order.
     590            List<Tag> tags = new LinkedList<Tag>(recentTags.keySet());
     591            for (int i = tags.size()-1; i >= 0 && count <= tagsToShow; i--, count++) {
     592                final Tag t = tags.get(i);
     593                // Find and display icon
     594                ImageIcon icon = MapPaintStyles.getNodeIcon(t, false); // Filters deprecated icon
     595                if (icon == null) {
     596                    icon = new ImageIcon(new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB));
     597                }
     598                GridBagConstraints gbc = new GridBagConstraints();
     599                gbc.ipadx = 5;
     600                p.add(new JLabel(icon), gbc);
     601                // Create action for reusing the tag, with keyboard shortcut Ctrl+(1-5)
     602                String actionShortcutKey = "properties:recent:"+count;
     603                Shortcut sc = Shortcut.registerShortcut(actionShortcutKey, null, KeyEvent.VK_0+count, Shortcut.CTRL);
     604                final JosmAction action = new JosmAction(actionShortcutKey, null, tr("Use this tag again"), sc, false) {
     605                    @Override
     606                    public void actionPerformed(ActionEvent e) {
     607                        keys.getEditor().setItem(t.getKey());
     608                        values.getEditor().setItem(t.getValue());
     609                    }
     610                };
     611                p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), actionShortcutKey);
     612                p.getActionMap().put(actionShortcutKey, action);
     613                tagsActions.add(action);
     614                // Display clickable tag
     615                final JLabel tagLabel = new JLabel("<html>"
     616                    + "<style>td{border:1px solid gray; font-weight:normal;}</style>"
     617                    + "<table><tr><td>" + t.toString() + "</td></tr></table></html>");
     618                tagLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
     619                tagLabel.setToolTipText((String) action.getValue(Action.SHORT_DESCRIPTION));
     620                tagLabel.addMouseListener(new MouseAdapter() {
     621                    @Override
     622                    public void mouseClicked(MouseEvent e) {
     623                        action.actionPerformed(null);
     624                    }
     625                });
     626                p.add(tagLabel, GBC.eol());
     627            }
     628        }
    555629    }
    556630
     
    11891263        @Override
    11901264        public void actionPerformed(ActionEvent e) {
    1191             add();
     1265            addProperty();
    11921266        }
    11931267    }
     
    12071281            if (propertyTable.getSelectedRowCount() == 1) {
    12081282                int row = propertyTable.getSelectedRow();
    1209                 propertyEdit(row);
     1283                editProperty(row);
    12101284            } else if (membershipTable.getSelectedRowCount() == 1) {
    12111285                int row = membershipTable.getSelectedRow();
    1212                 membershipEdit(row);
     1286                editMembership(row);
    12131287            }
    12141288        }
  • trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java

    r5219 r5383  
    1111import java.util.Arrays;
    1212import java.util.Collection;
     13import java.util.Iterator;
    1314import java.util.LinkedList;
    1415import java.util.List;
     
    1920
    2021import org.openstreetmap.josm.Main;
     22import org.openstreetmap.josm.data.osm.Node;
     23import org.openstreetmap.josm.data.osm.Tag;
    2124import org.openstreetmap.josm.gui.PleaseWaitRunnable;
     25import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList;
    2226import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
    2327import org.openstreetmap.josm.gui.mappaint.xml.XmlStyleSource;
     
    118122                .setArchive(source.zipIcons)
    119123                .setOptional(true).get();
     124    }
     125   
     126    public static ImageIcon getNodeIcon(Tag tag) {
     127        return getNodeIcon(tag, true);
     128    }
     129   
     130    public static ImageIcon getNodeIcon(Tag tag, boolean includeDeprecatedIcon) {
     131        if (tag != null) {
     132            Node virtualNode = new Node();
     133            virtualNode.put(tag.getKey(), tag.getValue());
     134            StyleList styleList = getStyles().generateStyles(virtualNode, 0, null, false).a;
     135            if (styleList != null) {
     136                for (Iterator<ElemStyle> it = styleList.iterator(); it.hasNext(); ) {
     137                    ElemStyle style = it.next();
     138                    if (style instanceof NodeElemStyle) {
     139                        MapImage mapImage = ((NodeElemStyle) style).mapImage;
     140                        if (mapImage != null) {
     141                            if (includeDeprecatedIcon || mapImage.name == null || !mapImage.name.equals("misc/deprecated.png")) {
     142                                return new ImageIcon(mapImage.getImage());
     143                            } else {
     144                                return null; // Deprecated icon found but not wanted
     145                            }
     146                        }
     147                    }
     148                }
     149            }
     150        }
     151        return null;
    120152    }
    121153
Note: See TracChangeset for help on using the changeset viewer.