Changeset 5642 in josm


Ignore:
Timestamp:
2012-12-28T19:07:59+01:00 (12 years ago)
Author:
akks
Message:

see #8024: After adding recent tags by shift-click, Cancel can undo all operations.
Caution: new refactoring - now Add Tags and Edit Tags are ExtendedDialog subclasses

File:
1 edited

Legend:

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

    r5640 r5642  
    6666import org.openstreetmap.josm.tools.GBC;
    6767import org.openstreetmap.josm.tools.Shortcut;
     68import org.openstreetmap.josm.tools.WindowGeometry;
    6869
    6970/**
     
    7677    private String changedKey;
    7778
    78     private String lastAddKey = null;
    79     private String lastAddValue = null;
    80 
    81     public static final int DEFAULT_LRU_TAGS_NUMBER = 5;
    82     public static final int MAX_LRU_TAGS_NUMBER = 9;
    83 
     79   
    8480    private String objKey;
    8581
     
    9086    };
    9187
    92    
    93     // LRU cache for recently added tags (http://java-planet.blogspot.com/2005/08/how-to-set-up-simple-lru-cache-using.html)
    94     private final Map<Tag, Void> recentTags = new LinkedHashMap<Tag, Void>(MAX_LRU_TAGS_NUMBER+1, 1.1f, true) {
    95         @Override
    96         protected boolean removeEldestEntry(Map.Entry<Tag, Void> eldest) {
    97             return size() > MAX_LRU_TAGS_NUMBER;
    98         }
    99     };
     88    Collection<OsmPrimitive> sel;
     89       
     90            private String lastAddKey = null;
     91        private String lastAddValue = null;
     92
     93        public static final int DEFAULT_LRU_TAGS_NUMBER = 5;
     94        public static final int MAX_LRU_TAGS_NUMBER = 9;
     95
     96        // LRU cache for recently added tags (http://java-planet.blogspot.com/2005/08/how-to-set-up-simple-lru-cache-using.html)
     97        private final Map<Tag, Void> recentTags = new LinkedHashMap<Tag, Void>(MAX_LRU_TAGS_NUMBER+1, 1.1f, true) {
     98            @Override
     99            protected boolean removeEldestEntry(Map.Entry<Tag, Void> eldest) {
     100                return size() > MAX_LRU_TAGS_NUMBER;
     101            }
     102        };
    100103
    101104    TagEditHelper(DefaultTableModel propertyData, Map<String, Map<String, Integer>> valueCount) {
     
    110113    public void addProperty() {
    111114        changedKey = null;
    112         Collection<OsmPrimitive> sel;
    113115        if (Main.map.mapMode instanceof DrawAction) {
    114116            sel = ((DrawAction) Main.map.mapMode).getInProgressSelection();
     
    120122        if (sel.isEmpty()) return;
    121123
    122         final AddTagsPanel p = new AddTagsPanel(sel);
    123 
    124         final JOptionPane optionPane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
    125             @Override public void selectInitialValue() {
    126                 // save unix system selection (middle mouse paste)
    127                 Clipboard sysSel = Toolkit.getDefaultToolkit().getSystemSelection();
    128                 if(sysSel != null) {
    129                     Transferable old = sysSel.getContents(null);
    130                     p.keys.requestFocusInWindow();
    131                     p.keys.getEditor().selectAll();
    132                     sysSel.setContents(old, null);
    133                 } else {
    134                     p.keys.requestFocusInWindow();
    135                     p.keys.getEditor().selectAll();
    136                 }
    137             }
    138         };
    139         final JDialog dialog = optionPane.createDialog(Main.parent, tr("Add value?"));
    140         dialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL);
    141         // We specify what to do if panel wants to close the entire dialog
    142         p.setCloseActionListener(new ActionListener() {
    143             public void actionPerformed(ActionEvent e) {
    144                 dialog.setVisible(false);
    145                 optionPane.setValue(JOptionPane.OK_OPTION);
    146             }
    147         });
    148         dialog.setVisible(true);
    149        
    150         p.destroyActions();
    151        
    152         if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(optionPane.getValue()))
    153             return;
    154         p.performTagAdding();
     124        final AddTagsDialog addDialog = new AddTagsDialog();       
     125       
     126        addDialog.showDialog();
     127       
     128        addDialog.destroyActions();
     129        if (addDialog.getValue() == 1)           
     130            addDialog.performTagAdding();
     131        else
     132            addDialog.undoAllTagsAdding();
    155133    }
    156134   
     135    /**
     136    * Edit the value in the properties table row
     137    * @param row The row of the table from which the value is edited.
     138    */
     139    public void editProperty(final int row) {
     140        changedKey = null;
     141        Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected();
     142        if (sel.isEmpty()) return;
     143
     144        String key = propertyData.getValueAt(row, 0).toString();
     145        objKey=key;
     146       
     147        final EditTagDialog editDialog = new EditTagDialog(key, row,
     148                (Map<String, Integer>) propertyData.getValueAt(row, 1));
     149        editDialog.showDialog();
     150        if (editDialog.getValue() !=1 ) return;
     151        editDialog.performTagEdit();
     152    }
     153    /**
     154     * If during last editProperty call user changed the key name, this key will be returned
     155     * Elsewhere, returns null.
     156     */
     157    public String getChangedKey() {
     158        return changedKey;
     159    }
     160   
     161    public void resetChangedKey() {
     162        changedKey = null;
     163    }
     164
     165    /**
     166     * For a given key k, return a list of keys which are used as keys for
     167     * auto-completing values to increase the search space.
     168     * @param key the key k
     169     * @return a list of keys
     170     */
     171    private static List<String> getAutocompletionKeys(String key) {
     172        if ("name".equals(key) || "addr:street".equals(key))
     173            return Arrays.asList("addr:street", "name");
     174        else
     175            return Arrays.asList(key);
     176    }
     177
    157178    /**
    158179     * Create a focus handling adapter and apply in to the editor component of value
     
    185206    }
    186207   
    187     /**
    188     * Edit the value in the properties table row
    189     * @param row The row of the table from which the value is edited.
    190     */
    191     public void editProperty(final int row) {
    192         changedKey = null;
    193         Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected();
    194         if (sel.isEmpty()) return;
    195 
    196         String key = propertyData.getValueAt(row, 0).toString();
    197         objKey=key;
    198        
    199         @SuppressWarnings("unchecked")
    200         final EditTagsPanel p = new EditTagsPanel(key, row, sel,
    201                 (Map<String, Integer>) propertyData.getValueAt(row, 1));
    202 
    203         final JOptionPane optionPane = new JOptionPane(p, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
    204             @Override public void selectInitialValue() {
    205                 // save unix system selection (middle mouse paste)
    206                 Clipboard sysSel = Toolkit.getDefaultToolkit().getSystemSelection();
    207                 if(sysSel != null) {
    208                     Transferable old = sysSel.getContents(null);
    209                     p.values.requestFocusInWindow();
    210                     p.values.getEditor().selectAll();
    211                     sysSel.setContents(old, null);
    212                 } else {
    213                     p.values.requestFocusInWindow();
    214                     p.values.getEditor().selectAll();
    215                 }
    216             }
    217         };
    218        
    219         final JDialog dialog = optionPane.createDialog(Main.parent, trn("Change value?", "Change values?", p.getValueCount()));
    220         dialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL);
    221         Dimension dlgSize = dialog.getSize();
    222         if(dlgSize.width > Main.parent.getSize().width) {
    223             dlgSize.width = Math.max(250, Main.parent.getSize().width);
    224             dialog.setSize(dlgSize);
    225         }
    226         dialog.setLocationRelativeTo(Main.parent);
    227        
    228         // Auto-close dialog when user selects a value from list
    229         p.values.getEditor().addActionListener(new ActionListener() {
    230             public void actionPerformed(ActionEvent e) {
    231                 dialog.setVisible(false);
    232                 optionPane.setValue(JOptionPane.OK_OPTION);
    233             }
    234         });
    235 
    236         dialog.setVisible(true);
    237        
    238          if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(optionPane.getValue())) {
    239             return;
    240          }
    241 
    242         p.performTagEdit();
    243 
    244     }
    245    
    246     /**
    247      * If during last editProperty call user changed the key name, this key will be returned
    248      * Elsewhere, returns null.
    249      */
    250     public String getChangedKey() {
    251         return changedKey;
    252     }
    253    
    254     public void resetChangedKey() {
    255         changedKey = null;
    256     }
    257 
    258     /**
    259      * For a given key k, return a list of keys which are used as keys for
    260      * auto-completing values to increase the search space.
    261      * @param key the key k
    262      * @return a list of keys
    263      */
    264     private static List<String> getAutocompletionKeys(String key) {
    265         if ("name".equals(key) || "addr:street".equals(key))
    266             return Arrays.asList("addr:street", "name");
    267         else
    268             return Arrays.asList(key);
    269     }
    270 
    271    
    272     class EditTagsPanel extends JPanel {
    273         final AutoCompletingComboBox keys;
    274         final AutoCompletingComboBox values;
     208       
     209    public class EditTagDialog extends ExtendedDialog {
     210        AutoCompletingComboBox keys;
     211        AutoCompletingComboBox values;
    275212        String oldValue;
    276         final String key;
    277         final Collection<OsmPrimitive> sel;
    278         final Map<String, Integer> m;
    279            
    280         public EditTagsPanel(final String key, final int row, Collection<OsmPrimitive> sel, Map<String, Integer> countMap) {
    281             super(new BorderLayout());
    282             this.key = key;
    283             this.sel = sel;
    284             m = countMap;
    285    
    286  
    287             String msg = "<html>"+trn("This will change {0} object.",
    288                     "This will change up to {0} objects.", sel.size(), sel.size())
    289                     +"<br><br>("+tr("An empty value deletes the tag.", key)+")</html>";
    290 
    291             add(new JLabel(msg), BorderLayout.NORTH);
    292 
    293             JPanel p = new JPanel(new GridBagLayout());
    294             add(p, BorderLayout.CENTER);
    295 
    296             AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager();
    297             List<AutoCompletionListItem> keyList = autocomplete.getKeys();
    298             Collections.sort(keyList, defaultACItemComparator);
    299 
    300             keys = new AutoCompletingComboBox(key);
    301             keys.setPossibleACItems(keyList);
    302             keys.setEditable(true);
    303             keys.setSelectedItem(key);
    304 
    305             p.add(new JLabel(tr("Key")), GBC.std());
    306             p.add(Box.createHorizontalStrut(10), GBC.std());
    307             p.add(keys, GBC.eol().fill(GBC.HORIZONTAL));
    308 
    309            
    310             Comparator<AutoCompletionListItem> usedValuesAwareComparator = new Comparator<AutoCompletionListItem>() {
    311 
     213        String key;
     214        Map<String, Integer> m;
     215        int row;
     216
     217        Comparator<AutoCompletionListItem> usedValuesAwareComparator = new Comparator<AutoCompletionListItem>() {
    312218                @Override
    313219                public int compare(AutoCompletionListItem o1, AutoCompletionListItem o2) {
     
    322228                }
    323229            };
    324 
    325             List<AutoCompletionListItem> valueList = autocomplete.getValues(getAutocompletionKeys(key));
    326             Collections.sort(valueList, usedValuesAwareComparator);
    327 
    328             final String selection= m.size()!=1?tr("<different>"):m.entrySet().iterator().next().getKey();
    329 
    330             values = new AutoCompletingComboBox(selection);
    331             values.setRenderer(new DefaultListCellRenderer() {
     230       
     231        DefaultListCellRenderer cellRenderer = new DefaultListCellRenderer() {
    332232                @Override public Component getListCellRendererComponent(JList list,
    333233                        Object value, int index, boolean isSelected,  boolean cellHasFocus){
     
    347247                    return c;
    348248                }
    349             });
     249            };
     250       
     251        private EditTagDialog(String key, int row, Map<String, Integer> map) {
     252            super(Main.parent, trn("Change value?", "Change values?", map.size()), new String[] {tr("OK"),tr("Cancel")});
     253            setButtonIcons(new String[] {"ok","cancel"});
     254            setCancelButton(2);
     255            setIcon(JOptionPane.QUESTION_MESSAGE);
     256            this.key = key;
     257            this.row = row;
     258            this.m = map;
     259           
     260            // TODO : How to remember position, allowing autosizing?
     261            // setRememberWindowGeometry(getClass().getName() + ".geometry",
     262            //    WindowGeometry.centerInWindow(Main.parent, new Dimension(270, 180)));
     263            //setRememberWindowGeometry(getClass().getName() + ".geometry",
     264            //        WindowGeometry.centerInWindow(Main.parent, new Dimension(270, 180)));
     265           
     266            JPanel mainPanel = new JPanel(new BorderLayout());
     267                   
     268            String msg = "<html>"+trn("This will change {0} object.",
     269                    "This will change up to {0} objects.", sel.size(), sel.size())
     270                    +"<br><br>("+tr("An empty value deletes the tag.", key)+")</html>";
     271
     272            mainPanel.add(new JLabel(msg), BorderLayout.NORTH);
     273
     274            JPanel p = new JPanel(new GridBagLayout());
     275            mainPanel.add(p, BorderLayout.CENTER);
     276
     277            AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager();
     278            List<AutoCompletionListItem> keyList = autocomplete.getKeys();
     279            Collections.sort(keyList, defaultACItemComparator);
     280
     281            keys = new AutoCompletingComboBox(key);
     282            keys.setPossibleACItems(keyList);
     283            keys.setEditable(true);
     284            keys.setSelectedItem(key);
     285
     286            p.add(new JLabel(tr("Key")), GBC.std());
     287            p.add(Box.createHorizontalStrut(10), GBC.std());
     288            p.add(keys, GBC.eol().fill(GBC.HORIZONTAL));
     289
     290            List<AutoCompletionListItem> valueList = autocomplete.getValues(getAutocompletionKeys(key));
     291            Collections.sort(valueList, usedValuesAwareComparator);
     292
     293            final String selection= m.size()!=1?tr("<different>"):m.entrySet().iterator().next().getKey();
     294           
     295            values = new AutoCompletingComboBox(selection);
     296            values.setRenderer(cellRenderer);
    350297
    351298            values.setEditable(true);
     
    356303            p.add(Box.createHorizontalStrut(10), GBC.std());
    357304            p.add(values, GBC.eol().fill(GBC.HORIZONTAL));
     305            values.getEditor().addActionListener(new ActionListener() {
     306                public void actionPerformed(ActionEvent e) {
     307                    buttonAction(0, null); // emulate OK button click
     308                }
     309            });
    358310            addFocusAdapter(keys, values, autocomplete, usedValuesAwareComparator);
    359311           
    360         }
    361        
    362         private int getValueCount() {
    363             return m.size();
    364         }
    365 
    366         /**
     312            setContent(mainPanel, false);
     313           
     314            // TODO: Is it correct place for thois code - was in
     315            //  new JOptionPane(p, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
     316            //    @Override public void selectInitialValue() {
     317            Clipboard sysSel = Toolkit.getDefaultToolkit().getSystemSelection();
     318                if(sysSel != null) {
     319                    Transferable old = sysSel.getContents(null);
     320                    values.requestFocusInWindow();
     321                    values.getEditor().selectAll();
     322                    sysSel.setContents(old, null);
     323                } else {
     324                    values.requestFocusInWindow();
     325                    values.getEditor().selectAll();
     326                }
     327        }
     328       
     329           /**
    367330         * Edit tags of multiple selected objects according to selected ComboBox values
    368331         * If value == "", tag will be deleted
     
    436399            changedKey = newkey;
    437400        }
    438        
    439        
    440401    }
    441402   
    442     class AddTagsPanel extends JPanel {
    443         final AutoCompletingComboBox keys = new AutoCompletingComboBox();
    444         final AutoCompletingComboBox values = new AutoCompletingComboBox();
     403    class AddTagsDialog extends ExtendedDialog {
     404        AutoCompletingComboBox keys;
     405        AutoCompletingComboBox values;
    445406        List<JosmAction> recentTagsActions = new ArrayList<JosmAction>();
    446         Collection<OsmPrimitive> sel;
    447         private ActionListener autoCloseActionListener;
    448        
    449         public AddTagsPanel(Collection<OsmPrimitive> sel) {
    450             super(new GridBagLayout());
    451             this.sel = sel;
    452             add(new JLabel("<html>"+trn("This will change up to {0} object.",
     407       
     408        // Counter of added commands for possible undo
     409        private int commandCount;
     410
     411        public AddTagsDialog() {
     412            super(Main.parent, tr("Add value?"), new String[] {tr("OK"),tr("Cancel")});
     413            setButtonIcons(new String[] {"ok","cancel"});
     414            setCancelButton(2);
     415           
     416            // TODO : How to remember position, allowing autosizing?
     417            // setRememberWindowGeometry(getClass().getName() + ".geometry",
     418            //    WindowGeometry.centerInWindow(Main.parent, new Dimension(270, 180)));
     419           
     420            JPanel mainPanel = new JPanel(new GridBagLayout());
     421            keys = new AutoCompletingComboBox();
     422            values = new AutoCompletingComboBox();
     423           
     424            mainPanel.add(new JLabel("<html>"+trn("This will change up to {0} object.",
    453425                "This will change up to {0} objects.", sel.size(),sel.size())
    454426                +"<br><br>"+tr("Please select a key")), GBC.eol().fill(GBC.HORIZONTAL));
     
    480452            keys.setEditable(true);
    481453
    482             add(keys, GBC.eop().fill());
    483 
    484             add(new JLabel(tr("Please select a value")), GBC.eol());
     454            mainPanel.add(keys, GBC.eop().fill());
     455
     456            mainPanel.add(new JLabel(tr("Please select a value")), GBC.eol());
    485457            values.setEditable(true);
    486             add(values, GBC.eop().fill());
     458            mainPanel.add(values, GBC.eop().fill());
    487459            if (itemToSelect != null) {
    488460                keys.setSelectedItem(itemToSelect);
     
    500472                recentTagsToShow = MAX_LRU_TAGS_NUMBER;
    501473            }
    502             suggestRecentlyAddedTags(recentTagsToShow, focus);
    503         }
    504 
    505         private void suggestRecentlyAddedTags(int tagsToShow, final FocusAdapter focus) {
     474            suggestRecentlyAddedTags(mainPanel, recentTagsToShow, focus);
     475           
     476            setContent(mainPanel, false);
     477           
     478            // TODO: Is it correct place for thois code - was in
     479            //  new JOptionPane(p, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
     480            //    @Override public void selectInitialValue() {
     481            Clipboard sysSel = Toolkit.getDefaultToolkit().getSystemSelection();
     482                if(sysSel != null) {
     483                    Transferable old = sysSel.getContents(null);
     484                    values.requestFocusInWindow();
     485                    values.getEditor().selectAll();
     486                    sysSel.setContents(old, null);
     487                } else {
     488                    values.requestFocusInWindow();
     489                    values.getEditor().selectAll();
     490                }
     491               
     492           
     493        }
     494
     495        private void suggestRecentlyAddedTags(JPanel mainPanel, int tagsToShow, final FocusAdapter focus) {
    506496            if (!(tagsToShow > 0 && !recentTags.isEmpty()))
    507497                return;
    508498
    509             add(new JLabel(tr("Recently added tags")), GBC.eol());
     499            mainPanel.add(new JLabel(tr("Recently added tags")), GBC.eol());
    510500           
    511501            int count = 1;
     
    538528                GridBagConstraints gbc = new GridBagConstraints();
    539529                gbc.ipadx = 5;
    540                 add(new JLabel(action.isEnabled() ? icon : GuiHelper.getDisabledIcon(icon)), gbc);
     530                mainPanel.add(new JLabel(action.isEnabled() ? icon : GuiHelper.getDisabledIcon(icon)), gbc);
    541531                // Create tag label
    542532                final String color = action.isEnabled() ? "" : "; color:gray";
     
    546536                if (action.isEnabled()) {
    547537                    // Register action
    548                     getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), actionShortcutKey);
    549                     getActionMap().put(actionShortcutKey, action);
     538                    mainPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), actionShortcutKey);
     539                    mainPanel.getActionMap().put(actionShortcutKey, action);
    550540                    // Make the tag label clickable and set tooltip to the action description (this displays also the keyboard shortcut)
    551541                    tagLabel.setToolTipText((String) action.getValue(Action.SHORT_DESCRIPTION));
     
    558548                            if (e.getClickCount()>1) {
    559549                                performTagAdding();
    560                                 if (autoCloseActionListener!=null)
    561                                     autoCloseActionListener.actionPerformed(null);
     550                                buttonAction(0, null); // emulate OK click and close the dialog
    562551                            }
    563552                            // add tags on Shift-Click
     
    576565                JPanel tagPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
    577566                tagPanel.add(tagLabel);
    578                 add(tagPanel, GBC.eol().fill(GBC.HORIZONTAL));
     567                mainPanel.add(tagPanel, GBC.eol().fill(GBC.HORIZONTAL));
    579568            }
    580569        }
     
    597586            lastAddValue = value;
    598587            recentTags.put(new Tag(key, value), null);
     588            commandCount++;
    599589            Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, value));
    600590            changedKey = key;
    601591        }
     592       
     593       
     594        public void undoAllTagsAdding() {
     595            Main.main.undoRedo.undo(commandCount);
     596        }
     597
    602598
    603599        private void disableTagIfNeeded(final Tag t, final JosmAction action) {
     
    612608        }
    613609
    614         /**
    615          * @param autoCloseActionListener will be called when we need to close the entire dialog
    616          */
    617         public void setCloseActionListener(ActionListener autoCloseActionListener) {
    618             this.autoCloseActionListener = autoCloseActionListener;
    619         }
    620     }
    621 }
    622    
    623    
     610    }
     611 }
Note: See TracChangeset for help on using the changeset viewer.