Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java	(revision 2047)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java	(revision 2048)
@@ -66,6 +66,4 @@
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
 import org.openstreetmap.josm.gui.SideButton;
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionCache;
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionList;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
@@ -75,4 +73,6 @@
 import org.openstreetmap.josm.gui.tagging.TagEditorModel;
 import org.openstreetmap.josm.gui.tagging.TagTable;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
 import org.openstreetmap.josm.io.OsmApi;
 import org.openstreetmap.josm.io.OsmServerObjectReader;
@@ -125,5 +125,5 @@
         //
         acCache = AutoCompletionCache.getCacheForLayer(getLayer());
-        acCache.initFromJOSMDataset();
+        acCache.initFromDataSet();
         acList = new AutoCompletionList();
 
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberRoleCellEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberRoleCellEditor.java	(revision 2047)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberRoleCellEditor.java	(revision 2048)
@@ -9,9 +9,9 @@
 import javax.swing.table.TableCellEditor;
 
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionCache;
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionItemPritority;
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionList;
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionListItem;
 import org.openstreetmap.josm.gui.tagging.AutoCompletingTextField;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionItemPritority;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionListItem;
 
 public class MemberRoleCellEditor extends AbstractCellEditor implements TableCellEditor {
Index: trunk/src/org/openstreetmap/josm/gui/tagging/AutoCompletingTextField.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/AutoCompletingTextField.java	(revision 2047)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/AutoCompletingTextField.java	(revision 2048)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.gui.tagging;
 
+import java.awt.Component;
 import java.awt.event.FocusAdapter;
 import java.awt.event.FocusEvent;
@@ -8,4 +9,5 @@
 import java.util.logging.Logger;
 
+import javax.swing.ComboBoxEditor;
 import javax.swing.JTextField;
 import javax.swing.text.AttributeSet;
@@ -14,5 +16,5 @@
 import javax.swing.text.PlainDocument;
 
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionList;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
 
 /**
@@ -25,5 +27,5 @@
  *
  */
-public class AutoCompletingTextField extends JTextField  {
+public class AutoCompletingTextField extends JTextField implements ComboBoxEditor {
 
     static private Logger logger = Logger.getLogger(AutoCompletingTextField.class.getName());
@@ -54,5 +56,22 @@
                 return;
             }
+
             String currentText = getText(0, getLength());
+            // if the text starts with a number we don't autocomplete
+            //
+            try {
+                Long.parseLong(str);
+                if (currentText.length() == 0) {
+                    // we don't autocomplete on numbers
+                    super.insertString(offs, str, a);
+                    return;
+                }
+                Long.parseLong(currentText);
+                super.insertString(offs, str, a);
+                return;
+            } catch(NumberFormatException e) {
+                // either the new text or the current text isn't a number. We continue with
+                // autocompletion
+            }
             String prefix = currentText.substring(0, offs);
             autoCompletionList.applyFilter(prefix+str);
@@ -150,3 +169,22 @@
         this.autoCompletionList = autoCompletionList;
     }
+
+    public Component getEditorComponent() {
+        return this;
+    }
+
+    public Object getItem() {
+        return getText();
+    }
+
+    public void setItem(Object anObject) {
+        if (anObject == null) {
+            setText("");
+        } else {
+            setText(anObject.toString());
+        }
+
+    }
+
+
 }
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TagCellEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TagCellEditor.java	(revision 2047)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TagCellEditor.java	(revision 2048)
@@ -9,8 +9,8 @@
 import javax.swing.table.TableCellEditor;
 
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionCache;
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionItemPritority;
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionList;
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionListItem;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionItemPritority;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionListItem;
 
 /**
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorPanel.java	(revision 2047)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorPanel.java	(revision 2048)
@@ -20,7 +20,7 @@
 import javax.swing.event.ListSelectionListener;
 
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionCache;
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionList;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
 import org.openstreetmap.josm.tools.ImageProvider;
 
@@ -228,5 +228,5 @@
         //
         acCache = AutoCompletionCache.getCacheForLayer(layer);
-        acCache.initFromJOSMDataset();
+        acCache.initFromDataSet();
         acList = new AutoCompletionList();
 
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TagTable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TagTable.java	(revision 2047)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TagTable.java	(revision 2048)
@@ -34,6 +34,6 @@
 
 import org.openstreetmap.josm.gui.dialogs.relation.RunnableAction;
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionCache;
-import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionList;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
 
 /**
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 2047)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 2048)
@@ -18,9 +18,8 @@
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Set;
+import java.util.TreeSet;
 
 import javax.swing.AbstractAction;
@@ -45,4 +44,8 @@
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.QuadStateCheckBox;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionItemPritority;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
 import org.openstreetmap.josm.io.MirroredInputStream;
 import org.openstreetmap.josm.tools.GBC;
@@ -66,4 +69,13 @@
 
     public static abstract class Item {
+        protected void initAutoCompletionField(AutoCompletingTextField field, String key) {
+            OsmDataLayer layer = Main.main.getEditLayer();
+            if (layer == null) return;
+            AutoCompletionCache cache = AutoCompletionCache.getCacheForLayer(layer);
+            AutoCompletionList list = new AutoCompletionList();
+            cache.populateWithValues(list, false /* don't append */);
+            field.setAutoCompletionList(list);
+        }
+
         public boolean focus = false;
         abstract boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel);
