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 20585)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/AdvancedEditorPanel.java	(revision 20586)
@@ -38,8 +38,9 @@
 		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."
-		));
+		msg.setText("<html><body>" + 
+				tr("In the following table you can edit the <strong>raw tags</strong>"
+			  + " of the OSM relation representing this turn restriction.")
+			  + "</body></html>"
+		);
 		pnl.add(msg, BorderLayout.NORTH);
 		pnlTagEditor = new TagEditorPanel(model.getTagEditorModel());	
@@ -57,8 +58,8 @@
 		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."
-		));
+		msg.setText("<html><body>"  
+			  + tr("In the following table you can edit the <strong>raw members</strong>"
+			  + " of the OSM relation representing this turn restriction.") + "</body></html>"
+		);
 		pnl.add(msg, BorderLayout.NORTH);
 		
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/BasicEditorPanel.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/BasicEditorPanel.java	(revision 20585)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/BasicEditorPanel.java	(revision 20586)
@@ -11,4 +11,6 @@
 import javax.swing.JScrollPane;
 
+import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.NavigationControler.BasicEditorFokusTargets;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 
@@ -17,10 +19,16 @@
  * i.e. its restriction type, the from, the to, and the via objects.
  * 
- *
  */
-public class BasicEditorPanel extends JPanel {
+public class BasicEditorPanel extends VerticallyScrollablePanel {
 
 	/** the turn restriction model */
 	private TurnRestrictionEditorModel model;
+	
+	/** the UI widgets */
+	private TurnRestrictionLegEditor fromEditor;
+	private TurnRestrictionLegEditor toEditor;
+	private ViaList lstVias;
+	private TurnRestrictionComboBox cbTurnRestrictions;
+	private VehicleExceptionEditor vehicleExceptionsEditor;
 	
 	/**
@@ -40,5 +48,5 @@
 	    gc.gridx = 1;
 	    gc.weightx = 1.0;
-	    add(new TurnRestrictionComboBox(new TurnRestrictionComboBoxModel(model)), gc);
+	    add(cbTurnRestrictions = new TurnRestrictionComboBox(new TurnRestrictionComboBoxModel(model)), gc);
 
 		// the editor for selecting the 'from' leg
@@ -50,5 +58,5 @@
 	    gc.gridx = 1;
 	    gc.weightx = 1.0;
-	    add(new TurnRestrictionLegEditor(model, TurnRestrictionLegRole.FROM),gc);
+	    add(fromEditor = new TurnRestrictionLegEditor(model, TurnRestrictionLegRole.FROM),gc);
 
 	    // the editor for selecting the 'to' leg
@@ -61,5 +69,5 @@
 	    gc.gridx = 1;
 	    gc.weightx = 1.0;
-	    add(new TurnRestrictionLegEditor(model, TurnRestrictionLegRole.TO),gc);
+	    add(toEditor = new TurnRestrictionLegEditor(model, TurnRestrictionLegRole.TO),gc);
 	    
 	    // the editor for selecting the 'vias' 
@@ -73,9 +81,18 @@
 	    gc.weightx = 1.0;
 	    DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
-	    add(new JScrollPane(new ViaList(new ViaListModel(model, selectionModel), selectionModel)),gc);
+	    add(new JScrollPane(lstVias = new ViaList(new ViaListModel(model, selectionModel), selectionModel)),gc);
+	    
+	    // the editor for vehicle exceptions
+	    vehicleExceptionsEditor = new VehicleExceptionEditor(model);
+	    gc.gridx = 0;
+	    gc.gridy = 4;
+		gc.weightx = 1.0;
+		gc.gridwidth = 2;
+	    gc.insets = new Insets(0,0,5,5);	
+	    add(vehicleExceptionsEditor, gc);
 	    
 	    // just a filler - grabs remaining space 
 	    gc.gridx = 0;
-	    gc.gridy = 4;
+	    gc.gridy = 5;
 	    gc.gridwidth = 2;
 	    gc.weighty = 1.0;
@@ -99,4 +116,27 @@
 	}
 	
-	
+	/**
+	 * Requests the focus on one of the input widgets for turn
+	 * restriction data.
+	 * 
+	 * @param focusTarget the target component to request focus for.
+	 * Ignored if null.
+	 */
+	public void requestFocusFor(BasicEditorFokusTargets focusTarget){
+		if (focusTarget == null) return;
+		switch(focusTarget){
+		case RESTRICION_TYPE:
+			cbTurnRestrictions.requestFocusInWindow();
+			break;
+		case FROM:
+			fromEditor.requestFocusInWindow();
+			break;
+		case TO:
+			toEditor.requestFocusInWindow();
+			break;
+		case VIA:
+			lstVias.requestFocusInWindow();
+			break;
+		}
+	}	
 }
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/ExceptValueModel.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/ExceptValueModel.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/ExceptValueModel.java	(revision 20586)
@@ -0,0 +1,213 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.editor;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * ExceptValueModel is a model for the value of the tag 'except' in a turn
+ * restriction. 
+ *
+ */
+public class ExceptValueModel {
+	/**
+	 * The set of standard vehicle types which can be used in the
+	 * 'except' tag 
+	 */
+	static public final Set<String> STANDARD_VEHICLE_EXCEPTION_VALUES;
+	static {
+		HashSet<String> s = new HashSet<String>();
+		s.add("psv");
+		s.add("hgv");
+		s.add("bicycle");
+		s.add("motorcar");
+		STANDARD_VEHICLE_EXCEPTION_VALUES = Collections.unmodifiableSet(s);
+	}
+	
+	/**
+	 * Replies true, if {@code v} is a standard vehicle type. Replies
+	 * false if {@code v} is null
+	 * 
+	 * @param v the vehicle type. 
+	 * @return true, if {@code v} is a standard vehicle type.
+	 */
+	static public boolean isStandardVehicleExceptionValue(String v){
+		if (v == null) return false;
+		v = v.trim().toLowerCase();
+		return STANDARD_VEHICLE_EXCEPTION_VALUES.contains(v);
+	}
+		
+	private String value = "";
+	private boolean isStandard = true;
+	private final Set<String> vehicleExceptions = new HashSet<String>();
+	
+	
+	protected void parseValue(String value) {
+		if (value == null || value.trim().equals("")) value = "";
+		this.value = value;
+		isStandard = true;
+		vehicleExceptions.clear();
+		if (value.equals("")) return;
+		String[] values = value.split(";");
+		for (String v: values){
+			v = v.trim().toLowerCase();
+			if (isStandardVehicleExceptionValue(v)) {
+				vehicleExceptions.add(v);
+			} else {
+				isStandard = false;
+			}
+		}
+	}
+	
+	/**
+	 * Creates a new model for an empty standard value 
+	 */
+	public ExceptValueModel() {}
+	
+	/**
+	 * Creates a new model for the tag value {@code value}. 
+	 * 
+	 * @param value the tag value
+	 * @see #parseValue(String)
+	 */
+	public ExceptValueModel(String value){
+		if (value == null || value.trim().equals("")) 
+			return;
+		parseValue(value);
+	}
+
+	/**
+	 * Replies the tag value representing the state of this model.
+	 * 
+	 * @return 
+	 */
+	public String getValue() {
+		if (isStandard){
+			StringBuffer sb = new StringBuffer();
+			// we use an ordered list because equals()
+			// is based on getValue()
+			//
+			List<String> values = new ArrayList<String>(vehicleExceptions);
+			Collections.sort(values);
+			for (String v: values){
+				if (sb.length() > 0) {
+					sb.append(";");
+				}
+				sb.append(v);
+			}
+			return sb.toString();
+		} else {
+			return value;
+		}
+	}
+
+	/**
+	 * Sets the value in this model
+	 * 
+	 * @param value
+	 */
+	public void setValue(String value) {
+		parseValue(value);
+	}
+
+	/**
+	 * Replies true if this model currently holds a standard 'except' value
+	 * 
+	 * @return
+	 */
+	public boolean isStandard() {
+		return isStandard;
+	}	
+	
+	/**
+	 * Tells this model to use standard values only.
+	 * 
+	 */
+	public void setStandard(boolean isStandard) {
+		this.isStandard = isStandard;
+	}
+	
+	/**
+	 * Replies true if {@code vehicleType} is currently set as exception in this
+	 * model.
+	 * 
+	 * @param vehicleType one of the standard vehicle types from {@see #STANDARD_VEHICLE_EXCEPTION_VALUES}
+	 * @return true if {@code vehicleType} is currently set as exception in this
+	 * model.
+	 * @exception IllegalArgumentException thrown if {@code vehicleType} isn't a standard vehicle type 
+	 */
+	public boolean isVehicleException(String vehicleType) throws IllegalArgumentException{
+		if (vehicleType == null) return false;
+		if (!isStandardVehicleExceptionValue(vehicleType)) {
+			throw new IllegalArgumentException(MessageFormat.format("vehicleType ''{0}'' isn''t a valid standard vehicle type", vehicleType));
+		}
+		vehicleType = vehicleType.trim().toLowerCase();
+		return vehicleExceptions.contains(vehicleType);
+	}
+	
+	/**
+	 * Sets the {@code vehicleType} as exception in this turn restriction.
+	 * 
+	 * @param vehicleType one of the standard vehicle types from {@see #STANDARD_VEHICLE_EXCEPTION_VALUES}
+	 * @exception IllegalArgumentException thrown if {@code vehicleType} isn't a standard vehicle type 
+	 */
+	public void setVehicleException(String vehicleType) throws IllegalArgumentException{
+		if (!isStandardVehicleExceptionValue(vehicleType)) {
+			throw new IllegalArgumentException(MessageFormat.format("vehicleType ''{0}'' isn''t a valid standard vehicle type", vehicleType));
+		}
+		vehicleExceptions.add(vehicleType.trim().toLowerCase());
+	}
+	
+
+	/**
+	 * Sets or removes the {@code vehicleType} as exception in this turn restriction, depending
+	 * on whether {@code setOrRemove} is true or false, respectively.
+	 * 
+	 * @param vehicleType one of the standard vehicle types from {@see #STANDARD_VEHICLE_EXCEPTION_VALUES}
+	 * @param setOrRemove if true, the exception is set; otherwise, it is removed
+	 * @exception IllegalArgumentException thrown if {@code vehicleType} isn't a standard vehicle type 
+	 */
+	public void setVehicleException(String vehicleType, boolean setOrRemove) throws IllegalArgumentException{
+		if (setOrRemove){
+			setVehicleException(vehicleType);
+		} else {
+			removeVehicleException(vehicleType);
+		}
+	}
+	
+	/**
+	 * Removes the {@code vehicleType} as exception in this turn restriction
+	 * 
+	 * @param vehicleType one of the standard vehicle types from {@see #STANDARD_VEHICLE_EXCEPTION_VALUES}
+	 * @exception IllegalArgumentException thrown if {@code vehicleType} isn't a standard vehicle type 
+	 */
+	public void removeVehicleException(String vehicleType) throws IllegalArgumentException{
+		if (!isStandardVehicleExceptionValue(vehicleType)) {
+			throw new IllegalArgumentException(MessageFormat.format("vehicleType ''{0}'' isn''t a valid standard vehicle type", vehicleType));
+		}
+		vehicleExceptions.remove(vehicleType.trim().toLowerCase());
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + getValue().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;
+		ExceptValueModel other = (ExceptValueModel) obj;
+		return getValue().equals(other.getValue());
+	}		
+}
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 20585)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/JosmSelectionListModel.java	(revision 20586)
@@ -16,5 +16,4 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.SelectionChangedListener;
-import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
@@ -45,5 +44,5 @@
     private final List<OsmPrimitive> selection = new ArrayList<OsmPrimitive>();
     private DefaultListSelectionModel selectionModel;
