Changeset 5383 in josm


Ignore:
Timestamp:
Jul 30, 2012 7:53:01 PM (10 months 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.