Changeset 3214 in josm


Ignore:
Timestamp:
02.05.2010 18:12:34 (22 months 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.