Changeset 3214 in josm for trunk/src/org


Ignore:
Timestamp:
2010-05-02T18:12:34+02:00 (15 years ago)
Author:
bastiK
Message:

autocompletion cleanup - fixes #2729

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

Legend:

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

    r3210 r3214  
    2626import java.util.HashMap;
    2727import java.util.HashSet;
     28import java.util.Iterator;
    2829import java.util.List;
    2930import java.util.Map;
     
    8182import org.openstreetmap.josm.gui.tagging.TaggingPreset;
    8283import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingComboBox;
     84import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
     85import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionListItem;
    8386import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
    8487import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
     
    148151    private final Map<String, Map<String, Integer>> valueCount = new TreeMap<String, Map<String, Integer>>();
    149152
    150     Comparator<String> defaultKeyComparator = String.CASE_INSENSITIVE_ORDER;
    151     Comparator<String> defaultValueComparator = String.CASE_INSENSITIVE_ORDER;
     153    Comparator<AutoCompletionListItem> defaultACItemComparator = new Comparator<AutoCompletionListItem>() {
     154        public int compare(AutoCompletionListItem o1, AutoCompletionListItem o2) {
     155            return String.CASE_INSENSITIVE_ORDER.compare(o1.getValue(), o2.getValue());
     156        }
     157    };
    152158
    153159    private DataSetListenerAdapter dataChangedAdapter = new DataSetListenerAdapter(this);
     
    191197
    192198        AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager();
    193 
     199        List<AutoCompletionListItem> keyList = autocomplete.getKeys();
     200        Collections.sort(keyList, defaultACItemComparator);
     201       
    194202        final AutoCompletingComboBox keys = new AutoCompletingComboBox();
    195         keys.setPossibleItems(autocomplete.getKeys(defaultKeyComparator));
     203        keys.setPossibleACItems(keyList);
    196204        keys.setEditable(true);
    197205        keys.setSelectedItem(key);
     
    209217                if (c instanceof JLabel) {
    210218                    String str = null;
    211                     str=(String) value;
     219                    str=((AutoCompletionListItem) value).getValue();
    212220                    if (valueCount.containsKey(objKey)){
    213221                        Map<String, Integer> m=valueCount.get(objKey);
     
    223231        });
    224232        values.setEditable(true);
    225         values.setPossibleItems(autocomplete.getValues(key, defaultValueComparator));
     233       
     234        List<AutoCompletionListItem> valueList = autocomplete.getValues(key);
     235        Collections.sort(valueList, defaultACItemComparator);
     236       
     237        values.setPossibleACItems(valueList);
    226238        Map<String, Integer> m=(Map<String, Integer>)propertyData.getValueAt(row, 1);
    227239        final String selection= m.size()!=1?tr("<different>"):m.entrySet().iterator().next().getKey();
     
    344356        final AutoCompletingComboBox keys = new AutoCompletingComboBox();
    345357        AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager();
    346         List<String> usedKeys =
    347                 new ArrayList<String>(autocomplete.getKeys(defaultKeyComparator));
    348         for (int i = 0; i < propertyData.getRowCount(); ++i) {
    349             usedKeys.remove(propertyData.getValueAt(i, 0));
    350         }
    351         keys.setPossibleItems(usedKeys);
     358        List<AutoCompletionListItem> keyList = autocomplete.getKeys();
     359
     360        // remove the object's tag keys from the list
     361        Iterator<AutoCompletionListItem> iter = keyList.iterator();
     362        while (iter.hasNext()) {
     363            AutoCompletionListItem item = iter.next();
     364            for (int i = 0; i < propertyData.getRowCount(); ++i) {
     365                if (item.getValue().equals(propertyData.getValueAt(i, 0))) {
     366                    iter.remove();
     367                    break;
     368                }
     369            }
     370        }
     371
     372        Collections.sort(keyList, defaultACItemComparator);
     373        keys.setPossibleACItems(keyList);
    352374        keys.setEditable(true);
    353375
     
    397419            @Override public void focusGained(FocusEvent e) {
    398420                String key = keys.getEditor().getItem().toString();
    399                 values.setPossibleItems(autocomplete.getValues(key, defaultValueComparator));
     421               
     422                List<AutoCompletionListItem> valueList = autocomplete.getValues(key);
     423                Collections.sort(valueList, defaultACItemComparator);
     424
     425                values.setPossibleACItems(valueList);
    400426                objKey=key;
    401427            }
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java

    r3210 r3214  
    306306                    public void focusGained(FocusEvent e) {
    307307                        AutoCompletionList list = tfRole.getAutoCompletionList();
     308                        list.clear();
    308309                        getLayer().data.getAutoCompletionManager().populateWithMemberRoles(list);
    309310                    }
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberRoleCellEditor.java

    r3210 r3214  
    4343        String role = (String)value;
    4444        editor.setText(role);
     45        autoCompletionList.clear();
    4546        ds.getAutoCompletionManager().populateWithMemberRoles(autoCompletionList);
    4647        return editor;
  • trunk/src/org/openstreetmap/josm/gui/tagging/TagTable.java

    r3210 r3214  
    409409        if (autocomplete == null) {
    410410            logger.warning("argument autocomplete should not be null. Aborting.");
     411            Thread.dumpStack();
    411412            return;
    412413        }
  • trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingComboBox.java

    r3210 r3214  
    22package org.openstreetmap.josm.gui.tagging.ac;
    33
     4import java.awt.Component;
    45import java.awt.event.FocusEvent;
    56import java.awt.event.FocusListener;
    67import java.util.Collection;
    78
     9import javax.swing.ComboBoxEditor;
    810import javax.swing.ComboBoxModel;
    911import javax.swing.DefaultComboBoxModel;
    1012import javax.swing.JComboBox;
     13import javax.swing.JLabel;
     14import javax.swing.JList;
     15import javax.swing.ListCellRenderer;
    1116import javax.swing.text.AttributeSet;
    1217import javax.swing.text.BadLocationException;
     
    4146
    4247        @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
    43             if(selecting || (offs == 0 && str.equals(getText(0, getLength()))))
     48            if (selecting || (offs == 0 && str.equals(getText(0, getLength()))))
    4449                return;
    4550            boolean initial = (offs == 0 && getLength() == 0 && str.length() > 1);
     
    5863            int end = start;
    5964            String curText = getText(0, size);
     65           
     66            // if the text starts with a number we don't autocomplete
     67            //
     68            try {
     69                Long.parseLong(str);
     70                if (curText.length() == 0) {
     71                    // we don't autocomplete on numbers
     72                    return;
     73                }
     74                Long.parseLong(curText);
     75                return;
     76            } catch (NumberFormatException e) {
     77                // either the new text or the current text isn't a number. We continue with
     78                // autocompletion
     79            }
     80           
    6081            // lookup and select a matching item
    6182            Object item = lookupItem(curText);
    6283            setSelectedItem(item);
    63             if(initial) {
     84            if (initial) {
    6485                start = 0;
    6586            }
    6687            if (item != null) {
    67                 String newText = item.toString();
    68                 if(!newText.equals(curText))
     88                String newText = ((AutoCompletionListItem) item).getValue();
     89                if (!newText.equals(curText))
    6990                {
    7091                    selecting = true;
     
    89110        private Object lookupItem(String pattern) {
    90111            ComboBoxModel model = comboBox.getModel();
     112            AutoCompletionListItem bestItem = null;
    91113            for (int i = 0, n = model.getSize(); i < n; i++) {
    92                 Object currentItem = model.getElementAt(i);
    93                 if (currentItem.toString().startsWith(pattern))
    94                     return currentItem;
    95             }
    96             return null;
     114                AutoCompletionListItem currentItem = (AutoCompletionListItem) model.getElementAt(i);;
     115                if (currentItem.getValue().startsWith(pattern)) {
     116                    if (bestItem == null || currentItem.getPriority().compareTo(bestItem.getPriority()) > 0) {
     117                        bestItem = currentItem;
     118                    }
     119                }
     120            }
     121            return bestItem; // may be null
    97122        }
    98123    }
    99124
    100125    public AutoCompletingComboBox() {
     126        setRenderer(new AutoCompleteListCellRenderer());
    101127        final JTextComponent editor = (JTextComponent) this.getEditor().getEditorComponent();
    102128        editor.setDocument(new AutoCompletingComboBoxDocument(this));
     
    112138    }
    113139
     140    /**
     141     * Convert the selected item into a String
     142     * that can be edited in the editor component.
     143     *
     144     * @param editor    the editor
     145     * @param item      excepts AutoCompletionListItem, String and null
     146     */
     147    @Override public void configureEditor(ComboBoxEditor editor, Object item) {
     148        if (item == null) {
     149            editor.setItem(null);
     150        } else if (item instanceof String) {
     151            editor.setItem(item);
     152        } else if (item instanceof AutoCompletionListItem) {
     153            editor.setItem(((AutoCompletionListItem)item).getValue());
     154        } else
     155            throw new IllegalArgumentException();
     156    }
     157
     158    /**
     159     * Selects a given item in the ComboBox model
     160     * @param item      excepts AutoCompletionListItem, String and null
     161     */
     162    @Override public void setSelectedItem(Object item) {
     163        if (item == null) {
     164            super.setSelectedItem(null);
     165        } else if (item instanceof AutoCompletionListItem) {
     166            super.setSelectedItem(item);
     167        } else if (item instanceof String) {
     168            String s = (String) item;
     169            // find the string in the model or create a new item
     170            for (int i=0; i< getModel().getSize(); i++) {
     171                AutoCompletionListItem acItem = (AutoCompletionListItem) getModel().getElementAt(i);
     172                if (s.equals(acItem.getValue())) {
     173                    super.setSelectedItem(acItem);
     174                    return;
     175                }
     176            }
     177            super.setSelectedItem(new AutoCompletionListItem(s, AutoCompletionItemPritority.UNKNOWN));
     178        } else
     179            throw new IllegalArgumentException();
     180    }
     181
     182    /**
     183     * sets the items of the combobox to the given strings
     184     */
    114185    public void setPossibleItems(Collection<String> elems) {
    115186        DefaultComboBoxModel model = (DefaultComboBoxModel)this.getModel();
     
    117188        model.removeAllElements();
    118189        for (String elem : elems) {
     190            model.addElement(new AutoCompletionListItem(elem, AutoCompletionItemPritority.UNKNOWN));
     191        }
     192        this.getEditor().setItem(oldValue);
     193    }
     194
     195    /**
     196     * sets the items of the combobox to the given AutoCompletionListItems
     197     */
     198    public void setPossibleACItems(Collection<AutoCompletionListItem> elems) {
     199        DefaultComboBoxModel model = (DefaultComboBoxModel)this.getModel();
     200        Object oldValue = this.getEditor().getItem();
     201        model.removeAllElements();
     202        for (AutoCompletionListItem elem : elems) {
    119203            model.addElement(elem);
    120204        }
    121205        this.getEditor().setItem(oldValue);
    122206    }
     207
    123208
    124209    protected boolean isAutocompleteEnabled() {
     
    129214        this.autocompleteEnabled = autocompleteEnabled;
    130215    }
     216
     217    /**
     218     * ListCellRenderer for AutoCompletingComboBox
     219     * renders an AutoCompletionListItem by showing only the string value part
     220     */
     221    public class AutoCompleteListCellRenderer extends JLabel implements ListCellRenderer {
     222
     223        public AutoCompleteListCellRenderer() {
     224            setOpaque(true);
     225        }
     226
     227        public Component getListCellRendererComponent(
     228                JList list,
     229                Object value,
     230                int index,
     231                boolean isSelected,
     232                boolean cellHasFocus)
     233        {
     234            if (isSelected) {
     235                setBackground(list.getSelectionBackground());
     236                setForeground(list.getSelectionForeground());
     237            } else {
     238                setBackground(list.getBackground());
     239                setForeground(list.getForeground());
     240            }
     241
     242            AutoCompletionListItem item = (AutoCompletionListItem) value;
     243            setText(item.getValue());
     244            return this;
     245        }
     246    }
    131247}
  • trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionItemPritority.java

    r3083 r3214  
    22package org.openstreetmap.josm.gui.tagging.ac;
    33
    4 public enum AutoCompletionItemPritority implements Comparable<AutoCompletionItemPritority> {
    5 
    6     /** Indicates that a value is in the current selection. */
    7     IS_IN_SELECTION,
     4/**
     5 * Describes the priority of an item in an autocompletion list.
     6 * The selected flag is currently only used in plugins.
     7 *
     8 * Instances of this class are not modifiable.
     9 */
     10public class AutoCompletionItemPritority implements Comparable<AutoCompletionItemPritority> {
    811
    912    /**
     
    1215     * usually not used by the user.
    1316     */
    14     IS_IN_STANDARD_AND_IN_DATASET,
     17    public static AutoCompletionItemPritority IS_IN_STANDARD_AND_IN_DATASET = new AutoCompletionItemPritority(true, true, false);
     18
     19    /**
     20     * Indicates that this is an arbitrary value from the data set, i.e.
     21     * the value of a tag name=*.
     22     */
     23    public static AutoCompletionItemPritority IS_IN_DATASET = new AutoCompletionItemPritority(true, false, false);
    1524
    1625    /**
     
    1827     * or a standard value for a given tag name (from the presets).
    1928     */
    20     IS_IN_STANDARD,
     29    public static AutoCompletionItemPritority IS_IN_STANDARD = new AutoCompletionItemPritority(false, true, false);
     30   
     31    /**
     32     * Indicates that this is a value from a selected object.
     33     */
     34    public static AutoCompletionItemPritority  IS_IN_SELECTION  = new AutoCompletionItemPritority(false, false, true);
     35
     36    /** Unknown priority. This is the lowest priority. */
     37    public static AutoCompletionItemPritority UNKNOWN = new AutoCompletionItemPritority(false, false, false);
     38
     39    private final boolean inDataSet;
     40    private final boolean inStandard;
     41    private final boolean selected;
     42
     43    public AutoCompletionItemPritority(boolean inDataSet, boolean inStandard, boolean selected) {
     44        this.inDataSet = inDataSet;
     45        this.inStandard = inStandard;
     46        this.selected = selected;
     47    }
     48
     49    public boolean isInDataSet() {
     50        return inDataSet;
     51    }
     52
     53    public boolean isInStandard() {
     54        return inStandard;
     55    }
     56
     57    public boolean isSelected() {
     58        return selected;
     59    }
    2160
    2261    /**
    23      * Indicates that this is an arbitrary value from the data set, i.e.
    24      * the value of a tag name=*.
     62     * Imposes an ordering on the priorities.
     63     * Currently, being in the current DataSet is worth more than being in the Presets.
    2564     */
    26     IS_IN_DATASET,
     65    public int compareTo(AutoCompletionItemPritority other) {
     66        int sel = new Boolean(selected).compareTo(other.selected);
     67        if (sel != 0) return sel;
    2768
    28     /** Unknown priority. This is the lowest priority. */
    29     UNKNOWN
     69        int ds = new Boolean(inDataSet).compareTo(other.inDataSet);
     70        if (ds != 0) return ds;
     71
     72        int std = new Boolean(inStandard).compareTo(other.inStandard);
     73        if (std != 0) return std;
     74
     75        return 0;
     76    }
     77
     78    /**
     79     * Merges two priorities.
     80     * The resulting priority is always >= the original ones.
     81     */
     82    public AutoCompletionItemPritority mergeWith(AutoCompletionItemPritority other) {
     83        return new AutoCompletionItemPritority(
     84                        inDataSet || other.inDataSet,
     85                        inStandard || other.inStandard,
     86                        selected || other.selected);
     87    }
     88
     89    @Override public String toString() {
     90        return String.format("<Priority; inDataSet: %b, inStandard: %b, selected: %b>", inDataSet, inStandard, selected);
     91    }
    3092}
  • trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionList.java

    r3210 r3214  
    149149    }
    150150
    151     protected void appendOrUpdatePriority(AutoCompletionListItem toadd) {
    152         AutoCompletionListItem item = valutToItemMap.get(toadd.getValue());
     151    protected void appendOrUpdatePriority(AutoCompletionListItem toAdd) {
     152        AutoCompletionListItem item = valutToItemMap.get(toAdd.getValue());
    153153        if (item == null) {
    154154            // new item does not exist yet. Add it to the list
    155             //
    156             list.add(toadd);
    157             valutToItemMap.put(toadd.getValue(), toadd);
     155            list.add(toAdd);
     156            valutToItemMap.put(toAdd.getValue(), toAdd);
    158157        } else {
    159             // new item already exists. Update priority if necessary
    160 
    161             // If it is both in the dataset and in the presets, update the priority.
    162             final AutoCompletionItemPritority IS_IN_DATASET = AutoCompletionItemPritority.IS_IN_DATASET;
    163             final AutoCompletionItemPritority IS_IN_STANDARD = AutoCompletionItemPritority.IS_IN_STANDARD;
    164             if ((toadd.getPriority() == IS_IN_STANDARD && item.getPriority() == IS_IN_DATASET) ||
    165                 (toadd.getPriority() == IS_IN_DATASET && item.getPriority() == IS_IN_STANDARD)) {
    166 
    167                 item.setPriority(AutoCompletionItemPritority.IS_IN_STANDARD_AND_IN_DATASET);
    168             } else {
    169                 if (toadd.getPriority().compareTo(item.getPriority()) < 0) {
    170                     item.setPriority(toadd.getPriority());
    171                 }
    172             }
     158            item.setPriority(item.getPriority().mergeWith(toAdd.getPriority()));
    173159        }
    174160    }
     
    272258    }
    273259
     260    List<AutoCompletionListItem> getList() {
     261        return Collections.unmodifiableList(list);
     262    }
     263
    274264    /**
    275265     * removes all elements from the auto completion list
  • trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionListItem.java

    r3210 r3214  
    112112    public int compareTo(AutoCompletionListItem other) {
    113113        int ret = this.priority.compareTo(other.priority);
     114        ret = -ret; // higher priority items come first in the list
    114115        if (ret != 0)
    115116            return ret;
  • trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionManager.java

    r3213 r3214  
    109109
    110110    protected void cachePrimitives(Collection<? extends OsmPrimitive> primitives) {
    111         if (tagCache == null) {
    112             // We are coming from a DataSetListener event and
    113             // rebuild has not been called yet, so do it now and
    114             // ignore the method parameter.
    115             rebuild();
    116             return;
    117         }
    118111        for (OsmPrimitive primitive : primitives) {
    119112            cachePrimitiveTags(primitive);
     
    204197    }
    205198
    206     public TreeSet<String> getKeys(Comparator<String> c) {
    207         TreeSet<String> ret = new TreeSet<String>(c);
    208         ret.addAll(getDataKeys());
    209         ret.addAll(getPresetKeys());
    210         return ret;
    211     }
    212 
    213199    /**
    214200     * replies the auto completion values allowed for a specific key. Replies
     
    226212    }
    227213
    228     public TreeSet<String> getValues(String key, Comparator<String> c) {
    229         TreeSet<String> ret = new TreeSet<String>(c);
    230         ret.addAll(getDataValues(key));
    231         ret.addAll(getPresetValues(key));
    232         return ret;
    233     }
    234 
    235214    /**
    236215     * Replies the list of member roles
     
    249228     */
    250229    public void populateWithMemberRoles(AutoCompletionList list) {
    251         list.clear();
    252230        list.add(getRoleCache(), AutoCompletionItemPritority.IS_IN_DATASET);
     231    }
     232
     233    /**
     234     * Populates the an {@see AutoCompletionList} with the currently cached
     235     * tag keys
     236     *
     237     * @param list the list to populate
     238     * @param append true to add the keys to the list; false, to replace the keys
     239     * in the list by the keys in the cache
     240     */
     241    public void populateWithKeys(AutoCompletionList list) {
     242        list.add(getPresetKeys(), AutoCompletionItemPritority.IS_IN_STANDARD);
     243        list.add(getDataKeys(), AutoCompletionItemPritority.IS_IN_DATASET);
    253244    }
    254245
     
    263254     */
    264255    public void populateWithTagValues(AutoCompletionList list, String key) {
     256        list.add(getPresetValues(key), AutoCompletionItemPritority.IS_IN_STANDARD);
    265257        list.add(getDataValues(key), AutoCompletionItemPritority.IS_IN_DATASET);
    266         list.add(getPresetValues(key), AutoCompletionItemPritority.IS_IN_STANDARD);
    267     }
    268 
    269     /**
    270      * Populates the an {@see AutoCompletionList} with the currently cached
    271      * tag keys
    272      *
    273      * @param list the list to populate
    274      * @param append true to add the keys to the list; false, to replace the keys
    275      * in the list by the keys in the cache
    276      */
    277     public void populateWithKeys(AutoCompletionList list) {
    278         list.add(getDataKeys(), AutoCompletionItemPritority.IS_IN_DATASET);
    279         list.add(getPresetKeys(), AutoCompletionItemPritority.IS_IN_STANDARD);
     258    }
     259
     260    public List<AutoCompletionListItem> getKeys() {
     261        AutoCompletionList list = new AutoCompletionList();
     262        populateWithKeys(list);
     263        return new ArrayList<AutoCompletionListItem>(list.getList());
     264    }
     265
     266    public List<AutoCompletionListItem> getValues(String key) {
     267        AutoCompletionList list = new AutoCompletionList();
     268        populateWithTagValues(list, key);
     269        return new ArrayList<AutoCompletionListItem>(list.getList());
    280270    }
    281271
     
    286276
    287277    public void primtivesAdded(PrimitivesAddedEvent event) {
     278        if (dirty)
     279            return;
    288280        cachePrimitives(event.getPrimitives());
    289281    }
     
    294286
    295287    public void tagsChanged(TagsChangedEvent event) {
     288        if (dirty)
     289            return;
    296290        Map<String, String> newKeys = event.getPrimitive().getKeys();
    297291        Map<String, String> oldKeys = event.getOriginalKeys();
Note: See TracChangeset for help on using the changeset viewer.