Index: trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java	(revision 1915)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java	(revision 1916)
@@ -19,4 +19,5 @@
 import javax.swing.JScrollPane;
 import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
@@ -77,11 +78,5 @@
         displaylist.setCellRenderer(new OsmPrimitivRenderer());
         displaylist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-        displaylist.addMouseListener(new MouseAdapter(){
-            @Override public void mouseClicked(MouseEvent e) {
-                if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) {
-                    Main.main.getCurrentDataSet().setSelected((Relation)displaylist.getSelectedValue());
-                }
-            }
-        });
+        displaylist.addMouseListener(new DoubleClickAdapter());
         add(new JScrollPane(displaylist), BorderLayout.CENTER);
 
@@ -101,4 +96,10 @@
         displaylist.addListSelectionListener(editAction);
         buttonPanel.add(new SideButton(editAction), GBC.std());
+
+        // the edit action
+        //
+        DuplicateAction duplicateAction = new DuplicateAction();
+        displaylist.addListSelectionListener(duplicateAction);
+        buttonPanel.add(new SideButton(duplicateAction), GBC.std());
 
         // the delete action
@@ -235,9 +236,29 @@
     }
 
+    class DoubleClickAdapter extends MouseAdapter {
+        protected void setCurrentRelationAsSelection() {
+            Main.main.getCurrentDataSet().setSelected((Relation)displaylist.getSelectedValue());
+        }
+
+        protected void editCurrentRelation() {
+            new EditAction().launchEditor(getSelected());
+        }
+
+        @Override public void mouseClicked(MouseEvent e) {
+            if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) {
+                if (e.isControlDown()) {
+                    editCurrentRelation();
+                } else {
+                    setCurrentRelationAsSelection();
+                }
+            }
+        }
+    }
+
     /**
      * The edit action
      *
      */
