Index: applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ErrorTreePanel.java
===================================================================
--- applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ErrorTreePanel.java	(revision 10486)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ErrorTreePanel.java	(revision 10490)
@@ -126,12 +126,28 @@
 
 		Map<Severity, Bag<String, TestError>> errorTree = new HashMap<Severity, Bag<String, TestError>>();
+		Map<Severity, HashMap<String, Bag<String, TestError>>> errorTreeDeep = new HashMap<Severity, HashMap<String, Bag<String, TestError>>>();
 		for(Severity s : Severity.values())
 		{
 			errorTree.put(s, new Bag<String, TestError>(20));
+			errorTreeDeep.put(s, new HashMap<String, Bag<String, TestError>>());
 		}
 
 		for(TestError e : errors)
 		{
-			errorTree.get(e.getSeverity()).add(e.getMessage(), e);
+			Severity s = e.getSeverity();
+			String d = e.getDescription();
+			String m = e.getMessage();
+			if(d != null)
+			{
+				Bag<String, TestError> b = errorTreeDeep.get(s).get(m);
+				if(b == null)
+				{
+					b = new Bag<String, TestError>(20);
+					errorTreeDeep.get(s).put(m, b);
+				}
+				b.add(d, e);
+			}
+			else
+				errorTree.get(s).add(m, e);
 		}
 
@@ -140,5 +156,6 @@
 		{
 			Bag<String, TestError> severityErrors = errorTree.get(s);
-			if( severityErrors.isEmpty() )
+			Map<String, Bag<String, TestError>> severityErrorsDeep = errorTreeDeep.get(s);
+			if(severityErrors.isEmpty() && severityErrorsDeep.isEmpty())
 				continue;
 
@@ -168,4 +185,34 @@
 				}
 			}
+			for(Entry<String, Bag <String, TestError>> bag : severityErrorsDeep.entrySet())
+			{
+				// Group node
+				Bag <String, TestError> errorlist = bag.getValue();
+				String nmsg = bag.getKey() + " (" + errorlist.size() + ")";
+				DefaultMutableTreeNode groupNode = new DefaultMutableTreeNode(nmsg);
+				severityNode.add(groupNode);
+
+				if( oldSelectedRows.contains(bag.getKey()))
+					 expandedPaths.add( new TreePath( new Object[] {rootNode, severityNode, groupNode} ) );
+
+				for(Entry<String, List<TestError>> msgErrors : errorlist.entrySet())
+				{
+					// Message node
+					List<TestError> errors = msgErrors.getValue();
+					String msg = msgErrors.getKey() + " (" + errors.size() + ")";
+					DefaultMutableTreeNode messageNode = new DefaultMutableTreeNode(msg);
+					groupNode.add(messageNode);
+
+					if( oldSelectedRows.contains(msgErrors.getKey()))
+						 expandedPaths.add( new TreePath( new Object[] {rootNode, severityNode, groupNode, messageNode} ) );
+
+					for (TestError error : errors) 
+					{
+						// Error node
+						DefaultMutableTreeNode errorNode = new DefaultMutableTreeNode(error);
+						messageNode.add(errorNode);
+					}
+				}
+			}
 		}
 
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 10486)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/Test.java	(revision 10490)
@@ -123,5 +123,5 @@
         for (OsmPrimitive p : selection)
         {
-        	if( !p.deleted || !p.incomplete )
+        	if( !p.deleted && !p.incomplete )
         		p.visit(this);
         }
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 10486)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/TestError.java	(revision 10490)
@@ -26,4 +26,5 @@
 	/** Deeper error description */
 	private String description;
+	private String description_en;
 	/** The affected primitives */
 	private List<? extends OsmPrimitive> primitives;
@@ -46,5 +47,5 @@
 	 * @param code The test error reference code
 	 */
