Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/Test.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/Test.java	(revision 2590)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/Test.java	(revision 2591)
@@ -1,8 +1,11 @@
 package org.openstreetmap.josm.plugins.validator;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 
 import javax.swing.JPanel;
 
+import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.data.osm.*;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
@@ -30,4 +33,7 @@
 	/** The list of errors */
 	protected List<TestError> errors = new ArrayList<TestError>(30);
+
+	/** Whether the test is run on a partial selection data */
+	protected boolean partialSelection;
 
 	/**
@@ -66,4 +72,13 @@
 		errors = new ArrayList<TestError>(30);
 	}
+
+	/**
+	 * Flag notifying that this test is run over a partial data selection
+	 * @param partialSelection Whether the test is on a partial selection data
+	 */ 
+	public void setPartialSelection(boolean partialSelection) 
+	{
+		this.partialSelection = partialSelection;
+	}
 	
 	/**
@@ -92,5 +107,6 @@
         for (OsmPrimitive p : selection)
         {
-            p.visit(this);
+        	if( !p.deleted )
+        		p.visit(this);
         }
     }
@@ -116,3 +132,25 @@
 	{
 	}
+	
+	/**
+	 * Fixes the error with the appropiate command
+	 * 
+	 * @param testError
+	 * @return The command to fix the error
+	 */
+	public Command fixError(TestError testError)
+	{
+		return null;
+	}
+	
+	/**
+	 * Returns true if the given error can be fixed automatically
+	 * 
+	 * @param testError The error to check if can be fixed
+	 * @return true if the error can be fixed
+	 */
+	public boolean isFixable(TestError testError)
+	{
+		return false;
+	}	
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/TestError.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/TestError.java	(revision 2590)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/TestError.java	(revision 2591)
@@ -4,4 +4,5 @@
 import java.util.List;
 
+import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 
@@ -17,5 +18,9 @@
 	private String message;
 	/** The affected primitives */
-	private List<? extends OsmPrimitive> primitives;
+	private List<OsmPrimitive> primitives;
+	/** The tester that raised this error */
+	private Test tester;
+	/** Internal code used by testers to classify errors */
+	private int internalCode;
 	
 	/**
@@ -28,10 +33,12 @@
 	/**
 	 * Constructor
+	 * @param tester The tester
 	 * @param severity The severity of this error
 	 * @param message The error message
 	 * @param primitives The affected primitives
 	 */
