Index: trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
===================================================================
--- trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java	(revision 3210)
@@ -19,4 +19,13 @@
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
+
+/**
+ * A ReverseWayTagCorrector handles necessary corrections of tags
+ * when a way is reversed. E.g. oneway=yes needs to be changed
+ * to oneway=-1 and vice versa.
+ *
+ * The Corrector offers the automatic resolution in an dialog
+ * for the user to confirm.
+ */
 
 public class ReverseWayTagCorrector extends TagCorrector<Way> {
Index: trunk/src/org/openstreetmap/josm/corrector/TagCorrection.java
===================================================================
--- trunk/src/org/openstreetmap/josm/corrector/TagCorrection.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/corrector/TagCorrection.java	(revision 3210)
@@ -2,4 +2,8 @@
 package org.openstreetmap.josm.corrector;
 
+/**
+ * TagCorrection reprepresents a change of a single
+ * tag. Both key and value can be subject of this change.
+ */
 public class TagCorrection implements Correction {
 
Index: trunk/src/org/openstreetmap/josm/corrector/TagCorrector.java
===================================================================
--- trunk/src/org/openstreetmap/josm/corrector/TagCorrector.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/corrector/TagCorrector.java	(revision 3210)
@@ -34,4 +34,12 @@
 import org.openstreetmap.josm.tools.ImageProvider;
 
+/**
+ * Abstract base class for automatic tag corrections.
+ *
+ * Subclasses call applyCorrections() with maps of the requested
+ * corrections and a dialog is pesented to the user to
+ * confirm these changes.
+ */
+ 
 public abstract class TagCorrector<P extends OsmPrimitive> {
 
Index: trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 3210)
@@ -28,4 +28,5 @@
 import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
 import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
 import org.openstreetmap.josm.tools.Predicate;
 
@@ -68,4 +69,17 @@
     public int getHighlightUpdateCount() {
         return highlightUpdateCount;
+    }
+
+    /**
+     * Maintain a list of used tags for autocompletion
+     */
+    private AutoCompletionManager autocomplete;
+
+    public AutoCompletionManager getAutoCompletionManager() {
+        if (autocomplete == null) {
+            autocomplete = new AutoCompletionManager(this);
+            addDataSetListener(autocomplete);
+        }
+        return autocomplete;
     }
 
Index: trunk/src/org/openstreetmap/josm/data/osm/event/DataSetListener.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/event/DataSetListener.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/data/osm/event/DataSetListener.java	(revision 3210)
@@ -1,2 +1,3 @@
+package org.openstreetmap.josm.data.osm.event;
 /*
  *  JOSMng - a Java Open Street Map editor, the next generation.
@@ -19,6 +20,4 @@
  *  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
-
-package org.openstreetmap.josm.data.osm.event;
 
 /**
Index: trunk/src/org/openstreetmap/josm/gui/conflict/tags/RelationMemberConflictResolver.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/conflict/tags/RelationMemberConflictResolver.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/conflict/tags/RelationMemberConflictResolver.java	(revision 3210)
@@ -33,7 +33,7 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.JMultilineLabel;
-import org.openstreetmap.josm.gui.tagging.AutoCompletingTextField;
-import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
 import org.openstreetmap.josm.tools.ImageProvider;
 
@@ -183,7 +183,6 @@
 
     public void prepareForEditing() {
-        AutoCompletionCache.getCacheForLayer(Main.main.getEditLayer()).initFromDataSet();
         AutoCompletionList acList = new AutoCompletionList();
-        AutoCompletionCache.getCacheForLayer(Main.main.getEditLayer()).populateWithMemberRoles(acList);
+        Main.main.getEditLayer().data.getAutoCompletionManager().populateWithMemberRoles(acList);
         tfRole.setAutoCompletionList(acList);
         AutoCompletingTextField editor = (AutoCompletingTextField) tblResolver.getColumnModel().getColumn(2).getCellEditor();
@@ -192,5 +191,5 @@
         }
         AutoCompletionList acList2 = new AutoCompletionList();
-        AutoCompletionCache.getCacheForLayer(Main.main.getEditLayer()).populateWithKeys(acList2, false /* don'tappend */);
+        Main.main.getEditLayer().data.getAutoCompletionManager().populateWithKeys(acList2);
         tfKey.setAutoCompletionList(acList2);
     }
Index: trunk/src/org/openstreetmap/josm/gui/conflict/tags/RelationMemberConflictResolverColumnModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/conflict/tags/RelationMemberConflictResolverColumnModel.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/conflict/tags/RelationMemberConflictResolverColumnModel.java	(revision 3210)
@@ -8,5 +8,5 @@
 
 import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