-	public TestError(Test tester, Severity severity, String message, String description, int code,
+	public TestError(Test tester, Severity severity, String message, String description, String description_en, int code,
 			List<? extends OsmPrimitive> primitives, List<?> highlighted) {
 		this.tester = tester;
@@ -52,4 +53,5 @@
 		this.message = message;
 		this.description = description;
+		this.description_en = description_en;
 		this.primitives = primitives;
 		this.highlighted = highlighted;
@@ -58,21 +60,23 @@
 	public TestError(Test tester, Severity severity, String message, int code, List<? extends OsmPrimitive> primitives, List<?> highlighted)
 	{
-		this(tester, severity, message, null, code, primitives, highlighted);
-	}
-	public TestError(Test tester, Severity severity, String message, String description, int code, List<? extends OsmPrimitive> primitives)
-	{
-		this(tester, severity, message, description, code, primitives, primitives);
+		this(tester, severity, message, null, null, code, primitives, highlighted);
+	}
+	public TestError(Test tester, Severity severity, String message, String description, String description_en,
+	int code, List<? extends OsmPrimitive> primitives)
+	{
+		this(tester, severity, message, description, description_en, code, primitives, primitives);
 	}
 	public TestError(Test tester, Severity severity, String message, int code, List<? extends OsmPrimitive> primitives)
 	{
-		this(tester, severity, message, null, code, primitives, primitives);
+		this(tester, severity, message, null, null, code, primitives, primitives);
 	}
 	public TestError(Test tester, Severity severity, String message, int code, OsmPrimitive primitive)
 	{
-		this(tester, severity, message, null, code, Collections.singletonList(primitive), Collections.singletonList(primitive));
-	}
-	public TestError(Test tester, Severity severity, String message, String description, int code, OsmPrimitive primitive)
-	{
-		this(tester, severity, message, description, code, Collections.singletonList(primitive));
+		this(tester, severity, message, null, null, code, Collections.singletonList(primitive), Collections.singletonList(primitive));
+	}
+	public TestError(Test tester, Severity severity, String message, String description,
+	String description_en, int code, OsmPrimitive primitive)
+	{
+		this(tester, severity, message, description, description_en, code, Collections.singletonList(primitive));
 	}
 
@@ -147,5 +151,5 @@
 	{
 		Collection<String> strings = new TreeSet<String>();
-		String ignorestring = Integer.toString(code);
+		String ignorestring = getIgnoreSubGroup();
 		for (OsmPrimitive o : primitives)
 		{
@@ -164,4 +168,17 @@
 		}
 		return ignorestring;
+	}
+
+	public String getIgnoreSubGroup()
+	{
+		String ignorestring = getIgnoreGroup();
+		if(description_en != null)
+			ignorestring += "_"+description_en;
+		return ignorestring;
+	}
+
+	public String getIgnoreGroup()
+	{
+		return Integer.toString(code);
 	}
 
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 10486)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidateAction.java	(revision 10490)
@@ -103,8 +103,14 @@
 			for(TestError error : errors)
 			{
-				String state = error.getIgnoreState();
-				if(state != null && plugin.validationDialog.ignoredErrors.contains(state))
+				List<String> s = new ArrayList<String>();
+				s.add(error.getIgnoreState());
+				s.add(error.getIgnoreGroup());
+				s.add(error.getIgnoreSubGroup());
+				for(String state : s)
 				{
-					error.setIgnored(true);
+					if(state != null && plugin.validationDialog.ignoredErrors.contains(state))
+					{
+						error.setIgnored(true);
+					}
 				}
 			}
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 10486)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidateUploadHook.java	(revision 10490)
@@ -52,5 +52,5 @@
         tests = null;
         
-        return displaErrorScreen(errors);
+        return displayErrorScreen(errors);
     }
     
@@ -62,5 +62,5 @@
      *          if the user requested cancel.
      */
-    private boolean displaErrorScreen(List<TestError> errors) 
+    private boolean displayErrorScreen(List<TestError> errors) 
     {
         if( errors == null || errors.isEmpty() ) 
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 10486)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidatorDialog.java	(revision 10490)
@@ -30,4 +30,5 @@
 import org.openstreetmap.josm.plugins.validator.util.Bag;
 import org.openstreetmap.josm.plugins.validator.util.Util;