-	public TestError(Severity severity, String message, List<? extends OsmPrimitive> primitives)
+	public TestError(Test tester, Severity severity, String message, List<OsmPrimitive> primitives)
 	{
+		this.tester = tester;
 		this.severity = severity;
 		this.message = message;
@@ -41,10 +48,12 @@
 	/**
 	 * Constructor
+	 * @param tester The tester
 	 * @param severity The severity of this error
 	 * @param message The error message
 	 * @param primitive The affected primitive
 	 */
-	public TestError(Severity severity, String message, OsmPrimitive primitive)
+	public TestError(Test tester, Severity severity, String message, OsmPrimitive primitive)
 	{
+		this.tester = tester;
 		this.severity = severity;
 		this.message = message;
@@ -54,4 +63,18 @@
 		
 		this.primitives = primitives;
+	}
+	
+	/**
+	 * Constructor
+	 * @param tester The tester
+	 * @param severity The severity of this error
+	 * @param message The error message
+	 * @param primitive The affected primitive
+	 * @param internalCode The internal code
+	 */
+	public TestError(Test tester, Severity severity, String message, OsmPrimitive primitive, int internalCode)
+	{
+		this(tester, severity, message, primitive);
+		this.internalCode = internalCode;
 	}
 	
@@ -78,5 +101,5 @@
 	 * @return the list of primitives affected by this error
 	 */
-	public List<? extends OsmPrimitive> getPrimitives() 
+	public List<OsmPrimitive> getPrimitives() 
 	{
 		return primitives;
@@ -110,3 +133,54 @@
 		this.severity = severity;
 	}
+
+	/**
+	 * Gets the tester that raised this error 
+	 * @return the tester that raised this error
+	 */
+	public Test getTester() 
+	{
+		return tester;
+	}
+
+	/**
+	 * Gets the internal code
+	 * @return the internal code
+	 */
+	public int getInternalCode() 
+	{
+		return internalCode;
+	}
+
+	
+	/**
+	 * Sets the internal code
+	 * @param internalCode The internal code
+	 */
+	public void setInternalCode(int internalCode) 
+	{
+		this.internalCode = internalCode;
+	}
+	
+	/**
+	 * Returns true if the error can be fixed automatically
+	 * 
+	 * @return true if the error can be fixed
+	 */
+	public boolean isFixable()
+	{
+		return tester != null && tester.isFixable(this);
+	}
+	
+	/**
+	 * Fixes the error with the appropiate command
+	 * 
+	 * @return The command to fix the error
+	 */
+	public Command getFix()
+	{
+		if( tester == null )
+			return null;
+		
+		return tester.fixError(this);
+	}	
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidateAction.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidateAction.java	(revision 2590)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidateAction.java	(revision 2591)
@@ -24,4 +24,7 @@
     private static final long serialVersionUID = -2304521273582574603L;
 
+	/** Last selection used to validate */
+	private Collection<OsmPrimitive> lastSelection;
+	
     /**
 	 * Constructor
@@ -34,4 +37,19 @@
 	public void actionPerformed(ActionEvent ev)
 	{
+		doValidate(ev, true);
+	}
+	
+	/**
+	 * Does the validation.
+	 * <p>
+	 * If getSelectedItems is true, the selected items (or all items, if no one
+	 * is selected) are validated. If it is false, last selected items are
+	 * revalidated
+	 * 
+	 * @param ev The event
+	 * @param getSelectedItems If selected or last selected items must be validated
+	 */
+	public void doValidate(ActionEvent ev, boolean getSelectedItems)
+	{
 		OSMValidatorPlugin plugin = OSMValidatorPlugin.getPlugin();
 		plugin.errors = new ArrayList<TestError>();
@@ -42,15 +60,31 @@
 			return;
 		
-		Collection<OsmPrimitive> selection = Main.ds.getSelected();
-		if( selection.isEmpty() )
-			selection = Main.ds.allNonDeletedPrimitives();
+		Collection<OsmPrimitive> selection;
+		if( getSelectedItems )
+		{
+			selection = Main.ds.getSelected();
+			if( selection.isEmpty() )
+			{
+				selection = Main.ds.allNonDeletedPrimitives();
+				lastSelection = null;
+			}
+			else
+			{
+				AgregatePrimitivesVisitor v = new AgregatePrimitivesVisitor();
+				selection = v.visit(selection);
+				lastSelection = selection;
+			}
+		}
 		else
 		{
-			AgregatePrimitivesVisitor v = new AgregatePrimitivesVisitor();
-			selection = v.visit(selection);
+			if( lastSelection == null )
+				selection = Main.ds.allNonDeletedPrimitives();
+			else
+				selection = lastSelection;
 		}
 
 		for(Test test : tests) 
         {
+			test.setPartialSelection(lastSelection != null);
 		    test.startTest();
 		    test.visit(selection);
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidatorDialog.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidatorDialog.java	(revision 2590)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidatorDialog.java	(revision 2591)
@@ -9,10 +9,12 @@
 import java.util.Map.Entry;
 
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTree;
+import javax.swing.*;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
 import javax.swing.tree.*;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
@@ -41,4 +43,9 @@
      */
     protected JTree tree = new JTree(treeModel);
+
+    /** 
+     * The fix button
+     */
+	private JButton fixButton;
     
 
@@ -54,5 +61,6 @@
 		tree.expandRow(0);
 		tree.setVisibleRowCount(8);
-		tree.addMouseListener(new DblClickWatch());
+		tree.addMouseListener(new ClickWatch());
+		tree.addTreeSelectionListener(new SelectionWatch());
 		tree.setCellRenderer(new ErrorTreeRenderer());
 		tree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
@@ -65,4 +73,8 @@
         add(buttonPanel, BorderLayout.SOUTH);
         buttonPanel.add(Util.createButton("Validate", "dialogs/refresh", "Validate the data.", this)); 
+        add(buttonPanel, BorderLayout.SOUTH);
+        fixButton = Util.createButton("Fix", "dialogs/fix", "Fix the selected errors.", this);
+        fixButton.setEnabled(false);
+        buttonPanel.add(fixButton); 
         add(buttonPanel, BorderLayout.SOUTH);
     }
@@ -136,9 +148,70 @@
 	}
 	
+	/**
+	 * Fix selected errors
+	 * @param e 
+	 */
+	@SuppressWarnings("unchecked")
+	private void fixErrors(ActionEvent e) 
+	{
+		DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
+    	if( node == null )
+    		return;
+
+        Bag<String, Command> commands = new Bag<String, Command>();
+
+		Enumeration<DefaultMutableTreeNode> children = node.breadthFirstEnumeration();
+		while( children.hasMoreElements() )
+		{
+    		DefaultMutableTreeNode childNode = children.nextElement();
+    		Object nodeInfo = childNode.getUserObject();
+    		if( nodeInfo instanceof TestError)
+    		{
+    			TestError error = (TestError)nodeInfo;
+    			Command fixCommand = error.getFix();
+    			if( fixCommand != null )
+    			{
+    				commands.add(error.getMessage(), fixCommand);
+    			}
+    		}
+		}
+		
+		Command fixCommand = null;
+		if( commands.size() == 0 )
+			return;
+		else if( commands.size() > 1 )
+		{
+			List<Command> allComands = new ArrayList<Command>(50);
+			for( Entry<String, List<Command>> errorType : commands.entrySet())
+			{
+				String description = errorType.getKey();
+				List<Command> errorCommands = errorType.getValue();
+				allComands.add( new SequenceCommand("Fix " + description, errorCommands) );
+			}
+			
+			fixCommand = new SequenceCommand("Fix errors", allComands);
+		}
+		else 
+		{
+			for( Entry<String, List<Command>> errorType : commands.entrySet())
+			{
+				String description = errorType.getKey();
+				List<Command> errorCommands = errorType.getValue();
+				fixCommand = new SequenceCommand("Fix " + description, errorCommands);
+			}
+		}
+		
+		Main.main.editLayer().add( fixCommand );
+		Main.map.repaint();
+		Main.ds.fireSelectionChanged(Main.ds.getSelected());
+		       
+    	OSMValidatorPlugin.getPlugin().validateAction.doValidate(e, false);
+	}	
+	
     /**
      * Sets the selection of the map to the current selected items.
      */
     @SuppressWarnings("unchecked")
-    public void setSelectedItems() 
+    private void setSelectedItems() 
     {
         Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>(40);
@@ -160,4 +233,5 @@
     		}
         }