-    private DataSet dataSet;
+    private OsmDataLayer layer;
 
     /**
@@ -51,13 +50,14 @@
      * 
      * @param selectionModel the selection model used in the list. Must not be null.
-     * @param dataSet the dataset this model is displaying the selection from. Must not be null.
+     * @param layer the layer this model is displaying the selection from. Must not be null.
      * @throws IllegalArgumentException thrown if {@code selectionModel} is null
-     */
-    public JosmSelectionListModel(DataSet dataSet, DefaultListSelectionModel selectionModel) {
+     * @throws IllegalArgumentException thrown if {@code layer} is null
+     */
+    public JosmSelectionListModel(OsmDataLayer layer, DefaultListSelectionModel selectionModel) {
     	CheckParameterUtil.ensureParameterNotNull(selectionModel, "selectionModel");
-    	CheckParameterUtil.ensureParameterNotNull(dataSet, "dataSet");
-    	this.dataSet = dataSet;
+    	CheckParameterUtil.ensureParameterNotNull(layer, "layer");
+    	this.layer = layer;
         this.selectionModel = selectionModel;
-        setJOSMSelection(dataSet.getSelected());
+        setJOSMSelection(layer.data.getSelected());
     }
 
@@ -160,5 +160,5 @@
         	// don't show a JOSM selection if we don't have a data layer 
             setJOSMSelection(null);
-        } else if (newLayer.data != dataSet){
+        } else if (newLayer != layer){
         	// don't show a JOSM selection if this turn restriction editor doesn't
         	// manipulate data in the current data layer
@@ -177,5 +177,5 @@
     	OsmDataLayer layer = Main.main.getEditLayer();
     	if(layer == null) return;
-    	if (layer.data != dataSet) return;
+    	if (layer != this.layer) return;
         setJOSMSelection(newSelection);
     }