+import org.openstreetmap.josm.tools.ImageProvider;
 
 /**
@@ -77,5 +78,6 @@
 		selectButton.setEnabled(false);
 		buttonPanel.add(selectButton);
-		buttonPanel.add(new SideButton(marktr("Validate"), "refresh", "Validator", tr("Validate the data."), this));
+		buttonPanel.add(new SideButton(marktr("Validate"), "refresh", "Validator",
+		tr("Validate either current selection or complete dataset."), this));
 		fixButton = new SideButton(marktr("Fix"), "fix", "Validator", tr("Fix the selected errors."), this);
 		fixButton.setEnabled(false);
@@ -187,4 +189,5 @@
 	private void ignoreErrors(ActionEvent e)
 	{
+		int asked = JOptionPane.DEFAULT_OPTION;
 		boolean changed = false;
 		TreePath[] selectionPaths = tree.getSelectionPaths();
@@ -198,4 +201,44 @@
 			if( node == null )
 				continue;
+
+			Object mainNodeInfo = node.getUserObject();
+			if(!(mainNodeInfo instanceof TestError))
+			{
+				int depth = 1;
+				Set<String> state = new HashSet<String>();
+				// ask if the whole set should be ignored
+				if(asked == JOptionPane.DEFAULT_OPTION)
+				{
+					String[] a = new String[]{tr("Whole group"), tr("Single elements"),tr("Nothing")};
+					asked = JOptionPane.showOptionDialog(Main.parent, tr("Ignore whole group or individual elements?"),
+					tr("Ignoring elements"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE,
+					ImageProvider.get("dialogs", "delete"), a, a[1]);
+				}
+				if(asked == JOptionPane.YES_NO_OPTION)
+				{
+					Enumeration<DefaultMutableTreeNode> children = node.breadthFirstEnumeration();
+					while(children.hasMoreElements())
+					{
+						DefaultMutableTreeNode childNode = children.nextElement();
+						if(processedNodes.contains(childNode))
+							continue;
+
+						processedNodes.add(childNode);
+						Object nodeInfo = childNode.getUserObject();
+						if(nodeInfo instanceof TestError)
+						{
+							TestError err = (TestError)nodeInfo;
+							err.setIgnored(true);
+							changed = true;
+							state.add(node.getDepth() == 1 ? err.getIgnoreSubGroup() : err.getIgnoreGroup());
+						}
+					}
+					for(String s : state)
+						ignoredErrors.add(s);
+					continue;
+				}
+				else if(asked == JOptionPane.CANCEL_OPTION)
+					continue;
+			}
 
 			Enumeration<DefaultMutableTreeNode> children = node.breadthFirstEnumeration();
Index: applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/TagChecker.java
===================================================================
--- applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/TagChecker.java	(revision 10486)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/TagChecker.java	(revision 10490)
@@ -1,4 +1,5 @@
 package org.openstreetmap.josm.plugins.validator.tests;
 
+import static org.openstreetmap.josm.tools.I18n.marktr;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
@@ -14,4 +15,5 @@
 import java.lang.IllegalStateException;
 import java.net.URL;
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -298,5 +300,5 @@
 				{
 					errors.add( new TestError(this, d.getSeverity(), tr("Illegal tag/value combinations"),
-					d.getDescription(), d.getCode(), p) );
+					d.getDescription(), d.getDescriptionOrig(), d.getCode(), p) );
 					withErrors.add(p, "TC");
 					break;
@@ -308,4 +310,5 @@
 		for(Entry<String, String> prop: props.entrySet() )
 		{
+			String s = marktr("Key ''{0}'' invalid.");
 			String key = prop.getKey();
 			String value = prop.getValue();
@@ -313,5 +316,5 @@
 			{
 				errors.add( new TestError(this, Severity.WARNING, tr("Tags with empty values"),
-				tr("Key ''{0}'' invalid.", key), EMPTY_VALUES, p) );
+				tr(s, key), MessageFormat.format(s, key), EMPTY_VALUES, p) );
 				withErrors.add(p, "EV");
 			}
@@ -319,5 +322,5 @@
 			{
 				errors.add( new TestError(this, Severity.WARNING, tr("Invalid property key"),
-				tr("Key ''{0}'' invalid.", key), INVALID_KEY, p) );
+				tr(s, key), MessageFormat.format(s, key), INVALID_KEY, p) );
 				withErrors.add(p, "IPK");
 			}
@@ -325,5 +328,5 @@
 			{
 				errors.add( new TestError(this, Severity.WARNING, tr("Invalid white space in property key"),
-				tr("Key ''{0}'' invalid.", key), INVALID_KEY_SPACE, p) );
+				tr(s, key), MessageFormat.format(s, key), INVALID_KEY_SPACE, p) );
 				withErrors.add(p, "IPK");
 			}
@@ -331,5 +334,5 @@
 			{
 				errors.add( new TestError(this, Severity.OTHER, tr("Property values start or end with white space"),
-				tr("Key ''{0}'' invalid.", key), INVALID_SPACE, p) );
+				tr(s, key), MessageFormat.format(s, key), INVALID_SPACE, p) );
 				withErrors.add(p, "SPACE");
 			}
@@ -340,5 +343,5 @@
 				{
 					errors.add( new TestError(this, Severity.OTHER, tr("Unknown property values"),
-					tr("Key ''{0}'' invalid.", key), INVALID_VALUE, p) );
+					tr(s, key), MessageFormat.format(s, key), INVALID_VALUE, p) );
 					withErrors.add(p, "UPV");
 				}
@@ -758,4 +761,8 @@
 			return tr(description);
 		}
+		public String getDescriptionOrig()
+		{
+			return description;
+		}
 		public Severity getSeverity()
 		{
Index: applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UnclosedWays.java
===================================================================
--- applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UnclosedWays.java	(revision 10486)
+++ applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UnclosedWays.java	(revision 10490)
@@ -1,7 +1,10 @@
 package org.openstreetmap.josm.plugins.validator.tests;
 
+import static org.openstreetmap.josm.tools.I18n.marktr;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.util.*;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -44,10 +47,30 @@
 	}
 
+	private String type;
+	private String etype;
+	private int mode;
+	private boolean force;
+	public void set(boolean f, int m, String text, String desc)
+	{
+		etype = MessageFormat.format(text, desc);
+		type = tr(text, tr(desc));
+		mode = m;
+		force = f;
+	}
+	public void set(boolean f, int m, String text)
+	{
+		etype = text;
+		type = tr(text);
+		mode = m;
+		force = f;
+	}
+
 	@Override
 	public void visit(Way w)
 	{
-		boolean force = false; /* force even if end-to-end distance is long */
-		String type = null, test;
-		int mode = 0;
+		String test;
+		force = false; /* force even if end-to-end distance is long */
+		type = etype = null;
+		mode = 0;
 
 		if( w.deleted || w.incomplete )
