Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/dnd/PrimitiveIdListTransferHandler.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/dnd/PrimitiveIdListTransferHandler.java	(revision 20495)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/dnd/PrimitiveIdListTransferHandler.java	(revision 20527)
@@ -24,4 +24,17 @@
 	
 	/**
+	 * Replies true if {@code transferFlavors} includes the data flavor {@see PrimitiveIdTransferable#PRIMITIVE_ID_LIST_FLAVOR}.
+
+	 * @param transferFlavors an array of transferFlavors
+	 * @return true if {@code transferFlavors} includes the data flavor {@see PrimitiveIdTransferable#PRIMITIVE_ID_LIST_FLAVOR}.
+	 */
+	public static boolean isSupportedFlavor(DataFlavor[] transferFlavors) {
+		for (DataFlavor df: transferFlavors) {
+			if (df.equals(PrimitiveIdTransferable.PRIMITIVE_ID_LIST_FLAVOR)) return true;
+		}
+		return false;
+	}
+	
+	/**
 	 * Creates the transfer handler 
 	 * 
@@ -34,16 +47,5 @@
 	}
 
-	/**
-	 * Replies true if {@code transferFlavors} includes the data flavor {@see PrimitiveIdTransferable#PRIMITIVE_ID_LIST_FLAVOR}.
-
-	 * @param transferFlavors an array of transferFlavors
-	 * @return
-	 */
-	protected boolean isSupportedFlavor(DataFlavor[] transferFlavors) {
-		for (DataFlavor df: transferFlavors) {
-			if (df.equals(PrimitiveIdTransferable.PRIMITIVE_ID_LIST_FLAVOR)) return true;
-		}
-		return false;
-	}
+	
 	
 	protected Transferable createTransferable(JComponent c) {
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/AdvancedEditorPanel.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/AdvancedEditorPanel.java	(revision 20527)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/AdvancedEditorPanel.java	(revision 20527)
@@ -0,0 +1,119 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.editor;
+
+import java.awt.BorderLayout;
+
+import java.awt.event.HierarchyEvent;
+import java.awt.event.HierarchyListener;
+import java.util.logging.Logger;
+
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+
+import org.openstreetmap.josm.gui.tagging.TagEditorPanel;
+import org.openstreetmap.josm.gui.widgets.HtmlPanel;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+/**
+ * AdvancedEditorPanel consists of two advanced editors for parts of the turn
+ * restriction data: a tag editor and a relation member editor.
+ */
+public class AdvancedEditorPanel extends JPanel {
+	private static final Logger logger = Logger.getLogger(AdvancedEditorPanel.class.getName());
+
+	private TurnRestrictionEditorModel model;
+	private TagEditorPanel pnlTagEditor; 
+	private JPanel pnlRelationMemberEditor;
+	private JTable tblRelationMemberEditor;
+	private JSplitPane spEditors;
+	
+	/**
+	 * Creates the panel with the tag editor 
+	 * 
+	 * @return
+	 */
+	protected JPanel buildTagEditorPanel() {
+		JPanel pnl = new JPanel(new BorderLayout());
+		HtmlPanel msg = new HtmlPanel();
+		msg.setText(tr(
+				"<html><body>In the following table you can edit the <strong>raw tags</strong>"
+			  + " of the OSM relation representing this turn restriction."
+		));
+		pnl.add(msg, BorderLayout.NORTH);
+		pnlTagEditor = new TagEditorPanel(model.getTagEditorModel());	
+		pnlTagEditor.initAutoCompletion(model.getLayer());
+		pnl.add(pnlTagEditor, BorderLayout.CENTER);
+		return pnl;
+	}
+	
+	/**
+	 * Builds the panel with the table for editing relation members
+	 * 
+	 * @return
+	 */
+	protected JPanel buildMemberEditorPanel() {
+		JPanel pnl = new JPanel(new BorderLayout());
+		HtmlPanel msg = new HtmlPanel();
+		msg.setText(tr(
+				"<html><body>In the following table you can edit the <strong>raw members</strong>"
+			  + " of the OSM relation representing this turn restriction."
+		));
+		pnl.add(msg, BorderLayout.NORTH);
+		
+		tblRelationMemberEditor = new RelationMemberTable(model);
+		JScrollPane pane = new JScrollPane(tblRelationMemberEditor);
+		pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+		pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+		pnl.add(pane);
+		return pnl;
+	}
+	
+	/**
+	 * Creates the main split panel 
+	 * @return
+	 */
+	protected JSplitPane buildSplitPane() {
+		spEditors = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+		spEditors.setTopComponent(buildTagEditorPanel());
+		spEditors.setBottomComponent(buildMemberEditorPanel());
+		spEditors.setOneTouchExpandable(false);
+		spEditors.setDividerSize(5);
+		spEditors.addHierarchyListener(new SplitPaneDividerInitializer());
+		return spEditors;
+	}
+	
+	/**
+	 * Builds the user interface
+	 */
+	protected void build() {
+		setLayout(new BorderLayout());
+		add(buildSplitPane(), BorderLayout.CENTER);
+	}
+	
+	/**
+	 * Creates the advanced editor
+	 * 
+	 * @param model the editor model. Must not be null.
+	 * @throws IllegalArgumentException thrown if model is null
+	 */
+	public AdvancedEditorPanel(TurnRestrictionEditorModel model) throws IllegalArgumentException{
+		CheckParameterUtil.ensureParameterNotNull(model, "model");
+		this.model = model;
+		build();
+	}
+	
+	/**
+	 * Initializes the divider location when the components becomes visible the
+	 * first time 
+	 */
+	class SplitPaneDividerInitializer implements HierarchyListener {
+		public void hierarchyChanged(HierarchyEvent e) {
+			if (isShowing()) {
+				spEditors.setDividerLocation(0.5);
+				spEditors.removeHierarchyListener(this);
+			}			
+		}		
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/JosmSelectionListModel.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/JosmSelectionListModel.java	(revision 20495)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/JosmSelectionListModel.java	(revision 20527)
@@ -227,6 +227,8 @@
 	public List<PrimitiveId> getSelectedPrimitiveIds() {
 		List<PrimitiveId> ret = new ArrayList<PrimitiveId>(getSelected().size());
-		for(OsmPrimitive p: getSelected()) {
-			ret.add(p.getPrimitiveId());
+		for(int i=0; i< selection.size(); i++) {
+			if (selectionModel.isSelectedIndex(i)) {
+				ret.add(selection.get(i).getPrimitiveId());
+			}
 		}
 		return ret;
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberColumnModel.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberColumnModel.java	(revision 20527)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberColumnModel.java	(revision 20527)
@@ -0,0 +1,46 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.editor;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import javax.swing.DefaultListSelectionModel;
+import javax.swing.table.DefaultTableColumnModel;
+import javax.swing.table.TableColumn;
+
+import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+/**
+ * RelationMemberColumnModel is the column model for the table of relation members
+ * displayed in the {@see AdvancedEditorPanel}.
+ */
+public class RelationMemberColumnModel extends DefaultTableColumnModel{
+	protected void build() {
+		TableColumn col = new TableColumn();
+		
+		 // the role column
+		 col.setHeaderValue(tr("Role"));
+		 col.setResizable(true);
+		 col.setPreferredWidth(100);				 
+		 addColumn(col);
+		 
+		  // column 1 - the member
+	      col = new TableColumn(1);
+	      col.setHeaderValue(tr("Refers to"));
+	      col.setResizable(true);
+	      col.setPreferredWidth(300);
+	      col.setCellRenderer(new OsmPrimitivRenderer());
+	      addColumn(col);	      
+	}
+	
+	/**
+	 * Creates the column model with a given column selection model.
+	 * 
+	 * @param colSelectionModel the column selection model. Must not be null.
+	 * @throws IllegalArgumentException thrown if {@code colSelectionModel} is null
+	 */
+	public RelationMemberColumnModel(DefaultListSelectionModel colSelectionModel) throws IllegalArgumentException{
+		CheckParameterUtil.ensureParameterNotNull(colSelectionModel, "colSelectionModel");
+		setSelectionModel(colSelectionModel);
+		build();
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberEditorModel.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberEditorModel.java	(revision 20527)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberEditorModel.java	(revision 20527)
@@ -0,0 +1,422 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.editor;
+
+
+import java.text.MessageFormat;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import javax.swing.DefaultListSelectionModel;
+import javax.swing.table.AbstractTableModel;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.gui.DefaultNameFormatter;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+public class RelationMemberEditorModel extends AbstractTableModel{	
+	static private final Logger logger = Logger.getLogger(RelationMemberEditorModel.class.getName());
+	private final ArrayList<RelationMemberModel> members = new ArrayList<RelationMemberModel>();
+	private OsmDataLayer layer;
+	private DefaultListSelectionModel rowSelectionModel;
+	private DefaultListSelectionModel colSelectionModel;
+	
+	/**
+	 * Creates a new model in the context of an {@see OsmDataLayer}. Internally allocates
+	 * a row and a column selection model, see {@see #getRowSelectionModel()} and 
+	 * {@see #getColSelectionModel()}.
+	 * 
+	 * @param layer the data layer. Must not be null.
+	 * @exception IllegalArgumentException thrown if layer is null
+	 */
+	public RelationMemberEditorModel(OsmDataLayer layer) throws IllegalArgumentException{
+		CheckParameterUtil.ensureParameterNotNull(layer, "layer");
+		this.layer = layer;
+		rowSelectionModel = new DefaultListSelectionModel();
+		colSelectionModel = new DefaultListSelectionModel();
+	}
+
+	/**
+	 *  Creates a new model in the context of an {@see OsmDataLayer}
+	 *  
+	 * @param layer layer the data layer. Must not be null.
+	 * @param rowSelectionModel the row selection model. Must not be null.
+	 * @param colSelectionModel the column selection model. Must not be null.
+	 * @throws IllegalArgumentException thrown if layer is null
+	 * @throws IllegalArgumentException thrown if rowSelectionModel is null
+	 * @throws IllegalArgumentException thrown if colSelectionModel is null
+	 */
+	public RelationMemberEditorModel(OsmDataLayer layer, DefaultListSelectionModel rowSelectionModel, DefaultListSelectionModel colSelectionModel) throws IllegalArgumentException{
+		CheckParameterUtil.ensureParameterNotNull(layer, "layer");
+		CheckParameterUtil.ensureParameterNotNull(rowSelectionModel, "rowSelectionModel");
+		CheckParameterUtil.ensureParameterNotNull(colSelectionModel, "colSelectionModel");
+		this.layer = layer;
+		this.rowSelectionModel = rowSelectionModel;
+		this.colSelectionModel = colSelectionModel;
+	}
+
+	/**
+	 * Replies the row selection model used in this table model.
+	 * 
+	 * @return the row selection model 
+	 */
+	public DefaultListSelectionModel getRowSelectionModel() {
+		return rowSelectionModel;
+	}
+	
+	/**
+	 * Replies the column selection model used in this table model.
+	 * 
+	 * @return the col selection model
+	 */
+	public DefaultListSelectionModel getColSelectionModel() {
+		return colSelectionModel;
+	}
+	
+	/**
+	 * Replies the set of {@see OsmPrimitive}s with the role {@code role}. If no
+	 * such primitives exists, the empty set is returned.
+	 * 
+	 * @return the set of {@see OsmPrimitive}s with the role {@code role}
+	 */
+	protected Set<OsmPrimitive> getPrimitivesWithRole(String role) {
+		HashSet<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
+		for (RelationMemberModel rm: members){
+			if (rm.getRole().equals(role)){
+				OsmPrimitive p = layer.data.getPrimitiveById(rm.getTarget());
+				if (p != null){
+					ret.add(p);
+				}
+			}
+		}
+		return ret;
+	}
+	
+	/**
+	 * Replies the list of {@see RelationMemberModel}s with the role {@code role}. If no
+	 * such primitives exists, the empty set is returned.
+	 * 
+	 * @return the set of {@see RelationMemberModel}s with the role {@code role}
+	 */
+	protected List<RelationMemberModel> getRelationMembersWithRole(String role) {
+		ArrayList<RelationMemberModel> ret = new ArrayList<RelationMemberModel>();
+		for (RelationMemberModel rm: members){
+			if (rm.getRole().equals(role)){
+				ret.add(rm);
+			}
+		}
+		return ret;
+	}
+	
+	/**
+	 * Removes all members with role {@code role}.
+	 * 
+	 * @param role the role. Ignored if null.
+	 * @return true if the list of members was modified; false, otherwise
+	 */
+	protected boolean removeMembersWithRole(String role){
+		if (role == null) return false;
+		boolean isChanged = false;
+		for(Iterator<RelationMemberModel> it = members.iterator(); it.hasNext(); ){
+			RelationMemberModel rm = it.next();
+			if (rm.getRole().equals(role)) {
+				it.remove();
+				isChanged = true;
+			}
+		}
+		return isChanged;
+	}
+	
+	/**
+	 * Replies the set of {@see OsmPrimitive}s with the role 'from'. If no
+	 * such primitives exists, the empty set is returned.
+	 * 
+	 * @return the set of {@see OsmPrimitive}s with the role 'from'
+	 */
+	public Set<OsmPrimitive> getFromPrimitives() {
+		return getPrimitivesWithRole("from");		
+	}
+	
+	/**
+	 * Replies the set of {@see OsmPrimitive}s with the role 'to'. If no
+	 * such primitives exists, the empty set is returned.
+	 * 
+	 * @return the set of {@see OsmPrimitive}s with the role 'from'
+	 */
+	public Set<OsmPrimitive> getToPrimitives() {
+		return getPrimitivesWithRole("to");
+	}
+	
+	/**
+	 * Replies the list of 'via' objects in the order they occur in the
+	 * member list. Replies an empty list if no vias exist
+	 * 
+	 * @return 
+	 */
+	public List<OsmPrimitive> getVias() {
+		ArrayList<OsmPrimitive> ret = new ArrayList<OsmPrimitive>();
+		for (RelationMemberModel rm: getRelationMembersWithRole("via")){
+			ret.add(layer.data.getPrimitiveById(rm.getTarget()));
+		}
+		return ret;
+	}
+	
+	/**
+	 * Sets the list of vias. Removes all 'vias' if {@code vias} is null.
+	 * 
+	 * null vias are skipped. A via must belong to the dataset of the layer in whose context
+	 * this editor is working, otherwise an {@see IllegalArgumentException} is thrown.
+	 * 
+	 * @param vias the vias.
+	 * @exception IllegalArgumentException thrown if a via doesn't belong to the dataset of the layer
+	 * in whose context this editor is working 
+	 */
+	public void setVias(List<OsmPrimitive> vias){
+		boolean viasDeleted = removeMembersWithRole("via");
+		if (vias == null || vias.isEmpty()){
+			if (viasDeleted){
+				fireTableDataChanged();
+			}
+			return;
+		}
+		// check vias 
+		for (OsmPrimitive via: vias) {
+			if (via == null) continue;
+			if (via.getDataSet() == null || via.getDataSet() != layer.data){
+				throw new IllegalArgumentException(MessageFormat.format("via object ''{0}'' must belong to dataset of layer ''{1}''", via.getDisplayName(DefaultNameFormatter.getInstance()), layer.getName()));
+			}
+		}
+		// add vias 
+		for (OsmPrimitive via: vias) {
+			if (via == null) continue;
+			RelationMemberModel model = new RelationMemberModel("via", via);
+			members.add(model);
+		}
+		fireTableDataChanged();
+	}
+	
+	/**
+	 * Sets the turn restriction member with role {@code role}. Removes all
+	 * members with role {@code role} if {@code id} is null.
+	 * 
+	 * @param id the id 
+	 * @return true if the model was modified; false, otherwise
+	 */
+	protected boolean setPrimitiveWithRole(PrimitiveId id, String role){
+		if (id == null){
+			return removeMembersWithRole(role);
+		}
+		
+		List<RelationMemberModel> fromMembers = getRelationMembersWithRole(role);
+		if (fromMembers.isEmpty()){
+			RelationMemberModel rm = new RelationMemberModel(role, id);
+			members.add(rm);
+			return true;
+		} else if (fromMembers.size() == 1){
+			RelationMemberModel rm = fromMembers.get(0);
+			if (!rm.getTarget().equals(id)){
+				rm.setTarget(id);
+				return true;
+			}
+			return false;
+		} else {
+			removeMembersWithRole(role);
+			RelationMemberModel rm = new RelationMemberModel(role, id);
+			members.add(rm);
+			return true;
+		}
+	}
+	
+	/**
+	 * Sets the turn restriction member with role 'from'. Removes all
+	 * members with role 'from' if {@code id} is null.
+	 * 
+	 * @param id the id 
+	 */
+	public void setFromPrimitive(PrimitiveId id){
+		if (setPrimitiveWithRole(id, "from")) {
+			fireTableDataChanged();
+		}
+	}
+	
+	/**
+	 * Sets the turn restriction member with role 'to'. Removes all
+	 * members with role 'to' if {@code id} is null.
+	 * 
+	 * @param id the id 
+	 */
+	public void setToPrimitive(PrimitiveId id){
+		if (setPrimitiveWithRole(id, "to")) {
+			fireTableDataChanged();
+		}
+	}
+	
+	/**
+	 * Replies the set of {@see OsmPrimitive}s referred to by members in
+	 * this model.
+	 * 
+	 * @return the set of {@see OsmPrimitive}s referred to by members in
+	 * this model.
+	 */
+	public Set<OsmPrimitive> getMemberPrimitives() {
+		Set<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
+		for (RelationMemberModel rm: members){
+			OsmPrimitive p = layer.data.getPrimitiveById(rm.getTarget());
+			if (p != null) ret.add(p);
+		}
+		return ret;
+	}
+	
+	/**
+	 * Populates the model with the relation member of a turn restriction. Clears
+	 * the model if {@code tr} is null. 
+	 * 
+	 * @param tr the turn restriction
+	 */
+	public void populate(Relation tr){
+		members.clear();
+		if (tr == null){
+			fireTableDataChanged();
+			return;
+		}
+		for(RelationMember rm: tr.getMembers()){
+			members.add(new RelationMemberModel(rm));
+		}
+		fireTableDataChanged();
+	}
+	
+	/**
+	 * Replaces the member of turn restriction {@code tr} by the relation members currently
+	 * edited in this model.
+	 * 
+	 * @param tr the turn restriction. Ignored if null.
+	 */
+	public void applyTo(Relation tr){
+		if (tr == null) return;
+		List<RelationMember> newMembers = new ArrayList<RelationMember>();
+		for(RelationMemberModel model: members){
+			RelationMember rm = new RelationMember(model.getRole(), layer.data.getPrimitiveById(model.getTarget()));
+			newMembers.add(rm);
+		}
+		tr.setMembers(newMembers);
+	}
+	
+	/**
+	 * Clears the roles of all relation members currently selected in the 
+	 * table.
+	 */
+	protected void clearSelectedRoles(){
+		for(int i=0; i < getRowCount();i++){
+			if (rowSelectionModel.isSelectedIndex(i)) {
+				members.get(i).setRole("");
+			}
+		}		
+	}
+	
+	/**
+	 * Removes the currently selected rows from the model 
+	 */
+	protected void removedSelectedMembers() {
+		int j = 0;
+		for(int i=0; i < getRowCount();i++){
+			if (rowSelectionModel.isSelectedIndex(i)) {
+				members.remove(i - j);
+				j++;
+			}
+		}
+	}
+	
+	/**
+	 * Deletes the current selection.
+	 * 
+	 * If only cells in the first column are selected, the roles of the selected
+	 * members are reset to the empty string. Otherwise the selected members are
+	 * removed from the model. 
+	 * 
+	 */
+	public void deleteSelected() {
+		if (colSelectionModel.isSelectedIndex(0) && !colSelectionModel.isSelectedIndex(1)) {
+			clearSelectedRoles();
+		} else if (rowSelectionModel.getMinSelectionIndex() >= 0){
+			removedSelectedMembers();
+		}
+		fireTableDataChanged();
+	}
+	
+	/**
+	 * Inserts a list of new relation members with the empty role for the primitives
+	 * with id in {@code ids}. Inserts the new primitives at the position of the first
+	 * selected row. If no row is selected, at the end of the list. 
+	 * 
+	 *  null values are skipped. If there is an id for which there is no primitive in the context 
+	 *  layer, if the primitive is deleted or invisible, an {@see IllegalArgumentException}
+	 *  is thrown and nothing is inserted. 
+	 * 
+	 * @param ids the list of ids. Ignored if null.
+	 * @throws IllegalArgumentException thrown if one of the ids can't be inserted
+	 */
+	public void insertMembers(Collection<PrimitiveId> ids) throws IllegalArgumentException {
+		if (ids == null) return;	
+		ArrayList<RelationMemberModel> newMembers = new ArrayList<RelationMemberModel>();
+		for (PrimitiveId id: ids){
+			OsmPrimitive p = layer.data.getPrimitiveById(id);
+			if (p == null){
+				throw new IllegalArgumentException(tr("Cannot find object with id ''{0}'' in layer ''{1}''", id.toString(), layer.getName()));
+			}
+			if (p.isDeleted() || ! p.isVisible()) {
+				throw new IllegalArgumentException(tr("Cannot add object ''{0}'' as relation member because it is deleted or invisible in layer ''{1}''", p.getDisplayName(DefaultNameFormatter.getInstance()), layer.getName()));				
+			}
+			newMembers.add(new RelationMemberModel("",id));
+		}
+		if (newMembers.isEmpty()) return;
+		int insertPos = rowSelectionModel.getMinSelectionIndex();
+		if ( insertPos >=0){
+			members.addAll(insertPos, newMembers);
+		} else {
+			members.addAll(newMembers);
+		}
+		fireTableDataChanged();
+		if (insertPos < 0) insertPos = 0;		
+		colSelectionModel.setSelectionInterval(0, 1); // select both columns
+		rowSelectionModel.setSelectionInterval(insertPos, insertPos + newMembers.size()-1);
+	}
+
+	public int getColumnCount() {
+		return 2;
+	}
+
+	public int getRowCount() {
+		return members.size();
+	}
+
+	public Object getValueAt(int rowIndex, int columnIndex) {
+		switch(columnIndex){
+		case 0: return members.get(rowIndex).getRole();
+		case 1: return layer.data.getPrimitiveById(members.get(rowIndex).getTarget());
+		}
+		return null;
+	}
+
+	@Override
+	public boolean isCellEditable(int rowIndex, int columnIndex) {
+		return columnIndex == 0;
+	}
+
+	@Override
+	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+		if (columnIndex !=0)return;
+		String role = (String)aValue;
+		RelationMemberModel model = members.get(rowIndex);
+		model.setRole(role);
+		fireTableCellUpdated(rowIndex, columnIndex);
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberModel.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberModel.java	(revision 20527)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberModel.java	(revision 20527)
@@ -0,0 +1,114 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.editor;
+
+import java.io.Serializable;
+
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+/**
+ * RelationMemberModel is a mutable relation member. In contrast to
+ * {@see RelationMember} it doesn't keep references to the referred
+ * primitive. Internally, it only keeps their the unique id.
+ *
+ *
+ */
+public class RelationMemberModel implements Serializable{
+	private String role;
+	private SimplePrimitiveId target;
+	
+	/**
+	 * Creates a new relation member model
+	 * 
+	 * @param role the member role. Reset to "" if null.
+	 * @param target the id of the target object. Must not be null.
+	 * @throws IllegalArgumentException thrown if {@code target} is null
+	 */
+	public RelationMemberModel(String role, PrimitiveId target) throws IllegalArgumentException {
+		CheckParameterUtil.ensureParameterNotNull(target, "target");
+		this.role = role == null? "" : role;
+		this.target = new SimplePrimitiveId(target.getUniqueId(), target.getType());
+	}
+	
+	/**
+	 * Creates a new relation member model from a relation member 
+	 * 
+	 * @param member the relation member. Must not be null.
+	 * @throws IllegalArgumentException thrown if {@code member} is null
+	 */
+	public RelationMemberModel(RelationMember member) throws IllegalArgumentException{
+		CheckParameterUtil.ensureParameterNotNull(member, "member");
+		this.role = member.getRole();
+		setTarget(member.getMember().getPrimitiveId());
+	}
+
+	/**
+	 * Replies the current role in this model. Never null.
+	 * 
+	 * @return the current role in this model
+	 */
+	public String getRole() {
+		return role;
+	}
+
+	/**
+	 * Sets the current role in this model. 
+	 * 
+	 * @param role the role. Reset to "" if null.
+	 */
+	public void setRole(String role) {
+		this.role = role == null? "" : role;
+	}
+
+	/**
+	 * Replies the id of the target object of this relation member.
+	 * 
+	 * @return the id of the target object of this relation member.
+	 */
+	public PrimitiveId getTarget() {
+		return target;
+	}
+
+	/**
+	 * Sets the id of the target object.  
+	 * 
+	 * @param target the id of the target object. Must not be null.
+	 * @throws IllegalArgumentException thrown if {@code target} is null
+	 */
+	public void setTarget(PrimitiveId target) throws IllegalArgumentException{
+		CheckParameterUtil.ensureParameterNotNull(target, "target");
+		this.target = new SimplePrimitiveId(target.getUniqueId(), target.getType());
+	}
+	
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((role == null) ? 0 : role.hashCode());
+		result = prime * result + ((target == null) ? 0 : target.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		RelationMemberModel other = (RelationMemberModel) obj;
+		if (role == null) {
+			if (other.role != null)
+				return false;
+		} else if (!role.equals(other.role))
+			return false;
+		if (target == null) {
+			if (other.target != null)
+				return false;
+		} else if (!target.equals(other.target))
+			return false;
+		return true;
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberTable.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberTable.java	(revision 20527)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberTable.java	(revision 20527)
@@ -0,0 +1,293 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.editor;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.MenuItem;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTarget;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.io.IOException;
+import java.util.List;
+import java.util.logging.Logger;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JComponent;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.JTable;
+import javax.swing.KeyStroke;
+import javax.swing.ListSelectionModel;
+import javax.swing.TransferHandler;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
+import org.openstreetmap.josm.plugins.turnrestrictions.dnd.PrimitiveIdListTransferHandler;
+import org.openstreetmap.josm.plugins.turnrestrictions.dnd.PrimitiveIdTransferable;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * RelationMemberTable is the table for editing the raw member list of 
+ * a turn restriction.
+ * 
+ */
+public class RelationMemberTable extends JTable {
+	static private final Logger logger = Logger.getLogger(RelationMemberTable.class.getName());
+	
+	private TurnRestrictionEditorModel model;
+	private DeleteAction actDelete;
+	private PasteAction actPaste;
+	private TransferHandler transferHandler;
+	
+	public RelationMemberTable(TurnRestrictionEditorModel model) {
+		super(
+				model.getRelationMemberEditorModel(),
+				new RelationMemberColumnModel(model.getRelationMemberEditorModel().getColSelectionModel()),
+				model.getRelationMemberEditorModel().getRowSelectionModel()
+		);
+		this.model = model;
+		setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+        setRowSelectionAllowed(true);
+        setColumnSelectionAllowed(true);
+
+		// register the popup menu launcher
+		addMouseListener(new TablePopupLauncher());
+		
+		// transfer handling
+		setDragEnabled(true);
+		setTransferHandler(new RelationMemberTransferHandler());
+		setDropTarget(new RelationMemberTableDropTarget());
+		
+		// initialize the delete action
+		//
+		actDelete = new DeleteAction();
+		model.getRelationMemberEditorModel().getRowSelectionModel().addListSelectionListener(actDelete);
+		registerKeyboardAction(actDelete, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0), WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+		
+		// initialize the paste action (will be used in the popup, the action map already includes
+		// the standard paste action for transfer handling) 
+		actPaste = new PasteAction();
+	}
+
+	/**
+	 * The action for deleting the selected table cells 
+	 * 
+	 */
+	class DeleteAction extends AbstractAction implements ListSelectionListener{
+		public DeleteAction() {
+			putValue(NAME, tr("Delete"));
+			putValue(SHORT_DESCRIPTION, tr("Clear the selected roles or delete the selected members"));
+			putValue(SMALL_ICON, ImageProvider.get("deletesmall"));
+			putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0));
+			updateEnabledState();
+		}
+		
+		public void updateEnabledState() {
+			setEnabled(model.getRelationMemberEditorModel().getRowSelectionModel().getMinSelectionIndex()>=0);
+		}
+
+		public void actionPerformed(ActionEvent e) {
+			model.getRelationMemberEditorModel().deleteSelected();
+		}
+
+		public void valueChanged(ListSelectionEvent e) {
+			updateEnabledState();
+		}
+	}	
+	
+	/**
+	 * The action for pasting into the relation member table
+	 * 
+	 */
+	class PasteAction extends AbstractAction{		
+		public PasteAction() {
+			putValue(NAME, tr("Paste"));
+			putValue(SHORT_DESCRIPTION, tr("Insert new relation members from object in the clipboard"));
+			putValue(SMALL_ICON, ImageProvider.get("paste"));
+			putValue(ACCELERATOR_KEY, Shortcut.getPasteKeyStroke());
+			updateEnabledState();
+		}
+		
+		public void updateEnabledState() {
+			DataFlavor[] flavors = Toolkit.getDefaultToolkit().getSystemClipboard().getAvailableDataFlavors();
+			setEnabled(PrimitiveIdListTransferHandler.isSupportedFlavor(flavors));
+		}
+
+		public void actionPerformed(ActionEvent evt) {
+			// tried to delegate to 'paste' action in the action map of the
+			// table, but didn't work. Now duplicating the logic of importData(...) in
+			// the transfer handler.
+			//
+			Clipboard cp = Toolkit.getDefaultToolkit().getSystemClipboard();
+			if (!PrimitiveIdListTransferHandler.isSupportedFlavor(cp.getAvailableDataFlavors())) return;
+			try {
+				List<PrimitiveId> ids;
+				ids = (List<PrimitiveId>)cp.getData(PrimitiveIdTransferable.PRIMITIVE_ID_LIST_FLAVOR);
+				try {
+					model.getRelationMemberEditorModel().insertMembers(ids);
+				} catch(IllegalArgumentException e){
+					e.printStackTrace();
+					// FIXME: provide user feedback
+				}
+			} catch(IOException e){
+				e.printStackTrace();
+			} catch(UnsupportedFlavorException e){
+				e.printStackTrace();
+			} 
+		}
+	}	
+	
+	class TablePopupLauncher extends PopupMenuLauncher {
+		@Override
+		public void launch(MouseEvent evt) {
+			int row = rowAtPoint(evt.getPoint());
+			if (getSelectionModel().getMinSelectionIndex() < 0 && row >=0){
+				getSelectionModel().setSelectionInterval(row, row);
+				getColumnModel().getSelectionModel().setSelectionInterval(0, 1);
+			}
+			new PopupMenu().show(RelationMemberTable.this, evt.getX(), evt.getY());
+		}		
+	}
+	
+	class PopupMenu extends JPopupMenu {
+		public PopupMenu() {
+			JMenuItem item = add(actPaste);
+			item.setTransferHandler(transferHandler);
+			actPaste.updateEnabledState();
+			addSeparator();
+			add(actDelete);
+		}
+	}
+	
+	/**
+	 * The transfer handler for the relation member table. 
+	 *
+	 */
+	class RelationMemberTransferHandler extends TransferHandler {
+		
+		@Override
+		public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
+			return PrimitiveIdListTransferHandler.isSupportedFlavor(transferFlavors);
+		}
+
+		@Override
+		public boolean importData(JComponent comp, Transferable t) {
+			try {
+				List<PrimitiveId> ids;
+				ids = (List<PrimitiveId>)t.getTransferData(PrimitiveIdTransferable.PRIMITIVE_ID_LIST_FLAVOR);
+				try {
+					model.getRelationMemberEditorModel().insertMembers(ids);
+				} catch(IllegalArgumentException e){
+					e.printStackTrace();
+					// FIXME: provide user feedback
+					return false;
+				}
+				return true;
+			} catch(IOException e){
+				e.printStackTrace();
+			} catch(UnsupportedFlavorException e){
+				e.printStackTrace();
+			} 
+			return false;
+		}
+
+		@Override
+		public int getSourceActions(JComponent c) {
+			return  COPY_OR_MOVE;
+		}
+	}
+	
+	/**
+	 * A custom drop target for the relation member table. During dragging we need to
+	 * disable colum selection model.  
+	 *
+	 */
+	class RelationMemberTableDropTarget extends DropTarget{		
+		private boolean dropAccepted = false;	
+		
+		/**
+		 * Replies true if {@code transferFlavors} includes the data flavor {@see PrimitiveIdTransferable#PRIMITIVE_ID_LIST_FLAVOR}.
+
+		 * @param transferFlavors an array of transferFlavors
+		 * @return
+		 */
+		protected boolean isSupportedFlavor(DataFlavor[] transferFlavors) {
+			for (DataFlavor df: transferFlavors) {
+				if (df.equals(PrimitiveIdTransferable.PRIMITIVE_ID_LIST_FLAVOR)) return true;
+			}
+			return false;
+		}		
+		
+		public synchronized void dragEnter(DropTargetDragEvent dtde) {
+			if (isSupportedFlavor(dtde.getCurrentDataFlavors())) {
+				if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY_OR_MOVE) != 0){
+					dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);		
+					setColumnSelectionAllowed(false);
+					dropAccepted  = true;
+				} else {
+					dtde.rejectDrag();
+				}
+			} else {
+				dtde.rejectDrag();
+			}
+		}
+		
+		public synchronized void dragExit(DropTargetEvent dte) {
+			setColumnSelectionAllowed(true);
+			dropAccepted = false;
+		}
+		
+		@Override
+		public synchronized void dragOver(DropTargetDragEvent dtde) {
+			int row = rowAtPoint(dtde.getLocation());
+			int selectedRow = getSelectionModel().getMinSelectionIndex();
+			if (row >= 0 && row != selectedRow){
+				getSelectionModel().setSelectionInterval(row, row);
+			}			
+		}
+
+		public synchronized void drop(DropTargetDropEvent dtde) {
+			try {
+				if (!dropAccepted) return; 
+				if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
+					return;
+				}
+				List<PrimitiveId> ids;
+				ids = (List<PrimitiveId>)dtde.getTransferable().getTransferData(PrimitiveIdTransferable.PRIMITIVE_ID_LIST_FLAVOR);
+				try {
+					model.getRelationMemberEditorModel().insertMembers(ids);
+				} catch(IllegalArgumentException e){
+					e.printStackTrace();
+					// FIXME: provide user feedback
+				}
+			} catch(IOException e){
+				e.printStackTrace();
+			} catch(UnsupportedFlavorException e){
+				e.printStackTrace();
+			} finally {
+				setColumnSelectionAllowed(true);
+			}
+		}
+		
+		public synchronized void dropActionChanged(DropTargetDragEvent dtde) {
+			if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
+				dtde.rejectDrag();
+			} else {
+				dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
+			}
+		}
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionEditor.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionEditor.java	(revision 20495)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionEditor.java	(revision 20527)
@@ -77,4 +77,5 @@
     private JosmSelectionPanel pnlJosmSelection;
     private BasicEditorPanel pnlBasicEditor;
+    private AdvancedEditorPanel pnlAdvancedEditor;
     private TurnRestrictionEditorModel editorModel;
     
@@ -117,4 +118,9 @@
     	tpEditors.setTitleAt(0, tr("Basic"));
     	tpEditors.setToolTipTextAt(0, tr("Edit basic attributes of a turn restriction"));
+    	
+    	tpEditors.add(pnlAdvancedEditor = new AdvancedEditorPanel(editorModel));
+    	tpEditors.setTitleAt(1, tr("Advanced"));
+    	tpEditors.setToolTipTextAt(1, tr("Edit the raw tags and members of this turn restriction"));
+    	
     	pnl.add(tpEditors, BorderLayout.CENTER);
     	return pnl;
@@ -161,5 +167,5 @@
      */
     protected void build() {    	
-    	editorModel = new TurnRestrictionEditorModel();
+    	editorModel = new TurnRestrictionEditorModel(getLayer());
     	Container c = getContentPane();
     	c.setLayout(new BorderLayout());
@@ -222,11 +228,9 @@
       
         if (turnRestriction == null) {
-        	editorModel.populate(new Relation(), getLayer().data);
-        } else if (turnRestriction.getDataSet() == null) {
-        	editorModel.populate(turnRestriction, getLayer().data);
-        } else if (turnRestriction.getDataSet() == getLayer().data) {
+        	editorModel.populate(new Relation());
+        } else if (turnRestriction.getDataSet() == null || turnRestriction.getDataSet() == getLayer().data) {
         	editorModel.populate(turnRestriction);
         } else {
-        	throw new IllegalArgumentException(MessageFormat.format("turnRestriction must not belong to the layer {0}", getLayer().getName()));
+        	throw new IllegalArgumentException(MessageFormat.format("turnRestriction must belong to layer ''{0}''", getLayer().getName()));
         }
         setTurnRestrictionSnapshot(turnRestriction == null ? null : new Relation(turnRestriction));
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionEditorModel.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionEditorModel.java	(revision 20495)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionEditorModel.java	(revision 20527)
@@ -2,9 +2,11 @@
 
 import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Observable;
+import java.util.Set;
 import java.util.logging.Logger;
+
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
 
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -13,5 +15,4 @@
 import org.openstreetmap.josm.data.osm.PrimitiveId;
 import org.openstreetmap.josm.data.osm.Relation;
-import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.TagCollection;
 import org.openstreetmap.josm.data.osm.Way;
@@ -27,4 +28,7 @@
 import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
 import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.tagging.TagEditorModel;
+import org.openstreetmap.josm.gui.tagging.TagModel;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 
@@ -59,29 +63,19 @@
 	}
 	
-	
-	/** 
-	 * holds the relation member of turn restriction relation from which the turn
-	 * restriction leg with role 'from' was initialized. This is needed if OSM
-	 * data contains turn restrictions with multiple 'from' members. The
-	 * field is null if a turn restriction didn't have a member with role
-	 * 'from'.
-	 */
-	private RelationMember fromRelationMember;
-	
-	/** 
-	 * holds the relation member of turn restriction relation from which the turn
-	 * restriction leg with role 'to' was initialized. This is needed if OSM
-	 * data contains turn restrictions with multiple 'to' members. The
-	 * field is null if a turn restriction didn't have a member with role
-	 * 'to'.
-	 */
-	private RelationMember toRelationMember;
-	private Way from;
-	private Way to;
-	private TagCollection tags = new TagCollection();
-	private DataSet dataSet;
-	private final List<OsmPrimitive> vias = new ArrayList<OsmPrimitive>();
-	
-	public TurnRestrictionEditorModel(){
+	private OsmDataLayer layer;
+	private final TagEditorModel tagEditorModel = new TagEditorModel();
+	private  RelationMemberEditorModel memberModel;
+	
+	/**
+	 * Creates a model in the context of a {@see OsmDataLayer}
+	 * 
+	 * @param layer the layer. Must not be null.
+	 * @throws IllegalArgumentException thrown if {@code layer} is null
+	 */
+	public TurnRestrictionEditorModel(OsmDataLayer layer) throws IllegalArgumentException{
+		CheckParameterUtil.ensureParameterNotNull(layer, "layer");
+		this.layer = layer;
+		memberModel = new RelationMemberEditorModel(layer);
+		memberModel.addTableModelListener(new RelationMemberModelListener());
 	}
 	
@@ -96,22 +90,14 @@
 	public void setTurnRestrictionLeg(TurnRestrictionLegRole role, Way way) {
 		CheckParameterUtil.ensureParameterNotNull(role, "role");
-		Way oldValue = null;
 		switch(role){
-		case FROM: 
-			oldValue = this.from;
-			this.from = way; 
+		case FROM:
+			memberModel.setFromPrimitive(way);
 			break;
 		case TO:
-			oldValue = this.to;
-			this.to = way; 
+			memberModel.setToPrimitive(way);
 			break;
 		}
+	}	
 		
-		if (oldValue != way) {
-			setChanged();
-			notifyObservers();		
-		}
-	}	
-	
 	/**
 	 * Sets the way participating in the turn restriction in a given role.
@@ -132,11 +118,8 @@
 			throw new IllegalArgumentException(MessageFormat.format("parameter ''wayId'' of type {0} expected, got {1}", OsmPrimitiveType.WAY, wayId.getType()));
 		}
-		
-		if (dataSet == null) {			
-			throw new IllegalStateException("data set not initialized");			
-		}
-		OsmPrimitive p = dataSet.getPrimitiveById(wayId);
+
+		OsmPrimitive p = layer.data.getPrimitiveById(wayId);
 		if (p == null) {
-			throw new IllegalStateException(MessageFormat.format("didn't find way with id {0} in dataset {1}", wayId, dataSet));			
+			throw new IllegalStateException(MessageFormat.format("didn''t find way with id {0} in layer ''{1}''", wayId, layer.getName()));			
 		}
 		setTurnRestrictionLeg(role, (Way)p);
@@ -144,17 +127,26 @@
 	
 	/**
-	 * Replies the turn restrictioin leg with role {@code role}
+	 * "Officially" a turn restriction should have exactly one member with 
+	 * role {@see TurnRestrictionLegRole#FROM} and one member with role {@see TurnRestrictionLegRole#TO},
+	 * both referring to an OSM {@see Way}. In order to deals with turn restrictions where these
+	 * integrity constraints are violated, this model also supports relation with multiple or no
+	 * 'from' or 'to' members.
+	 * 
+	 * Replies the turn restriction legs with role {@code role}. If no leg with this
+	 * role exists, an empty set is returned. If multiple legs exists, the set of referred
+	 * primitives is returned.  
 	 * 
 	 * @param role the role. Must not be null.
-	 * @return the turn restrictioin leg with role {@code role}. null, if
+	 * @return the set of turn restriction legs with role {@code role}. The empty set, if
 	 * no such turn restriction leg exists
 	 * @throws IllegalArgumentException thrown if role is null
 	 */
-	public Way getTurnRestrictionLeg(TurnRestrictionLegRole role){
+	public Set<OsmPrimitive>getTurnRestrictionLeg(TurnRestrictionLegRole role){
 		CheckParameterUtil.ensureParameterNotNull(role, "role");
 		switch(role){
-		case FROM: return from;
-		case TO: return to;
-		}
+		case FROM: return memberModel.getFromPrimitives();
+		case TO: return memberModel.getToPrimitives();
+		}
+		// should not happen
 		return null;
 	}
@@ -167,35 +159,12 @@
 	 */
 	protected void initFromTurnRestriction(Relation turnRestriction) {
-		this.from = null;
-		this.to = null;
-		this.fromRelationMember = null;
-		this.toRelationMember = null;
-		this.tags = new TagCollection();
-		this.vias.clear();
-		if (turnRestriction == null) return;
-		for (RelationMember rm: turnRestriction.getMembers()) {
-			if (rm.getRole().equals("from") && rm.isWay()) {
-				this.fromRelationMember = rm;
-				this.from = rm.getWay();
-				break;
-			}
-		}
-		for (RelationMember rm: turnRestriction.getMembers()) {
-			if (rm.getRole().equals("to") && rm.isWay()) {
-				this.toRelationMember = rm;
-				this.to = rm.getWay();
-				break;
-			}
-		}
 		
-		for (RelationMember rm: turnRestriction.getMembers()) {
-			if (rm.getRole().equals("via")) {
-				this.vias.add(rm.getMember());
-			}
-		}
+		// populate the member model
+		memberModel.populate(turnRestriction);
 		
 		// make sure we have a restriction tag
-		tags = TagCollection.from(turnRestriction);
+		TagCollection tags = TagCollection.from(turnRestriction);
 		tags.setUniqueForKey("type", "restriction");
+		tagEditorModel.initFromTags(tags);
 				
 		setChanged();
@@ -215,58 +184,13 @@
 	public void populate(Relation turnRestriction) {
 		CheckParameterUtil.ensureParameterNotNull(turnRestriction, "turnRestriction");
-		if (turnRestriction.getDataSet() == null) {			 
+		if (turnRestriction.getDataSet() != null && turnRestriction.getDataSet() != layer.data) {			
 			throw new IllegalArgumentException(
 				// don't translate - it's a technical message
-				MessageFormat.format("turnRestriction {0} must belong to a dataset", turnRestriction.getId())
+				MessageFormat.format("turnRestriction {0} must not belong to a different dataset than the dataset of layer ''{1}''", turnRestriction.getId(), layer.getName())
 			);
 		}
-		this.dataSet = turnRestriction.getDataSet();
 		initFromTurnRestriction(turnRestriction);
 	}
 	
-	/**
-	 * Populates the turn restriction editor model with a new turn restriction,
-	 * which isn't added to a data set yet. {@code ds} is the data set the turn
-	 * restriction is eventually being added to. Relation members of this
-	 * turn restriction must refer to objects in {@code ds}. 
-	 *  
-	 * {@code turnRestriction} is an arbitrary relation. A tag type=restriction
-	 * isn't required. If it is missing, it is added here.  {@code turnRestriction}
-	 * is required to be a new turn restriction with a negative id. It must not be
-	 * part of a dataset yet
-	 * 
-	 * @param turnRestriction the turn restriction. Must not be null. New turn restriction
-	 * required
-	 * @param ds the dataset. Must not be null.
-	 * @throws IllegalArgumentException thrown if turnRestriction is null
-	 * @throws IllegalArgumentException thrown if turnRestriction is part of a dataset
-	 * @throws IllegalArgumentException thrown if turnRestriction isn't a new turn restriction  
-	 */
-	public void populate(Relation turnRestriction, DataSet ds) {
-		CheckParameterUtil.ensureParameterNotNull(turnRestriction, "turnRestriction");
-		CheckParameterUtil.ensureParameterNotNull(ds, "ds");
-		if (!turnRestriction.isNew()){			
-			throw new IllegalArgumentException(
-					// don't translate - it's a technical message
-					MessageFormat.format("new turn restriction expected, got turn restriction with id {0}", turnRestriction.getId())
-			);
-		}
-		if (turnRestriction.getDataSet() != null) {
-			throw new IllegalArgumentException(
-                    // don't translate - it's a technical message
-					MessageFormat.format("expected turn restriction not assigned to a  dataset, got turn restriction with id {0} assigned to {1}", turnRestriction.getId(), turnRestriction.getDataSet())
-			);
-		}
-		for(RelationMember rm: turnRestriction.getMembers()) {
-			if (rm.getMember().getDataSet() != ds) {
-				throw new IllegalArgumentException(
-	                    // don't translate - it's a technical message
-						MessageFormat.format("expected all members assigned to dataset {0}, got member {1} assigned to {2}", ds, rm, rm.getMember().getDataSet())
-				);
-			}
-		}
-		this.dataSet = ds;
-		initFromTurnRestriction(turnRestriction);
-	}
 	
 	/**
@@ -277,18 +201,8 @@
 	public void apply(Relation turnRestriction) {
 		CheckParameterUtil.ensureParameterNotNull(turnRestriction, "turnRestriction");
-		// apply the tags
+		
+		TagCollection tags = tagEditorModel.getTagCollection();
 		tags.applyTo(turnRestriction);
-		
-		List<RelationMember> members = new ArrayList<RelationMember>();
-		if (from != null){
-			members.add(new RelationMember("from", from));
-		}
-		if (to != null) {
-			members.add(new RelationMember("to", to));			
-		}
-		for(OsmPrimitive via: vias) {
-			members.add(new RelationMember("via", via));
-		}
-		turnRestriction.setMembers(members);
+		memberModel.applyTo(turnRestriction);		
 	}
 	
@@ -300,4 +214,5 @@
 	 */
 	public String getRestrictionTagValue() {
+		TagCollection tags = tagEditorModel.getTagCollection();
 		if (!tags.hasTagsFor("restriction")) return null;
 		return tags.getJoinedValues("restriction");
@@ -312,7 +227,12 @@
 	public void setRestrictionTagValue(String value){
 		if (value == null || value.trim().equals("")) {
-			tags.removeByKey("restriction");
+			tagEditorModel.delete("restriction");			
 		} else {
-			tags.setUniqueForKey("restriction", value.trim());
+			TagModel  tm = tagEditorModel.get("restriction");
+			if (tm != null){
+				tm.setValue(value);
+			} else {
+				tagEditorModel.add(new TagModel("restriction", value));
+			}
 		}
 		setChanged();
@@ -327,5 +247,5 @@
 	 */
 	public List<OsmPrimitive> getVias() {
-		return Collections.unmodifiableList(vias);
+		return memberModel.getVias();
 	}
 	
@@ -342,32 +262,16 @@
 	 */
 	public void setVias(List<OsmPrimitive> vias) {
-		if (vias == null) {
-			this.vias.clear();
-			setChanged();
-			notifyObservers();
-			return;
-		}
-		for (OsmPrimitive p: vias) {
-			if (p == null)
-				throw new IllegalArgumentException("a via object must not be null");
-			if (p.getDataSet() != dataSet)
-				throw new IllegalArgumentException(MessageFormat.format("a via object must belong to dataset {1}, object {2} belongs to {3}", dataSet, p.getPrimitiveId(), p.getDataSet()));
-		}
-		this.vias.clear();
-		this.vias.addAll(vias);
-		setChanged();
-		notifyObservers();
-	}
-	
-	/**
-	 * Replies the dataset this turn restriction editor model is 
-	 * working with
-	 * 
-	 * @return the dataset 
-	 */
-	public DataSet getDataSet() {
-		return this.dataSet;
-	}
-
+		memberModel.setVias(vias);
+	}
+	
+	/**
+	 * Replies the layer in whose context this editor is working
+	 * 
+	 * @return the layer in whose context this editor is working
+	 */
+	public OsmDataLayer getLayer() {
+		return layer;
+	}
+	
 	/**
 	 * Registers this model with global event sources like {@see DatasetEventManager}
@@ -383,18 +287,33 @@
 		DatasetEventManager.getInstance().removeDatasetListener(this);
 	}
+	
+	/**
+	 * Replies the tag  editor model 
+	 * 
+	 * @return the tag  editor model
+	 */
+	public TagEditorModel getTagEditorModel() {
+		return tagEditorModel;
+	}
+	
+	/**
+	 * Replies the editor model for the relation members
+	 * 
+	 * @return the editor model for the relation members
+	 */
+	public RelationMemberEditorModel getRelationMemberEditorModel() {
+		return memberModel;
+	}
 
 	/* ----------------------------------------------------------------------------------------- */
 	/* interface DataSetListener                                                                 */
-	/* ----------------------------------------------------------------------------------------- */
-	
+	/* ----------------------------------------------------------------------------------------- */	
 	protected boolean isAffectedByDataSetUpdate(DataSet ds, List<? extends OsmPrimitive> updatedPrimitives) {
-		if (ds != dataSet) return false;
+		if (ds != layer.data) return false;
 		if (updatedPrimitives == null || updatedPrimitives.isEmpty()) return false;
-		if (from != null && updatedPrimitives.contains(from)) return true;
-		if (to != null && updatedPrimitives.contains(to)) return true;
-		for (OsmPrimitive via: vias){
-			if (updatedPrimitives.contains(via)) return true;
-		}
-		return false;
+		Set<OsmPrimitive> myPrimitives = memberModel.getMemberPrimitives();
+		int size1 = myPrimitives.size();
+		myPrimitives.retainAll(updatedPrimitives);
+		return size1 != myPrimitives.size();
 	}
 	
@@ -402,6 +321,5 @@
 		// refresh the views
 		setChanged();
-		notifyObservers();
-		
+		notifyObservers();		
 	}
 
@@ -439,3 +357,10 @@
 		}		
 	}	
+	
+	class RelationMemberModelListener implements TableModelListener {
+		public void tableChanged(TableModelEvent e) {
+			setChanged();
+			notifyObservers();
+		}		
+	}	
 }
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionLegEditor.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionLegEditor.java	(revision 20495)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionLegEditor.java	(revision 20527)
@@ -5,5 +5,4 @@
 import java.awt.BorderLayout;
 import java.awt.Font;
-import java.awt.Image;
 import java.awt.Toolkit;
 import java.awt.datatransfer.Clipboard;
@@ -20,7 +19,9 @@
 import java.io.IOException;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Observable;
 import java.util.Observer;
+import java.util.Set;
 import java.util.logging.Logger;
 
@@ -28,5 +29,4 @@
 import javax.swing.Action;
 import javax.swing.BorderFactory;
-import javax.swing.ImageIcon;
 import javax.swing.JButton;
 import javax.swing.JComponent;
@@ -39,7 +39,7 @@
 import javax.swing.UIManager;
 
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.data.osm.PrimitiveId;
-import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.gui.DefaultNameFormatter;
 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
@@ -58,5 +58,5 @@
  
 	private JLabel lblOsmObject;
-	private Way way;
+	private final Set<OsmPrimitive> legs = new HashSet<OsmPrimitive>();
 	private TurnRestrictionEditorModel model;
 	private TurnRestrictionLegRole role; 
@@ -140,16 +140,22 @@
 
 	protected void refresh(){
-		Way newWay = model.getTurnRestrictionLeg(role);
-		way = newWay;
-		if (way == null) {
+		legs.clear();
+		legs.addAll(model.getTurnRestrictionLeg(role));
+		if (legs.isEmpty()) {
 			lblOsmObject.setFont(UIManager.getFont("Label.font").deriveFont(Font.ITALIC));
 			lblOsmObject.setIcon(null);
 			lblOsmObject.setText(tr("please select a way"));
 			lblOsmObject.setToolTipText(null);
-		} else {
+		} else if (legs.size() == 1){
+			OsmPrimitive leg = legs.iterator().next();
 			lblOsmObject.setFont(UIManager.getFont("Label.font"));
 			lblOsmObject.setIcon(ImageProvider.get("data", "way"));
-			lblOsmObject.setText(DefaultNameFormatter.getInstance().format(way));
-			lblOsmObject.setToolTipText(DefaultNameFormatter.getInstance().buildDefaultToolTip(way));
+			lblOsmObject.setText(leg.getDisplayName(DefaultNameFormatter.getInstance()));
+			lblOsmObject.setToolTipText(DefaultNameFormatter.getInstance().buildDefaultToolTip(leg));
+		} else {
+			lblOsmObject.setFont(UIManager.getFont("Label.font").deriveFont(Font.ITALIC));
+			lblOsmObject.setIcon(null);
+			lblOsmObject.setText(tr("multiple objects with role ''{0}''",this.role.toString()));
+			lblOsmObject.setToolTipText(null);			
 		}
 		renderColors();
@@ -201,6 +207,8 @@
 	/* ----------------------------------------------------------------------------- */
 	public List<PrimitiveId> getSelectedPrimitiveIds() {
-		if (way == null) return Collections.emptyList();
-		return Collections.singletonList(way.getPrimitiveId());
+		if (legs.size() == 1) {
+			return Collections.singletonList(legs.iterator().next().getPrimitiveId());
+		}
+		return Collections.emptyList();
 	}
 	
@@ -247,5 +255,5 @@
 		
 		public void updateEnabledState() {
-			setEnabled(way != null);
+			setEnabled(legs.size()>0);
 		}
 	}
@@ -284,5 +292,5 @@
 		@Override
 		protected Transferable createTransferable(JComponent c) {
-			if (way == null) return null;
+			if (legs.size() != 1) return null;
 			return super.createTransferable(c);
 		}
@@ -326,5 +334,5 @@
 		
 		public void updateEnabledState() {
-			setEnabled(way != null);
+			setEnabled(legs.size() == 1);
 		}
 	}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/ViaListModel.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/ViaListModel.java	(revision 20495)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/ViaListModel.java	(revision 20527)
@@ -171,5 +171,5 @@
 		if (idsToInsert == null) return;
 		List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>(idsToInsert.size());
-		DataSet ds = model.getDataSet();
+		DataSet ds = model.getLayer().data;
 		for(PrimitiveId id: idsToInsert){
 			OsmPrimitive p = ds.getPrimitiveById(id);
