You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by iv...@apache.org on 2006/10/14 22:01:11 UTC

svn commit: r464003 - in /incubator/wicket/trunk/wicket/src: main/java/wicket/ main/java/wicket/feedback/ main/java/wicket/markup/html/form/ main/java/wicket/markup/html/form/validation/ main/java/wicket/markup/html/panel/ main/java/wicket/util/tester/...

Author: ivaynberg
Date: Sat Oct 14 13:01:09 2006
New Revision: 464003

URL: http://svn.apache.org/viewvc?view=rev&rev=464003
Log:
made feedback more flexible by allowing Serializable as message object instead of only strings - also feedback message has a factory method for generating components to display errors instead of always using Lable

Added:
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/ValidationErrorFeedback.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/FeedbackPanel.html
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/FeedbackPanel.java
Modified:
    incubator/wicket/trunk/wicket/src/main/java/wicket/Component.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/Session.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/feedback/FeedbackMessage.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/feedback/FeedbackMessages.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/FormComponent.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/validation/AbstractFormValidator.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/util/tester/WicketTester.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/validation/ValidationError.java
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/form/ValidatorPropertiesTest.java
    incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_4/FormTesterTest.java

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/Component.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/Component.java?view=diff&rev=464003&r1=464002&r2=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/Component.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/Component.java Sat Oct 14 13:01:09 2006
@@ -810,7 +810,7 @@
 	 * @param message
 	 *            The feedback message
 	 */
-	public final void debug(final String message)
+	public final void debug(final Serializable message)
 	{
 		getPage().getFeedbackMessages().debug(this, message);
 	}
@@ -839,7 +839,7 @@
 	 * @param message
 	 *            The feedback message
 	 */
-	public final void error(final String message)
+	public final void error(final Serializable message)
 	{
 		getPage().getFeedbackMessages().error(this, message);
 	}
@@ -850,7 +850,7 @@
 	 * @param message
 	 *            The feedback message
 	 */
-	public final void fatal(final String message)
+	public final void fatal(final Serializable message)
 	{
 		getPage().getFeedbackMessages().fatal(this, message);
 	}
@@ -1374,7 +1374,7 @@
 	 * @param message
 	 *            The feedback message
 	 */
-	public final void info(final String message)
+	public final void info(final Serializable message)
 	{
 		getPage().getFeedbackMessages().info(this, message);
 	}
@@ -2456,7 +2456,7 @@
 	 * @param message
 	 *            The feedback message
 	 */
-	public final void warn(final String message)
+	public final void warn(final Serializable message)
 	{
 		getPage().getFeedbackMessages().warn(this, message);
 	}

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/Session.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/Session.java?view=diff&rev=464003&r1=464002&r2=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/Session.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/Session.java Sat Oct 14 13:01:09 2006
@@ -166,9 +166,10 @@
 	private String style;
 
 	/** feedback messages */
-	private FeedbackMessages feedbackMessages = new FeedbackMessages(new CopyOnWriteArrayList<FeedbackMessage>());
+	private FeedbackMessages feedbackMessages = new FeedbackMessages(
+			new CopyOnWriteArrayList<FeedbackMessage>());
 
-	private transient Map<PageMap,Thread> pageMapsUsedInRequest;
+	private transient Map<PageMap, Thread> pageMapsUsedInRequest;
 
 	/** cached id because you can't access the id after session unbound */
 	private String id = null;
@@ -443,8 +444,7 @@
 	 * @return The page based on the first path component (the page id), or null
 	 *         if the requested version of the page cannot be found.
 	 */
