Index: applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ErrorLayer.java
===================================================================
--- applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ErrorLayer.java	(revision 2791)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ErrorLayer.java	(revision 2792)
@@ -8,7 +8,9 @@
 import javax.swing.tree.DefaultMutableTreeNode;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.RenameLayerAction;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
 import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
 import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
 import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
@@ -21,5 +23,5 @@
  * @author frsantos
  */
-public class ErrorLayer extends Layer
+public class ErrorLayer extends Layer implements LayerChangeListener
 {
 	/**
@@ -30,4 +32,5 @@
     {
 		super(name);
+        Main.map.mapView.addLayerChangeListener(this); 
 	}
 
@@ -48,5 +51,5 @@
     public void paint(final Graphics g, final MapView mv) 
     {
-        DefaultMutableTreeNode root = (DefaultMutableTreeNode) OSMValidatorPlugin.getPlugin().validationDialog.treeModel.getRoot();
+        DefaultMutableTreeNode root = OSMValidatorPlugin.getPlugin().validationDialog.tree.getRoot();
         if( root == null || root.getChildCount() == 0)
             return;
@@ -113,3 +116,18 @@
 
 	@Override public void destroy() { }
+
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) { }
+
+    public void layerAdded(Layer newLayer) { }
+
+    /**
+     * If layer is the OSM Data layer, remove all errors
+     */
+    public void layerRemoved(Layer oldLayer)
+    {
+        if(oldLayer == Main.map.mapView.editLayer ) 
+        {
+            Main.map.mapView.removeLayer(this); 
+        }
+    }
 }
Index: applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/OSMValidatorPlugin.java
===================================================================
--- applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/OSMValidatorPlugin.java	(revision 2791)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/OSMValidatorPlugin.java	(revision 2792)
@@ -10,4 +10,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.UploadAction;
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
@@ -72,4 +73,12 @@
 	        newFrame.addToggleDialog(validationDialog);
             Main.main.addLayer(new ErrorLayer(tr("Validation errors")));
+            try
+            {
+                ((UploadAction)Main.main.menu.upload).uploadHooks.add( new ValidateUploadHook() );
+            }
+            catch(Throwable t)
+            {
+                // JOSM has no upload hooks in older versions 
+            }
 		}
 	}
@@ -107,5 +116,8 @@
 			}
 			test.enabled = true;
-			enabledTests.put(testClass.getSimpleName(), test);
+            
+            String simpleName = testClass.getSimpleName();
+            test.testBeforeUpload = Main.pref.getBoolean( "tests." + simpleName + ".checkBeforeUpload");            
+			enabledTests.put(simpleName, test);
 		}
 
Index: applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/PreferenceEditor.java
===================================================================
--- applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/PreferenceEditor.java	(revision 2791)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/PreferenceEditor.java	(revision 2792)
@@ -32,4 +32,7 @@
 		testPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
 		
+        testPanel.add( new JLabel(), GBC.std() );
+        testPanel.add( new JLabel("On upload"), GBC.eop() );
+        
 		allTests = OSMValidatorPlugin.getTests(false);
 		for(final Test test: allTests) 
@@ -37,15 +40,19 @@
 			final JCheckBox testCheck = new JCheckBox(test.name, test.enabled);
 			testCheck.setToolTipText(test.description);
-			testPanel.add(testCheck, GBC.eop().insets(20,0,0,0));
-			test.addGui(testPanel);
+			testPanel.add(testCheck, GBC.std().insets(20,0,0,0));
 
-			testCheck.addActionListener(new ActionListener(){
-				public void actionPerformed(ActionEvent e) {
-					test.enabled = testCheck.isSelected();
-				}
-			});
+            testCheck.addActionListener(new ActionListener(){
+                public void actionPerformed(ActionEvent e) {
+                    boolean selected = testCheck.isSelected();
+                    test.enabled = selected;
+                    test.setGuiEnabled(selected );
+                }
+            });
+            
+            test.addGui(testPanel);
+            test.setGuiEnabled(test.enabled);
 		}
 		