@@ -56,73 +79,32 @@
 		test = w.get("natural");
 		if(test != null)
-		{
-			if(!"coastline".equals(test))
-				force = true;
-			type = tr("natural type {0}", tr(test));
-			mode = 1101;
-		}
+			set(!"coastline".equals(test), 1101, marktr("natural type {0}"), test);
 		test = w.get("landuse");
 		if(test != null)
-		{
-			force = true;
-			type = tr("landuse type {0}", tr(test));
-			mode = 1102;
-		}
+			set(true, 1102, marktr("landuse type {0}"), test);
 		test = w.get("amenities");
 		if(test != null)
-		{
-			force = true;
-			type = tr("amenities type {0}", tr(test));
-			mode = 1103;
-		}
+			set(true, 1103, marktr("amenities type {0}"), test);
 		test = w.get("sport");
-		if(test != null)
-		{
-			force = true;
-			type = tr("sport type {0}", tr(test));
-			mode = 1104;
-		}
+		if(test != null && !test.equals("water_slide"))
+			set(true, 1104, marktr("sport type {0}"), test);
 		test = w.get("tourism");
 		if(test != null)
-		{
-			force = true;
-			type = tr("tourism type {0}", tr(test));
-			mode = 1105;
-		}
+			set(true, 1105, marktr("tourism type {0}"), test);
 		test = w.get("shop");
 		if(test != null)
-		{
-			force = true;
-			type = tr("shop type {0}", tr(test));
-			mode = 1106;
-		}
+			set(true, 1106, marktr("shop type {0}"), test);
 		test = w.get("leisure");
 		if(test != null)
-		{
-			force = true;
-			type = tr("leisure type {0}", tr(test));
-			mode = 1107;
-		}
+			set(true, 1107, marktr("leisure type {0}"), test);
 		test = w.get("waterway");
 		if(test != null && test.equals("riverbank"))
-		{
-			force = true;
-			type = tr("waterway type {0}", tr(test));
-			mode = 1108;
-		}
+			set(true, 1108, marktr("waterway type {0}"), test);
 		Boolean btest = OsmUtils.getOsmBoolean(w.get("building"));
 		if (btest != null && btest)
-		{
-			force = true;
-			type = tr("building");
-			mode = 1120;
-		}
+			set(true, 1120, marktr("building"));
 		btest = OsmUtils.getOsmBoolean(w.get("area"));
 		if (btest != null && btest)
-		{
-			force = true;
-			type = tr("area");
-			mode = 1130;
-		}
+			set(true, 1130, marktr("area"));
 
 		if(type != null)
@@ -135,5 +117,5 @@
 				List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
 				primitives.add(w);
-				errors.add(new TestError(this, Severity.WARNING, tr("Unclosed way"), type, mode, primitives));
+				errors.add(new TestError(this, Severity.WARNING, tr("Unclosed way"), type, etype, mode, primitives));
 				_errorWays.add(w,w);
 			}