-	public final Page getPage(final String pageMapName, final String path,
-			final int versionNumber)
+	public final Page getPage(final String pageMapName, final String path, final int versionNumber)
 	{
 		if (log.isDebugEnabled())
 		{
@@ -452,37 +452,42 @@
 		}
 
 		// Get page map by name, creating the default page map automatically
-		PageMap pageMap = pageMapForName(pageMapName, Objects.equal(PageMap.DEFAULT_NAME,pageMapName));
+		PageMap pageMap = pageMapForName(pageMapName, Objects.equal(PageMap.DEFAULT_NAME,
+				pageMapName));
 		if (pageMap != null)
 		{
-			synchronized(pageMapsUsedInRequest)
+			synchronized (pageMapsUsedInRequest)
 			{
 				long startTime = System.currentTimeMillis();
-				
+
 				if (pageMapsUsedInRequest == null)
 				{
 					pageMapsUsedInRequest = new HashMap<PageMap, Thread>(3);
 				}
-				
+
 				// Get page entry for id and version
 				Thread t = pageMapsUsedInRequest.get(pageMap);
 				while (t != null && t != Thread.currentThread())
 				{
 					try
 					{
-						pageMapsUsedInRequest.wait(20000); // wait 20 seconds max.
+						pageMapsUsedInRequest.wait(20000); // wait 20 seconds
+															// max.
 					}
 					catch (InterruptedException ex)
 					{
 						throw new WicketRuntimeException(ex);
 					}
 					t = pageMapsUsedInRequest.get(pageMap);
-					if (t != null && t != Thread.currentThread() && (startTime + 20000) < System.currentTimeMillis())
+					if (t != null && t != Thread.currentThread()
+							&& (startTime + 20000) < System.currentTimeMillis())
 					{
-						// if it is still not the right thread.. 
-						// This must be a wicket bug or some other (dead)lock in the code.
-						throw new WicketRuntimeException("After 20s the Pagemap " + pageMapName + 
-								" is still locked by: " + t + ", giving up trying to get the page for path: " + path);
+						// if it is still not the right thread..
+						// This must be a wicket bug or some other (dead)lock in
+						// the code.
+						throw new WicketRuntimeException("After 20s the Pagemap " + pageMapName
+								+ " is still locked by: " + t
+								+ ", giving up trying to get the page for path: " + path);
 					}
 				}
 				pageMapsUsedInRequest.put(pageMap, Thread.currentThread());
@@ -790,14 +795,13 @@
 		}
 	}
 
-
 	/**
 	 * Registers an informational feedback message for this session
 	 * 
 	 * @param message
 	 *            The feedback message
 	 */
-	public final void info(final String message)
+	public final void info(final Serializable message)
 	{
 		addFeedbackMessage(message, FeedbackMessage.INFO);
 	}
@@ -808,7 +812,7 @@
 	 * @param message
 	 *            The feedback message
 	 */
-	public final void warn(final String message)
+	public final void warn(final Serializable message)
 	{
 		addFeedbackMessage(message, FeedbackMessage.WARNING);
 	}
@@ -819,7 +823,7 @@
 	 * @param message
 	 *            The feedback message
 	 */
-	public final void error(final String message)
+	public final void error(final Serializable message)
 	{
 		addFeedbackMessage(message, FeedbackMessage.ERROR);
 	}
@@ -863,7 +867,7 @@
 	 * @param level
 	 * 
 	 */
-	private void addFeedbackMessage(String message, int level)
+	private void addFeedbackMessage(Serializable message, int level)
 	{
 		getFeedbackMessages().add(null, message, level);
 		dirty();
@@ -1061,8 +1065,9 @@
 	{
 		int size = feedbackMessages.size();
 		feedbackMessages.clearRendered();
-		// mark the session as dirty when the feedback messages have been altered.
-		if(size != feedbackMessages.size())
+		// mark the session as dirty when the feedback messages have been
+		// altered.
+		if (size != feedbackMessages.size())
 		{
 			dirty();
 		}
@@ -1087,16 +1092,17 @@
 	 */
 	final void requestDetached()
 	{
-		if(pageMapsUsedInRequest != null)
+		if (pageMapsUsedInRequest != null)
 		{
-			synchronized(pageMapsUsedInRequest)
+			synchronized (pageMapsUsedInRequest)
 			{
 				Thread t = Thread.currentThread();
-				Iterator<Map.Entry<PageMap,Thread>> it = pageMapsUsedInRequest.entrySet().iterator();
-				while(it.hasNext())
+				Iterator<Map.Entry<PageMap, Thread>> it = pageMapsUsedInRequest.entrySet()
+						.iterator();
+				while (it.hasNext())
 				{
 					Entry<PageMap, Thread> entry = it.next();
-					if(entry.getValue() == t)
+					if (entry.getValue() == t)
 					{
 						it.remove();
 					}
@@ -1105,7 +1111,7 @@
 			}
 		}
 	}
-	
+
 	/**
 	 * @param map
 	 *            The page map to add to dirty objects list

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/feedback/FeedbackMessage.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/feedback/FeedbackMessage.java?view=diff&rev=464003&r1=464002&r2=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/feedback/FeedbackMessage.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/feedback/FeedbackMessage.java Sat Oct 14 13:01:09 2006
@@ -66,7 +66,7 @@
 	private final int level;
 
 	/** The actual message. */
-	private final String message;
+	private final Serializable message;
 
 	/** The reporting component. */
 	private final Component reporter;
@@ -84,7 +84,7 @@
 	 * @param level
 	 *            The level of the message
 	 */
-	public FeedbackMessage(final Component reporter, final String message, final int level)
+	public FeedbackMessage(final Component reporter, final Serializable message, final int level)
 	{
 		this.reporter = reporter;
 		this.message = message;
@@ -138,7 +138,7 @@
 	 * 
 	 * @return the message.
 	 */
-	public final String getMessage()
+	public final Serializable getMessage()
 	{
 		return message;
 	}

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/feedback/FeedbackMessages.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/feedback/FeedbackMessages.java?view=diff&rev=464003&r1=464002&r2=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/feedback/FeedbackMessages.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/feedback/FeedbackMessages.java Sat Oct 14 13:01:09 2006
@@ -59,20 +59,21 @@
 	}
 
 	/**
-	 * Call this constructor if you want to replace the internal
-	 * store with another implemention then the default (ArrayList). 
-	 * This could be a {@link CopyOnWriteArrayList} if this feedbackmessages 
-	 * instance is used by multiply threads.
+	 * Call this constructor if you want to replace the internal store with
+	 * another implemention then the default (ArrayList). This could be a
+	 * {@link CopyOnWriteArrayList} if this feedbackmessages instance is used by
+	 * multiply threads.
 	 * 
-	 * @param messagesList 
+	 * @param messagesList
 	 * 
 	 */
 	public FeedbackMessages(List<FeedbackMessage> messagesList)
 	{
-		if(messagesList == null) throw new IllegalArgumentException("messages list can't be null");
+		if (messagesList == null)
+			throw new IllegalArgumentException("messages list can't be null");
 		messages = messagesList;
 	}
-	
+
 	/**
 	 * Clears any existing messages
 	 */
@@ -115,7 +116,7 @@
 	 * @param message
 	 *            the actual message
 	 */
-	public final void debug(Component reporter, String message)
+	public final void debug(Component reporter, Serializable message)
 	{
 		add(new FeedbackMessage(reporter, message, FeedbackMessage.DEBUG));
 	}
@@ -128,7 +129,7 @@
 	 * @param message
 	 *            the actual message
 	 */
-	public final void error(Component reporter, String message)
+	public final void error(Component reporter, Serializable message)
 	{
 		add(new FeedbackMessage(reporter, message, FeedbackMessage.ERROR));
 	}
@@ -141,7 +142,7 @@
 	 * @param message
 	 *            the actual message
 	 */
-	public final void fatal(Component reporter, String message)
+	public final void fatal(Component reporter, Serializable message)
 	{
 		add(new FeedbackMessage(reporter, message, FeedbackMessage.FATAL));
 	}
@@ -207,7 +208,7 @@
 	 * @param message
 	 *            The actual message
 	 */
-	public final void info(Component reporter, String message)
+	public final void info(Component reporter, Serializable message)
 	{
 		add(new FeedbackMessage(reporter, message, FeedbackMessage.INFO));
 	}
@@ -286,7 +287,7 @@
 	 * @param message
 	 *            the actual message
 	 */
-	public final void warn(Component reporter, String message)
+	public final void warn(Component reporter, Serializable message)
 	{
 		add(new FeedbackMessage(reporter, message, FeedbackMessage.WARNING));
 	}
@@ -298,7 +299,7 @@
 	 * @param message
 	 * @param level
 	 */
-	public final void add(Component reporter, String message, int level)
+	public final void add(Component reporter, Serializable message, int level)
 	{
 		add(new FeedbackMessage(reporter, message, level));
 	}

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/FormComponent.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/FormComponent.java?view=diff&rev=464003&r1=464002&r2=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/FormComponent.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/FormComponent.java Sat Oct 14 13:01:09 2006
@@ -97,7 +97,9 @@
  * @author Johan Compagner
  * @author Igor Vaynberg (ivaynberg)
  */
-public abstract class FormComponent<T> extends WebMarkupContainer<T> implements IFormProcessingListener
+public abstract class FormComponent<T> extends WebMarkupContainer<T>
+		implements
+			IFormProcessingListener
 {
 	private static final long serialVersionUID = 1L;
 
@@ -124,7 +126,7 @@
 	}
 
 	/**
-	 * Visitor for traversing form components 
+	 * Visitor for traversing form components
 	 */
 	public static abstract class AbstractVisitor implements IVisitor
 	{
@@ -133,8 +135,9 @@
 		 */
 		public Object formComponent(IFormProcessingListener component)
 		{
-			if (component instanceof FormComponent) {
-				onFormComponent((FormComponent) component);
+			if (component instanceof FormComponent)
+			{
+				onFormComponent((FormComponent)component);
 			}
 			return Component.IVisitor.CONTINUE_TRAVERSAL;
 		}
@@ -608,7 +611,7 @@
 	{
 		if (!checkRequired())
 		{
-			error(new ValidationError().addMessageKey("RequiredValidator"));
+			error((IValidationError)new ValidationError().addMessageKey("RequiredValidator"));
 		}
 	}
 
@@ -649,7 +652,7 @@
 					error.setVar("format", ((SimpleDateFormat)format).toLocalizedPattern());
 				}
 
-				error(error);
+				error((IValidationError)error);
 
 			}
 		}
@@ -680,7 +683,7 @@
 					error.setVar("format", ((SimpleDateFormat)format).toLocalizedPattern());
 				}
 
-				error(error);
+				error((IValidationError)error);
 			}
 		}
 	}