-		JScrollPane testPane = new JScrollPane(testPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+		JScrollPane testPane = new JScrollPane(testPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
 		testPane.setBorder(null);
 
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 2791)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/Test.java	(revision 2792)
@@ -1,13 +1,14 @@
 package org.openstreetmap.josm.plugins.validator;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
+import java.util.*;
 
+import javax.swing.JCheckBox;
 import javax.swing.JPanel;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.data.osm.*;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
+import org.openstreetmap.josm.tools.GBC;
 
 /**
@@ -28,6 +29,15 @@
 	protected String description;
 	
-	/** Whether this test is enabled. Used by peferences */
-	protected boolean enabled;
+    /** Whether this test is enabled. Used by peferences */
+    protected boolean enabled;
+
+    /** The preferences check for validation on upload */
+    protected JCheckBox checkBeforeUpload;
+    
+    /** Whether this test must check before upload. Used by peferences */
+    protected boolean testBeforeUpload;
+
+    /** Whether this test is performing just before an upload */
+    protected boolean isBeforeUpload;
 
 	/** The list of errors */
@@ -124,5 +134,17 @@
 	public void addGui(@SuppressWarnings("unused") JPanel testPanel) 
 	{
+        checkBeforeUpload = new JCheckBox();
+        checkBeforeUpload.setSelected(testBeforeUpload);
+        testPanel.add(checkBeforeUpload, GBC.eop().insets(20,0,0,0));
 	}
+
+    /**
+     * Enables or disables the test in the preferences gui
+     * @param enabled
+     */
+    public void setGuiEnabled(boolean enabled)
+    {
+        checkBeforeUpload.setEnabled(enabled);
+    }   
 
 	/**
@@ -131,4 +153,6 @@
 	public void ok() 
 	{
+        String simpleName = getClass().getSimpleName();
+        Main.pref.put("tests." + simpleName + ".checkBeforeUpload", checkBeforeUpload.isSelected() );
 	}
 	
@@ -153,4 +177,22 @@
 	{
 		return false;
-	}	
+	}
+
+    /**
+     * Returns true if this plugin must check the uploaded data before uploading
+     * @return true if this plugin must check the uploaded data before uploading
+     */
+    public boolean testBeforeUpload()
+    {
+        return testBeforeUpload;
+    }
+
+    /**
+     * Sets the flag that marks an upload check
+     * @param isUpload if true, the test is before upload
+     */
+    public void setBeforeUpload(boolean isUpload)
+    {
+        this.isBeforeUpload = isUpload;
+    }
 }
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 2791)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidateAction.java	(revision 2792)
@@ -53,4 +53,7 @@
 	{
 		OSMValidatorPlugin plugin = OSMValidatorPlugin.getPlugin();
+        if( plugin.validateAction == null || Main.map == null || !Main.map.isVisible() )
+            return;
+        
 		plugin.errors = new ArrayList<TestError>();
 		plugin.validationDialog.setVisible(true);
@@ -94,5 +97,5 @@
 		tests = null;
 		
-		plugin.validationDialog.refresh();
+		plugin.validationDialog.refresh(plugin.errors);
         Main.map.repaint();
         Main.ds.fireSelectionChanged(Main.ds.getSelected());
Index: applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidateUploadHook.java
===================================================================
--- applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidateUploadHook.java	(revision 2792)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidateUploadHook.java	(revision 2792)
@@ -0,0 +1,81 @@
+package org.openstreetmap.josm.plugins.validator;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.util.*;
+
+import javax.swing.*;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.UploadAction.UploadHook;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.plugins.validator.util.AgregatePrimitivesVisitor;
+import org.openstreetmap.josm.tools.GBC;
+
+/**
+ * The action that does the validate thing.
+ * <p>
+ * This action iterates through all active tests and give them the data, so that
+ * each one can test it.
+ * 
+ * @author frsantos
+ */
+public class ValidateUploadHook implements UploadHook
+{
+	/** Serializable ID */
+    private static final long serialVersionUID = -2304521273582574603L;
+
+    /**
+     * Validate the modified data before uploading
+     */
+    public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete)
+    {
+        Collection<Test> tests = OSMValidatorPlugin.getTests(true);
+        if( tests.isEmpty() )
+            return true;
+        
+        AgregatePrimitivesVisitor v = new AgregatePrimitivesVisitor();
+        v.visit(add);
+        Collection<OsmPrimitive> selection = v.visit(update);
+
+        List<TestError> errors = new ArrayList<TestError>(30);
+        for(Test test : tests) 
+        {
+            if( !test.testBeforeUpload() )
+                continue;
+
+            test.setBeforeUpload(true);
+            test.setPartialSelection(true);
+            test.startTest();
+            test.visit(selection);
+            test.endTest();
+            errors.addAll( test.getErrors() );
+        }
+        tests = null;
+        
+        return displaErrorScreen(errors);
+    }
+    
+    /**
+     * Displays a screen where the actions that would be taken are displayed and
+     * give the user the possibility to cancel the upload.
+     * @return <code>true</code>, if the upload should continue. <code>false</code>
+     *          if the user requested cancel.
+     */
+    private boolean displaErrorScreen(List<TestError> errors) 
+    {
+        if( errors == null || errors.isEmpty() ) 
+        {
+            return true;
+        }
+
+        JPanel p = new JPanel(new GridBagLayout());
+        ErrorTreePanel errorPanel = new ErrorTreePanel(errors);
+        errorPanel.expandAll();
+        p.add(new JScrollPane(errorPanel), GBC.eol());
+
+        return JOptionPane.showConfirmDialog(Main.parent, p, tr("Data with errors. Upload anyway?"),
+                                             JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
+    }    
+}
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 2791)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidatorDialog.java	(revision 2792)
@@ -23,9 +23,9 @@
 
 /**
- * A small tool dialog for displaying the current selection. The selection manager
+ * A small tool dialog for displaying the current errors. The selection manager
  * respects clicks into the selection list. Ctrl-click will remove entries from
  * the list while single click will make the clicked entry the only selection.
  *
- * @author imi
+ * @author frsantos
  */
 public class ValidatorDialog extends ToggleDialog implements ActionListener