@@ -185,10 +185,10 @@
     /* ------------------------------------------------------------------------ */
     public void dataChanged(DataChangedEvent event) {
-        if (event.getDataset() != dataSet) return;
+        if (event.getDataset() != layer.data) return;
         fireContentsChanged(this, 0, getSize());
     }
 
     public void nodeMoved(NodeMovedEvent event) {
-        if (event.getDataset() != dataSet) return;
+        if (event.getDataset() != layer.data) return;
         // may influence the display name of primitives, update the data
     	update(event.getPrimitives());
@@ -196,5 +196,5 @@
 
     public void otherDatasetChange(AbstractDatasetChangedEvent event) {
-        if (event.getDataset() != dataSet) return;
+        if (event.getDataset() != layer.data) return;
         // may influence the display name of primitives, update the data
         update(event.getPrimitives());
@@ -202,5 +202,5 @@
 
     public void relationMembersChanged(RelationMembersChangedEvent event) {
-        if (event.getDataset() != dataSet) return;
+        if (event.getDataset() != layer.data) return;
         // may influence the display name of primitives, update the data
         update(event.getPrimitives());
@@ -208,5 +208,5 @@
 
     public void tagsChanged(TagsChangedEvent event) {
-        if (event.getDataset() != dataSet) return;
+        if (event.getDataset() != layer.data) return;
         // may influence the display name of primitives, update the data
         update(event.getPrimitives());
@@ -214,5 +214,5 @@
 
     public void wayNodesChanged(WayNodesChangedEvent event) {
-        if (event.getDataset() != dataSet) return;
+        if (event.getDataset() != layer.data) return;
         // may influence the display name of primitives, update the data
         update(event.getPrimitives());
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/JosmSelectionPanel.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/JosmSelectionPanel.java	(revision 20585)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/JosmSelectionPanel.java	(revision 20586)
@@ -53,8 +53,8 @@
 	 * builds the UI for the panel 
 	 */
-	protected void build(DataSet ds) {
+	protected void build(OsmDataLayer layer) {
 		setLayout(new BorderLayout());
 		DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
-		model = new JosmSelectionListModel(ds,selectionModel);
+		model = new JosmSelectionListModel(layer,selectionModel);
 		lstSelection = new JList(model);
 		lstSelection.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
@@ -73,12 +73,12 @@
 	
 	/**
-	 * Creates the JOSM selection panel for the selection in a data set. 
+	 * Creates the JOSM selection panel for the selection in an OSM data layer
 	 * 
-	 * @param ds the dataset. Must not be null.
-	 * @exception IllegalArgumentException thrown if ds is null
+	 * @param layer the data layer. Must not be null.
+	 * @exception IllegalArgumentException thrown if {@code layer} is null
 	 */
-	public JosmSelectionPanel(DataSet ds) throws IllegalArgumentException{
-		CheckParameterUtil.ensureParameterNotNull(ds, "ds");
-		build(ds); 
+	public JosmSelectionPanel(OsmDataLayer layer) throws IllegalArgumentException{
+		CheckParameterUtil.ensureParameterNotNull(layer, "layer");
+		build(layer); 
 	}
 	
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/NavigationControler.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/NavigationControler.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/NavigationControler.java	(revision 20586)
@@ -0,0 +1,13 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.editor;
+
+public interface NavigationControler {
+	public enum BasicEditorFokusTargets {
+		RESTRICION_TYPE,
+		FROM,
+		TO,
+		VIA
+	}	
+	void gotoBasicEditor();	
+	void gotoAdvancedEditor();
+	void gotoBasicEditor(BasicEditorFokusTargets focusTarget);	
+}
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 20585)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/RelationMemberEditorModel.java	(revision 20586)
@@ -136,5 +136,5 @@
 		return isChanged;
 	}
-	
+		
 	/**
 	 * Replies the set of {@see OsmPrimitive}s with the role 'from'. If no
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 20585)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionEditor.java	(revision 20586)
@@ -19,4 +19,6 @@
 import java.util.Iterator;
 import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
 import java.util.logging.Logger;
 
@@ -26,4 +28,5 @@
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
+import javax.swing.JScrollPane;
 import javax.swing.JSplitPane;
 import javax.swing.JTabbedPane;
@@ -46,9 +49,9 @@
 import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.plugins.turnrestrictions.qa.IssuesView;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.ImageProvider;
 
-
-public class TurnRestrictionEditor extends JDialog {
+public class TurnRestrictionEditor extends JDialog implements NavigationControler{
 	final private static Logger logger = Logger.getLogger(TurnRestrictionEditor.class.getName());
 	
@@ -81,5 +84,7 @@
     private BasicEditorPanel pnlBasicEditor;
     private AdvancedEditorPanel pnlAdvancedEditor;
+    private IssuesView pnlIssuesView;
     private TurnRestrictionEditorModel editorModel;
+    private JTabbedPane tpEditors;
     
     /**
@@ -105,5 +110,5 @@
      */
     protected JPanel buildJOSMSelectionPanel() {
-    	pnlJosmSelection = new JosmSelectionPanel(layer.data);
+    	pnlJosmSelection = new JosmSelectionPanel(layer);
     	return pnlJosmSelection;
     }
@@ -117,6 +122,9 @@
     protected JPanel buildEditorPanel() {
     	JPanel pnl = new JPanel(new BorderLayout());
-    	JTabbedPane tpEditors = new JTabbedPane();
-    	tpEditors.add(pnlBasicEditor =new BasicEditorPanel(editorModel));
+    	tpEditors = new JTabbedPane();
+    	JScrollPane pane = new JScrollPane(pnlBasicEditor =new BasicEditorPanel(editorModel));
+    	pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+    	pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+    	tpEditors.add(pane);
     	tpEditors.setTitleAt(0, tr("Basic"));
     	tpEditors.setToolTipTextAt(0, tr("Edit basic attributes of a turn restriction"));
@@ -125,4 +133,8 @@
     	tpEditors.setTitleAt(1, tr("Advanced"));
     	tpEditors.setToolTipTextAt(1, tr("Edit the raw tags and members of this turn restriction"));
+    	
+    	tpEditors.add(pnlIssuesView = new IssuesView(editorModel.getIssuesModel()));
+    	tpEditors.setTitleAt(2, tr("Errors/Warnings"));
+    	tpEditors.setToolTipTextAt(2, tr("Show errors and warnings related to this turn restriction"));
     	
     	pnl.add(tpEditors, BorderLayout.CENTER);
@@ -182,5 +194,5 @@
      */
     protected void build() {    	
-    	editorModel = new TurnRestrictionEditorModel(getLayer());
+    	editorModel = new TurnRestrictionEditorModel(getLayer(), this);
     	Container c = getContentPane();
     	c.setLayout(new BorderLayout());
@@ -188,4 +200,6 @@
     	c.add(buildContentPanel(), BorderLayout.CENTER);    	
     	c.add(buildOkCancelButtonPanel(), BorderLayout.SOUTH);
+    	
+    	editorModel.getIssuesModel().addObserver(new IssuesModelObserver());
     	setSize(600,600);
     }    
@@ -346,5 +360,21 @@
     }
     
-    /**
+    /* ----------------------------------------------------------------------- */
+    /* interface NavigationControler                                           */
+    /* ----------------------------------------------------------------------- */
+    public void gotoBasicEditor() {
+    	tpEditors.setSelectedIndex(0);
+	}
+
+    public void gotoAdvancedEditor() {
+    	tpEditors.setSelectedIndex(1);
+	}
+
+	public void gotoBasicEditor(BasicEditorFokusTargets focusTarget) {
+		tpEditors.setSelectedIndex(0);
+		pnlBasicEditor.requestFocusFor(focusTarget);
+	}
+
+	/**
      * The abstract base action for applying the updates of a turn restriction
      * to the dataset.
@@ -745,3 +775,33 @@
 		}
     }
+    
+    class IssuesModelObserver implements Observer {
+		public void update(Observable o, Object arg) {
+			int numWarnings = editorModel.getIssuesModel().getNumWarnings();
+			int numErrors = editorModel.getIssuesModel().getNumErrors();
+			String warningText = null;
+			if (numWarnings > 0){
+				warningText = trn("{0} warning", "{0} warnings", numWarnings, numWarnings);
+			}
+			String errorText = null;
+			if (numErrors > 0){
+				errorText = trn("{0} error", "{0} errors", numErrors, numErrors);
+			}
+			String title = "";
+			if (errorText != null) {
+				title += errorText;
+			}
+			if (warningText != null){
+				if (title.length() > 0){
+					title += "/";
+				}
+				title += warningText;
+			}
+			if (title.length() == 0){
+				title = tr("no issues");
+			}
+			tpEditors.setTitleAt(2, title);
+			tpEditors.setEnabledAt(2, numWarnings + numErrors > 0);
+		}    	
+    }
 }
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 20585)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionEditorModel.java	(revision 20586)
@@ -31,4 +31,5 @@
 import org.openstreetmap.josm.gui.tagging.TagEditorModel;
 import org.openstreetmap.josm.gui.tagging.TagModel;
+import org.openstreetmap.josm.plugins.turnrestrictions.qa.IssuesModel;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 
@@ -66,4 +67,5 @@
 	private final TagEditorModel tagEditorModel = new TagEditorModel();
 	private  RelationMemberEditorModel memberModel;
+	private  IssuesModel issuesModel;
 	
 	/**
@@ -73,9 +75,12 @@
 	 * @throws IllegalArgumentException thrown if {@code layer} is null
 	 */
-	public TurnRestrictionEditorModel(OsmDataLayer layer) throws IllegalArgumentException{
+	public TurnRestrictionEditorModel(OsmDataLayer layer, NavigationControler navigationControler) throws IllegalArgumentException{
 		CheckParameterUtil.ensureParameterNotNull(layer, "layer");
 		this.layer = layer;
 		memberModel = new RelationMemberEditorModel(layer);
 		memberModel.addTableModelListener(new RelationMemberModelListener());
+		issuesModel = new IssuesModel(this,navigationControler);
+		addObserver(issuesModel);
+		tagEditorModel.addTableModelListener(new TagEditorModelObserver());
 	}
 	
@@ -305,4 +310,57 @@
 		return memberModel;
 	}
+	
+	/**
+	 * Replies the model for the open issues in this turn restriction
+	 * editor.
+	 * 
+	 * @return the model for the open issues in this turn restriction
+	 * editor
+	 */
+	public IssuesModel getIssuesModel() {
+		return issuesModel;
+	}
+	
+	/**
+	 * Replies the current value of the tag "except", or the empty string
+	 * if the tag doesn't exist.
+	 * 
+	 * @return
+	 */
+	public ExceptValueModel getExcept() {
+		TagModel tag = tagEditorModel.get("except");
+		if (tag == null) return new ExceptValueModel("");
+		return new ExceptValueModel(tag.getValue());
+	}
+	
+	/**
+	 * Sets the current value of the tag "except". Removes the
+	 * tag is {@code value} is null or consists of white
+	 * space only. 
+	 * 
+	 * @param value the new value for 'except'
+	 */
+	public void setExcept(ExceptValueModel value){
+		if (value == null || value.getValue().equals("")) {
+			if (tagEditorModel.get("except") != null){
+				tagEditorModel.delete("except");
+				setChanged();
+				notifyObservers();				
+			}
+			return;			
+		}
+		TagModel tag = tagEditorModel.get("except");
+		if (tag == null) {
+			tagEditorModel.prepend(new TagModel("except", value.getValue()));
+			setChanged();
+			notifyObservers();
+		} else {
+			if (!tag.getValue().equals(value.getValue())) {
+				tag.setValue(value.getValue().trim());
+				setChanged();
+				notifyObservers();
+			}
+		}		
+	}
 
 	/* ----------------------------------------------------------------------------------------- */
@@ -363,4 +421,11 @@
 			notifyObservers();
 		}		
-	}	
+	}
+	
+	class TagEditorModelObserver 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 20585)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionLegEditor.java	(revision 20586)
@@ -195,5 +195,5 @@
 		return role;
 	}		
-
+	
 	/* ----------------------------------------------------------------------------- */
 	/* interface Observer                                                            */
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionType.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionType.java	(revision 20585)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/TurnRestrictionType.java	(revision 20586)
@@ -56,3 +56,13 @@
 		return null;
 	}