-    class EditAction extends AbstractAction implements ListSelectionListener, Runnable{
+    class EditAction extends AbstractAction implements ListSelectionListener{
         public EditAction() {
             putValue(SHORT_DESCRIPTION,tr( "Open an editor for the selected relation"));
@@ -257,7 +278,5 @@
         }
 
-        public void run() {
-            if (!isEnabled()) return;
-            Relation toEdit = getSelected();
+        public void launchEditor(Relation toEdit) {
             if (toEdit == null)
                 return;
@@ -266,5 +285,7 @@
 
         public void actionPerformed(ActionEvent e) {
-            run();
+            if (!isEnabled())
+                return;
+            launchEditor(getSelected());
         }
 
@@ -344,3 +365,44 @@
         }
     }
+
+    /**
+     * Creates a new relation with a copy of the current editor state
+     * 
+     */
+    class DuplicateAction extends AbstractAction implements ListSelectionListener {
+        public DuplicateAction() {
+            putValue(SHORT_DESCRIPTION, tr("Create a copy of this relation and open it in another editor window"));
+            // FIXME provide an icon
+            putValue(SMALL_ICON, ImageProvider.get("duplicate"));
+            putValue(NAME, tr("Duplicate"));
+            updateEnabledState();
+        }
+
+        public void launchEditorForDuplicate(Relation original) {
+            Relation copy = new Relation();
+            copy.cloneFrom(original);
+            copy.id = 0;
+            copy.modified = true;
+            RelationEditor editor = RelationEditor.getEditor(
+                    Main.main.getEditLayer(),
+                    copy,
+                    null /* no selected members */
+            );
+            editor.setVisible(true);
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            if (!isEnabled())
+                return;
+            launchEditorForDuplicate(getSelected());
+        }
+
+        protected void updateEnabledState() {
+            setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length == 1);
+        }
+
+        public void valueChanged(ListSelectionEvent e) {
+            updateEnabledState();
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/AutoCompletingTextField.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/AutoCompletingTextField.java	(revision 1916)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/AutoCompletingTextField.java	(revision 1916)
@@ -0,0 +1,152 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs.relation;
+
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.logging.Logger;
+
+import javax.swing.JTextField;
+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.dialogs.relation.ac.AutoCompletionList;
+
+/**
+ * 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  {
+
+    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());
+            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("");
+                        }
+                    }
+                }
+        );
+    }
+
+    /**
+     * 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;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java	(revision 1915)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java	(revision 1916)
@@ -27,4 +27,5 @@
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 import java.util.logging.Logger;
 
@@ -106,5 +107,5 @@
     private SelectionTableModel selectionTableModel;
 
-    private JTextField tfRole;
+    private AutoCompletingTextField tfRole;
 
     /**
@@ -124,5 +125,6 @@
         // initialize the autocompletion infrastructure
         //
-        acCache = AutoCompletionCache.getCacheForLayer(Main.map.mapView.getEditLayer());
+        acCache = AutoCompletionCache.getCacheForLayer(getLayer());
+        acCache.initFromJOSMDataset();
         acList = new AutoCompletionList();
 
@@ -130,5 +132,5 @@
         //
         tagEditorModel = new TagEditorModel();
-        memberTableModel = new MemberTableModel();
+        memberTableModel = new MemberTableModel(getLayer());
         selectionTableModel = new SelectionTableModel(getLayer());
         referrerModel = new ReferringRelationsBrowserModel(relation);
@@ -198,4 +200,5 @@
 
         memberTableModel.setSelectedMembers(selectedMembers);
+        DataSet.selListeners.add(memberTableModel);
     }
 
@@ -266,5 +269,4 @@
         //
         tagTable = new TagTable(tagEditorModel);
-        acCache.initFromJOSMDataset();
         TagCellEditor editor = ((TagCellEditor) tagTable.getColumnModel().getColumn(0).getCellEditor());
         editor.setAutoCompletionCache(acCache);
@@ -330,4 +332,7 @@
         // setting up the member table
         memberTable = new MemberTable(getLayer(),memberTableModel);
+        MemberRoleCellEditor editor = ((MemberRoleCellEditor) memberTable.getColumnModel().getColumn(0).getCellEditor());
+        editor.setAutoCompletionCache(acCache);
+        editor.setAutoCompletionList(acList);
 
         memberTable.getSelectionModel().addListSelectionListener(new SelectionSynchronizer());
@@ -592,5 +597,5 @@
         // --- role editing
         buttonPanel.add(new JLabel(tr("Role:")));
-        tfRole = new JTextField(10);
+        tfRole = new AutoCompletingTextField(10);
         tfRole.addFocusListener(new FocusAdapter() {
             @Override
@@ -599,4 +604,14 @@
             }
         });
+        tfRole.setAutoCompletionList(acList);
+        tfRole.addFocusListener(
+                new FocusAdapter() {
+                    @Override
+                    public void focusGained(FocusEvent e) {
+                        acCache.populateWithMemberRoles(acList);
+                    }
+                }
+        );
+
         buttonPanel.add(tfRole);
         SetRoleAction setRoleAction = new SetRoleAction();
@@ -626,4 +641,5 @@
     public void dispose() {
         selectionTableModel.unregister();
+        DataSet.selListeners.remove(memberTableModel);
         super.dispose();
     }
@@ -1432,15 +1448,21 @@
     }
 
+    /**
+     * Updates the selection in the current data set with the selected referers in
+     * in the member table.
+     *
+     */
     class SelectionSynchronizer implements ListSelectionListener {
         public void valueChanged(ListSelectionEvent e) {
-            ArrayList<OsmPrimitive> sel;
-            int cnt = memberTable.getSelectedRowCount();
-            if (cnt <= 0)
+            if (e.getValueIsAdjusting())
                 return;
-            sel = new ArrayList<OsmPrimitive>(cnt);
-            for (int i : memberTable.getSelectedRows()) {
-                sel.add(memberTableModel.getReferredPrimitive(i));
-            }
-            getLayer().data.setSelected(sel);
+
+            // Avoid endless loops. memberTableModel is registered as SelectionChangeListener
+            // too. Only update the selection if it is not in sync with what is already
+            // selected.
+            //
+            if (!memberTableModel.selectionsAreInSync()) {
+                getLayer().data.setSelected(memberTableModel.getSelectedReferers());
+            }
         }
     }
@@ -1448,5 +1470,4 @@
     /**
      * The asynchronous task for downloading relation members.
-     * 
      * 
      */
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberRoleCellEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberRoleCellEditor.java	(revision 1916)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberRoleCellEditor.java	(revision 1916)
@@ -0,0 +1,110 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs.relation;
+
+import java.awt.Component;
+import java.util.logging.Logger;
+
+import javax.swing.AbstractCellEditor;
+import javax.swing.JTable;
+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;
+
+public class MemberRoleCellEditor extends AbstractCellEditor implements TableCellEditor {
+
+    /** the logger object */
+    static private Logger logger = Logger.getLogger(MemberRoleCellEditor.class.getName());
+
+    private AutoCompletingTextField editor = null;
+
+    /** the cache of auto completion items derived from the current JOSM data set */
+    private AutoCompletionCache acCache = null;
+
+    /** user input is matched against this list of auto completion items */
+    private AutoCompletionList autoCompletionList = null;
+
+    /**
+     * constructor
+     */
+    public MemberRoleCellEditor() {
+        editor = new AutoCompletingTextField();
+        acCache = new AutoCompletionCache();
+    }
+
+    /**
+     * initializes the autocompletion editor with the list of member roles in
+     * the current dataset
+     * 
+     */
+    protected void initAutoCompletionListRoles() {
+        if (autoCompletionList == null) {
+            logger.warning("autoCompletionList is null. Make sure an instance of AutoCompletionList is injected into MemberRoleCellEditor.");
+            return;
+        }
+        autoCompletionList.clear();
+
+        // add the list of keys in the current data set
+        //
+        for (String key : acCache.getMemberRoles()) {
+            autoCompletionList.add(
+                    new AutoCompletionListItem(key, AutoCompletionItemPritority.IS_IN_DATASET)
+            );
+        }
+        autoCompletionList.fireTableDataChanged();
+    }
+
+    /**
+     * replies the table cell editor
+     */
+    public Component getTableCellEditorComponent(JTable table,
+            Object value, boolean isSelected, int row, int column) {
+
+        String role = (String)value;
+        editor.setText(role);
+        initAutoCompletionListRoles();
+        return editor;
+    }
+
+    public Object getCellEditorValue() {
+        return editor.getText();
+    }
+
+    @Override
+    public void cancelCellEditing() {
+        super.cancelCellEditing();
+    }
+
+    @Override
+    public boolean stopCellEditing() {
+        return super.stopCellEditing();
+    }
+
+    /**
+     * replies the {@link AutoCompletionList} this table cell editor synchronizes with
+     * 
+     * @return the auto completion list
+     */
+    public AutoCompletionList getAutoCompletionList() {
+        return autoCompletionList;
+    }
+
+    /**
+     * sets the {@link AutoCompletionList} this table cell editor synchronizes with
+     * @param autoCompletionList the auto completion list
+     */
+    public void setAutoCompletionList(AutoCompletionList autoCompletionList) {
+        this.autoCompletionList = autoCompletionList;
+        editor.setAutoCompletionList(autoCompletionList);
+    }
+
+    public void setAutoCompletionCache(AutoCompletionCache acCache) {
+        this.acCache = acCache;
+    }
+
+    public AutoCompletingTextField getEditor() {
+        return editor;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableColumnModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableColumnModel.java	(revision 1915)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableColumnModel.java	(revision 1916)
@@ -17,5 +17,5 @@
         col.setResizable(true);
         col.setCellRenderer(new MemberTableRoleCellRenderer());
-
+        col.setCellEditor(new MemberRoleCellEditor());
         addColumn(col);
 
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java	(revision 1915)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java	(revision 1916)
@@ -1,3 +1,2 @@
-// License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.dialogs.relation;
 
@@ -10,4 +9,5 @@
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
 import java.util.Vector;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -17,4 +17,6 @@
 import javax.swing.table.AbstractTableModel;
 
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
@@ -23,17 +25,20 @@
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
-
-public class MemberTableModel extends AbstractTableModel {
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+
+public class MemberTableModel extends AbstractTableModel implements SelectionChangedListener{
 
     private ArrayList<RelationMember> members;
     private DefaultListSelectionModel listSelectionModel;
     private CopyOnWriteArrayList<IMemberModelListener> listeners;
+    private OsmDataLayer layer;
 
     /**
      * constructor
      */
-    public MemberTableModel() {
+    public MemberTableModel(OsmDataLayer layer) {
         members = new ArrayList<RelationMember>();
         listeners = new CopyOnWriteArrayList<IMemberModelListener>();
+        this.layer = layer;
     }
 
@@ -82,10 +87,10 @@
     public Object getValueAt(int rowIndex, int columnIndex) {
         switch (columnIndex) {
-        case 0:
-            return members.get(rowIndex).role;
-        case 1:
-            return members.get(rowIndex).member;
-        case 2:
-            return linked(rowIndex);
+            case 0:
+                return members.get(rowIndex).role;
+            case 1:
+                return members.get(rowIndex).member;
+            case 2:
+                return linked(rowIndex);
         }
         // should not happen
@@ -119,10 +124,11 @@
         }
         fireTableDataChanged();
-        getSelectionModel();
-        listSelectionModel.clearSelection();
+        getSelectionModel().setValueIsAdjusting(true);
+        getSelectionModel().clearSelection();
         for (int row : selectedRows) {
             row--;
-            listSelectionModel.addSelectionInterval(row, row);
-        }
+            getSelectionModel().addSelectionInterval(row, row);
+        }
+        getSelectionModel().setValueIsAdjusting(false);
         fireMakeMemberVisible(selectedRows[0] - 1);
     }
@@ -141,9 +147,11 @@
         fireTableDataChanged();
         getSelectionModel();
-        listSelectionModel.clearSelection();
+        getSelectionModel().setValueIsAdjusting(true);
+        getSelectionModel().clearSelection();
         for (int row : selectedRows) {
             row++;
-            listSelectionModel.addSelectionInterval(row, row);
-        }
+            getSelectionModel().addSelectionInterval(row, row);
+        }
+        getSelectionModel().setValueIsAdjusting(false);
         fireMakeMemberVisible(selectedRows[0] + 1);
     }
@@ -290,8 +298,10 @@
         }
         fireTableDataChanged();
+        getSelectionModel().setValueIsAdjusting(true);
         getSelectionModel().clearSelection();
         for (int i = 0; i < primitives.size(); i++) {
             getSelectionModel().addSelectionInterval(idx + i, idx + i);
         }
+        getSelectionModel().setValueIsAdjusting(false);
         fireMakeMemberVisible(idx);
     }
@@ -307,8 +317,10 @@
         }
         fireTableDataChanged();
+        getSelectionModel().setValueIsAdjusting(true);
         getSelectionModel().clearSelection();
         for (int i = 0; i < primitives.size(); i++) {
             getSelectionModel().addSelectionInterval(idx + 1 + i, idx + 1 + i);
         }
+        getSelectionModel().setValueIsAdjusting(false);
         fireMakeMemberVisible(idx + 1);
     }