-import org.openstreetmap.josm.gui.tagging.AutoCompletingTextField;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
 
 public class RelationMemberConflictResolverColumnModel extends DefaultTableColumnModel{
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/properties/ListOfUsedTags.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/properties/ListOfUsedTags.java	(revision 3209)
+++ 	(revision )
@@ -1,124 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.dialogs.properties;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.Map.Entry;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
-import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
-import org.openstreetmap.josm.data.osm.event.DataSetListener;
-import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
-import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
-import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
-import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
-import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
-import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
-
-public class ListOfUsedTags implements DataSetListener {
-
-    final TreeMap<String, TreeSet<String>> allData = new TreeMap<String, TreeSet<String>>();
-    private boolean dirty;
-
-    public Collection<String> getUsedKeys() {
-        if (dirty) {
-            rebuild();
-        }
-        return allData.keySet();
-    }
-
-    /**
-     *
-     * @param key
-     * @return List of used values or empty list if key is not used
-     */
-    public Collection<String> getUsedValues(String key) {
-        if (dirty) {
-            rebuild();
-        }
-        Collection<String> values = allData.get(key);
-        if (values == null)
-            return Collections.emptyList();
-        else
-            return values;
-    }
-
-    public void rebuildNecessary() {
-        dirty = true;
-    }
-
-    private void rebuild() {
-        dirty = false;
-        allData.clear();
-        DataSet currentDataset = Main.main.getCurrentDataSet();
-        if (currentDataset != null) {
-            addPrimitives(currentDataset.allNonDeletedPrimitives());
-        }
-    }
-
-    private void addPrimitives(Collection<? extends OsmPrimitive> primitives) {
-        for (OsmPrimitive osm : primitives) {
-            addPrimitive(osm);
-        }
-    }
-
-    private void addPrimitive(OsmPrimitive primitive) {
-        for (String key: primitive.keySet()) {
-            addKey(key, primitive.get(key));
-        }
-    }
-
-    private void addKey(String key, String value) {
-        TreeSet<String> values = allData.get(key);
-        if (values == null) {
-            values = new TreeSet<String>();
-            allData.put(key, values);
-        }
-        values.add(value);
-    }
-
-    public void dataChanged(DataChangedEvent event) {
-        rebuild();
-    }
-
-    public void nodeMoved(NodeMovedEvent event) {/* ignored */}
-
-    public void otherDatasetChange(AbstractDatasetChangedEvent event) {/* ignored */}
-
-    public void primtivesAdded(PrimitivesAddedEvent event) {
-        addPrimitives(event.getPrimitives());
-    }
-
-    public void primtivesRemoved(PrimitivesRemovedEvent event) {
-        dirty = true;
-    }
-
-    public void relationMembersChanged(RelationMembersChangedEvent event) {/* ignored */}
-
-    public void tagsChanged(TagsChangedEvent event) {
-        Map<String, String> newKeys = event.getPrimitive().getKeys();
-        Map<String, String> oldKeys = event.getOriginalKeys();
-
-        if (!newKeys.keySet().containsAll(oldKeys.keySet())) {
-            // Some keys removed, might be the last instance of key, rebuild necessary
-            dirty = true;
-        } else {
-            for (Entry<String, String> oldEntry: oldKeys.entrySet()) {
-                if (!oldEntry.getValue().equals(newKeys.get(oldEntry.getKey()))) {
-                    // Value changed, might be last instance of value, rebuild necessary
-                    dirty = true;
-                    return;
-                }
-            }
-            addPrimitive(event.getPrimitive());
-        }
-    }
-
-    public void wayNodesChanged(WayNodesChangedEvent event) {/* ignored */}
-}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java	(revision 3210)
@@ -23,4 +23,5 @@
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -79,5 +80,6 @@
 import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference;
 import org.openstreetmap.josm.gui.tagging.TaggingPreset;
-import org.openstreetmap.josm.gui.widgets.AutoCompleteComboBox;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingComboBox;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
 import org.openstreetmap.josm.tools.GBC;
@@ -145,5 +147,7 @@
 
     private final Map<String, Map<String, Integer>> valueCount = new TreeMap<String, Map<String, Integer>>();
-    private final ListOfUsedTags listOfUsedTags = new ListOfUsedTags();
+
+    Comparator<String> defaultKeyComparator = String.CASE_INSENSITIVE_ORDER;
+    Comparator<String> defaultValueComparator = String.CASE_INSENSITIVE_ORDER;
 
     private DataSetListenerAdapter dataChangedAdapter = new DataSetListenerAdapter(this);
@@ -151,7 +155,5 @@
     @Override
     public void showNotify() {
-        DatasetEventManager.getInstance().addDatasetListener(listOfUsedTags, FireMode.IMMEDIATELY);
         DatasetEventManager.getInstance().addDatasetListener(dataChangedAdapter, FireMode.IN_EDT_CONSOLIDATED);
-        listOfUsedTags.rebuildNecessary();
         SelectionEventManager.getInstance().addSelectionListener(this, FireMode.IN_EDT_CONSOLIDATED);
         MapView.addEditLayerChangeListener(this);
@@ -161,5 +163,4 @@
     @Override
     public void hideNotify() {
-        DatasetEventManager.getInstance().removeDatasetListener(listOfUsedTags);
         DatasetEventManager.getInstance().removeDatasetListener(dataChangedAdapter);
         SelectionEventManager.getInstance().removeSelectionListener(this);
@@ -189,6 +190,8 @@
         panel.add(p, BorderLayout.CENTER);
 
-        final AutoCompleteComboBox keys = new AutoCompleteComboBox();
-        keys.setPossibleItems(listOfUsedTags.getUsedKeys());
+        AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager();
+
+        final AutoCompletingComboBox keys = new AutoCompletingComboBox();
+        keys.setPossibleItems(autocomplete.getKeys(defaultKeyComparator));
         keys.setEditable(true);
         keys.setSelectedItem(key);
@@ -198,5 +201,5 @@
         p.add(keys, GBC.eol().fill(GBC.HORIZONTAL));
 
-        final AutoCompleteComboBox values = new AutoCompleteComboBox();
+        final AutoCompletingComboBox values = new AutoCompletingComboBox();
         values.setRenderer(new DefaultListCellRenderer() {
             @Override public Component getListCellRendererComponent(JList list,
@@ -220,5 +223,5 @@
         });
         values.setEditable(true);
-        values.setPossibleItems(listOfUsedTags.getUsedValues(key));
+        values.setPossibleItems(autocomplete.getValues(key, defaultValueComparator));
         Map<String, Integer> m=(Map<String, Integer>)propertyData.getValueAt(row, 1);
         final String selection= m.size()!=1?tr("<different>"):m.entrySet().iterator().next().getKey();
@@ -228,5 +231,5 @@
         p.add(Box.createHorizontalStrut(10), GBC.std());
         p.add(values, GBC.eol().fill(GBC.HORIZONTAL));
-        addFocusAdapter(row, keys, values);
+        addFocusAdapter(row, keys, values, autocomplete);
 
         final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
@@ -339,6 +342,8 @@
                 "This will change up to {0} objects.", sel.size(),sel.size())
                 +"<br><br>"+tr("Please select a key")), BorderLayout.NORTH);
-        final AutoCompleteComboBox keys = new AutoCompleteComboBox();
-        List<String> usedKeys = new ArrayList<String>(listOfUsedTags.getUsedKeys());
+        final AutoCompletingComboBox keys = new AutoCompletingComboBox();
+        AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager();
+        List<String> usedKeys =
+                new ArrayList<String>(autocomplete.getKeys(defaultKeyComparator));
         for (int i = 0; i < propertyData.getRowCount(); ++i) {
             usedKeys.remove(propertyData.getValueAt(i, 0));
@@ -352,9 +357,12 @@
         p.add(p2, BorderLayout.SOUTH);
         p2.add(new JLabel(tr("Please select a value")), BorderLayout.NORTH);
-        final AutoCompleteComboBox values = new AutoCompleteComboBox();
+        final AutoCompletingComboBox values = new AutoCompletingComboBox();
         values.setEditable(true);
         p2.add(values, BorderLayout.CENTER);
 
-        addFocusAdapter(-1, keys, values);
+        FocusAdapter focus = addFocusAdapter(-1, keys, values, autocomplete);
+        // fire focus event in advance or otherwise the popup list will be too small at first
+        focus.focusGained(null);
+
         JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
             @Override public void selectInitialValue() {
@@ -381,16 +389,18 @@
      * @param values
      */
-    private void addFocusAdapter(final int row, final AutoCompleteComboBox keys, final AutoCompleteComboBox values) {
+    private FocusAdapter addFocusAdapter(final int row, final AutoCompletingComboBox keys, final AutoCompletingComboBox values, final AutoCompletionManager autocomplete) {
         // get the combo box' editor component
         JTextComponent editor = (JTextComponent)values.getEditor()
         .getEditorComponent();
         // Refresh the values model when focus is gained
-        editor.addFocusListener(new FocusAdapter() {
+        FocusAdapter focus = new FocusAdapter() {
             @Override public void focusGained(FocusEvent e) {
                 String key = keys.getEditor().getItem().toString();
-                values.setPossibleItems(listOfUsedTags.getUsedValues(key));
+                values.setPossibleItems(autocomplete.getValues(key, defaultValueComparator));
                 objKey=key;
             }
-        });
+        };
+        editor.addFocusListener(focus);
+        return focus;
     }
     private String objKey;
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java	(revision 3210)
@@ -66,8 +66,8 @@
 import org.openstreetmap.josm.gui.help.HelpUtil;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
-import org.openstreetmap.josm.gui.tagging.AutoCompletingTextField;
 import org.openstreetmap.josm.gui.tagging.TagEditorPanel;
-import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Shortcut;
@@ -111,8 +111,4 @@
         setRememberWindowGeometry(getClass().getName() + ".geometry",
                 WindowGeometry.centerInWindow(Main.parent, new Dimension(700, 650)));
-
-        // initialize the autocompletion infrastructure
-        //
-        AutoCompletionCache.getCacheForLayer(getLayer()).initFromDataSet();
 
         // init the various models
@@ -310,5 +306,5 @@
                     public void focusGained(FocusEvent e) {
                         AutoCompletionList list = tfRole.getAutoCompletionList();
-                        AutoCompletionCache.getCacheForLayer(Main.main.getEditLayer()).populateWithMemberRoles(list);
+                        getLayer().data.getAutoCompletionManager().populateWithMemberRoles(list);
                     }
                 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberRoleCellEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberRoleCellEditor.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberRoleCellEditor.java	(revision 3210)
@@ -10,6 +10,7 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.tagging.AutoCompletingTextField;
-import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
 
@@ -19,4 +20,5 @@
 
     private AutoCompletingTextField editor = null;
+    private DataSet ds;
 
     /** user input is matched against this list of auto completion items */
@@ -26,5 +28,6 @@
      * constructor
      */
-    public MemberRoleCellEditor() {
+    public MemberRoleCellEditor(DataSet ds) {
+        this.ds = ds;
         editor = new AutoCompletingTextField();
         autoCompletionList = new AutoCompletionList();
@@ -40,5 +43,5 @@
         String role = (String)value;
         editor.setText(role);
-        AutoCompletionCache.getCacheForLayer(Main.main.getEditLayer()).populateWithMemberRoles(autoCompletionList);
+        ds.getAutoCompletionManager().populateWithMemberRoles(autoCompletionList);
         return editor;
     }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java	(revision 3210)
@@ -48,5 +48,5 @@
      */
     public MemberTable(OsmDataLayer layer, MemberTableModel model) {
-        super(model, new MemberTableColumnModel(), model.getSelectionModel());
+        super(model, new MemberTableColumnModel(layer.data), model.getSelectionModel());
         this.layer = layer;
         model.addMemberModelListener(this);
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableColumnModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableColumnModel.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableColumnModel.java	(revision 3210)
@@ -7,7 +7,9 @@
 import javax.swing.table.TableColumn;
 
+import org.openstreetmap.josm.data.osm.DataSet;
+
 public class MemberTableColumnModel extends DefaultTableColumnModel {
 
-    public MemberTableColumnModel() {
+    public MemberTableColumnModel(DataSet ds) {
         TableColumn col = null;
 
@@ -18,5 +20,5 @@
         col.setPreferredWidth(100);
         col.setCellRenderer(new MemberTableRoleCellRenderer());
-        col.setCellEditor(new MemberRoleCellEditor());
+        col.setCellEditor(new MemberRoleCellEditor(ds));
         addColumn(col);
 
Index: trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 3210)
@@ -21,5 +21,5 @@
 import org.openstreetmap.josm.gui.tagging.TaggingPresetMenu;
 import org.openstreetmap.josm.gui.tagging.TaggingPresetSeparator;
-import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
 import org.openstreetmap.josm.tools.GBC;
 
@@ -88,5 +88,5 @@
         else
         {
-            AutoCompletionCache.cachePresets(taggingPresets);
+            AutoCompletionManager.cachePresets(taggingPresets);
             HashMap<TaggingPresetMenu,JMenu> submenus = new HashMap<TaggingPresetMenu,JMenu>();
             for (final TaggingPreset p : taggingPresets)
Index: trunk/src/org/openstreetmap/josm/gui/tagging/AutoCompletingTextField.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/AutoCompletingTextField.java	(revision 3209)
+++ 	(revision )
@@ -1,244 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.tagging;
-
-import java.awt.Component;
-import java.awt.event.FocusAdapter;
-import java.awt.event.FocusEvent;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.util.EventObject;
-import java.util.logging.Logger;
-
-import javax.swing.ComboBoxEditor;
-import javax.swing.JTable;
-import javax.swing.JTextField;
-import javax.swing.event.CellEditorListener;
-import javax.swing.table.TableCellEditor;
-import javax.swing.text.AttributeSet;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Document;
-import javax.swing.text.PlainDocument;
-
-import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
-import org.openstreetmap.josm.gui.util.TableCellEditorSupport;
-
-/**
- * AutoCompletingTextField is an text field with autocompletion behaviour. It
- * can be used as table cell editor in {@see JTable}s.
- *
- * Autocompletion is controlled by a list of {@see AutoCompletionListItem}s
- * managed in a {@see AutoCompletionList}.
- *
- *
- */
-public class AutoCompletingTextField extends JTextField implements ComboBoxEditor, TableCellEditor {
-    @SuppressWarnings("unused")
-    static private Logger logger = Logger.getLogger(AutoCompletingTextField.class.getName());
-
-    /**
-     * The document model for the editor
-     */
-    class AutoCompletionDocument extends PlainDocument {
-
-        /**
-         * inserts a string at a specific position
-         *
-         */
-        @Override
-        public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
-            if (autoCompletionList == null) {
-                super.insertString(offs, str, a);
-                return;
-            }
-
-            // if the current offset isn't at the end of the document we don't autocomplete.
-            // If a highlighted autocompleted suffix was present and we get here Swing has
-            // already removed it from the document. getLength() therefore doesn't include the
-            // autocompleted suffix.
-            //
-            if (offs < getLength()) {
-                super.insertString(offs, str, a);
-                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);
-            if (autoCompletionList.getFilteredSize()>0) {
-                // there are matches. Insert the new text and highlight the
-                // auto completed suffix
-                //
-                String matchingString = autoCompletionList.getFilteredItem(0).getValue();
-                remove(0,getLength());
-                super.insertString(0,matchingString,a);
-
-                // highlight from end to insert position
-                //
-                setCaretPosition(getLength());
-                moveCaretPosition(offs + str.length());
-            } else {
-                // there are no matches. Insert the new text, do not highlight
-                //
-                String newText = prefix + str;
-                remove(0,getLength());
-                super.insertString(0,newText,a);
-                setCaretPosition(getLength());
-
-            }
-        }
-    }
-
-    /** the auto completion list user input is matched against */
-    protected AutoCompletionList autoCompletionList = null;
-
-    /**
-     * creates the default document model for this editor
-     *
-     */
-    @Override
-    protected Document createDefaultModel() {
-        return new AutoCompletionDocument();
-    }
-
-    protected void init() {
-        addFocusListener(
-                new FocusAdapter() {
-                    @Override public void focusGained(FocusEvent e) {
-                        selectAll();
-                        applyFilter(getText());
-                    }
-                }
-        );
-
-        addKeyListener(
-                new KeyAdapter() {
-
-                    @Override
-                    public void keyReleased(KeyEvent e) {
-                        if (getText().equals("")) {
-                            applyFilter("");
-                        }
-                    }
-                }
-        );
-        tableCellEditorSupport = new TableCellEditorSupport(this);
-    }
-
-    /**
-     * constructor
-     */
-    public AutoCompletingTextField() {
-        init();
-    }
-
-    public AutoCompletingTextField(int columns) {
-        super(columns);
-        init();
-    }
-
-    protected void applyFilter(String filter) {
-        if (autoCompletionList != null) {
-            autoCompletionList.applyFilter(filter);
-        }
-    }
-
-    /**
-     *
-     * @return the auto completion list; may be null, if no auto completion list is set
-     */
-    public AutoCompletionList getAutoCompletionList() {
-        return autoCompletionList;
-    }
-
-    /**
-     * sets the auto completion list
-     * @param autoCompletionList the auto completion list; if null, auto completion is
-     *   disabled
-     */
-    public void setAutoCompletionList(AutoCompletionList autoCompletionList) {
-        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());
-        }
-    }
-
-    /* ------------------------------------------------------------------------------------ */
-    /* TableCellEditor interface                                                            */
-    /* ------------------------------------------------------------------------------------ */
-
-    private TableCellEditorSupport tableCellEditorSupport;
-    private String originalValue;
-
-    public void addCellEditorListener(CellEditorListener l) {
-        tableCellEditorSupport.addCellEditorListener(l);
-    }
-
-    protected void rememberOriginalValue(String value) {
-        this.originalValue = value;
-    }
-
-    protected void restoreOriginalValue() {
-        setText(originalValue);
-    }
-
-    public void removeCellEditorListener(CellEditorListener l) {
-        tableCellEditorSupport.removeCellEditorListener(l);
-    }
-    public void cancelCellEditing() {
-        restoreOriginalValue();
-        tableCellEditorSupport.fireEditingCanceled();
-
-    }
-
-    public Object getCellEditorValue() {
-        return getText();
-    }
-
-    public boolean isCellEditable(EventObject anEvent) {
-        return true;
-    }
-
-    public boolean shouldSelectCell(EventObject anEvent) {
-        return true;
-    }
-
-    public boolean stopCellEditing() {
-        tableCellEditorSupport.fireEditingStopped();
-        return true;
-    }
-
-    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
-        setText( value == null ? "" : value.toString());
-        rememberOriginalValue(getText());
-        return this;
-    }
-}
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TagCellEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TagCellEditor.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TagCellEditor.java	(revision 3210)
@@ -9,6 +9,7 @@
 import javax.swing.table.TableCellEditor;
 
-import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
 
 /**
@@ -26,5 +27,5 @@
 
     /** the cache of auto completion items derived from the current JOSM data set */
-    protected AutoCompletionCache acCache = null;
+    protected AutoCompletionManager autocomplete = null;
 
     /** user input is matched against this list of auto completion items */
@@ -36,5 +37,4 @@
     public TagCellEditor() {
         editor = new AutoCompletingTextField();
-        acCache = new AutoCompletionCache();
     }
 
@@ -58,5 +58,5 @@
         // add the list of keys in the current data set
         //
-        acCache.populateWithKeys(autoCompletionList, true);
+        autocomplete.populateWithKeys(autoCompletionList);
 
         // remove the keys already present in the current tag model
@@ -83,5 +83,6 @@
             return;
         }
-        acCache.populateWithTagValues(autoCompletionList, forKey, false);
+        autoCompletionList.clear();
+        autocomplete.populateWithTagValues(autoCompletionList, forKey);
     }
 
@@ -137,6 +138,6 @@
     }
 
-    public void setAutoCompletionCache(AutoCompletionCache acCache) {
-        this.acCache = acCache;
+    public void setAutoCompletionManager(AutoCompletionManager autocomplete) {
+        this.autocomplete = autocomplete;
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorPanel.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorPanel.java	(revision 3210)
@@ -14,6 +14,6 @@
 
 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.gui.tagging.ac.AutoCompletionManager;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 
@@ -33,5 +33,5 @@
     private TagTable tagTable;
 
-    private AutoCompletionCache acCache;
+    private AutoCompletionManager autocomplete;
     private AutoCompletionList acList;
 
@@ -141,15 +141,13 @@
     public void initAutoCompletion(OsmDataLayer layer) throws IllegalArgumentException{
         CheckParameterUtil.ensureParameterNotNull(layer, "layer");
-        // initialize the autocompletion infrastructure
-        //
-        acCache = AutoCompletionCache.getCacheForLayer(layer);
-        acCache.initFromDataSet();
+
+        autocomplete = layer.data.getAutoCompletionManager();
         acList = new AutoCompletionList();
 
         TagCellEditor editor = ((TagCellEditor) tagTable.getColumnModel().getColumn(0).getCellEditor());
-        editor.setAutoCompletionCache(acCache);
+        editor.setAutoCompletionManager(autocomplete);
         editor.setAutoCompletionList(acList);
         editor = ((TagCellEditor) tagTable.getColumnModel().getColumn(1).getCellEditor());
-        editor.setAutoCompletionCache(acCache);
+        editor.setAutoCompletionManager(autocomplete);
         editor.setAutoCompletionList(acList);
     }
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TagTable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TagTable.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TagTable.java	(revision 3210)
@@ -41,5 +41,5 @@
 
 import org.openstreetmap.josm.gui.dialogs.relation.RunnableAction;
-import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -406,11 +406,11 @@
     }
 
-    public void setAutoCompletionCache(AutoCompletionCache acCache) {
-        if (acCache == null) {
-            logger.warning("argument acCache should not be null. Aborting.");
+    public void setAutoCompletionManager(AutoCompletionManager autocomplete) {
+        if (autocomplete == null) {
+            logger.warning("argument autocomplete should not be null. Aborting.");
             return;
         }
         if (editor != null) {
-            editor.setAutoCompletionCache(acCache);
+            editor.setAutoCompletionManager(autocomplete);
         }
     }
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 3210)
@@ -51,7 +51,8 @@
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
-import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionCache;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionItemPritority;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
 import org.openstreetmap.josm.io.MirroredInputStream;
 import org.openstreetmap.josm.tools.GBC;
@@ -82,5 +83,5 @@
             if (layer == null) return;
             AutoCompletionList list  = new AutoCompletionList();
-            AutoCompletionCache.getCacheForLayer(Main.main.getEditLayer()).populateWithTagValues(list, key, false);
+            Main.main.getEditLayer().data.getAutoCompletionManager().populateWithTagValues(list, key);
             field.setAutoCompletionList(list);
         }
@@ -696,7 +697,4 @@
             return null;
         OsmDataLayer layer = Main.main.getEditLayer();
-        if (layer != null) {
-            AutoCompletionCache.getCacheForLayer(layer).initFromDataSet();
-        }
         PresetPanel p = new PresetPanel();
         LinkedList<Item> l = new LinkedList<Item>();
Index: trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingComboBox.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingComboBox.java	(revision 3210)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingComboBox.java	(revision 3210)
@@ -0,0 +1,131 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.tagging.ac;
+
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.util.Collection;
+
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.PlainDocument;
+
+/**
+ * @author guilhem.bonnefille@gmail.com
+ */
+public class AutoCompletingComboBox extends JComboBox {
+
+    private boolean autocompleteEnabled = true;
+
+    /**
+     * Auto-complete a JComboBox.
+     *
+     * Inspired by http://www.orbital-computer.de/JComboBox/
+     */
+    class AutoCompletingComboBoxDocument extends PlainDocument {
+        private JComboBox comboBox;
+        private boolean selecting = false;
+
+        public AutoCompletingComboBoxDocument(final JComboBox comboBox) {
+            this.comboBox = comboBox;
+        }
+
+        @Override public void remove(int offs, int len) throws BadLocationException {
+            if (selecting)
+                return;
+            super.remove(offs, len);
+        }
+
+        @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
+            if(selecting || (offs == 0 && str.equals(getText(0, getLength()))))
+                return;
+            boolean initial = (offs == 0 && getLength() == 0 && str.length() > 1);
+            super.insertString(offs, str, a);
+
+            // return immediately when selecting an item
+            // Note: this is done after calling super method because we need
+            // ActionListener informed
+            if (selecting)
+                return;
+            if (!autocompleteEnabled)
+                return;
+
+            int size = getLength();
+            int start = offs+str.length();
+            int end = start;
+            String curText = getText(0, size);
+            // lookup and select a matching item
+            Object item = lookupItem(curText);
+            setSelectedItem(item);
+            if(initial) {
+                start = 0;
+            }
+            if (item != null) {
+                String newText = item.toString();
+                if(!newText.equals(curText))
+                {
+                    selecting = true;
+                    super.remove(0, size);
+                    super.insertString(0, newText, a);
+                    selecting = false;
+                    start = size;
+                    end = getLength();
+                }
+            }
+            JTextComponent editor = (JTextComponent)comboBox.getEditor().getEditorComponent();
+            editor.setSelectionStart(start);
+            editor.setSelectionEnd(end);
+        }
+
+        private void setSelectedItem(Object item) {
+            selecting = true;
+            comboBox.setSelectedItem(item);
+            selecting = false;
+        }
+
+        private Object lookupItem(String pattern) {
+            ComboBoxModel model = comboBox.getModel();
+            for (int i = 0, n = model.getSize(); i < n; i++) {
+                Object currentItem = model.getElementAt(i);
+                if (currentItem.toString().startsWith(pattern))
+                    return currentItem;
+            }
+            return null;
+        }
+    }
+
+    public AutoCompletingComboBox() {
+        final JTextComponent editor = (JTextComponent) this.getEditor().getEditorComponent();
+        editor.setDocument(new AutoCompletingComboBoxDocument(this));
+        editor.addFocusListener(
+                new FocusListener() {
+                    public void focusLost(FocusEvent e) {
+                    }
+                    public void focusGained(FocusEvent e) {
+                        editor.selectAll();
+                    }
+                }
+        );
+    }
+
+    public void setPossibleItems(Collection<String> elems) {
+        DefaultComboBoxModel model = (DefaultComboBoxModel)this.getModel();
+        Object oldValue = this.getEditor().getItem();
+        model.removeAllElements();
+        for (String elem : elems) {
+            model.addElement(elem);
+        }
+        this.getEditor().setItem(oldValue);
+    }
+
+    protected boolean isAutocompleteEnabled() {
+        return autocompleteEnabled;
+    }
+
+    protected void setAutocompleteEnabled(boolean autocompleteEnabled) {
+        this.autocompleteEnabled = autocompleteEnabled;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingTextField.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingTextField.java	(revision 3210)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingTextField.java	(revision 3210)
@@ -0,0 +1,244 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.tagging.ac;
+
+import java.awt.Component;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.EventObject;
+import java.util.logging.Logger;
+
+import javax.swing.ComboBoxEditor;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.event.CellEditorListener;
+import javax.swing.table.TableCellEditor;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.PlainDocument;
+
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
+import org.openstreetmap.josm.gui.util.TableCellEditorSupport;
+
+/**
+ * AutoCompletingTextField is an text field with autocompletion behaviour. It
+ * can be used as table cell editor in {@see JTable}s.
+ *
+ * Autocompletion is controlled by a list of {@see AutoCompletionListItem}s
+ * managed in a {@see AutoCompletionList}.
+ *
+ *
+ */
+public class AutoCompletingTextField extends JTextField implements ComboBoxEditor, TableCellEditor {
+    @SuppressWarnings("unused")
+    static private Logger logger = Logger.getLogger(AutoCompletingTextField.class.getName());
+
+    /**
+     * The document model for the editor
+     */
+    class AutoCompletionDocument extends PlainDocument {
+
+        /**
+         * inserts a string at a specific position
+         *
+         */
+        @Override
+        public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
+            if (autoCompletionList == null) {
+                super.insertString(offs, str, a);
+                return;
+            }
+
+            // if the current offset isn't at the end of the document we don't autocomplete.
+            // If a highlighted autocompleted suffix was present and we get here Swing has
+            // already removed it from the document. getLength() therefore doesn't include the
+            // autocompleted suffix.
+            //
+            if (offs < getLength()) {
+                super.insertString(offs, str, a);
+                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);
+            if (autoCompletionList.getFilteredSize()>0) {
+                // there are matches. Insert the new text and highlight the
+                // auto completed suffix
+                //
+                String matchingString = autoCompletionList.getFilteredItem(0).getValue();
+                remove(0,getLength());
+                super.insertString(0,matchingString,a);
+
+                // highlight from end to insert position
+                //
+                setCaretPosition(getLength());
+                moveCaretPosition(offs + str.length());
+            } else {
+                // there are no matches. Insert the new text, do not highlight
+                //
+                String newText = prefix + str;
+                remove(0,getLength());
+                super.insertString(0,newText,a);
+                setCaretPosition(getLength());
+
+            }
+        }
+    }
+
+    /** the auto completion list user input is matched against */
+    protected AutoCompletionList autoCompletionList = null;
+
+    /**
+     * creates the default document model for this editor
+     *
+     */
+    @Override
+    protected Document createDefaultModel() {
+        return new AutoCompletionDocument();
+    }
+
+    protected void init() {
+        addFocusListener(
+                new FocusAdapter() {
+                    @Override public void focusGained(FocusEvent e) {
+                        selectAll();
+                        applyFilter(getText());
+                    }
+                }
+        );
+
+        addKeyListener(
+                new KeyAdapter() {
+
+                    @Override
+                    public void keyReleased(KeyEvent e) {
+                        if (getText().equals("")) {
+                            applyFilter("");
+                        }
+                    }
+                }
+        );
+        tableCellEditorSupport = new TableCellEditorSupport(this);
+    }
+
+    /**
+     * constructor
+     */
+    public AutoCompletingTextField() {
+        init();
+    }
+
+    public AutoCompletingTextField(int columns) {
+        super(columns);
+        init();
+    }
+
+    protected void applyFilter(String filter) {
+        if (autoCompletionList != null) {
+            autoCompletionList.applyFilter(filter);
+        }
+    }
+
+    /**
+     *
+     * @return the auto completion list; may be null, if no auto completion list is set
+     */
+    public AutoCompletionList getAutoCompletionList() {
+        return autoCompletionList;
+    }
+
+    /**
+     * sets the auto completion list
+     * @param autoCompletionList the auto completion list; if null, auto completion is
+     *   disabled
+     */
+    public void setAutoCompletionList(AutoCompletionList autoCompletionList) {
+        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());
+        }
+    }
+
+    /* ------------------------------------------------------------------------------------ */
+    /* TableCellEditor interface                                                            */
+    /* ------------------------------------------------------------------------------------ */
+
+    private TableCellEditorSupport tableCellEditorSupport;
+    private String originalValue;
+
+    public void addCellEditorListener(CellEditorListener l) {
+        tableCellEditorSupport.addCellEditorListener(l);
+    }
+
+    protected void rememberOriginalValue(String value) {
+        this.originalValue = value;
+    }
+
+    protected void restoreOriginalValue() {
+        setText(originalValue);
+    }
+
+    public void removeCellEditorListener(CellEditorListener l) {
+        tableCellEditorSupport.removeCellEditorListener(l);
+    }
+    public void cancelCellEditing() {
+        restoreOriginalValue();
+        tableCellEditorSupport.fireEditingCanceled();
+
+    }
+
+    public Object getCellEditorValue() {
+        return getText();
+    }
+
+    public boolean isCellEditable(EventObject anEvent) {
+        return true;
+    }
+
+    public boolean shouldSelectCell(EventObject anEvent) {
+        return true;
+    }
+
+    public boolean stopCellEditing() {
+        tableCellEditorSupport.fireEditingStopped();
+        return true;
+    }
+
+    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+        setText( value == null ? "" : value.toString());
+        rememberOriginalValue(getText());
+        return this;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionCache.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionCache.java	(revision 3209)
+++ 	(revision )
@@ -1,263 +1,0 @@
-package org.openstreetmap.josm.gui.tagging.ac;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-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.OsmUtils;
-import org.openstreetmap.josm.data.osm.Relation;
-import org.openstreetmap.josm.data.osm.RelationMember;
-import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.OsmDataLayer;
-import org.openstreetmap.josm.gui.tagging.TaggingPreset;
-import org.openstreetmap.josm.tools.MultiMap;
-
-/**
- * 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 {
-    @SuppressWarnings("unused")
-    static private final Logger logger = Logger.getLogger(AutoCompletionCache.class.getName());
-
-    private static HashMap<OsmDataLayer, AutoCompletionCache> caches;
-
-    static {
-        caches = new HashMap<OsmDataLayer, AutoCompletionCache>();
-        MapView.addLayerChangeListener(new MapView.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 given by a tag key and a list of values for this tag */
-    private MultiMap<String, String> tagCache;
-    /**  the layer this cache is built for */
-    private OsmDataLayer layer;
-    /** the same as tagCache but for the preset keys and values */
-    private static MultiMap<String, String> presetTagCache = new MultiMap<String, String>();
-    /** the cached list of member roles */
-    private  Set<String> roleCache;
-
-    /**
-     * constructor
-     */
-    public AutoCompletionCache(OsmDataLayer layer) {
-        tagCache = new MultiMap<String, String>();
-        roleCache = new HashSet<String>();
-        this.layer = layer;
-    }
-
-    public AutoCompletionCache() {
-        this(null);
-    }
-
-    /**
-     * 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);
-            tagCache.put(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 MultiMap<String, String>();
-        if (layer == null)
-            return;
-        Collection<OsmPrimitive> ds = layer.data.allNonDeletedPrimitives();
-        for (OsmPrimitive primitive : ds) {
-            cachePrimitive(primitive);
-        }
-        for (Relation relation : layer.data.getRelations()) {
-            if (relation.isIncomplete() || relation.isDeleted()) {
-                continue;
-            }
-            cacheRelationMemberRoles(relation);
-        }
-    }
-
-    /**
-     * Initialize the cache for presets. This is done only once.
-     */
-    public static void cachePresets(Collection<TaggingPreset> presets) {
-        for (final TaggingPreset p : presets) {
-            for (TaggingPreset.Item item : p.data) {
-                if (item instanceof TaggingPreset.Check) {
-                    TaggingPreset.Check ch = (TaggingPreset.Check) item;
-                    if (ch.key == null) {
-                        continue;
-                    }
-                    presetTagCache.put(ch.key, OsmUtils.falseval);
-                    presetTagCache.put(ch.key, OsmUtils.trueval);
-                } else if (item instanceof TaggingPreset.Combo) {
-                    TaggingPreset.Combo co = (TaggingPreset.Combo) item;
-                    if (co.key == null || co.values == null) {
-                        continue;
-                    }
-                    for (String value : co.values.split(",")) {
-                        presetTagCache.put(co.key, value);
-                    }
-                } else if (item instanceof TaggingPreset.Key) {
-                    TaggingPreset.Key ky = (TaggingPreset.Key) item;
-                    if (ky.key == null || ky.value == null) {
-                        continue;
-                    }
-                    presetTagCache.put(ky.key, ky.value);
-                } else if (item instanceof TaggingPreset.Text) {
-                    TaggingPreset.Text tt = (TaggingPreset.Text) item;
-                    if (tt.key == null) {
-                        continue;
-                    }
-                    presetTagCache.putVoid(tt.key);
-                    if (tt.default_ != null && !tt.default_.equals("")) {
-                        presetTagCache.put(tt.key, tt.default_);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * replies the keys held by the cache
-     *
-     * @return the list of keys held by the cache
-     */
-    protected List<String> getDataKeys() {
-        return new ArrayList<String>(tagCache.keySet());
-    }
-
-    protected List<String> getPresetKeys() {
-        return new ArrayList<String>(presetTagCache.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
-     */
-    protected List<String> getDataValues(String key) {
-        return new ArrayList<String>(tagCache.getValues(key));
-    }
-
-    protected static List<String> getPresetValues(String key) {
-        return new ArrayList<String>(presetTagCache.getValues(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(getDataValues(key), AutoCompletionItemPritority.IS_IN_DATASET);
-        list.add(getPresetValues(key), AutoCompletionItemPritority.IS_IN_STANDARD);
-    }
-
-    /**
-     * 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(getDataKeys(), AutoCompletionItemPritority.IS_IN_DATASET);
-        list.add(getPresetKeys(), AutoCompletionItemPritority.IS_IN_STANDARD);
-    }
-}
Index: trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionList.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionList.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionList.java	(revision 3210)
@@ -1,2 +1,3 @@
+// License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.tagging.ac;
 
@@ -297,5 +298,5 @@
         System.out.println("---------------------------------");
         for (AutoCompletionListItem item: list) {
-            System.out.println(item.getValue());
+            System.out.println(item);
         }
         System.out.println("---------------------------------");
Index: trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionListItem.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionListItem.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionListItem.java	(revision 3210)
@@ -72,11 +72,9 @@
     @Override public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("<AutoCompletionItemPritority: ");
-        sb.append("value='");
+        sb.append("<val='");
         sb.append(value);
         sb.append("',");
-        sb.append("priority='");
         sb.append(priority.toString());
-        sb.append("'>");
+        sb.append(">");
         return sb.toString();
     }
Index: trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionManager.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionManager.java	(revision 3210)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionManager.java	(revision 3210)
@@ -0,0 +1,320 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.tagging.ac;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.logging.Logger;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.OsmUtils;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
+import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
+import org.openstreetmap.josm.data.osm.event.DataSetListener;
+import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
+import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
+import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
+import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
+import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
+import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.tagging.TaggingPreset;
+import org.openstreetmap.josm.tools.MultiMap;
+
+/**
+ * AutoCompletionManager holds a cache of keys with a list of
+ * possible auto completion values for each key.
+ *
+ * Each DataSet is assigned one AutoCompletionManager instance 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.
+ *
+ * TODO: respect the relation type for member role autocompletion
+ */
+public class AutoCompletionManager implements DataSetListener {
+
+    /** If the dirty flag is set true, a rebuild is necessary. */
+    protected boolean dirty;
+    /** The data set that is managed */
+    protected DataSet ds;
+
+    /**
+     * the cached tags given by a tag key and a list of values for this tag
+     * only accessed by getTagCache(), rebuild() and cachePrimitiveTags()
+     * use getTagCache() accessor
+     */
+    protected MultiMap<String, String> tagCache;
+    /**
+     * the same as tagCache but for the preset keys and values
+     * can be accessed directly
+     */
+    protected static MultiMap<String, String> presetTagCache = new MultiMap<String, String>();
+    /** 
+     * the cached list of member roles 
+     * only accessed by getRoleCache(), rebuild() and cacheRelationMemberRoles()
+     * use getRoleCache() accessor
+     */
+    protected  Set<String> roleCache;
+
+    public AutoCompletionManager(DataSet ds) {
+        this.ds = ds;
+        dirty = true;
+    }
+
+    protected MultiMap<String, String> getTagCache() {
+        if (dirty) {
+            rebuild();
+            dirty = false;
+        }
+        return tagCache;
+    }
+
+    protected Set<String> getRoleCache() {
+        if (dirty) {
+            rebuild();
+            dirty = false;
+        }
+        return roleCache;
+    }
+
+    /**
+     * initializes the cache from the primitives in the dataset
+     *
+     */
+    protected void rebuild() {
+        tagCache = new MultiMap<String, String>();
+        roleCache = new HashSet<String>();
+        cachePrimitives(ds.allNonDeletedCompletePrimitives());
+    }
+
+    protected void cachePrimitives(Collection<? extends OsmPrimitive> primitives) {
+        for (OsmPrimitive primitive : primitives) {
+            cachePrimitiveTags(primitive);
+            if (primitive instanceof Relation) {
+                cacheRelationMemberRoles((Relation) primitive);
+            }
+        }
+    }
+
+    /**
+     * 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 cachePrimitiveTags(OsmPrimitive primitive) {
+        for (String key: primitive.keySet()) {
+            String value = primitive.get(key);
+            tagCache.put(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.add(m.getRole());
+            }
+        }
+    }
+
+    /**
+     * Initialize the cache for presets. This is done only once.
+     */
+    public static void cachePresets(Collection<TaggingPreset> presets) {
+        for (final TaggingPreset p : presets) {
+            for (TaggingPreset.Item item : p.data) {
+                if (item instanceof TaggingPreset.Check) {
+                    TaggingPreset.Check ch = (TaggingPreset.Check) item;
+                    if (ch.key == null) {
+                        continue;
+                    }
+                    presetTagCache.put(ch.key, OsmUtils.falseval);
+                    presetTagCache.put(ch.key, OsmUtils.trueval);
+                } else if (item instanceof TaggingPreset.Combo) {
+                    TaggingPreset.Combo co = (TaggingPreset.Combo) item;
+                    if (co.key == null || co.values == null) {
+                        continue;
+                    }
+                    for (String value : co.values.split(",")) {
+                        presetTagCache.put(co.key, value);
+                    }
+                } else if (item instanceof TaggingPreset.Key) {
+                    TaggingPreset.Key ky = (TaggingPreset.Key) item;
+                    if (ky.key == null || ky.value == null) {
+                        continue;
+                    }
+                    presetTagCache.put(ky.key, ky.value);
+                } else if (item instanceof TaggingPreset.Text) {
+                    TaggingPreset.Text tt = (TaggingPreset.Text) item;
+                    if (tt.key == null) {
+                        continue;
+                    }
+                    presetTagCache.putVoid(tt.key);
+                    if (tt.default_ != null && !tt.default_.equals("")) {
+                        presetTagCache.put(tt.key, tt.default_);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * replies the keys held by the cache
+     *
+     * @return the list of keys held by the cache
+     */
+    protected List<String> getDataKeys() {
+        return new ArrayList<String>(getTagCache().keySet());
+    }
+
+    protected List<String> getPresetKeys() {
+        return new ArrayList<String>(presetTagCache.keySet());
+    }
+
+    public TreeSet<String> getKeys(Comparator<String> c) {
+        TreeSet<String> ret = new TreeSet<String>(c);
+        ret.addAll(getDataKeys());
+        ret.addAll(getPresetKeys());
+        return ret;
+    }
+
+    /**
+     * 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
+     */
+    protected List<String> getDataValues(String key) {
+        return new ArrayList<String>(getTagCache().getValues(key));
+    }
+
+    protected static List<String> getPresetValues(String key) {
+        return new ArrayList<String>(presetTagCache.getValues(key));
+    }
+
+    public TreeSet<String> getValues(String key, Comparator<String> c) {
+        TreeSet<String> ret = new TreeSet<String>(c);
+        ret.addAll(getDataValues(key));
+        ret.addAll(getPresetValues(key));
+        return ret;
+    }
+
+    /**
+     * Replies the list of member roles
+     *
+     * @return the list of member roles
+     */
+    public List<String> getMemberRoles() {
+        return new ArrayList<String>(getRoleCache());
+    }
+
+    /**
+     * 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(getRoleCache(), 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) {
+        list.add(getDataValues(key), AutoCompletionItemPritority.IS_IN_DATASET);
+        list.add(getPresetValues(key), AutoCompletionItemPritority.IS_IN_STANDARD);
+    }
+
+    /**
+     * 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) {
+        list.add(getDataKeys(), AutoCompletionItemPritority.IS_IN_DATASET);
+        list.add(getPresetKeys(), AutoCompletionItemPritority.IS_IN_STANDARD);
+    }
+
+    /*********************************************************
+     * Implementation of the DataSetListener interface
+     *
+     **/
+
+    public void primtivesAdded(PrimitivesAddedEvent event) {
+        cachePrimitives(event.getPrimitives());
+    }
+
+    public void primtivesRemoved(PrimitivesRemovedEvent event) {
+        dirty = true;
+    }
+
+    public void tagsChanged(TagsChangedEvent event) {
+        Map<String, String> newKeys = event.getPrimitive().getKeys();
+        Map<String, String> oldKeys = event.getOriginalKeys();
+
+        if (!newKeys.keySet().containsAll(oldKeys.keySet())) {
+            // Some keys removed, might be the last instance of key, rebuild necessary
+            dirty = true;
+        } else {
+            for (Entry<String, String> oldEntry: oldKeys.entrySet()) {
+                if (!oldEntry.getValue().equals(newKeys.get(oldEntry.getKey()))) {
+                    // Value changed, might be last instance of value, rebuild necessary
+                    dirty = true;
+                    return;
+                }
+            }
+            cachePrimitives(Collections.singleton(event.getPrimitive()));
+        }
+    }
+
+    public void nodeMoved(NodeMovedEvent event) {/* ignored */}
+
+    public void wayNodesChanged(WayNodesChangedEvent event) {/* ignored */}
+
+    public void relationMembersChanged(RelationMembersChangedEvent event) {
+        dirty = true; // TODO: not necessary to rebuid if a member is added
+    }
+
+    public void otherDatasetChange(AbstractDatasetChangedEvent event) {/* ignored */}
+
+    public void dataChanged(DataChangedEvent event) {
+        dirty = true;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/widgets/AutoCompleteComboBox.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/widgets/AutoCompleteComboBox.java	(revision 3209)
+++ 	(revision )
@@ -1,131 +1,0 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
-package org.openstreetmap.josm.gui.widgets;
-
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.util.Collection;
-
-import javax.swing.ComboBoxModel;
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.JComboBox;
-import javax.swing.text.AttributeSet;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.JTextComponent;
-import javax.swing.text.PlainDocument;
-
-/**
- * @author guilhem.bonnefille@gmail.com
- */
-public class AutoCompleteComboBox extends JComboBox {
-
-    private boolean autocompleteEnabled = true;
-
-    /**
-     * Auto-complete a JComboBox.
-     *
-     * Inspired by http://www.orbital-computer.de/JComboBox/
-     */
-    class AutoCompleteComboBoxDocument extends PlainDocument {
-        private JComboBox comboBox;
-        private boolean selecting = false;
-
-        public AutoCompleteComboBoxDocument(final JComboBox comboBox) {
-            this.comboBox = comboBox;
-        }
-
-        @Override public void remove(int offs, int len) throws BadLocationException {
-            if (selecting)
-                return;
-            super.remove(offs, len);
-        }
-
-        @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
-            if(selecting || (offs == 0 && str.equals(getText(0, getLength()))))
-                return;
-            boolean initial = (offs == 0 && getLength() == 0 && str.length() > 1);
-            super.insertString(offs, str, a);
-
-            // return immediately when selecting an item
-            // Note: this is done after calling super method because we need
-            // ActionListener informed
-            if (selecting)
-                return;
-            if (!autocompleteEnabled)
-                return;
-
-            int size = getLength();
-            int start = offs+str.length();
-            int end = start;
-            String curText = getText(0, size);
-            // lookup and select a matching item
-            Object item = lookupItem(curText);
-            setSelectedItem(item);
-            if(initial) {
-                start = 0;
-            }
-            if (item != null) {
-                String newText = item.toString();
-                if(!newText.equals(curText))
-                {
-                    selecting = true;
-                    super.remove(0, size);
-                    super.insertString(0, newText, a);
-                    selecting = false;
-                    start = size;
-                    end = getLength();
-                }
-            }
-            JTextComponent editor = (JTextComponent)comboBox.getEditor().getEditorComponent();
-            editor.setSelectionStart(start);
-            editor.setSelectionEnd(end);
-        }
-
-        private void setSelectedItem(Object item) {
-            selecting = true;
-            comboBox.setSelectedItem(item);
-            selecting = false;
-        }
-
-        private Object lookupItem(String pattern) {
-            ComboBoxModel model = comboBox.getModel();
-            for (int i = 0, n = model.getSize(); i < n; i++) {
-                Object currentItem = model.getElementAt(i);
-                if (currentItem.toString().startsWith(pattern))
-                    return currentItem;
-            }
-            return null;
-        }
-    }
-
-    public AutoCompleteComboBox() {
-        final JTextComponent editor = (JTextComponent) this.getEditor().getEditorComponent();
-        editor.setDocument(new AutoCompleteComboBoxDocument(this));
-        editor.addFocusListener(
-                new FocusListener() {
-                    public void focusLost(FocusEvent e) {
-                    }
-                    public void focusGained(FocusEvent e) {
-                        editor.selectAll();
-                    }
-                }
-        );
-    }
-
-    public void setPossibleItems(Collection<String> elems) {
-        DefaultComboBoxModel model = (DefaultComboBoxModel)this.getModel();
-        Object oldValue = this.getEditor().getItem();
-        model.removeAllElements();
-        for (String elem : elems) {
-            model.addElement(elem);
-        }
-        this.getEditor().setItem(oldValue);
-    }
-
-    protected boolean isAutocompleteEnabled() {
-        return autocompleteEnabled;
-    }
-
-    protected void setAutocompleteEnabled(boolean autocompleteEnabled) {
-        this.autocompleteEnabled = autocompleteEnabled;
-    }
-}
Index: trunk/src/org/openstreetmap/josm/gui/widgets/HistoryComboBox.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/widgets/HistoryComboBox.java	(revision 3209)
+++ trunk/src/org/openstreetmap/josm/gui/widgets/HistoryComboBox.java	(revision 3210)
@@ -6,5 +6,7 @@
 import javax.swing.text.JTextComponent;
 
-public class HistoryComboBox extends AutoCompleteComboBox {
+import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingComboBox;
+
+public class HistoryComboBox extends AutoCompletingComboBox {
     private ComboBoxHistory model;
 