@@ -73,21 +85,19 @@
 
     public static class Usage {
-        Set<String> values;
-        Boolean hadKeys = false;
-        Boolean hadEmpty = false;
-        public Boolean allSimilar()
-        {
+        TreeSet<String> values;
+        boolean hadKeys = false;
+        boolean hadEmpty = false;
+        public boolean hasUniqueValue() {
             return values.size() == 1 && !hadEmpty;
         }
-        public Boolean unused()
-        {
+
+        public boolean unused() {
             return values.size() == 0;
         }
-        public String getFirst()
-        {
-            return (String)(values.toArray()[0]);
-        }
-        public Boolean hadKeys()
-        {
+        public String getFirst() {
+            return values.first();
+        }
+
+        public boolean hadKeys() {
             return hadKeys;
         }
@@ -98,5 +108,5 @@
     static Usage determineTextUsage(Collection<OsmPrimitive> sel, String key) {
         Usage returnValue = new Usage();
-        returnValue.values = new HashSet<String>();
+        returnValue.values = new TreeSet<String>();
         for (OsmPrimitive s : sel) {
             String v = s.get(key);
@@ -106,5 +116,5 @@
                 returnValue.hadEmpty = true;
             }
-            returnValue.hadKeys = returnValue.hadKeys | s.hasKeys();
+            returnValue.hadKeys = ! returnValue.values.isEmpty() | returnValue.hadEmpty;
         }
         return returnValue;
@@ -114,5 +124,5 @@
 
         Usage returnValue = new Usage();
-        returnValue.values = new HashSet<String>();
+        returnValue.values = new TreeSet<String>();
         for (OsmPrimitive s : sel) {
             returnValue.values.add(OsmUtils.getNamedOsmBoolean(s.get(key)));
@@ -133,29 +143,35 @@
         private JComponent value;
 
+
         @Override public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
 
             // find out if our key is already used in the selection.
             Usage usage = determineTextUsage(sel, key);
-            if (usage.unused())
-            {
-                value = new JTextField();
+            if (usage.unused()){
+                AutoCompletingTextField textField = new AutoCompletingTextField();
+                initAutoCompletionField(textField, key);
                 if (use_last_as_default && lastValue.containsKey(key)) {
-                    ((JTextField)value).setText(lastValue.get(key));
+                    textField.setText(lastValue.get(key));
                 } else {
-                    ((JTextField)value).setText(default_);
-                }
+                    textField.setText(default_);
+                }
+                value = textField;
                 originalValue = null;
-            } else if (usage.allSimilar()) {
+            } else if (usage.hasUniqueValue()) {
                 // all objects use the same value
-                value = new JTextField();
-                for (String s : usage.values) {
-                    ((JTextField) value).setText(s);
-                }
-                originalValue = ((JTextField)value).getText();
+                AutoCompletingTextField textField = new AutoCompletingTextField();
+                initAutoCompletionField(textField, key);
+                textField.setText(usage.getFirst());
+                value = textField;
+                originalValue = usage.getFirst();
             } else {
                 // the objects have different values
-                value = new JComboBox(usage.values.toArray());
-                ((JComboBox)value).setEditable(true);
-                ((JComboBox)value).getEditor().setItem(DIFFERENT);
+                AutoCompletingTextField textField = new AutoCompletingTextField();
+                initAutoCompletionField(textField, key);
+                JComboBox comboBox = new JComboBox(usage.values.toArray());
+                comboBox.setEditable(true);
+                comboBox.setEditor(textField);
+                comboBox.getEditor().setItem(DIFFERENT);
+                value=comboBox;
                 originalValue = DIFFERENT;
             }
@@ -300,6 +316,5 @@
 
             lhm = new LinkedHashMap<String,String>();
-            if (!usage.allSimilar() && !usage.unused())
-            {
+            if (!usage.hasUniqueValue() && !usage.unused()){
                 lhm.put(DIFFERENT, DIFFERENT);
             }
@@ -309,6 +324,5 @@
                                 tr(display_array[i]) : display_array[i]);
             }
-            if(!usage.unused())
-            {
+            if(!usage.unused()){
                 for (String s : usage.values) {
                     if (!lhm.containsKey(s)) {
@@ -326,22 +340,23 @@
             combo = new JComboBox(lhm.values().toArray());
             combo.setEditable(editable);
-            if (usage.allSimilar() && !usage.unused())
-            {
+            AutoCompletingTextField tf = new AutoCompletingTextField();
+            initAutoCompletionField(tf, key);
+            tf.getAutoCompletionList().add(Arrays.asList(display_array), AutoCompletionItemPritority.IS_IN_STANDARD);
+            combo.setEditor(tf);
+
+            if (usage.hasUniqueValue() && !usage.unused()){
                 originalValue=usage.getFirst();
                 combo.setSelectedItem(lhm.get(originalValue));
             }
             // use default only in case it is a totally new entry
-            else if(default_ != null && !usage.hadKeys())
-            {
+            else if(default_ != null && !usage.hadKeys()) {
                 combo.setSelectedItem(default_);
                 originalValue=DIFFERENT;
             }
-            else if(usage.unused())
-            {
+            else if(usage.unused()){
                 combo.setSelectedItem("");
                 originalValue="";
             }
-            else
-            {
+            else{
                 combo.setSelectedItem(DIFFERENT);
                 originalValue=DIFFERENT;
@@ -628,11 +643,13 @@
         if (data == null)
             return null;
+        OsmDataLayer layer = Main.main.getEditLayer();
+        if (layer != null) {
+            AutoCompletionCache.getCacheForLayer(layer).initFromDataSet();
+        }
         PresetPanel p = new PresetPanel();
         LinkedList<Item> l = new LinkedList<Item>();
-        if(types != null)
-        {
+        if(types != null){
             JPanel pp = new JPanel();
-            for(String t : types)
-            {
+            for(String t : types){
                 JLabel la = new JLabel(ImageProvider.get("Mf_" + t));
                 la.setToolTipText(tr("Elements of type {0} are supported.", tr(t)));
@@ -642,10 +659,8 @@
         }
 
-        for (Item i : data)
-        {
+        for (Item i : data){
             if(i instanceof Link) {
                 l.add(i);
-            } else
-            {
+            } else {
                 if(i.addToPanel(p, selected)) {
                     p.hasElements = true;
@@ -683,5 +698,7 @@
                             true);
                     contentConstraints = GBC.eol().fill().insets(5,10,5,0);
-                    setupDialog(content, new String[] {"ok.png", "cancel.png" });
+                    setButtonIcons(new String[] {"ok.png", "cancel.png" });
+                    setContent(content);
+                    setupDialog();
                     buttons.get(0).setEnabled(!disableApply);
                     buttons.get(0).setToolTipText(title);
Index: trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionCache.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionCache.java	(revision 2048)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionCache.java	(revision 2048)
@@ -0,0 +1,254 @@
+package org.openstreetmap.josm.gui.tagging.ac;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
+
+/**
+ * AutoCompletionCache temporarily holds a cache of keys with a list of
+ * possible auto completion values for each key.
+ *
+ * The cache can initialize itself from the current JOSM data set such that
+ * <ol>
+ *   <li>any key used in a tag in the data set is part of the key list in the cache</li>
+ *   <li>any value used in a tag for a specific key is part of the autocompletion list of
+ *     this key</li>
+ * </ol>
+ *
+ * Building up auto completion lists should not
+ * slow down tabbing from input field to input field. Looping through the complete
+ * data set in order to build up the auto completion list for a specific input
+ * field is not efficient enough, hence this cache.
+ *
+ */
+public class AutoCompletionCache {
+    static private final Logger logger = Logger.getLogger(AutoCompletionCache.class.getName());
+
+    private static HashMap<OsmDataLayer, AutoCompletionCache> caches;
+
+    static {
+        caches = new HashMap<OsmDataLayer, AutoCompletionCache>();
+        Layer.listeners.add(new LayerChangeListener() {
+            public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+                // do nothing
+            }
+
+            public void layerAdded(Layer newLayer) {
+                // do noting
+            }
+
+            public void layerRemoved(Layer oldLayer) {
+                if (oldLayer instanceof OsmDataLayer) {
+                    caches.remove(oldLayer);
+                }
+            }
+        }
+        );
+    }
+
+    static public AutoCompletionCache getCacheForLayer(OsmDataLayer layer) {
+        AutoCompletionCache cache = caches.get(layer);
+        if (cache == null) {
+            cache = new AutoCompletionCache(layer);
+            caches.put(layer, cache);
+        }
+        return cache;
+    }
+
+
+    /** the cached tags give by a tag key and a list of values for this tag*/
+    private HashMap<String, Set<String>> tagCache;
+    /** the cached list of member roles */
+    private  Set<String> roleCache;
+    /** the cache of all tag values */
+    private  Set<String> allTagValues;
+    /**  the layer this cache is built for */
+    private OsmDataLayer layer;
+
+
+    /**
+     * constructor
+     */
+    public AutoCompletionCache(OsmDataLayer layer) {
+        tagCache = new HashMap<String, Set<String>>();
+        roleCache = new HashSet<String>();
+        allTagValues = new HashSet<String>();
+        this.layer = layer;
+    }
+
+    public AutoCompletionCache() {
+        this(null);
+    }
+
+    /**
+     * make sure, <code>key</code> is in the cache
+     *
+     * @param key  the key
+     */
+    protected void cacheKey(String key) {
+        if (tagCache.containsKey(key))
+            return;
+        tagCache.put(key, new HashSet<String>());
+    }
+
+    /**
+     * make sure, value is one of the auto completion values allowed for key
+     *
+     * @param key the key
+     * @param value the value
+     */
+    protected void cacheValue(String key, String value) {
+        cacheKey(key);
+        tagCache.get(key).add(value);
+        allTagValues.add(value);
+    }
+
+    /**
+     * make sure, the keys and values of all tags held by primitive are
+     * in the auto completion cache
+     *
+     * @param primitive an OSM primitive
+     */
+    protected void cachePrimitive(OsmPrimitive primitive) {
+        for (String key: primitive.keySet()) {
+            String value = primitive.get(key);
+            cacheValue(key, value);
+        }
+    }
+
+    /**
+     * Caches all member roles of the relation <code>relation</code>
+     *
+     * @param relation the relation
+     */
+    protected void cacheRelationMemberRoles(Relation relation){
+        for (RelationMember m: relation.getMembers()) {
+            if (m.hasRole() && !roleCache.contains(m.getRole())) {
+                roleCache.add(m.getRole());
+            }
+        }
+    }
+
+    /**
+     * initializes the cache from the primitives in the dataset of
+     * {@see #layer}
+     *
+     */
+    public void initFromDataSet() {
+        tagCache = new HashMap<String, Set<String>>();
+        if (layer == null)
+            return;
+        Collection<OsmPrimitive> ds = layer.data.allNonDeletedPrimitives();
+        for (OsmPrimitive primitive : ds) {
+            cachePrimitive(primitive);
+        }
+        for (Relation relation : layer.data.relations) {
+            if (relation.incomplete || relation.isDeleted()) {
+                continue;
+            }
+            cacheRelationMemberRoles(relation);
+        }
+    }
+
+    /**
+     * replies the keys held by the cache
+     *
+     * @return the list of keys held by the cache
+     */
+    public List<String> getKeys() {
+        return new ArrayList<String>(tagCache.keySet());
+    }
+
+    /**
+     * replies the auto completion values allowed for a specific key. Replies
+     * an empty list if key is null or if key is not in {@link #getKeys()}.
+     *
+     * @param key
+     * @return the list of auto completion values
+     */
+    public List<String> getValues(String key) {
+        if (!tagCache.containsKey(key))
+            return new ArrayList<String>();
+        return new ArrayList<String>(tagCache.get(key));
+    }
+
+    /**
+     * Replies the list of member roles
+     *
+     * @return the list of member roles
+     */
+    public List<String> getMemberRoles() {
+        return new ArrayList<String>(roleCache);
+    }
+
+    /**
+     * Populates the an {@see AutoCompletionList} with the currently cached
+     * member roles.
+     *
+     * @param list the list to populate
+     */
+    public void populateWithMemberRoles(AutoCompletionList list) {
+        list.clear();
+        list.add(roleCache, AutoCompletionItemPritority.IS_IN_DATASET);
+    }
+
+    /**
+     * Populates the an {@see AutoCompletionList} with the currently cached
+     * values for a tag
+     *
+     * @param list the list to populate
+     * @param key the tag key
+     * @param append true to add the values to the list; false, to replace the values
+     * in the list by the tag values
+     */
+    public void populateWithTagValues(AutoCompletionList list, String key, boolean append) {
+        if (!append) {
+            list.clear();
+        }
+        list.add(getValues(key), AutoCompletionItemPritority.IS_IN_DATASET);
+    }
+
+    /**
+     * Populates the an {@see AutoCompletionList} with the currently cached
+     * tag keys
+     *
+     * @param list the list to populate
+     * @param append true to add the keys to the list; false, to replace the keys
+     * in the list by the keys in the cache
+     */
+    public void populateWithKeys(AutoCompletionList list, boolean append) {
+        if (!append) {
+            list.clear();
+        }
+        list.add(tagCache.keySet(), AutoCompletionItemPritority.IS_IN_DATASET);
+    }
+
+
+    /**
+     * Populates the an {@see AutoCompletionList} with the currently cached
+     * tag values
+     *
+     * @param list the list to populate
+     * @param append true to add the keys to the list; false, to replace the keys
+     * in the list by the keys in the cache
+     */
+    public void populateWithValues(AutoCompletionList list, boolean append) {
+        if (!append) {
+            list.clear();
+        }
+        list.add(this.allTagValues, AutoCompletionItemPritority.IS_IN_DATASET);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionItemPritority.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionItemPritority.java	(revision 2048)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionItemPritority.java	(revision 2048)
@@ -0,0 +1,23 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.tagging.ac;
+
+public enum AutoCompletionItemPritority implements Comparable<AutoCompletionItemPritority> {
+
+    /** indicates that a value is in the current selection */
+    IS_IN_SELECTION,
+
+    /** indicates that this is a standard value, i.e. a standard tag name
+     *  or a standard value for a given tag name
+     */
+    IS_IN_STANDARD,
+
+
+    /**
+     * indicates that this is an arbitrary value from the data set, i.e.
+     * the value of a tag name=xxx
+     */
+    IS_IN_DATASET,
+
+    /** unknown priority. This is the lowest priority. */
+    UNKNOWN
+}
Index: trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionList.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionList.java	(revision 2048)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionList.java	(revision 2048)
@@ -0,0 +1,303 @@
+package org.openstreetmap.josm.gui.tagging.ac;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.JTable;
+import javax.swing.table.AbstractTableModel;
+
+/**
+ * AutoCompletionList manages a list of {@see AutoCompletionListItem}s.
+ * 
+ * The list is sorted, items with higher priority first, then according to lexicographic order
+ * on the value of the {@see AutoCompletionListItem}.
+ * 
+ * AutoCompletionList maintains two views on the list of {@see AutoCompletionListItem}s.
+ * <ol>
+ *   <li>the bare, unfiltered view which includes all items</li>
+ *   <li>a filtered view, which includes only items which match a current filter expression</li>
+ * </ol>
+ * 
+ * AutoCompletionList is an {@link AbstractTableModel} which serves the list of filtered
+ * items to a {@link JTable}.
+ * 
+ */
+public class AutoCompletionList extends AbstractTableModel {
+
+    /** the bare list of AutoCompletionItems */
+    private ArrayList<AutoCompletionListItem> list = null;
+    /**  the filtered list of AutoCompletionItems */
+    private ArrayList<AutoCompletionListItem> filtered = null;
+    /** the filter expression */
+    private String filter = null;
+
+    /**
+     * constructor
+     */
+    public AutoCompletionList() {
+        list = new ArrayList<AutoCompletionListItem>();
+        filtered = new ArrayList<AutoCompletionListItem>();
+    }
+
+
+    /**
+     * applies a filter expression to the list of {@see AutoCompletionListItem}s.
+     * 
+     * The matching criterion is a case insensitive substring match.
+     * 
+     * @param filter  the filter expression; must not be null
+     * 
+     * @exception IllegalArgumentException thrown, if filter is null
+     */
+    public void applyFilter(String filter) {
+        if (filter == null)
+            throw new IllegalArgumentException("argument 'filter' must not be null");
+        this.filter = filter;
+        filter();
+    }
+
+    /**
+     * clears the current filter
+     * 
+     */
+    public void clearFilter() {
+        filter = null;
+        filter();
+    }
+
+    /**
+     * @return the current filter expression; null, if no filter expression is set
+     */
+    public String getFilter() {
+        return filter;
+    }
+
+
+    /**
+     * adds an AutoCompletionListItem to the list. Only adds the item if it
+     * is not null and if not in the list yet.
+     * 
+     * @param item the item
+     */
+    public void add(AutoCompletionListItem item) {
+        if (item == null)
+            return;
+        appendOrUpdatePriority(item);
+        sort();
+        filter();
+    }
+
+
+    /**
+     * adds another AutoCompletionList to this list. An item is only
+     * added it is not null and if it does not exist in the list yet.
+     * 
+     * @param other another auto completion list; must not be null
+     * @exception IllegalArgumentException thrown, if other is null
+     */
+    public void add(AutoCompletionList other) {
+        if (other == null)
+            throw new IllegalArgumentException("argument 'other' must not be null");
+        for (AutoCompletionListItem item : other.list) {
+            appendOrUpdatePriority(item);
+        }
+        sort();
+        filter();
+    }
+
+
+    /**
+     * adds a list of AutoCompletionListItem to this list. Only items which
+     * are not null and which do not exist yet in the list are added.
+     * 
+     * @param other a list of AutoCompletionListItem; must not be null
+     * @exception IllegalArgumentException thrown, if other is null
+     */
+    public void add(List<AutoCompletionListItem> other) {
+        if (other == null)
+            throw new IllegalArgumentException("argument 'other' must not be null");
+        for (AutoCompletionListItem toadd : other) {
+            appendOrUpdatePriority(toadd);
+        }
+        sort();
+        filter();
+    }
+
+    /**
+     * adds a list of strings to this list. Only strings which
+     * are not null and which do not exist yet in the list are added.
+     * 
+     * @param value a list of strings to add
+     * @param priority the priority to use
+     */
+    public void add(Collection<String> values, AutoCompletionItemPritority priority) {
+        if (values == null) return;
+        for (String value: values) {
+            if (value == null) {
+                continue;
+            }
+            AutoCompletionListItem item = new AutoCompletionListItem(value,priority);
+            appendOrUpdatePriority(item);
+
+        }
+        sort();
+        filter();
+    }
+
+    protected void appendOrUpdatePriority(AutoCompletionListItem toadd) {
+        AutoCompletionListItem item = lookup(toadd.getValue());
+        if (item == null) {
+            // new item does not exist yet. Add it to the list
+            //
+            list.add(toadd);
+        } else {
+            // new item already exists. Update priority if necessary
+            //
+            if (toadd.getPriority().compareTo(item.getPriority()) < 0) {
+                item.setPriority(toadd.getPriority());
+            }
+        }
+    }
+
+    /**
+     * checks whether a specific item is already in the list. Matches for the
+     * the value <strong>and</strong> the priority of the item
+     * 
+     * @param item the item to check
+     * @return true, if item is in the list; false, otherwise
+     */
+    public boolean contains(AutoCompletionListItem item) {
+        if (item == null)
+            return false;
+        return list.contains(item);
+    }
+
+    /**
+     * checks whether an item with the given value is already in the list. Ignores
+     * priority of the items.
+     * 
+     * @param value the value of an auto completion item
+     * @return true, if value is in the list; false, otherwise
+     */
+    public boolean contains(String value) {
+        if (value == null)
+            return false;
+        for (AutoCompletionListItem item: list) {
+            if (item.getValue().equals(value))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * 
+     * @param value a specific value
+     * @return  the auto completion item for this value; null, if there is no
+     *   such auto completion item
+     */
+    public AutoCompletionListItem lookup(String value) {
+        if (value == null)
+            return null;
+        for (AutoCompletionListItem item : list) {
+            if (item.getValue().equals(value))
+                return item;
+        }
+        return null;
+    }
+
+
+    /**
+     * removes the auto completion item with key <code>key</code>
+     * @param key  the key;
+     */
+    public void remove(String key) {
+        if (key == null)
+            return;
+        for (int i=0;i< list.size();i++) {
+            AutoCompletionListItem item = list.get(i);
+            if (item.getValue().equals(key)) {
+                list.remove(i);
+                return;
+            }
+        }
+    }
+
+    /**
+     * sorts the list
+     */
+    protected void sort() {
+        Collections.sort(list);
+    }
+
+    protected void filter() {
+        filtered.clear();
+        if (filter == null) {
+            // Collections.copy throws an exception "Source does not fit in dest"
+            // Collections.copy(filtered, list);
+            filtered.ensureCapacity(list.size());
+            for (AutoCompletionListItem item: list) {
+                filtered.add(item);
+            }
+            return;
+        }
+
+        // apply the pattern to list of possible values. If it matches, add the
+        // value to the list of filtered values
+        //
+        for (AutoCompletionListItem item : list) {
+            if (item.getValue().startsWith(filter)) {
+                filtered.add(item);
+            }
+        }
+        fireTableDataChanged();
+    }
+
+    /**
+     * replies the number of filtered items
+     * 
+     * @return the number of filtered items
+     */
+    public int getFilteredSize() {
+        return this.filtered.size();
+    }
+
+    /**
+     * replies the idx-th item from the list of filtered items
+     * @param idx the index; must be in the range 0<= idx < {@see #getFilteredSize()}
+     * @return the item
+     * 
+     * @exception IndexOutOfBoundsException thrown, if idx is out of bounds
+     */
+    public AutoCompletionListItem getFilteredItem(int idx) {
+        if (idx < 0 || idx >= getFilteredSize())
+            throw new IndexOutOfBoundsException("idx out of bounds. idx=" + idx);
+        return filtered.get(idx);
+    }
+
+
+    /**
+     * removes all elements from the auto completion list
+     * 
+     */
+    public void clear() {
+        list.clear();
+        fireTableDataChanged();
+    }
+
+
+    public int getColumnCount() {
+        return 1;
+    }
+
+    public int getRowCount() {
+
+        return list == null ? 0 : getFilteredSize();
+    }
+
+    public Object getValueAt(int rowIndex, int columnIndex) {
+        return list == null ? null : getFilteredItem(rowIndex);
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionListItem.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionListItem.java	(revision 2048)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionListItem.java	(revision 2048)
@@ -0,0 +1,122 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.tagging.ac;
+
+/**
+ * Represents an entry in the list of auto completion values.
+ * 
+ *  An AutoCompletionListItem has a <em>priority</em> and a <em>value</em>.
+ * 
+ *  The priority helps to sort the auto completion items according to their importance. For instance,
+ *  in an auto completion list for tag names, standard tag names would be assigned a higher
+ *  priority than arbitrary tag names present in the current data set. There are three priority levels,
+ *  {@see AutoCompletionItemPritority}.
+ *
+ * The value is a string which will be displayed in the auto completion list.
+ * 
+ */
+public class AutoCompletionListItem implements Comparable<AutoCompletionListItem>{
+
+    /** the pritority of this item */
+    private  AutoCompletionItemPritority priority;
+    /** the value of this item */
+    private String value;
+
+    /**
+     * constructor
+     */
+    public AutoCompletionListItem() {
+        value = "";
+        priority = AutoCompletionItemPritority.UNKNOWN;
+    }
+
+    public AutoCompletionListItem(String value, AutoCompletionItemPritority priority) {
+        this.value = value;
+        this.priority = priority;
+    }
+
+    /**
+     * 
+     * @return the priority
+     */
+    public AutoCompletionItemPritority getPriority() {
+        return priority;
+    }
+
+    /**
+     * sets the priority
+     * @param priority  the priority
+     */
+    public void setPriority(AutoCompletionItemPritority priority) {
+        this.priority = priority;
+    }
+
+    /**
+     * 
+     * @return the value
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * sets the value
+     * @param value the value; must not be null
+     * @exception IllegalArgumentException thrown, if value if null
+     */
+    public void setValue(String value) {
+        if (value == null)
+            throw new IllegalArgumentException("argument 'value' must not be null");
+        this.value = value;
+    }
+
+    @Override public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("<AutoCompletionItemPritority: ");
+        sb.append("value='");
+        sb.append(value);
+        sb.append("',");
+        sb.append("priority='");
+        sb.append(priority.toString());
+        sb.append("'>");
+        return sb.toString();
+    }
+
+    @Override public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result
+        + ((priority == null) ? 0 : priority.hashCode());
+        result = prime * result + ((value == null) ? 0 : value.hashCode());
+        return result;
+    }
+
+    @Override public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final AutoCompletionListItem other = (AutoCompletionListItem)obj;
+        if (priority == null) {
+            if (other.priority != null)
+                return false;
+        } else if (!priority.equals(other.priority))
+            return false;
+        if (value == null) {
+            if (other.value != null)
+                return false;
+        } else if (!value.equals(other.value))
+            return false;
+        return true;
+    }
+
+
+    public int compareTo(AutoCompletionListItem other) {
+        int ret = this.priority.compareTo(other.priority);
+        if (ret != 0)
+            return ret;
+        else
+            return this.value.compareTo(other.value);
+    }
+}