@@ -361,4 +373,29 @@
     }
 
+    /**
+     * Replies the set of selected referers. Never null, but may be empty.
+     * 
+     * @return the set of selected referers
+     */
+    public Set<OsmPrimitive> getSelectedReferers() {
+        HashSet<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
+        for (RelationMember m: getSelectedMembers()) {
+            ret.add(m.member);
+        }
+        return ret;
+    }
+
+    /**
+     * Replies true, if the selected {@see OsmPrimitive}s in the layer belonging
+     * to this model are in sync with the selected referers in this model.
+     * 
+     * @return
+     */
+    public boolean selectionsAreInSync() {
+        HashSet<OsmPrimitive> s1 = new HashSet<OsmPrimitive>(getSelectedReferers());
+        if (s1.size() > layer.data.getSelected().size()) return false;
+        s1.removeAll(layer.data.getSelected());
+        return s1.isEmpty();
+    }
     /**
      * Selects the members in the collection selectedMembers
@@ -386,8 +423,10 @@
         //
         Collections.sort(selectedIndices);
+        getSelectionModel().setValueIsAdjusting(true);
         getSelectionModel().clearSelection();
         for (int row : selectedIndices) {
             getSelectionModel().addSelectionInterval(row, row);
         }
+        getSelectionModel().setValueIsAdjusting(false);
 
         // make the first selected member visible
@@ -441,4 +480,49 @@
         }
         return false;
+    }
+
+    /**
+     * Selects all mebers which refer to {@see OsmPrimitive}s in the collections
+     * <code>primitmives</code>. Does nothing is primitives is null.
+     * 
+     * @param primitives the collection of primitives
+     */
+    public void selectMembersReferringTo(Collection<? extends OsmPrimitive> primitives) {
+        if (primitives == null || primitives.isEmpty()) return;
+        getSelectionModel().setValueIsAdjusting(true);
+        getSelectionModel().clearSelection();
+        for (int i=0; i< members.size();i++) {
+            RelationMember m = members.get(i);
+            if (primitives.contains(m.member)) {
+                this.getSelectionModel().addSelectionInterval(i,i);
+            }
+        }
+        getSelectionModel().setValueIsAdjusting(false);
+        if (getSelectedIndices().size() > 0) {
+            fireMakeMemberVisible(getSelectedIndices().get(0));
+        }
+    }
+
+    /**
+     * Replies true if the layer this model belongs to is equal to the active
+     * layer
+     * 
+     * @return true if the layer this model belongs to is equal to the active
+     * layer
+     */
+    protected boolean isActiveLayer() {
+        if (Main.map == null || Main.map.mapView == null) return false;
+        return Main.map.mapView.getActiveLayer() == layer;
+    }
+
+
+    /* ------------------------------------------------------------------------- */
+    /* Interface SelectionChangedListener                                        */
+    /* ------------------------------------------------------------------------- */
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        // ignore selection change events if they happen for a dataset in another
+        // layer
+        if (!isActiveLayer()) return;
+        selectMembersReferringTo(newSelection);
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/TagCellEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/TagCellEditor.java	(revision 1915)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/TagCellEditor.java	(revision 1916)
@@ -24,5 +24,5 @@
     static private Logger logger = Logger.getLogger(TagCellEditor.class.getName());
 