@@ -838,12 +841,12 @@
 	protected void onComponentTag(final ComponentTag tag)
 	{
 		tag.put("name", getInputName());
-		
+
 		if (!isEnabled() || !isEnableAllowed())
 		{
 			tag.put("disabled", "disabled");
 		}
-		
+
 		super.onComponentTag(tag);
 	}
 
@@ -1064,7 +1067,12 @@
 	}
 
 	/**
-	 * Reports a validation error against this form component
+	 * Reports a validation error against this form component.
+	 * 
+	 * The actual error is reported by creating a
+	 * {@link ValidationErrorFeedback} object that holds both the validation
+	 * error and the generated error message - so a custom feedback panel can
+	 * have access to both.
 	 * 
 	 * @param error
 	 *            validation error
@@ -1081,14 +1089,13 @@
 		if (message == null)
 		{
 			// XXX maybe make message source remember tried resource keys so a
-			// more specific error message can be created
-			error("Could not locate error message for error: " + error.toString());
-		}
-		else
-		{
-			error(message);
+			// more detailederror message can be created - like show which keys
+			// were tried
+			message = "Could not locate error message for error: " + error.toString();
 		}
 
+		error(new ValidationErrorFeedback(error, message));
+
 	}
 
 	/**
@@ -1273,6 +1280,6 @@
 	 */
 	public boolean processChildren()
 	{
-	    return true;
+		return true;
 	}
 }