+        
         Main.ds.setSelected(sel);
     }
@@ -165,50 +239,105 @@
 	public void actionPerformed(ActionEvent e) 
 	{
-		if( e.getActionCommand().equals("Select"))
+		String actionCommand = e.getActionCommand();
+		if( actionCommand.equals("Select"))
 			setSelectedItems();
-		else if( e.getActionCommand().equals("Validate"))
+		else if( actionCommand.equals("Validate"))
 	    	OSMValidatorPlugin.getPlugin().validateAction.actionPerformed(e);
+		else if( actionCommand.equals("Fix"))
+	    	fixErrors(e); 
+	}
+
+	/**
+	 * Refresh the error messages display
+	 */
+	public void refresh()
+	{
+		buildTree();
 	}
 	
-	/**
-	 * Refresh the error messages display
-	 */
-	public void refresh()
-	{
-		buildTree();
-	}
-	
-	/**
-	 * Watches for double clicks and from editing or new property, depending on the
-	 * location, the click was.
-	 * @author imi
-	 */
-	public class DblClickWatch extends MouseAdapter 
-	{
-        @SuppressWarnings("unchecked")
+    /**
+     * Checks for fixes in selected element and, if needed, adds to the sel parameter all selected elements
+     * @param sel The collection where to add all selected elements
+     * @param addSelected if true, add all selected elements to collection
+     * @return whether the selected elements has any fix
+     */
+    @SuppressWarnings("unchecked")
+	private boolean setSelection(Collection<OsmPrimitive> sel, boolean addSelected)
+	{
+		boolean hasFixes = false;
+
+		DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
+    	if( node == null ) 
+    		return hasFixes;
+
+		Enumeration<DefaultMutableTreeNode> children = node.breadthFirstEnumeration();
+		while( children.hasMoreElements() )
+		{
+    		DefaultMutableTreeNode childNode = children.nextElement();
+    		Object nodeInfo = childNode.getUserObject();
+    		if( nodeInfo instanceof TestError)
+    		{
+    			TestError error = (TestError)nodeInfo;
+    			hasFixes = hasFixes || error.isFixable();
+    			if( addSelected )
+    			{
+        			sel.addAll( error.getPrimitives() );
+    			}
+    		}
+		}
+		
+		return hasFixes;
+	}
+    
+	/**
+	 * Watches for clicks.
+	 */
+	public class ClickWatch extends MouseAdapter 
+	{
         @Override 
 		public void mouseClicked(MouseEvent e) 
 		{
-			if (e.getClickCount() < 2 || e.getSource() instanceof JScrollPane)
+	        fixButton.setEnabled(false);
+        	
+			if(e.getSource() instanceof JScrollPane)
 				return;
-			else 
+        	
+			DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
+        	if( node == null )
+        		return;
+
+	        Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>(40);
+			boolean isDblClick = e.getClickCount() > 1;
+			
+			boolean hasFixes = setSelection(sel, isDblClick);
+	        fixButton.setEnabled(hasFixes);
+	        
+	        if( isDblClick)
 			{
-		        Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>(40);
-
-	        	DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
-	    		Enumeration<DefaultMutableTreeNode> children = node.breadthFirstEnumeration();
-	    		while( children.hasMoreElements() )
-	    		{
-	        		DefaultMutableTreeNode childNode = children.nextElement();
-	        		Object nodeInfo = childNode.getUserObject();
-	        		if( nodeInfo instanceof TestError)
-	        		{
-	        			TestError error = (TestError)nodeInfo;
-	        			sel.addAll( error.getPrimitives() );
-	        		}
-	    		}
 	    		Main.ds.setSelected(sel);
 			}
 		}
 	}
+	
+	/**
+	 * Watches for tree selection.
+	 */
+	public class SelectionWatch implements TreeSelectionListener 
+	{
+        @SuppressWarnings("unchecked")
+		public void valueChanged(TreeSelectionEvent e) 
+		{
+	        fixButton.setEnabled(false);
+        	
+			if(e.getSource() instanceof JScrollPane)
+				return;
+        	
+			DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
+        	if( node == null )
+        		return;
+
+			boolean hasFixes = setSelection(null, false);
+	        fixButton.setEnabled(hasFixes);
+		}
+	}
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/ChangePropertyKeyCommand.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/ChangePropertyKeyCommand.java	(revision 2591)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/ChangePropertyKeyCommand.java	(revision 2591)
@@ -0,0 +1,83 @@
+package org.openstreetmap.josm.plugins.validator.tests;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trn;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.JLabel;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.MutableTreeNode;
+
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.visitor.NameVisitor;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+/**
+ * Command that replaces the key of several objects
+ * 
+ */
+public class ChangePropertyKeyCommand extends Command {
+	/**
+	 * All primitives, that are affected with this command.
+	 */
+	private final List<OsmPrimitive> objects;
+	/**
+	 * The key that is subject to change.
+	 */
+	private final String key;
+	/**
+	 * The mew key.
+	 */
+	private final String newKey;
+	
+	/**
+	 * Constructor
+	 * 
+	 * @param objects all objects subject to change replacement
+	 * @param key The key to replace
+	 * @param newKey the new value of the key
+	 */
+	public ChangePropertyKeyCommand(Collection<? extends OsmPrimitive> objects, String key, String newKey) {
+		this.objects = new LinkedList<OsmPrimitive>(objects);
+		this.key = key;
+		this.newKey = newKey;
+	}
+	
+	@Override public void executeCommand() {
+		super.executeCommand(); // save old
+		for (OsmPrimitive osm : objects) {
+			if(osm.keys != null) 
+			{
+				osm.modified = true;
+				osm.put(newKey, osm.keys.remove(key) );
+			}
+		}
+	}
+
+	@Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+		modified.addAll(objects);
+	}
+
+	@Override public MutableTreeNode description() {
+		String text = tr( "Replace \"{0}\" by \"{1}\" for", key, newKey);
+		if (objects.size() == 1) {
+			NameVisitor v = new NameVisitor();
+			objects.iterator().next().visit(v);
+			text += " "+tr(v.className)+" "+v.name;
+		} else
+			text += " "+objects.size()+" "+trn("object","objects",objects.size());
+		DefaultMutableTreeNode root = new DefaultMutableTreeNode(new JLabel(text, ImageProvider.get("data", "key"), JLabel.HORIZONTAL));
+		if (objects.size() == 1)
+			return root;
+		NameVisitor v = new NameVisitor();
+		for (OsmPrimitive osm : objects) {
+			osm.visit(v);
+			root.add(new DefaultMutableTreeNode(v.toLabel()));
+		}
+		return root;
+    }
+}
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicateNode.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicateNode.java	(revision 2590)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicateNode.java	(revision 2591)
@@ -5,6 +5,9 @@
 import java.util.List;
 
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.DeleteCommand;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.plugins.validator.Severity;
 import org.openstreetmap.josm.plugins.validator.Test;