-    private TagFieldEditor editor = null;
+    private AutoCompletingTextField editor = null;
     private TagModel currentTag = null;
     private TagEditorModel tagEditorModel = null;
@@ -39,5 +39,5 @@
      */
     public TagCellEditor() {
-        editor = new TagFieldEditor();
+        editor = new AutoCompletingTextField();
         acCache = new AutoCompletionCache();
     }
@@ -59,5 +59,4 @@
             return;
         }
-
         autoCompletionList.clear();
 
@@ -90,5 +89,4 @@
      */
     protected void initAutoCompletionListForValues(String forKey) {
-
         if (autoCompletionList == null) {
             logger.warning("autoCompletionList is null. Make sure an instance of AutoCompletionList is injected into TableCellEditor.");
@@ -96,5 +94,4 @@
         }
         autoCompletionList.clear();
-
         for (String value : acCache.getValues(forKey)) {
             autoCompletionList.add(
@@ -193,5 +190,5 @@
     }
 
-    public TagFieldEditor getEditor() {
+    public AutoCompletingTextField getEditor() {
         return editor;
     }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/TagFieldEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/TagFieldEditor.java	(revision 1915)
+++ 	(revision )
@@ -1,140 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.dialogs.relation;
-
-import java.awt.event.FocusAdapter;
-import java.awt.event.FocusEvent;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.util.logging.Logger;
-
-import javax.swing.JTextField;
-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.dialogs.relation.ac.AutoCompletionList;
-
-/**
- * TagFieldEditor is an editor for tag names or tag values. It supports auto completion
- * from a list of auto completion items.
- *
- */
-public class TagFieldEditor extends JTextField  {
-
-    static private Logger logger = Logger.getLogger(TagFieldEditor.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());
-            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();
-    }
-
-    /**
-     * constructor
-     */
-    public TagFieldEditor() {
-
-        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("");
-                        }
-                    }
-                }
-        );
-    }
-
-    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;
-    }
-}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/ac/AutoCompletionCache.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/ac/AutoCompletionCache.java	(revision 1915)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/ac/AutoCompletionCache.java	(revision 1916)
@@ -3,8 +3,12 @@
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+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;
@@ -29,6 +33,8 @@
  */
 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>();