@@ -34,13 +34,8 @@
     private static final long serialVersionUID = 2952292777351992696L;
 
-    /**
-     * The validation data.
-     */
-	protected DefaultTreeModel treeModel = new DefaultTreeModel(new DefaultMutableTreeNode());
-
 	/**
      * The display tree.
      */
-    protected JTree tree = new JTree(treeModel);
+    protected ErrorTreePanel tree;
 
     /** 
@@ -54,5 +49,5 @@
     private JButton selectButton;
     
-    /** Last selected truee element */
+    /** Last selected element */
     private DefaultMutableTreeNode lastSelectedNode = null;
 
@@ -64,12 +59,7 @@
         super(tr("Validation errors"), "validator", tr("Open the validation window."), KeyEvent.VK_V, 150);
         
-		tree.setRootVisible(false);
-		tree.setShowsRootHandles(true);
-		tree.expandRow(0);
-		tree.setVisibleRowCount(8);
+        tree = new ErrorTreePanel();
 		tree.addMouseListener(new ClickWatch());
 		tree.addTreeSelectionListener(new SelectionWatch());
-		tree.setCellRenderer(new ErrorTreeRenderer());
-		tree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
 
 		add(new JScrollPane(tree), BorderLayout.CENTER);
@@ -90,9 +80,8 @@
 
     @Override 
-    public void setVisible(boolean v) {
-		if (v)
-			buildTree();
-		else if (tree != null)
-			treeModel.setRoot(new DefaultMutableTreeNode());
+    public void setVisible(boolean v) 
+    {
+        if( tree != null )
+            tree.setVisible(v);
 		if( action != null && action.button != null )
 			action.button.setSelected(v);
@@ -101,60 +90,4 @@
     
     
-	/**
-	 * Builds the errors tree
-	 */
-	private void buildTree() 
-	{
-		DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
-
-		List<TestError> errorList = OSMValidatorPlugin.getPlugin().errors;
-		if( errorList == null || errorList.isEmpty() )
-		{
-			treeModel.setRoot(rootNode);
-			return;
-		}
-		
-		Map<Severity, Bag<String, TestError>> errorTree = new HashMap<Severity, Bag<String, TestError>>();
-		for(Severity s : Severity.values())
-		{
-			errorTree.put(s, new Bag<String, TestError>(20));
-		}
-		
-		for(TestError e : errorList)
-		{
-			errorTree.get(e.getSeverity()).add(e.getMessage(), e);
-		}
-		
-		for(Severity s : Severity.values())
-		{
-			Bag<String,	TestError> severityErrors = errorTree.get(s);
-			if( severityErrors.isEmpty() )
-				continue;
-			
-			// Severity node
-			DefaultMutableTreeNode severityNode = new DefaultMutableTreeNode(s);
-			rootNode.add(severityNode);
-			
-			for(Entry<String, List<TestError>> msgErrors : severityErrors.entrySet()  )
-			{
-				// Message node
-				List<TestError> errors = msgErrors.getValue();
-				String msg = msgErrors.getKey() + " (" + errors.size() + ")";
-				DefaultMutableTreeNode messageNode = new DefaultMutableTreeNode(msg);
-				severityNode.add(messageNode);
-				
-				for (TestError error : errors) 
-				{
-					// Error node
-					DefaultMutableTreeNode errorNode = new DefaultMutableTreeNode(error);
-					messageNode.add(errorNode);
-				}
-			}
-		}
-
-		treeModel.setRoot(rootNode);
-		tree.scrollRowToVisible(treeModel.getChildCount(rootNode)-1);
-	}
-	
 	/**
 	 * Fix selected errors
@@ -216,4 +149,5 @@
 		       
     	OSMValidatorPlugin.getPlugin().validateAction.doValidate(e, false);
+        // TODO keep the tree open as it was before the fix
 	}	
 	
@@ -265,8 +199,10 @@
 	/**
 	 * Refresh the error messages display
+	 * @param errors The errors to display
 	 */
-	public void refresh()
-	{
-		buildTree();
+	public void refresh(List<TestError> errors)
+	{
+        tree.setErrors(errors);
+		tree.buildTree();
 	}
 	
@@ -332,5 +268,4 @@
 		public void mouseClicked(MouseEvent e) 
 		{
-            System.out.println("mouseClicked " + e.getClickCount() + " " + e.getSource());
             fixButton.setEnabled(false);
             selectButton.setEnabled(false);
@@ -357,5 +292,4 @@
 		public void valueChanged(TreeSelectionEvent e) 
 		{
-            System.out.println("valueChanged");
 	        fixButton.setEnabled(false);
             selectButton.setEnabled(false);