+
+	/**
+	 * Replies true if {@code tagValue} is a standard restriction type. 
+	 * 
+	 * @param tagValue the tag value 
+	 * @return true if {@code tagValue} is a standard restriction type
+	 */
+	static public boolean isStandardTagValue(String tagValue){
+		return fromTagValue(tagValue) != null;
+	}
 }
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/VehicleExceptionEditor.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/VehicleExceptionEditor.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/editor/VehicleExceptionEditor.java	(revision 20586)
@@ -0,0 +1,327 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.editor;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.logging.Logger;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.gui.widgets.HtmlPanel;
+import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+/**
+ * VehicleExceptionEditor is UI widget for editing exceptions to a turn restriction
+ * based on vehicle types.
+ *  
+ */
+public class VehicleExceptionEditor extends JPanel implements Observer{
+	static private final Logger logger = Logger.getLogger(VehicleExceptionEditor.class.getName());
+	
+	private TurnRestrictionEditorModel model;
+	private JCheckBox cbPsv;
+	private JCheckBox cbBicyle;
+	private JCheckBox cbHgv;
+	private JCheckBox cbMotorcar;
+	private JTextField tfNonStandardValue;
+	private ButtonGroup bgStandardOrNonStandard;
+	private JRadioButton rbStandardException;
+	private JRadioButton rbNonStandardException;
+	private JPanel pnlStandard;
+	private JPanel pnlNonStandard;
+	private ExceptValueModel exceptValue = new ExceptValueModel();
+	
+	private JPanel buildMessagePanel() {
+		JPanel pnl = new JPanel(new BorderLayout());
+		HtmlPanel msg = new HtmlPanel();
+		pnl.add(msg, BorderLayout.CENTER);
+		msg.setText(
+				"<html><body>"
+				+ tr("Select the vehicle types this turn restriction is <strong>not</strong> applicable for.")
+				+ "</body></html>"
+	    );
+		return pnl;
+	}
+	
+	private JPanel buildStandardInputPanel() {
+		if (pnlStandard != null)
+			return pnlStandard;
+		
+		StandardVehicleTypeChangeListener changeHandler = new StandardVehicleTypeChangeListener();
+		
+		GridBagConstraints gc = new GridBagConstraints();
+		gc.anchor = GridBagConstraints.NORTHWEST;
+		gc.fill = GridBagConstraints.HORIZONTAL;
+		gc.gridx = 0;
+		gc.gridy = 0;
+		
+		pnlStandard = new JPanel(new GridBagLayout());
+		JLabel lbl;
+		cbPsv = new JCheckBox();
+		cbPsv.addItemListener(changeHandler);
+		lbl = new JLabel();
+		lbl.setText(tr("Public Service Vehicle"));
+		lbl.setToolTipText(tr("Public service vehicles like buses, tramways, etc."));
+		lbl.setIcon(ImageProvider.get("vehicle", "psv"));
+		
+		gc.weightx = 0.0;
+		pnlStandard.add(cbPsv, gc);
+		gc.weightx = 1.0;
+		gc.gridx++;
+		pnlStandard.add(lbl, gc);
+		
+		cbHgv = new JCheckBox();
+		cbHgv.addItemListener(changeHandler);
+		lbl = new JLabel();
+		lbl.setText(tr("Heavy Goods Vehicles"));
+		lbl.setIcon(ImageProvider.get("vehicle", "hgv"));
+
+		gc.weightx = 0.0;
+		gc.gridx++;
+		pnlStandard.add(cbHgv, gc);
+		gc.weightx = 1.0;
+		gc.gridx++;
+		pnlStandard.add(lbl, gc);
+
+		cbMotorcar = new JCheckBox();
+		cbMotorcar.addItemListener(changeHandler);
+		lbl = new JLabel();
+		lbl.setText(tr("Motorcars"));
+		lbl.setIcon(ImageProvider.get("vehicle", "motorcar"));
+		
+		gc.weightx = 0.0;
+		gc.gridx = 0;
+		gc.gridy = 1;
+		pnlStandard.add(cbMotorcar, gc);
+		gc.weightx = 1.0;
+		gc.gridx++;
+		pnlStandard.add(lbl, gc);
+		
+		cbBicyle = new JCheckBox();
+		cbBicyle.addItemListener(changeHandler);
+		lbl = new JLabel();
+		lbl.setText(tr("Bicycles"));
+		lbl.setIcon(ImageProvider.get("vehicle", "bicycle"));
+		
+
+		gc.weightx = 0.0;
+		gc.gridx++;
+		pnlStandard.add(cbBicyle, gc);
+		gc.weightx = 1.0;
+		gc.gridx++;
+		pnlStandard.add(lbl, gc);
+		
+		return pnlStandard;
+	}
+	
+	private JPanel buildNonStandardInputPanel() {
+		if (pnlNonStandard != null)
+			return pnlNonStandard;
+		pnlNonStandard = new JPanel(new GridBagLayout());
+		GridBagConstraints gc = new GridBagConstraints();
+		gc.anchor = GridBagConstraints.NORTHWEST;
+		gc.fill = GridBagConstraints.HORIZONTAL;
+		gc.weightx = 0.0;
+		gc.insets = new Insets(0, 0, 4, 0);
+		gc.gridx = 0;
+		gc.gridy = 0;
+		
+		pnlNonStandard.add(new JLabel(tr("Value:")), gc);
+		gc.gridx = 1;
+		gc.weightx = 1.0;
+		pnlNonStandard.add(tfNonStandardValue = new JTextField(), gc);
+		SelectAllOnFocusGainedDecorator.decorate(tfNonStandardValue);
+		
+		NonStandardVehicleTypesHandler inputChangedHandler = new NonStandardVehicleTypesHandler();
+		tfNonStandardValue.addActionListener(inputChangedHandler);
+		tfNonStandardValue.addFocusListener(inputChangedHandler);
+		return pnlNonStandard;
+	}
+		
+	/**
+	 * Builds the UI for entering standard values 
+	 */
+	protected void buildStandard() {
+		setLayout(new GridBagLayout());
+		GridBagConstraints gc = new GridBagConstraints();
+		gc.anchor = GridBagConstraints.NORTHWEST;
+		gc.fill = GridBagConstraints.HORIZONTAL;
+		gc.weightx = 1.0;
+		gc.gridx = 0;
+		gc.gridy = 0;
+		add(buildMessagePanel(), gc);
+		
+		gc.gridy=1;
+		add(buildStandardInputPanel(), gc);		
+	}
+	
+	/**
+	 * Builds the UI for entering either standard or non-standard values 
+	 */
+	protected void buildNonStandard() {
+		setLayout(new GridBagLayout());
+		GridBagConstraints gc = new GridBagConstraints();
+		gc.anchor = GridBagConstraints.NORTHWEST;
+		gc.fill = GridBagConstraints.HORIZONTAL;
+		gc.weightx = 1.0;
+		gc.gridx = 0;
+		gc.gridy = 0;
+		add(buildMessagePanel(), gc);
+				
+		gc.gridx=0;
+		gc.gridy=1;
+		gc.insets = new Insets(0,0,0,0);
+		add(rbStandardException = new JRadioButton(tr("Use standard exceptions")), gc);
+
+		gc.gridx=0;
+		gc.gridy=2;
+		gc.insets = new Insets(0, 20, 0,0);
+		add(buildStandardInputPanel(), gc);
+
+		gc.gridx=0;
+		gc.gridy=3;
+		gc.insets = new Insets(0,0,0,0);
+		add(rbNonStandardException = new JRadioButton(tr("Use non-standard exceptions")), gc);
+
+		gc.gridx=0;
+		gc.gridy=4;
+		gc.insets = new Insets(0, 20, 0,0);
+		add(buildNonStandardInputPanel(), gc);
+		
+		bgStandardOrNonStandard = new ButtonGroup();
+		bgStandardOrNonStandard.add(rbNonStandardException);
+		bgStandardOrNonStandard.add(rbStandardException);
+		
+		StandardNonStandardChangeHander changeHandler = new StandardNonStandardChangeHander();
+		rbNonStandardException.addItemListener(changeHandler);
+		rbStandardException.addItemListener(changeHandler);
+	}
+	
+	protected void build() {
+		removeAll();
+		buildNonStandardInputPanel();
+		buildStandardInputPanel();
+		if (exceptValue.isStandard()){
+			buildStandard();
+		} else {
+			buildNonStandard();
+		}
+		init();
+		invalidate();
+	}
+	
+	protected void init() {
+		cbPsv.setSelected(exceptValue.isVehicleException("psv"));
+		cbBicyle.setSelected(exceptValue.isVehicleException("bicycle"));
+		cbMotorcar.setSelected(exceptValue.isVehicleException("motorcar"));
+		cbHgv.setSelected(exceptValue.isVehicleException("hgv"));
+		if (!exceptValue.isStandard()){
+			rbNonStandardException.setSelected(true);
+			tfNonStandardValue.setText(exceptValue.getValue());
+			setEnabledNonStandardInputPanel(true);
+			setEnabledStandardInputPanel(false);
+		} else {
+			setEnabledNonStandardInputPanel(false);
+			setEnabledStandardInputPanel(true);
+		}
+	}
+	
+	protected void setEnabledStandardInputPanel(boolean enabled) {
+		for (Component c: pnlStandard.getComponents()){
+			c.setEnabled(enabled);
+		}
+	}
+	
+	protected void setEnabledNonStandardInputPanel(boolean enabled) {
+		for (Component c: pnlNonStandard.getComponents()){
+			c.setEnabled(enabled);
+		}
+	}
+
+	
+	/**
+	 * Creates the editor 
+	 * 
+	 * @param model the editor model. Must not be null.
+	 * @throws IllegalArgumentException thrown if {@code model} is null
+	 */
+	public VehicleExceptionEditor(TurnRestrictionEditorModel model) throws IllegalArgumentException {
+		CheckParameterUtil.ensureParameterNotNull(model, "model");
+		this.model = model;
+		build();
+		model.addObserver(this);
+	}
+	
+	/* ------------------------------------------------------------------------------------ */
+	/* interface Observer                                                                   */
+	/* ------------------------------------------------------------------------------------ */
+	public void update(Observable o, Object arg) {
+		if (!this.exceptValue.equals(model.getExcept())) {
+			this.exceptValue = model.getExcept();
+			build();
+		}
+	}
+
+	/* ------------------------------------------------------------------------------------ */
+	/* inner classes                                                                        */
+	/* ------------------------------------------------------------------------------------ */
+	class StandardNonStandardChangeHander implements ItemListener {
+		public void itemStateChanged(ItemEvent e) {
+			if (rbNonStandardException.isSelected()){
+				setEnabledNonStandardInputPanel(true);
+				setEnabledStandardInputPanel(false);
+				exceptValue.setStandard(false);
+			} else {
+				setEnabledNonStandardInputPanel(false);
+				setEnabledStandardInputPanel(true);
+				exceptValue.setStandard(true);
+			}
+			model.setExcept(exceptValue);
+		}
+	}
+	
+	class StandardVehicleTypeChangeListener implements ItemListener {
+		public void itemStateChanged(ItemEvent e) {
+			exceptValue.setVehicleException("bicycle", cbBicyle.isSelected());
+			exceptValue.setVehicleException("hgv", cbHgv.isSelected());
+			exceptValue.setVehicleException("psv", cbPsv.isSelected());
+			exceptValue.setVehicleException("motorcar", cbMotorcar.isSelected());
+			model.setExcept(exceptValue);
+		}
+	}
+	
+	class NonStandardVehicleTypesHandler implements ActionListener, FocusListener {
+		public void persist() {
+			exceptValue.setValue(tfNonStandardValue.getText());
+			model.setExcept(exceptValue);
+		}
+		
+		public void focusGained(FocusEvent e) {}
+		public void focusLost(FocusEvent e) {
+			persist();
+		}
+
+		public void actionPerformed(ActionEvent e) {
+			persist();			
+		}
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IdenticalTurnRestrictionLegsError.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IdenticalTurnRestrictionLegsError.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IdenticalTurnRestrictionLegsError.java	(revision 20586)
@@ -0,0 +1,65 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.DefaultNameFormatter;
+
+/**
+ * Issue when the 'from' and 'to' leg are identical.
+ * 
+ */
+public class IdenticalTurnRestrictionLegsError extends Issue{
+	private String value;
+	private OsmPrimitive leg;
+	
+	public IdenticalTurnRestrictionLegsError(IssuesModel parent, OsmPrimitive leg) {
+		super(parent, Severity.ERROR);
+		actions.add(new DeleteFromAction());
+		actions.add(new DeleteToAction());
+		actions.add(new FixInEditorAction());
+		this.leg = leg;
+	}
+
+	@Override
+	public String getText() {		
+		return tr("This turn restriction uses the OSM way <em>{0}</em> with role ''from'' <strong>and</strong> with role ''to''. "
+				+ "In a turn restriction, the way with role ''from'' should be different from the way with role ''to'', though.",
+				leg.getDisplayName(DefaultNameFormatter.getInstance())
+				);				
+	}
+	
+	class DeleteFromAction extends AbstractAction {
+		public DeleteFromAction() {
+			putValue(NAME, tr("Delete ''from''"));
+			putValue(SHORT_DESCRIPTION, tr("Removes the member with role ''from''"));
+		}
+		public void actionPerformed(ActionEvent e) {
+			getIssuesModel().getEditorModel().getRelationMemberEditorModel().setFromPrimitive(null);			
+		}		
+	}
+	
+	class DeleteToAction extends AbstractAction {
+		public DeleteToAction() {
+			putValue(NAME, tr("Delete ''to''"));
+			putValue(SHORT_DESCRIPTION, tr("Removes the member with role ''to''"));
+		}
+		public void actionPerformed(ActionEvent e) {
+			getIssuesModel().getEditorModel().getRelationMemberEditorModel().setToPrimitive(null);			
+		}		
+	}
+	
+	class FixInEditorAction extends AbstractAction {
+		public FixInEditorAction() {
+			putValue(NAME, tr("Fix in editor"));
+			putValue(SHORT_DESCRIPTION, tr("Go to Basic Editor and manually choose members with roles ''from'' and ''to''"));
+		}
+		public void actionPerformed(ActionEvent e) {
+			getIssuesModel().getNavigationControler().gotoBasicEditor();		
+		}		
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IllegalRestrictionTypeError.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IllegalRestrictionTypeError.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IllegalRestrictionTypeError.java	(revision 20586)
@@ -0,0 +1,42 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.NavigationControler;
+
+/**
+ * Issue when the restriction type isn't a standard value. Can't be fixed
+ * automatically, user is directed to the Basic editor.
+ * 
+ */
+public class IllegalRestrictionTypeError extends Issue{
+	private String value;
+	
+	public IllegalRestrictionTypeError(IssuesModel parent, String value) {
+		super(parent, Severity.ERROR);
+		actions.add(new FixInEditorAction());
+		this.value = value;
+	}
+
+	@Override
+	public String getText() {		
+		return tr("This turn restriction uses a non-standard restriction type <tt>{0}</tt> for the tag key <tt>restriction<tt>. "
+				+ "It is recommended to use standard values only. Please select one in the Basic editor.",
+				value
+				);				
+	}
+	
+	class FixInEditorAction extends AbstractAction {
+		public FixInEditorAction() {
+			putValue(NAME, tr("Fix in editor"));
+			putValue(SHORT_DESCRIPTION, tr("Go to Basic Editor and manually choose a turn restriction type"));
+		}
+		public void actionPerformed(ActionEvent e) {
+			getIssuesModel().getNavigationControler().gotoBasicEditor(NavigationControler.BasicEditorFokusTargets.RESTRICION_TYPE);			
+		}		
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/Issue.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/Issue.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/Issue.java	(revision 20586)
@@ -0,0 +1,100 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.Action;
+
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+/**
+ * An issue represents a data integrity violation in a turn restriction. 
+ * 
+ * The issue has a {@see Severity}. It is described to the user with a HTML formatted
+ * text (see {@see #getText()}) and it suggests a list of possible actions to fix
+ * the the issue (see {@see #getActions()}).
+ * 
+ */
+abstract public class Issue {
+	/** the parent model for this issue */
+	private IssuesModel parent;
+	private Severity severity;
+	protected final ArrayList<Action> actions = new ArrayList<Action>();
+	
+	/**
+	 * Creates a new issue associated with a parent model. Severity is
+	 * initialized to {@see Severity#WARNING}.
+	 * 
+	 * @param parent the parent model. Must not be null.
+	 * @throws IllegalArgumentException thrown if parent is null
+	 */
+	public Issue(IssuesModel parent) throws IllegalArgumentException{
+		CheckParameterUtil.ensureParameterNotNull(parent, "parent");
+		this.parent = parent;
+		this.severity = Severity.WARNING;
+	}
+	
+	/**
+	 * Creates a new issue of severity {@code severity} associated with
+	 * the parent model {@code parent}.
+	 * 
+	 * @param parent the parent model. Must not be null.
+	 * @param severity the severity. Must not be null.
+	 * @throws IllegalArgumentException thrown if parent is null
+	 * @throws IllegalArgumentException thrown if severity is null 
+	 */
+	public Issue(IssuesModel parent, Severity severity){
+		CheckParameterUtil.ensureParameterNotNull(parent, "parent");
+		CheckParameterUtil.ensureParameterNotNull(severity, "severity");
+		this.parent = parent;
+		this.severity = severity;
+	}
+
+	/**
+	 * Replies the parent model this issue is associated with 
+	 * 
+	 * @return the parent model 
+	 */
+	public IssuesModel getIssuesModel() {
+		return parent;
+	}
+
+	/**
+	 * Replies the severity of this issue 
+	 * 
+	 * @return the severity 
+	 */
+	public Severity getSeverity() {
+		return severity;
+	}
+
+	/**
+	 * Sets the severity of this issue. 
+	 * 
+	 * @param severity the severity. Must not be null.
+	 * @throws IllegalArgumentException thrown if severity is null
+	 */
+	public void setSeverity(Severity severity) throws IllegalArgumentException {
+		CheckParameterUtil.ensureParameterNotNull(severity, "severity");
+		this.severity = severity;
+	}
+
+	/**
+	 * Replies the HTML formatted description of the issue. The text should neither include
+	 * the &lt;html&gt;, nor the &lt;body&gt; tag.  
+	 * 
+	 * @return the HTML formatted description of the issue.
+	 */
+	public abstract String getText();
+	
+	/**
+	 * Replies a list of actions which can be applied to this issue in order to fix
+	 * it. The default implementation replies an empty list.
+	 * 
+	 * @return a list of action
+	 */
+	public List<Action> getActions() {
+		return Collections.unmodifiableList(actions);
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IssueView.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IssueView.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IssueView.java	(revision 20586)
@@ -0,0 +1,107 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+import org.openstreetmap.josm.gui.widgets.HtmlPanel;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+/**
+ * An IssueView is a view on an individual {@see Issue}.
+ */
+public class IssueView extends JPanel{
+
+	private HtmlPanel pnlMessage;
+	private JPanel pnlActions;
+	private Issue issue;
+	private JLabel lblIcon;
+	
+	protected void build() {
+		setLayout(new GridBagLayout());
+		setBackground(Color.WHITE);
+		setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1));
+		
+		// add the icon for the severity 
+		GridBagConstraints gc = new GridBagConstraints();
+		gc.anchor = GridBagConstraints.NORTHWEST;
+		gc.fill = GridBagConstraints.VERTICAL;
+		gc.gridheight = 2;
+		gc.weightx = 0.0;
+		gc.weighty = 1.0;
+		gc.gridx = 0;
+		gc.gridy = 0;
+		gc.insets = new Insets(2,2,2,2);
+		add(lblIcon = new JLabel(), gc);
+		lblIcon.setVerticalAlignment(SwingConstants.TOP);
+		lblIcon.setHorizontalAlignment(SwingConstants.CENTER);
+		lblIcon.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
+
+		// add the html panel with the issue description 
+		gc.insets = new Insets(0,0,0,0);
+		gc.anchor = GridBagConstraints.NORTHWEST;
+		gc.fill = GridBagConstraints.BOTH;
+		gc.gridx = 1;
+		gc.gridy = 0;
+		gc.gridheight = 1;
+		gc.weightx = 1.0;
+		gc.weighty = 1.0;
+		add(pnlMessage = new HtmlPanel(), gc);
+		pnlMessage.setBackground(Color.white);
+		pnlMessage.setText("<html><body>" + issue.getText() + "</html></bod>");
+		
+		// if there are any actions available to resolve the issue, add a panel with action buttons 
+		if (!issue.getActions().isEmpty()) {
+			pnlActions = new JPanel(new FlowLayout(FlowLayout.LEFT));
+			pnlActions.setBackground(Color.WHITE);
+			for (Action action: issue.getActions()){
+				JButton btn = new JButton(action);
+				pnlActions.add(btn);				
+			}
+			
+			gc.gridx = 1;			
+			gc.gridy = 1;			
+			gc.fill = GridBagConstraints.HORIZONTAL;
+			gc.weighty = 0.0;
+			add(pnlActions,gc);
+		}	
+		
+		// set the severity icon 
+		switch(issue.getSeverity()){
+		case WARNING: 
+			lblIcon.setIcon(ImageProvider.get("warning-small"));
+			break;
+		case ERROR:
+			lblIcon.setIcon(ImageProvider.get("styles/standard/misc", "error"));
+			break;
+		}		
+	}
+	
+	/**
+	 * Creates an issue view for an issue.
+	 * 
+	 * @param issue the issue. Must not be null.
+	 * @throws IllegalArgumentException thrown if issue is null.
+	 */
+	public IssueView(Issue issue) throws IllegalArgumentException{
+		CheckParameterUtil.ensureParameterNotNull(issue, "issue");
+		this.issue = issue;
+		build();
+	}
+
+	@Override
+	public Dimension getMinimumSize() {
+		return super.getPreferredSize();
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IssuesModel.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IssuesModel.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IssuesModel.java	(revision 20586)
@@ -0,0 +1,220 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.Set;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.tagging.TagEditorModel;
+import org.openstreetmap.josm.gui.tagging.TagModel;
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.ExceptValueModel;
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.NavigationControler;
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.TurnRestrictionEditorModel;
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.TurnRestrictionLegRole;
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.TurnRestrictionType;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+/**
+ * IssuesModel is a model for an observable list of {@code Issues}
+ * related to turn restriction.
+ * 
+ * It is also an {@see Observer} to an {@see TurnRestrictionEditorModel}
+ * and populates itself with issues it derives from the current state
+ * in the {@see TurnRestrictionEditorModel}.
+ *  
+ */
+public class IssuesModel extends Observable implements Observer{
+	private final ArrayList<Issue> issues = new ArrayList<Issue>();
+	private NavigationControler navigationContoler;
+	private TurnRestrictionEditorModel editorModel;
+	
+	/**
+	 * Creates the model 
+	 * 
+	 * {@code controler} is used in resolution actions for issues in
+	 * this model to direct the user to a specific input field in one
+	 * of the editor tabs in order to fix an issue. 
+	 * 
+	 * @param editorModel the editor model. Must not be null.
+	 * @param controler the navigation controler. Must not be null.
+	 * @throws IllegalArgumentException thrown if controler is null
+	 */
+	public IssuesModel(TurnRestrictionEditorModel editorModel, NavigationControler controler) throws IllegalArgumentException{
+		CheckParameterUtil.ensureParameterNotNull(editorModel, "editorModel");
+		CheckParameterUtil.ensureParameterNotNull(controler, "controler");
+		this.navigationContoler = controler;
+		this.editorModel = editorModel;
+		this.editorModel.addObserver(this);
+	}
+	
+	/**
+	 * Populates the model with a list of issues. Just clears the model
+	 * if {@code issues} is null or empty. 
+	 * 
+	 * @param issues the list of issues. 
+	 */
+	public void populate(List<Issue> issues){
+		this.issues.clear();
+		if (issues != null){
+			this.issues.addAll(issues);
+		}
+		setChanged();
+		notifyObservers();
+	}
+	
+	/**
+	 * Replies the (unmodifiable) list of issues in this model.
+	 * 
+	 * @return the (unmodifiable) list of issues in this model.
+	 */
+	public List<Issue> getIssues() {
+		return Collections.unmodifiableList(issues);
+	}
+	
+	/**
+	 * Replies the turn restriction editor model 
+	 * 
+	 * @return
+	 */
+	public TurnRestrictionEditorModel getEditorModel() {
+		return editorModel;
+	}
+	
+	/**
+	 * Populates this model with issues derived from the state of the
+	 * turn restriction editor model. If {@code editorModel} is null, the
+	 * list of issues is cleared.
+	 * 
+	 * @param editorModel the editor model. 
+	 */
+	public void populate() {
+		issues.clear();
+		if (editorModel != null) {
+			checkTags(editorModel);
+			checkFromLeg(editorModel);
+			checkToLeg(editorModel);
+			checkFromAndToEquals(editorModel);
+		}
+		setChanged();
+		notifyObservers();
+	}
+	
+	/**
+	 * Checks whether there are required tags missing. 
+	 * 
+	 * @param editorModel
+	 */
+	protected void checkTags(TurnRestrictionEditorModel editorModel) {
+		TagEditorModel tagEditorModel = editorModel.getTagEditorModel();
+		TagModel tag = tagEditorModel.get("type");
+		
+		// missing marker tag for a turn restriction
+		if (tag == null || ! tag.getValue().trim().equals("restriction")) {
+			issues.add(new RequiredTagMissingError(this, "type", "restriction"));
+		}
+		
+		// missing or illegal restriction type ?
+		tag = tagEditorModel.get("restriction");
+		if (tag == null) {
+			issues.add(new MissingRestrictionTypeError(this));
+		} else if (!TurnRestrictionType.isStandardTagValue(tag.getValue())) {
+			issues.add(new IllegalRestrictionTypeError(this, tag.getValue()));
+		}
+
+		// non-standard value for the 'except' tag? 
+		ExceptValueModel except = getEditorModel().getExcept();
+		if (!except.isStandard()) {
+			issues.add(new NonStandardExceptWarning(this, except));
+		}
+	}
+	
+	/**
+	 * Checks various data integrity restriction for the relation member with
+	 * role 'from'.
+	 * 
+	 */
+	protected void checkFromLeg(TurnRestrictionEditorModel editorModel) {
+		Set<OsmPrimitive> froms = editorModel.getTurnRestrictionLeg(TurnRestrictionLegRole.FROM);
+		if (froms.isEmpty()){
+			issues.add(new MissingTurnRestrictionLegError(this, TurnRestrictionLegRole.FROM));
+			return;
+		} else if (froms.size() > 1){
+			issues.add(new MultipleTurnRestrictionLegError(this, TurnRestrictionLegRole.FROM, froms.size()));
+			return;
+		} 
+		OsmPrimitive p = froms.iterator().next();
+		if (! (p instanceof Way)) {
+			issues.add(new WrongTurnRestrictionLegTypeError(this, TurnRestrictionLegRole.FROM, p));
+		}
+	}
+	
+	/**
+	 * Checks various data integrity restriction for the relation member with
+	 * role 'to'.
+	 * 
+	 */
+	protected void checkToLeg(TurnRestrictionEditorModel editorModel) {
+		Set<OsmPrimitive> toLegs = editorModel.getTurnRestrictionLeg(TurnRestrictionLegRole.TO);
+		if (toLegs.isEmpty()){
+			issues.add(new MissingTurnRestrictionLegError(this, TurnRestrictionLegRole.TO));
+			return;
+		} else if (toLegs.size() > 1){
+			issues.add(new MultipleTurnRestrictionLegError(this, TurnRestrictionLegRole.TO, toLegs.size()));
+			return;
+		} 
+		OsmPrimitive p = toLegs.iterator().next();
+		if (! (p instanceof Way)) {
+			issues.add(new WrongTurnRestrictionLegTypeError(this, TurnRestrictionLegRole.TO, p));
+		}
+	}
+	
+	/**
+	 * Creates an issue if this turn restriction has identical 'from' and to'.
+	 * 
+	 * @param editorModel
+	 */
+	protected void checkFromAndToEquals(TurnRestrictionEditorModel editorModel){
+		Set<OsmPrimitive> toLegs = editorModel.getTurnRestrictionLeg(TurnRestrictionLegRole.TO);
+		Set<OsmPrimitive> fromLegs = editorModel.getTurnRestrictionLeg(TurnRestrictionLegRole.FROM);
+		if (toLegs.size() != 1 || fromLegs.size() != 1) return;
+		
+		OsmPrimitive from = fromLegs.iterator().next();
+		OsmPrimitive to = toLegs.iterator().next();
+		if (! (from instanceof Way)) return;
+		if (! (to instanceof Way)) return;
+		if (from.equals(to)){
+			issues.add(new IdenticalTurnRestrictionLegsError(this, from));
+		}		
+	}
+	
+	public NavigationControler getNavigationControler() {
+		return navigationContoler;
+	}
+	
+	public int getNumWarnings() {
+		int ret = 0;
+		for (Issue issue: issues){
+			if (issue.getSeverity().equals(Severity.WARNING)) ret++;
+		}
+		return ret;
+	}
+
+	public int getNumErrors() {
+		int ret = 0;
+		for (Issue issue: issues){
+			if (issue.getSeverity().equals(Severity.ERROR)) ret++;
+		}
+		return ret;
+	}
+
+	/* ------------------------------------------------------------------------------------- */
+	/* interface Observer                                                                    */
+	/* ------------------------------------------------------------------------------------- */
+	public void update(Observable o, Object arg) {
+		populate();		
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IssuesView.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IssuesView.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/IssuesView.java	(revision 20586)
@@ -0,0 +1,70 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.logging.Logger;
+
+import javax.swing.JPanel;
+
+import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+/**
+ * IssuesView provides a view on a {@see IssuesModel}.
+ */
+public class IssuesView extends VerticallyScrollablePanel implements Observer{
+	static private final Logger logger = Logger.getLogger(IssuesView.class.getName());
+	
+	/** the issues model */
+	private IssuesModel model;
+	
+	protected void build(){
+		setLayout(new GridBagLayout());
+	}
+	
+	/**
+	 * Creates the view 
+	 * 
+	 * @param model the model. Must not be null.
+	 * @exception IllegalArgumentException thrown if model is null
+	 */
+	public IssuesView(IssuesModel model) throws IllegalArgumentException{
+		CheckParameterUtil.ensureParameterNotNull(model, "model");
+		this.model = model;
+		model.addObserver(this);
+		build();
+	}
+	
+	/**
+	 * Refreshes the view with the current state in the model
+	 */
+	public void refresh() {
+		removeAll();
+		if (! model.getIssues().isEmpty()){
+			GridBagConstraints gc = new GridBagConstraints();
+			gc.anchor = GridBagConstraints.NORTHWEST;
+			gc.fill = GridBagConstraints.HORIZONTAL;
+			gc.weightx = 1.0;
+			gc.weighty = 0.0;
+			gc.gridx = 0;
+			gc.gridy = 0;
+			for (Issue issue: model.getIssues()){
+				add(new IssueView(issue), gc);
+				gc.gridy++;
+			}
+			// filler - grabs remaining space
+			gc.weighty = 1.0;			
+			add(new JPanel(), gc);
+		}
+		invalidate();
+	}
+
+	/* ------------------------------------------------------------------------------- */
+	/* interface Observer                                                              */
+	/* ------------------------------------------------------------------------------- */
+	public void update(Observable o, Object arg) {
+		refresh();		
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/MissingRestrictionTypeError.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/MissingRestrictionTypeError.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/MissingRestrictionTypeError.java	(revision 20586)
@@ -0,0 +1,37 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.NavigationControler;
+
+/**
+ * Issue when the restriction type is missing. Can't be fixed automatically, user
+ * is redirected to the Basic Editor.
+ * 
+ */
+public class MissingRestrictionTypeError extends Issue{
+	
+	public MissingRestrictionTypeError(IssuesModel parent) {
+		super(parent, Severity.ERROR);
+		actions.add(new FixInEditorAction());
+	}
+
+	@Override
+	public String getText() {
+		return tr("A turn restriction must declare the type of restriction. Please select a type in the Basic Editor.");				
+	}
+	
+	class FixInEditorAction extends AbstractAction {
+		public FixInEditorAction() {
+			putValue(NAME, tr("Fix in editor"));
+			putValue(SHORT_DESCRIPTION, tr("Go to Basic Editor and manually choose a turn restriction type"));
+		}
+		public void actionPerformed(ActionEvent e) {
+			getIssuesModel().getNavigationControler().gotoBasicEditor(NavigationControler.BasicEditorFokusTargets.RESTRICION_TYPE);			
+		}		
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/MissingTurnRestrictionLegError.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/MissingTurnRestrictionLegError.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/MissingTurnRestrictionLegError.java	(revision 20586)
@@ -0,0 +1,69 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.TurnRestrictionLegRole;
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.plugins.turnrestrictions.editor.NavigationControler.BasicEditorFokusTargets.*;
+
+/**
+ * A member with role 'from' or 'to' is missing. Can't be fixed automatically.
+ * Redirect the user to the Basic editor panel.
+ * 
+ */
+public class MissingTurnRestrictionLegError extends Issue {
+	private TurnRestrictionLegRole role;
+
+	/**
+	 * Creates the issue. 
+	 * 
+	 * @param parent the parent model 
+	 * @param role the role of the missing way
+	 */
+	public MissingTurnRestrictionLegError(IssuesModel parent, TurnRestrictionLegRole role) {
+		super(parent, Severity.ERROR);
+		this.role = role;
+		actions.add(new FixAction());
+	}
+
+	@Override
+	public String getText() {
+		String msg = "";
+		switch(role){
+		case FROM: 
+			msg = tr("An OSM way with role <em>from</em> is required in a turn restriction.");
+			break;
+		case TO: 
+			msg = tr("An OSM way with role <em>to</em> is required in a turn restriction.");
+			break;
+		}
+		msg += " " + tr("Please go to the Basic editor and manually choose an OSM way.");
+		return msg;
+	}
+
+	class FixAction extends AbstractAction {
+		public FixAction() {
+			putValue(NAME, tr("Add in editor"));
+			switch(role){
+			case FROM:
+				putValue(SHORT_DESCRIPTION, tr("Add an OSM way with role ''from''"));
+				break;
+			case TO:
+				putValue(SHORT_DESCRIPTION, tr("Add an OSM way with role ''to''"));
+				break;				
+			}			
+		}
+		public void actionPerformed(ActionEvent e) {
+			switch(role){
+			case FROM:
+				getIssuesModel().getNavigationControler().gotoBasicEditor(FROM);
+				break;
+			case TO:
+				getIssuesModel().getNavigationControler().gotoBasicEditor(TO);
+				break;				
+			}			
+		}		
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/MultipleTurnRestrictionLegError.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/MultipleTurnRestrictionLegError.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/MultipleTurnRestrictionLegError.java	(revision 20586)
@@ -0,0 +1,63 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.TurnRestrictionLegRole;
+
+/**
+ * Issue when a turn restriction has multiple members with role 'from' or 'to'.
+ * 
+ */
+public class MultipleTurnRestrictionLegError extends Issue {
+	private TurnRestrictionLegRole role;
+	private int numLegs;
+	
+	/**
+	 * Create the issue
+	 * 
+	 * @param parent the parant model 
+	 * @param role the role of the turn restriction leg with multiple entries 
+	 * @param numLegs the number of legs
+	 */
+	public MultipleTurnRestrictionLegError(IssuesModel parent, TurnRestrictionLegRole role, int numLegs) {
+		super(parent, Severity.ERROR);
+		this.role = role;
+		this.numLegs = numLegs;
+		actions.add(new FixAction());
+	}
+
+	@Override
+	public String getText() {
+		switch(role){
+		case FROM: return 
+			tr("A turn restriction requires exactly one way with role <em>from</em>. "
+				+ "This turn restriction has {0} ways in this role. Please remove "
+				+ "{1} of them.",
+				numLegs,
+				numLegs -1
+			);
+		case TO: 
+			tr("A turn restriction requires exactly one way with role <em>from</em>. "
+					+ "This turn restriction has {0} ways in this role. Please remove "
+					+ "{1} of them.",
+					numLegs,
+					numLegs -1
+				);
+		}
+		return "";
+	}
+
+	class FixAction extends AbstractAction {
+		public FixAction() {
+			putValue(NAME, tr("Fix in editor"));
+			putValue(SHORT_DESCRIPTION, tr("Go to the Advanced Editor and remove the members"));
+		}
+		public void actionPerformed(ActionEvent e) {
+			getIssuesModel().getNavigationControler().gotoAdvancedEditor();
+		}		
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/NonStandardExceptWarning.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/NonStandardExceptWarning.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/NonStandardExceptWarning.java	(revision 20586)
@@ -0,0 +1,40 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.ExceptValueModel;
+
+/**
+ * Issue when the 'except' tag consists of non-standard values
+ * 
+ */
+public class NonStandardExceptWarning extends Issue{
+	private ExceptValueModel value;
+	public NonStandardExceptWarning(IssuesModel parent, ExceptValueModel value) {
+		super(parent, Severity.WARNING);
+		actions.add(new FixInEditorAction());
+		this.value  = value;
+	}
+
+	@Override
+	public String getText() {		
+		return tr("The tag <tt>except</tt> has the non-standard value <tt>{0}</tt>. "
+				+ "It is recommended to use standard values for <tt>except</tt> only.",
+				value.getValue()
+				);				
+	}
+	
+	class FixInEditorAction extends AbstractAction {
+		public FixInEditorAction() {
+			putValue(NAME, tr("Fix in editor"));
+			putValue(SHORT_DESCRIPTION, tr("Go to Basic Editor and select standard vehicle type based exceptions"));
+		}
+		public void actionPerformed(ActionEvent e) {
+			getIssuesModel().getNavigationControler().gotoBasicEditor();		
+		}		
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/RequiredTagMissingError.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/RequiredTagMissingError.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/RequiredTagMissingError.java	(revision 20586)
@@ -0,0 +1,58 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.util.logging.Logger;
+
+import javax.swing.AbstractAction;
+
+import org.openstreetmap.josm.gui.tagging.TagEditorModel;
+import org.openstreetmap.josm.gui.tagging.TagModel;
+
+/**
+ * Issue if a required tag is missing in the current turn restriction.
+ */
+public class RequiredTagMissingError extends Issue {
+	static private final Logger logger = Logger.getLogger(RequiredTagMissingError.class.getName());
+	private String tagKey;
+	private String tagValue;
+	
+	/**
+	 * Create the issue 
+	 * 
+	 * @param parent the issues model
+	 * @param tagKey the tag key 
+	 * @param tagValue the tag value 
+	 */
+	public RequiredTagMissingError(IssuesModel parent, String tagKey, String tagValue) {
+		super(parent, Severity.ERROR);
+		this.tagKey = tagKey;
+		this.tagValue = tagValue;
+		actions.add(new AddTagAction());
+	}
+
+	@Override
+	public String getText() {	
+		return tr("The required tag <tt>{0}={1}</tt> is missing.",				
+				this.tagKey,
+				this.tagValue
+		);
+	}
+
+	private class AddTagAction extends AbstractAction {
+		public AddTagAction(){
+			putValue(NAME,tr("Add missing tag"));
+			putValue(SHORT_DESCRIPTION, tr("Add the missing tag {0}={1}", tagKey, tagValue));		
+		}
+		
+		public void actionPerformed(ActionEvent e) {
+			TagEditorModel model = getIssuesModel().getEditorModel().getTagEditorModel();
+			TagModel t = model.get(tagKey);
+			if (t == null){
+				t = new TagModel(tagKey, tagValue);
+				model.prepend(t);
+			}			
+		}		 
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/Severity.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/Severity.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/Severity.java	(revision 20586)
@@ -0,0 +1,6 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+public enum Severity {
+	WARNING,
+	ERROR
+}
Index: applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/WrongTurnRestrictionLegTypeError.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/WrongTurnRestrictionLegTypeError.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/src/org/openstreetmap/josm/plugins/turnrestrictions/qa/WrongTurnRestrictionLegTypeError.java	(revision 20586)
@@ -0,0 +1,95 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.qa;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.DefaultNameFormatter;
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.NavigationControler;
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.RelationMemberEditorModel;
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.TurnRestrictionLegRole;
+import org.openstreetmap.josm.plugins.turnrestrictions.editor.NavigationControler.BasicEditorFokusTargets;
+
+/**
+ * Issue if the type of a turn restriction leg is either an OSM node or an OSM relation.
+ * 
+ */
+public class WrongTurnRestrictionLegTypeError extends Issue {
+	private TurnRestrictionLegRole role;
+	private OsmPrimitive leg;
+
+	/**
+	 * Create the issue 
+	 * 
+	 * @param parent the parent model 
+	 * @param role the role of the turn restriction leg
+	 * @param leg the leg 
+	 */
+	public WrongTurnRestrictionLegTypeError(IssuesModel parent, TurnRestrictionLegRole role, OsmPrimitive leg) {
+		super(parent, Severity.ERROR);
+		this.role = role;
+		this.leg = leg;
+		actions.add(new DeleteAction());
+		actions.add(new FixInEditorAction());
+	}
+
+	@Override
+	public String getText() {		
+		String msg = null;
+		switch(leg.getType()){
+		case NODE:
+			msg = tr(
+				"This turn restriction uses the OSM node ''{0}'' as member with role ''{1}''.",
+				leg.getDisplayName(DefaultNameFormatter.getInstance()),
+				role.toString()
+			);
+			break;
+		case RELATION:
+			msg = tr("This turn restriction uses the OSM relation ''{0}'' as member with role ''{1}''.",
+					leg.getDisplayName(DefaultNameFormatter.getInstance()),
+					role.toString()
+				);				
+			break;			
+		}
+		return msg + " " + tr("An OSM way is required instead.");
+	}
+
+	class DeleteAction extends AbstractAction {
+		public DeleteAction() {
+			putValue(NAME, tr("Delete"));
+			putValue(SHORT_DESCRIPTION, tr("Delete the member from the turn restriction"));
+		}
+		public void actionPerformed(ActionEvent e) {
+			RelationMemberEditorModel model = getIssuesModel().getEditorModel().getRelationMemberEditorModel();
+			switch(role){
+			case FROM: 
+				model.setFromPrimitive(null);
+				break;
+			case TO:
+				model.setToPrimitive(null);
+				break;
+			}
+		}		
+	}
+	
+	class FixInEditorAction extends AbstractAction {
+		public FixInEditorAction() {
+			putValue(NAME, tr("Fix in editor"));
+			putValue(SHORT_DESCRIPTION, tr("Change to the Basic Editor and select an OSM way"));
+		}
+		public void actionPerformed(ActionEvent e) {
+			NavigationControler controler = getIssuesModel().getNavigationControler();
+			switch(role){
+			case FROM: 
+				controler.gotoBasicEditor(BasicEditorFokusTargets.FROM);
+				break;
+			case TO:
+				controler.gotoBasicEditor(BasicEditorFokusTargets.TO);
+				break;
+			}
+		}		
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/test/org/openstreetmap/josm/plugins/turnrestrictions/editor/BasicEditorPanelTest.java
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/test/org/openstreetmap/josm/plugins/turnrestrictions/editor/BasicEditorPanelTest.java	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/test/org/openstreetmap/josm/plugins/turnrestrictions/editor/BasicEditorPanelTest.java	(revision 20586)
@@ -0,0 +1,49 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.editor;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+
+import javax.swing.JFrame;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+
+/**
+ * Simple functional test for the layout / basic functionality of {@see BasicEditorPanel} 
+ *   
+ */
+public class BasicEditorPanelTest extends JFrame {
+
+	private TurnRestrictionEditorModel model;
+	private DataSet ds;
+	
+	public BasicEditorPanelTest() {
+		ds = new DataSet();
+		OsmDataLayer layer =new OsmDataLayer(ds, "test",null);
+		// mock a controler 
+		NavigationControler controler = new NavigationControler() {
+			public void gotoAdvancedEditor() {
+			}
+
+			public void gotoBasicEditor() {
+			}
+
+			public void gotoBasicEditor(BasicEditorFokusTargets focusTarget) {
+			}			
+		};
+		model = new TurnRestrictionEditorModel(layer, controler);
+		
+		BasicEditorPanel panel = new BasicEditorPanel(model);
+		
+		Container c = getContentPane();
+		c.setLayout(new BorderLayout());
+		c.add(panel, BorderLayout.CENTER);		
+		setSize(600,600);
+		setDefaultCloseOperation(EXIT_ON_CLOSE);
+	}
+	
+	
+	static public void main(String args[]) {
+		new BasicEditorPanelTest().setVisible(true);
+	}
+}
Index: applications/editors/josm/plugins/turnrestrictions/test/org/openstreetmap/josm/plugins/turnrestrictions/editor/JosmSelectionListModelTest.groovy
===================================================================
--- applications/editors/josm/plugins/turnrestrictions/test/org/openstreetmap/josm/plugins/turnrestrictions/editor/JosmSelectionListModelTest.groovy	(revision 20586)
+++ applications/editors/josm/plugins/turnrestrictions/test/org/openstreetmap/josm/plugins/turnrestrictions/editor/JosmSelectionListModelTest.groovy	(revision 20586)
@@ -0,0 +1,151 @@
+package org.openstreetmap.josm.plugins.turnrestrictions.editor;
+import org.openstreetmap.josm.fixtures.JOSMFixture;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import javax.swing.DefaultListSelectionModel;
+import org.openstreetmap.josm.data.osm.*;
+import org.openstreetmap.josm.data.coor.*;
+
+import static org.junit.Assert.*;
+import org.junit.*;
+import javax.swing.JFrame;
+
+/**
+ * Unit test for {@see JosmSelctionListModel}
+ */
+class JosmSelectionListModelTest {
+	final shouldFail = new GroovyTestCase().&shouldFail
+	
+	@Test
+	public void test_Constructor(){
+		DataSet ds = new DataSet()
+		OsmDataLayer layer = new OsmDataLayer(ds, "test", null)
+		JosmSelectionListModel model = new JosmSelectionListModel(layer, new DefaultListSelectionModel());		
+		
+		shouldFail(IllegalArgumentException){
+			model = new JosmSelectionListModel(layer, null)
+		}
+		
+		shouldFail(IllegalArgumentException){
+			model = new JosmSelectionListModel(null, new DefaultListSelectionModel())
+		}
+	}
+	
+	@Test
+	public void test_setJOSMSelection() {
+		DataSet ds = new DataSet()
+		OsmDataLayer layer = new OsmDataLayer(ds, "test", null)
+		JosmSelectionListModel model = new JosmSelectionListModel(layer, new DefaultListSelectionModel());
+		
+		// set a selection with three objects 
+		def objects = [new Node(new LatLon(1,1)), new Way(), new Relation()]
+		model.setJOSMSelection objects
+		assert model.getSize() == 3
+		
+		// null is allowed 
+		model.setJOSMSelection(null)
+		assert model.getSize() == 0
+		assert model.getSelected().isEmpty()
+		
+		// empty has the same effect
+		model.setJOSMSelection([])
+		assert model.getSize() == 0
+		assert model.getSelected().isEmpty()
+	}
+	
+	@Test
+	public void test_setJOSMSelection_withSelected() {
+		DataSet ds = new DataSet()
+		OsmDataLayer layer = new OsmDataLayer(ds, "test", null)
+		JosmSelectionListModel model = new JosmSelectionListModel(layer, new DefaultListSelectionModel());
+		def objects = [new Node(new LatLon(1,1)), new Way(), new Relation()]	
+		model.setJOSMSelection(objects)
+		model.setSelected(objects[0..1])
+		assert model.getSelected().asList() == objects[0..1]
+		
+		// set new selection which includes one object which is currently
+        // selected in the model. Should still be selected after setting
+		// the new JOSM selection
+		objects = objects[1..2] 
+		model.setJOSMSelection(objects)
+		assert model.getSelected().asList() == [objects[0]]
+	}	
+	
+	@Test
+	public void test_getSelected() {
+		DataSet ds = new DataSet()
+		OsmDataLayer layer = new OsmDataLayer(ds, "test", null)
+		DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
+		
+		JosmSelectionListModel model = new JosmSelectionListModel(layer, selectionModel);
+		assert model.getSelected() != null
+		assert model.getSelected().isEmpty()
+	
+		// select one element 
+		def objects = [new Node(new LatLon(1,1)), new Way(), new Relation()]	
+		model.setJOSMSelection(objects)
+		selectionModel.setSelectionInterval(0, 0)
+		assert model.getSelected().asList() == [model.getElementAt(0)];
+		
+		// select two elements
+		selectionModel.setSelectionInterval(1,2)
+		assert model.getSelected().asList() == [model.getElementAt(1),model.getElementAt(2)];
+	}
+	
+	@Test
+	public void test_setSelected() {
+		DataSet ds = new DataSet()
+		OsmDataLayer layer = new OsmDataLayer(ds, "test", null)
+		DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
+		
+		// set selected with null is OK - nothing selected thereafter
+		JosmSelectionListModel model = new JosmSelectionListModel(layer, selectionModel);
+		model.setSelected(null)
+		assert model.getSelected().isEmpty()
+		
+		// set selected with empty list is OK - nothing selected thereafter
+		model.setSelected([])
+		assert model.getSelected().isEmpty()
+		
+		// select an object existing in the list of displayed objects 
+		def objects = [new Node(new LatLon(1,1)), new Way(), new Relation()]	
+		model.setJOSMSelection(objects)
+		model.setSelected([objects[0]])
+		assert model.getSelected().asList() == [objects[0]];
+		
+		// select an object not-existing in the list of displayed objects 	
+		model.setJOSMSelection(objects)
+		model.setSelected([new Way()])
+		assert model.getSelected().isEmpty()
+	}
+	
+	@Test 
+	public void test_editLayerChanged() {
+		DataSet ds = new DataSet()
+		DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();		
+		def objects = [new Node(new LatLon(1,1)), new Way(), new Relation()]	
+		objects.each {ds.addPrimitive(it)}
+		
+		OsmDataLayer layer1 = new OsmDataLayer(ds,"layer1", null)
+		OsmDataLayer layer2 = new OsmDataLayer(new DataSet(),"layer2", null)
+		
+		JosmSelectionListModel model = new JosmSelectionListModel(layer1, selectionModel);
+		
+		// switch from edit layer1 to edit layer2. content of the JOSM selection 
+		// should be empty thereafter 
+		model.editLayerChanged(layer1, layer2)
+		assert model.getSize() == 0
+		
+		// switch from layer2 to layer1 which has one object selected. Object should
+		// be displayed in the JOSM selection list 
+		ds.setSelected([objects[0]])
+		model.editLayerChanged(layer2, layer1)
+		assert model.getSize() == 1
+		assert model.getElementAt(0) == objects[0];
+		
+		// switch to a "null" edit layer (i.e. no edit layer)- nothing should
+		// be displayed in the selection list 
+		model.editLayerChanged(layer1, null)
+		assert model.getSize() == 0
+	}
+}