@@ -19,5 +22,5 @@
 {
 	/** Bag of all nodes */
-	Bag<LatLon, Node> nodes;
+	Bag<LatLon, OsmPrimitive> nodes;
 	
 	/**
@@ -34,5 +37,5 @@
 	public void startTest() 
 	{
-		nodes = new Bag<LatLon, Node>(1000);
+		nodes = new Bag<LatLon, OsmPrimitive>(1000);
 	}
 
@@ -40,9 +43,10 @@
 	public void endTest() 
 	{
-		for(List<Node> duplicated : nodes.values() )
+		for(List<OsmPrimitive> duplicated : nodes.values() )
 		{
 			if( duplicated.size() > 1)
 			{
-				errors.add( new TestError(Severity.ERROR, tr("Duplicated nodes"), duplicated) );
+				TestError testError = new TestError(this, Severity.ERROR, tr("Duplicated nodes"), duplicated);
+				errors.add( testError );
 			}
 		}
@@ -55,3 +59,16 @@
 		nodes.add(n.coor, n);
 	}
+	
+	@Override
+	public Command fixError(TestError testError)
+	{
+		//TODO Which should be the fix? 
+		return new DeleteCommand(testError.getPrimitives());
+	}
+	
+	@Override
+	public boolean isFixable(TestError testError)
+	{
+		return false; //(testError.getTester() instanceof DuplicateNode);
+	}	
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicateSegment.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicateSegment.java	(revision 2590)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicateSegment.java	(revision 2591)
@@ -6,4 +6,5 @@
 
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Segment;
 import org.openstreetmap.josm.plugins.validator.Severity;
@@ -19,5 +20,5 @@
 {
 	/** Bag of all segments */
-	Bag<CompoundLatLon, Segment> segments;
+	Bag<CompoundLatLon, OsmPrimitive> segments;
 	
 	/**
@@ -35,5 +36,5 @@
 	public void startTest() 
 	{
-		segments = new Bag<CompoundLatLon, Segment>(1000);
+		segments = new Bag<CompoundLatLon, OsmPrimitive>(1000);
 	}
 
@@ -41,9 +42,9 @@
 	public void endTest() 
 	{
-		for(List<Segment> duplicated : segments.values() )
+		for(List<OsmPrimitive> duplicated : segments.values() )
 		{
 			if( duplicated.size() > 1)
 			{
-				errors.add( new TestError(Severity.ERROR, tr("Duplicated segments"), duplicated) );
+				errors.add( new TestError(this, Severity.ERROR, tr("Duplicated segments"), duplicated) );
 			}
 		}
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/OrphanSegment.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/OrphanSegment.java	(revision 2590)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/OrphanSegment.java	(revision 2591)
@@ -43,5 +43,5 @@
 		for(Segment segment : segments )
 		{
-			errors.add( new TestError(Severity.OTHER, tr("Segments not in a way"), segment) );
+			errors.add( new TestError(this, Severity.OTHER, tr("Segments not in a way"), segment) );
 		}
 		segments = null;
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SingleNodeSegment.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SingleNodeSegment.java	(revision 2590)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SingleNodeSegment.java	(revision 2591)
@@ -3,4 +3,6 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.DeleteCommand;
 import org.openstreetmap.josm.data.osm.Segment;
 import org.openstreetmap.josm.plugins.validator.Severity;
@@ -31,6 +33,18 @@
 		if( !s.incomplete && s.from.equals(s.to) )
 		{
-			errors.add( new TestError(Severity.ERROR, tr("Single node segments"), s) );
+			errors.add( new TestError(this, Severity.ERROR, tr("Single node segments"), s) );
 		}
 	}
+	
+	@Override
+	public Command fixError(TestError testError)
+	{
+		return new DeleteCommand(testError.getPrimitives());
+	}
+	
+	@Override
+	public boolean isFixable(TestError testError)
+	{
+		return (testError.getTester() instanceof SingleNodeSegment);
+	}	
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SpellCheck.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SpellCheck.java	(revision 2590)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SpellCheck.java	(revision 2591)
@@ -13,4 +13,7 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.ChangePropertyCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
 import org.openstreetmap.josm.data.osm.*;
 import org.openstreetmap.josm.gui.annotation.AnnotationPreset;
@@ -45,4 +48,11 @@
 	protected JCheckBox prefCheckValues;
 
+	/** Empty values error */
+	protected static int EMPTY_VALUES 	= 0;
+	/** Invalid key error */
+	protected static int INVALID_KEY  	= 1;
+	/** Invalid value error */
+	protected static int INVALID_VALUE 	= 2;
+	
 	/**
 	 * Constructor
@@ -161,10 +171,10 @@
 			if( (value==null || value.trim().length() == 0) && !withErrors.contains(p, "EV"))
 			{
-				errors.add( new TestError(Severity.WARNING, tr("Tags with empty value"), p) );
+				errors.add( new TestError(this, Severity.WARNING, tr("Tags with empty values"), p, EMPTY_VALUES) );
 				withErrors.add(p, "EV");
 			}
 			if( spellCheckKeyData.containsKey(key) && !withErrors.contains(p, "IPK"))
 			{
-				errors.add( new TestError(Severity.WARNING, tr("Invalid property key"), p) );
+				errors.add( new TestError(this, Severity.WARNING, tr("Invalid property keys"), p, INVALID_KEY) );
 				withErrors.add(p, "IPK");
 			}
@@ -174,5 +184,5 @@
 				if( values != null && !values.contains(prop.getValue()) && !withErrors.contains(p, "UPV"))
 				{
-					errors.add( new TestError(Severity.OTHER, tr("Unknown property value"), p) );
+					errors.add( new TestError(this, Severity.OTHER, tr("Unknown property values"), p, INVALID_VALUE) );
 					withErrors.add(p, "UPV");
 				}
@@ -277,4 +287,48 @@
 		Main.pref.put(PREF_CHECK_VALUES, prefCheckValues.isSelected());
 	}
+	
+	@Override
+	public Command fixError(TestError testError)
+	{
+		List<Command> commands = new ArrayList<Command>(50);
+		
+		int i = -1;
+		List<OsmPrimitive> primitives = testError.getPrimitives();
+		for(OsmPrimitive p : primitives )
+		{
+			i++;
+			Map<String, String> tags = p.keys;
+			if( tags == null || tags.size() == 0 )
+				continue;
+		
+			for(Entry<String, String> prop: tags.entrySet() )
+			{
+				String key = prop.getKey();
+				String value = prop.getValue();
+				if( value == null || value.trim().length() == 0 )
+					commands.add( new ChangePropertyCommand(primitives.subList(i, i+1), key, null) );
+				else
+				{
+					String replacementKey = spellCheckKeyData.get(key);
+					if( replacementKey != null )
+						commands.add( new ChangePropertyKeyCommand(primitives.subList(i, i+1), key, replacementKey) );					
+				}
+			}
+		}
+		
+		return commands.size() > 1 ? new SequenceCommand("Fix properties", commands) : commands.get(0);
+	}
+	
+	@Override
+	public boolean isFixable(TestError testError)
+	{
+		if( testError.getTester() instanceof SpellCheck)
+		{
+			int code = testError.getInternalCode();
+			return code == INVALID_KEY || code == EMPTY_VALUES;
+		}
+		
+		return false;
+	}	
 }
 	
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/TaggedSegment.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/TaggedSegment.java	(revision 2590)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/TaggedSegment.java	(revision 2591)
@@ -3,6 +3,8 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.util.Map;
+import java.util.*;
 
+import org.openstreetmap.josm.command.*;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Segment;
 import org.openstreetmap.josm.plugins.validator.Severity;
@@ -35,13 +37,48 @@
 		if( tags == null )
 			return;
+		tags = new HashMap<String, String>(tags);
+		for( String tag : allowedTags)
+			tags.remove(tag);
 		
-		int numAllowedTags = 0;
-		for( String tag : allowedTags)
-			if( tags.containsKey(tag) ) numAllowedTags++;
-		
-		if( tags.size() - numAllowedTags > 0 )
+		if( tags.size() > 0 )
 		{
-			errors.add( new TestError(Severity.WARNING, tr("Segments with tags"), s) );
+			errors.add( new TestError(this, Severity.WARNING, tr("Segments with tags"), s) );
 		}
 	}
+	
+	@Override
+	public Command fixError(TestError testError)
+	{
+		List<Command> commands = new ArrayList<Command>(50);
+		
+		int i = -1;
+		List<OsmPrimitive> primitives = testError.getPrimitives();
+		for(OsmPrimitive p : primitives )
+		{
+			i++;
+			Map<String, String> tags = p.keys;
+			if( tags == null )
+				continue;
+			
+			tags = new HashMap<String, String>(tags);
+			for( String tag : allowedTags)
+				tags.remove(tag);
+			
+			if( tags.size() == 0 )
+				continue;
+		
+			for(String key : tags.keySet() )
+			{
+				commands.add( new ChangePropertyCommand(primitives.subList(i, i+1), key, null) );
+			}
+		}
+		
+		return commands.size() > 1 ? new SequenceCommand("Remove keys", commands) : commands.get(0);
+	}
+	
+	@Override
+	public boolean isFixable(TestError testError)
+	{
+		return (testError.getTester() instanceof TaggedSegment);
+	}	
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UnorderedWay.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UnorderedWay.java	(revision 2590)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UnorderedWay.java	(revision 2591)
@@ -3,4 +3,9 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.util.*;
+
+import org.openstreetmap.josm.actions.ReorderAction;
+import org.openstreetmap.josm.command.*;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Segment;
 import org.openstreetmap.josm.data.osm.Way;
@@ -33,5 +38,5 @@
 			if( last != null && !last.incomplete && !s.incomplete && !last.to.equals(s.from) )
 			{
-				errors.add( new TestError(Severity.WARNING, tr("Unordered ways"), w) );
+				errors.add( new TestError(this, Severity.WARNING, tr("Unordered ways"), w) );
 				break;
 			}
@@ -39,3 +44,26 @@
 		}
 	}
+	
+	@Override
+	public Command fixError(TestError testError)
+	{
+		List<Command> commands = new ArrayList<Command>(50);
+		
+		for(OsmPrimitive p : testError.getPrimitives() )
+		{
+			Way w = (Way)p;
+			Way newWay = new Way(w);
+			newWay.segments.clear();
+			newWay.segments.addAll(ReorderAction.sortSegments(new HashSet<Segment>(w.segments)));
+			return new ChangeCommand(p, newWay);
+		}
+		
+		return commands.size() > 1 ? new SequenceCommand("Remove keys", commands) : commands.get(0);
+	}
+	
+	@Override
+	public boolean isFixable(TestError testError)
+	{
+		return (testError.getTester() instanceof UnorderedWay);
+	}	
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UntaggedNode.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UntaggedNode.java	(revision 2590)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UntaggedNode.java	(revision 2591)
@@ -3,9 +3,11 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.DeleteCommand;
 import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Segment;
 import org.openstreetmap.josm.plugins.validator.Severity;
@@ -19,10 +21,10 @@
 public class UntaggedNode extends Test 
 {
-	/** Tags allowed in a segment */
+	/** Tags allowed in a node */
 	public static String[] allowedTags = new String[] { "created_by" };
 	
 	/** Bag of all nodes */
 	Set<Node> emptyNodes;
-
+	
 	/**
 	 * Constructor
@@ -40,4 +42,27 @@
 	}
 	
+	@Override
+    public void visit(Collection<OsmPrimitive> selection) 
+    {
+		// If there is a partial selection, it may be false positives if a
+		// node is selected, but not the container segment. So, in this
+		// case, we must visit all segments, selected or not.
+
+		for (OsmPrimitive p : selection)
+        {
+        	if( !p.deleted )
+        	{
+        		if( !partialSelection || p instanceof Node )
+        			p.visit(this);
+        	}
+        }
+        
+		if( partialSelection )
+		{
+			for( Segment s : Main.ds.segments)
+				visit(s);
+		}
+    }
+    
 	@Override
 	public void visit(Node n) 
@@ -70,7 +95,19 @@
 		for(Node node : emptyNodes)
 		{
-			errors.add( new TestError(Severity.OTHER, tr("Untagged and unconnected nodes"), node) );
+			errors.add( new TestError(this, Severity.OTHER, tr("Untagged and unconnected nodes"), node) );
 		}
 		emptyNodes = null;
 	}
+	
+	@Override
+	public Command fixError(TestError testError)
+	{
+		return new DeleteCommand(testError.getPrimitives());
+	}
+	
+	@Override
+	public boolean isFixable(TestError testError)
+	{
+		return (testError.getTester() instanceof UntaggedNode);
+	}		
 }