@@ -63,4 +69,5 @@
     /** the cache */
     private HashMap<String, ArrayList<String>> cache;
+    private  ArrayList<String> roleCache;
     private OsmDataLayer layer;
 
@@ -70,4 +77,5 @@
     public AutoCompletionCache(OsmDataLayer layer) {
         cache = new HashMap<String, ArrayList<String>>();
+        roleCache = new ArrayList<String>();
         this.layer = layer;
     }
@@ -114,4 +122,20 @@
             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.members) {
+            if (m.role == null || m.role.trim().equals("")) {
+                continue;
+            }
+            if (!roleCache.contains(m.role)) {
+                roleCache.add(m.role);
+            }
         }
     }
@@ -130,4 +154,11 @@
             cachePrimitive(primitive);
         }
+        for (Relation relation : layer.data.relations) {
+            if (relation.incomplete || relation.deleted) {
+                continue;
+            }
+            cacheRelationMemberRoles(relation);
+            Collections.sort(roleCache);
+        }
     }
 
@@ -151,6 +182,27 @@
         if (!cache.containsKey(key))
             return new ArrayList<String>();
-        else
-            return cache.get(key);
+        return cache.get(key);
+    }
+
+    /**
+     * Replies the list of member roles
+     * 
+     * @return the list of member roles
+     */
+    public List<String> getMemberRoles() {
+        return 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();
+        for (String role: roleCache) {
+            list.add(new AutoCompletionListItem(role, AutoCompletionItemPritority.IS_IN_DATASET));
+        }
     }
 }