Added: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/ValidationErrorFeedback.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/ValidationErrorFeedback.java?view=auto&rev=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/ValidationErrorFeedback.java (added)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/ValidationErrorFeedback.java Sat Oct 14 13:01:09 2006
@@ -0,0 +1,103 @@
+/*
+ * $Id: org.eclipse.jdt.ui.prefs 5004 2006-03-17 20:47:08 -0800 (Fri, 17 Mar 2006) eelco12 $
+ * $Revision: 5004 $
+ * $Date: 2006-03-17 20:47:08 -0800 (Fri, 17 Mar 2006) $
+ * 
+ * ==============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package wicket.markup.html.form;
+
+import java.io.Serializable;
+
+import wicket.Component;
+import wicket.validation.IMessageSource;
+import wicket.validation.IValidationError;
+
+/**
+ * This class is the parameter to {@link Component#error(Serializable)} instead
+ * of the generated error string itself (when
+ * {@link FormComponent#error(IValidationError)} is called). The advantage is
+ * that a custom feedback panel would still have access to the underlying
+ * {@link IValidationError} that generated the error message - providing much
+ * more context.
+ * 
+ * @author Igor Vaynberg (ivaynberg)
+ */
+public class ValidationErrorFeedback implements Serializable
+{
+	private static final long serialVersionUID = 1L;
+
+	/** error object */
+	private final IValidationError error;
+
+	/** error message */
+	private final String message;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param error
+	 * @param message
+	 */
+	public ValidationErrorFeedback(final IValidationError error, final String message)
+	{
+		if (error == null)
+		{
+			throw new IllegalArgumentException("Argument [[error]] cannot be null");
+		}
+		this.error = error;
+		this.message = message;
+	}
+
+	/**
+	 * Gets serialVersionUID.
+	 * 
+	 * @return serialVersionUID
+	 */
+	public static long getSerialVersionUID()
+	{
+		return serialVersionUID;
+	}
+
+	/**
+	 * Gets error.
+	 * 
+	 * @return error
+	 */
+	public IValidationError getError()
+	{
+		return error;
+	}
+
+	/**
+	 * Gets message.
+	 * 
+	 * @return message
+	 */
+	public String getMessage()
+	{
+		return message;
+	}
+
+	/**
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString()
+	{
+		return message;
+	}
+
+
+}

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/validation/AbstractFormValidator.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/validation/AbstractFormValidator.java?view=diff&rev=464003&r1=464002&r2=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/validation/AbstractFormValidator.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/form/validation/AbstractFormValidator.java Sat Oct 14 13:01:09 2006
@@ -25,6 +25,7 @@
 import wicket.markup.html.form.FormComponent;
 import wicket.model.IModel;
 import wicket.util.lang.Classes;
+import wicket.validation.IValidationError;
 import wicket.validation.ValidationError;
 
 /**
@@ -140,7 +141,7 @@
 		}
 
 		error.setVars(vars);
-		fc.error(error);
+		fc.error((IValidationError)error);
 	}
 
 	/**

Added: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/FeedbackPanel.html
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/FeedbackPanel.html?view=auto&rev=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/FeedbackPanel.html (added)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/FeedbackPanel.html Sat Oct 14 13:01:09 2006
@@ -0,0 +1,11 @@
+asdasdasd<html xmlns:wicket>
+<body>
+<wicket:panel>
+  <ul wicket:id="feedbackul">
+    <li wicket:id="messages" class="errorlevel">
+      <span wicket:id="message" class="errorlevel">A message</span>
+    </li>
+  </ul>
+</wicket:panel>
+</body>
+</html>

Added: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/FeedbackPanel.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/FeedbackPanel.java?view=auto&rev=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/FeedbackPanel.java (added)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/FeedbackPanel.java Sat Oct 14 13:01:09 2006
@@ -0,0 +1,318 @@
+/*
+ * $Id: FeedbackPanel.java 5844 2006-05-24 20:53:56 +0000 (Wed, 24 May 2006)
+ * joco01 $ $Revision: 461067 $ $Date: 2006-05-24 20:53:56 +0000 (Wed, 24 May
+ * 2006) $
+ * 
+ * ==============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package wicket.markup.html.panel;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import wicket.AttributeModifier;
+import wicket.Component;
+import wicket.MarkupContainer;
+import wicket.feedback.FeedbackMessage;
+import wicket.feedback.FeedbackMessagesModel;
+import wicket.feedback.IFeedback;
+import wicket.feedback.IFeedbackMessageFilter;
+import wicket.markup.html.WebMarkupContainer;
+import wicket.markup.html.basic.Label;
+import wicket.markup.html.list.ListItem;
+import wicket.markup.html.list.ListView;
+import wicket.model.IModel;
+import wicket.model.Model;
+
+/**
+ * A panel that displays {@link wicket.feedback.FeedbackMessage}s in a list
+ * view. The maximum number of messages to show can be set with
+ * setMaxMessages().
+ * 
+ * @see wicket.feedback.FeedbackMessage
+ * @see wicket.feedback.FeedbackMessages
+ * @author Jonathan Locke
+ * @author Eelco Hillenius
+ */
+public class FeedbackPanel extends Panel implements IFeedback
+{
+	private static final long serialVersionUID = 1L;
+
+	/** Message view */
+	private final MessageListView messageListView;
+
+	/**
+	 * List for messages.
+	 */
+	private final class MessageListView extends ListView<FeedbackMessage>
+	{
+		private static final long serialVersionUID = 1L;
+
+		/**
+		 * @see wicket.Component#Component(MarkupContainer,String)
+		 */
+		public MessageListView(MarkupContainer parent, final String id)
+		{
+			super(parent, id);
+			setModel(newFeedbackMessagesModel());
+		}
+
+		/**
+		 * @see wicket.markup.html.list.ListView#populateItem(wicket.markup.html.list.ListItem)
+		 */
+		@Override
+		protected void populateItem(final ListItem listItem)
+		{
+			final FeedbackMessage message = (FeedbackMessage)listItem.getModelObject();
+			message.markRendered();
+			final IModel<String> replacementModel = new Model<String>()
+			{
+				private static final long serialVersionUID = 1L;
+
+				/**
+				 * Returns feedbackPanel + the message level, eg
+				 * 'feedbackPanelERROR'. This is used as the class of the li /
+				 * span elements.
+				 * 
+				 * @see wicket.model.IModel#getObject()
+				 */
+				@Override
+				public String getObject()
+				{
+					return getCSSClass(message);
+				}
+			};
+
+			final Component label = newMessageDisplayComponent(listItem, "message", message);
+			final AttributeModifier levelModifier = new AttributeModifier("class", replacementModel);
+			label.add(levelModifier);
+			listItem.add(levelModifier);
+		}
+	}
+
+	/**
+	 * Generates a component that is used to display the message inside the
+	 * feedback panel. This component must handle being attached to
+	 * <code>span</code> tags.
+	 * 
+	 * By default a {@link Label} is used.
+	 * 
+	 * @param parent
+	 *            component parent
+	 * @param id
+	 *            parent id
+	 * @param message
+	 *            feedback message
+	 * @return component used to display the message
+	 */
+	protected Component newMessageDisplayComponent(MarkupContainer parent, String id,
+			FeedbackMessage message)
+	{
+		return new Label(parent, id, message.getMessage().toString());
+	}
+
+	/**
+	 * @see wicket.Component#Component(MarkupContainer,String)
+	 */
+	public FeedbackPanel(MarkupContainer parent, final String id)
+	{
+		this(parent, id, null);
+	}
+
+	/**
+	 * @see wicket.Component#Component(MarkupContainer,String)
+	 */
+	public FeedbackPanel(MarkupContainer parent, final String id, IFeedbackMessageFilter filter)
+	{
+		super(parent, id);
+		WebMarkupContainer messagesContainer = new WebMarkupContainer(this, "feedbackul")
+		{
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public boolean isVisible()
+			{
+				return anyMessage();
+			}
+		};
+		this.messageListView = new MessageListView(messagesContainer, "messages");
+		messageListView.setVersioned(false);
+
+		if (filter != null)
+		{
+			setFilter(filter);
+		}
+	}
+
+
+	/**
+	 * @return Model for feedback messages on which you can install filters and
+	 *         other properties
+	 */
+	public final FeedbackMessagesModel getFeedbackMessagesModel()
+	{
+		return (FeedbackMessagesModel)messageListView.getModel();
+	}
+
+	/**
+	 * @return The current message filter
+	 */
+	public final IFeedbackMessageFilter getFilter()
+	{
+		return getFeedbackMessagesModel().getFilter();
+	}
+
+	/**
+	 * @return The current sorting comparator
+	 */
+	public final Comparator getSortingComparator()
+	{
+		return getFeedbackMessagesModel().getSortingComparator();
+	}
+
+	/**
+	 * @see wicket.Component#isVersioned()
+	 */
+	@Override
+	public boolean isVersioned()
+	{
+		return false;
+	}
+
+	/**
+	 * Sets a filter to use on the feedback messages model
+	 * 
+	 * @param filter
+	 *            The message filter to install on the feedback messages model
+	 */
+	public final void setFilter(IFeedbackMessageFilter filter)
+	{
+		getFeedbackMessagesModel().setFilter(filter);
+	}
+
+	/**
+	 * @param maxMessages
+	 *            The maximum number of feedback messages that this feedback
+	 *            panel should show at one time
+	 */
+	public final void setMaxMessages(int maxMessages)
+	{
+		this.messageListView.setViewSize(maxMessages);
+	}
+
+	/**
+	 * Sets the comparator used for sorting the messages.
+	 * 
+	 * @param sortingComparator
+	 *            comparator used for sorting the messages.
+	 */
+	public final void setSortingComparator(Comparator<FeedbackMessage> sortingComparator)
+	{
+		getFeedbackMessagesModel().setSortingComparator(sortingComparator);
+	}
+
+	/**
+	 * @see wicket.feedback.IFeedback#updateFeedback()
+	 */
+	public void updateFeedback()
+	{
+		// Force model to load
+		messageListView.getModelObject();
+	}
+
+	/**
+	 * Search messages that this panel will render, and see if there is any
+	 * message of level ERROR or up. This is a convenience method; same as
+	 * calling 'anyMessage(FeedbackMessage.ERROR)'.
+	 * 
+	 * @return whether there is any message for this panel of level ERROR or up
+	 */
+	public final boolean anyErrorMessage()
+	{
+		return anyMessage(FeedbackMessage.ERROR);
+	}
+
+	/**
+	 * Search messages that this panel will render, and see if there is any
+	 * message.
+	 * 
+	 * @return whether there is any message for this panel
+	 */
+	public final boolean anyMessage()
+	{
+		return anyMessage(FeedbackMessage.UNDEFINED);
+	}
+
+	/**
+	 * Search messages that this panel will render, and see if there is any
+	 * message of the given level.
+	 * 
+	 * @param level
+	 *            the level, see FeedbackMessage
+	 * @return whether there is any message for this panel of the given level
+	 */
+	public final boolean anyMessage(int level)
+	{
+		List msgs = getCurrentMessages();
+
+		for (Iterator i = msgs.iterator(); i.hasNext();)
+		{
+			FeedbackMessage msg = (FeedbackMessage)i.next();
+			if (msg.isLevel(level))
+			{
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Gets the css class for the given message.
+	 * 
+	 * @param message
+	 *            the message
+	 * @return the css class; by default, this returns feedbackPanel + the
+	 *         message level, eg 'feedbackPanelERROR', but you can override this
+	 *         method to provide your own
+	 */
+	protected String getCSSClass(final FeedbackMessage message)
+	{
+		return "feedbackPanel" + message.getLevelAsString();
+	}
+
+	/**
+	 * Gets the currently collected messages for this panel.
+	 * 
+	 * @return the currently collected messages for this panel, possibly empty
+	 */
+	protected final List<FeedbackMessage> getCurrentMessages()
+	{
+		final List<FeedbackMessage> messages = messageListView.getModelObject();
+		return Collections.unmodifiableList(messages);
+	}
+
+	/**
+	 * Gets a new instance of FeedbackMessagesModel to use.
+	 * 
+	 * @return Instance of FeedbackMessagesModel to use
+	 */
+	protected FeedbackMessagesModel newFeedbackMessagesModel()
+	{
+		return new FeedbackMessagesModel(getPage());
+	}
+
+}

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/util/tester/WicketTester.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/util/tester/WicketTester.java?view=diff&rev=464003&r1=464002&r2=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/util/tester/WicketTester.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/util/tester/WicketTester.java Sat Oct 14 13:01:09 2006
@@ -18,6 +18,7 @@
  */
 package wicket.util.tester;
 
+import java.io.Serializable;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
@@ -803,7 +804,7 @@
 	 */
 	public void assertNoErrorMessage()
 	{
-		List<String> messages = getMessages(FeedbackMessage.ERROR);
+		List<Serializable> messages = getMessages(FeedbackMessage.ERROR);
 		Assert.assertTrue("expect no error message, but contains\n"
 				+ WicketTesterHelper.asLined(messages), messages.isEmpty());
 	}
@@ -813,7 +814,7 @@
 	 */
 	public void assertNoInfoMessage()
 	{
-		List<String> messages = getMessages(FeedbackMessage.INFO);
+		List<Serializable> messages = getMessages(FeedbackMessage.INFO);
 		Assert.assertTrue("expect no info message, but contains\n"
 				+ WicketTesterHelper.asLined(messages), messages.isEmpty());
 	}
@@ -826,8 +827,13 @@
 	 */
 	public void assertErrorMessages(String[] expectedErrorMessages)
 	{
-		List<String> actualMessages = getMessages(FeedbackMessage.ERROR);
-		WicketTesterHelper.assertEquals(Arrays.asList(expectedErrorMessages), actualMessages);
+		List<Serializable> actualMessages = getMessages(FeedbackMessage.ERROR);
+		List<String> msgs = new ArrayList<String>();
+		for (Serializable msg : actualMessages)
+		{
+			msgs.add(msg.toString());
+		}
+		WicketTesterHelper.assertEquals(Arrays.asList(expectedErrorMessages), msgs);
 	}
 
 	/**
@@ -838,7 +844,7 @@
 	 */
 	public void assertInfoMessages(String[] expectedInfoMessages)
 	{
-		List<String> actualMessages = getMessages(FeedbackMessage.INFO);
+		List<Serializable> actualMessages = getMessages(FeedbackMessage.INFO);
 		WicketTesterHelper.assertEquals(Arrays.asList(expectedInfoMessages), actualMessages);
 	}
 
@@ -848,10 +854,10 @@
 	 * @param level
 	 *            level of feedback message, ex.
 	 *            <code>FeedbackMessage.DEBUG or FeedbackMessage.INFO.. etc</code>
-	 * @return List list of messages (in String)
+	 * @return List list of messages (in Serializable)
 	 * @see FeedbackMessage
 	 */
-	public List<String> getMessages(final int level)
+	public List<Serializable> getMessages(final int level)
 	{
 		FeedbackMessages feedbackMessages = getLastRenderedPage().getFeedbackMessages();
 		List allMessages = feedbackMessages.messages(new IFeedbackMessageFilter()
@@ -863,7 +869,7 @@
 				return message.getLevel() == level;
 			}
 		});
-		List<String> actualMessages = new ArrayList<String>();
+		List<Serializable> actualMessages = new ArrayList<Serializable>();
 		for (Iterator iter = allMessages.iterator(); iter.hasNext();)
 		{
 			actualMessages.add(((FeedbackMessage)iter.next()).getMessage());
@@ -991,24 +997,24 @@
 	 * component by using:
 	 * 
 	 * <pre>
-	 *      ...
-	 *      component.add(new AjaxEventBehavior(ClientEvent.DBLCLICK) {
-	 *          public void onEvent(AjaxRequestTarget) {
-	 *              // Do something.
-	 *          }
-	 *      });
-	 *      ...
+	 *              ...
+	 *              component.add(new AjaxEventBehavior(ClientEvent.DBLCLICK) {
+	 *                  public void onEvent(AjaxRequestTarget) {
+	 *                      // Do something.
+	 *                  }
+	 *              });
+	 *              ...
 	 * </pre>
 	 * 
 	 * You can then test that the code inside onEvent actually does what it's
 	 * supposed to, using the WicketTester:
 	 * 
 	 * <pre>
-	 *      ...
-	 *      tester.executeAjaxEvent(component, ClientEvent.DBLCLICK);
-	 *                
-	 *      // Test that the code inside onEvent is correct.
-	 *      ...
+	 *              ...
+	 *              tester.executeAjaxEvent(component, ClientEvent.DBLCLICK);
+	 *                        
+	 *              // Test that the code inside onEvent is correct.
+	 *              ...
 	 * </pre>
 	 * 
 	 * PLEASE NOTE! This method doesn't actually insert the component in the

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/validation/ValidationError.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/validation/ValidationError.java?view=diff&rev=464003&r1=464002&r2=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/validation/ValidationError.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/validation/ValidationError.java Sat Oct 14 13:01:09 2006
@@ -18,6 +18,7 @@
  */
 package wicket.validation;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -40,8 +41,10 @@
  * 
  * @author ivaynberg
  */
-public final class ValidationError implements IValidationError
+public class ValidationError implements IValidationError, Serializable
 {
+	private static final long serialVersionUID = 1L;
+
 	// XXX 2.0: optimization - keys can be null by default until a key is added
 	/** List of message keys to try against the {@link IMessageSource} */
 	private List<String> keys = new ArrayList<String>(1);
@@ -110,7 +113,7 @@
 	 * 
 	 * @return map of variables for this error
 	 */
-	public Map<String, Object> getVars()
+	public final Map<String, Object> getVars()
 	{
 		if (vars == null)
 		{
@@ -126,7 +129,7 @@
 	 *            variable map
 	 * @return this for chaining
 	 */
-	public ValidationError setVars(Map<String, Object> vars)
+	public final ValidationError setVars(Map<String, Object> vars)
 	{
 		if (vars == null)
 		{
@@ -140,7 +143,7 @@
 	 * @see wicket.validation.IValidationError#getErrorMessage(wicket.validation.IMessageSource)
 	 */
 	@SuppressWarnings("unchecked")
-	public String getErrorMessage(IMessageSource messageSource)
+	public final String getErrorMessage(IMessageSource messageSource)
 	{
 		String errorMessage = null;
 
@@ -176,7 +179,7 @@
 	 * 
 	 * @return message
 	 */
-	public String getMessage()
+	public final String getMessage()
 	{
 		return message;
 	}
@@ -190,7 +193,7 @@
 	 * 
 	 * @return this for chaining
 	 */
-	public ValidationError setMessage(String message)
+	public final ValidationError setMessage(String message)
 	{
 		if (message == null)
 		{
@@ -200,6 +203,9 @@
 		return this;
 	}
 
+	/**
+	 * @see java.lang.Object#toString()
+	 */
 	@Override
 	public String toString()
 	{

Modified: incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/form/ValidatorPropertiesTest.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/form/ValidatorPropertiesTest.java?view=diff&rev=464003&r1=464002&r2=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/form/ValidatorPropertiesTest.java (original)
+++ incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/form/ValidatorPropertiesTest.java Sat Oct 14 13:01:09 2006
@@ -66,28 +66,37 @@
 		page.getText11().validateRequired();
 		page.getText12().setInput("");
 		page.getText12().validateRequired();
-		
-		String msg=page.getText1().getFeedbackMessage().getMessage();
 
-		assertEquals("text1label is required", page.getText1().getFeedbackMessage().getMessage());
-		assertEquals("text2 is required", page.getText2().getFeedbackMessage().getMessage());
-		assertEquals("ok: text3333 is missing", page.getText3().getFeedbackMessage().getMessage());
-		assertEquals("ok: Text4Label is missing", page.getText4().getFeedbackMessage().getMessage());
-		assertEquals("ok: text is missing", page.getText5().getFeedbackMessage().getMessage());
+		String msg = page.getText1().getFeedbackMessage().getMessage().toString();
+
+		assertEquals("text1label is required", page.getText1().getFeedbackMessage().getMessage()
+				.toString());
+		assertEquals("text2 is required", page.getText2().getFeedbackMessage().getMessage()
+				.toString());
+		assertEquals("ok: text3333 is missing", page.getText3().getFeedbackMessage().getMessage()
+				.toString());
+		assertEquals("ok: Text4Label is missing", page.getText4().getFeedbackMessage().getMessage()
+				.toString());
+		assertEquals("ok: text is missing", page.getText5().getFeedbackMessage().getMessage()
+				.toString());
 		assertEquals("Default message: text6 required", page.getText6().getFeedbackMessage()
-				.getMessage());
+				.getMessage().toString());
 		assertEquals("input for text7-Label is missing", page.getText7().getFeedbackMessage()
-				.getMessage());
+				.getMessage().toString());
 		assertEquals("Default message: text8-Label required", page.getText8().getFeedbackMessage()
-				.getMessage());
-		assertEquals("found it in panel", page.getText9().getFeedbackMessage().getMessage());
-		assertEquals("found it in form", page.getText10().getFeedbackMessage().getMessage());
-		assertEquals("found it in page", page.getText11().getFeedbackMessage().getMessage());
-		assertEquals("found it in page", page.getText12().getFeedbackMessage().getMessage());
+				.getMessage().toString());
+		assertEquals("found it in panel", page.getText9().getFeedbackMessage().getMessage()
+				.toString());
+		assertEquals("found it in form", page.getText10().getFeedbackMessage().getMessage()
+				.toString());
+		assertEquals("found it in page", page.getText11().getFeedbackMessage().getMessage()
+				.toString());
+		assertEquals("found it in page", page.getText12().getFeedbackMessage().getMessage()
+				.toString());
 
 		// Test caching
 		assertEquals("Default message: text8-Label required", page.getText8().getFeedbackMessage()
-				.getMessage());
+				.getMessage().toString());
 	}
 
 	/**

Modified: incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_4/FormTesterTest.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_4/FormTesterTest.java?view=diff&rev=464003&r1=464002&r2=464003
==============================================================================
--- incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_4/FormTesterTest.java (original)
+++ incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_4/FormTesterTest.java Sat Oct 14 13:01:09 2006
@@ -65,6 +65,6 @@
 		assertNull(page.getEmail());
 		assertTrue(page.getFeedbackMessages().hasMessageFor(page.get("form:email")));
 		assertEquals("wrong email address pattern for email", page.getFeedbackMessages()
-				.messageForComponent(page.get("form:email")).getMessage());
+				.messageForComponent(page.get("form:email")).getMessage().toString());
 	}
 }