Author: gseitz
Date: Wed Jan  9 13:59:33 2008
New Revision: 610593

URL: http://svn.apache.org/viewvc?rev=610593&view=rev
Log:
WICKET-1124: enhancement of nested form handling

Added:
    
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/FormSubmitTest.java
   (with props)
    
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.html
   (with props)
    
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.java
   (with props)
Modified:
    
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java
    
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java
    
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java

Modified: 
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java?rev=610593&r1=610592&r2=610593&view=diff
==============================================================================
--- 
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java
 (original)
+++ 
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java
 Wed Jan  9 13:59:33 2008
@@ -86,9 +86,9 @@
                        if (cursor == null)
                        {
                                throw new IllegalStateException(
-                                               "form was not specified in the 
constructor and cannot "
-                                                               + "be found in 
the hierarchy of the component this behavior "
-                                                               + "is attached 
to");
+                                       "form was not specified in the 
constructor and cannot "
+                                               + "be found in the hierarchy of 
the component this behavior "
+                                               + "is attached to");
                        }
                        else
                        {
@@ -106,12 +106,13 @@
 
 
                AppendingStringBuffer call = new 
AppendingStringBuffer("wicketSubmitFormById('").append(
-                               formId).append("', '").append(url).append("', 
");
+                       formId).append("', '").append(url).append("', ");
 
                if (getComponent() instanceof IFormSubmittingComponent)
                {
-                       
call.append("'").append(((IFormSubmittingComponent)getComponent()).getInputName())
-                                       .append("' ");
+                       call.append("'")
+                               
.append(((IFormSubmittingComponent)getComponent()).getInputName())
+                               .append("' ");
                }
                else
                {
@@ -124,6 +125,11 @@
        protected void onEvent(AjaxRequestTarget target)
        {
                getForm().onFormSubmitted();
+               if (!getForm().isSubmitted())
+               { // only process the form submission if the form was actually 
submitted -> needs to be
+                       // enabled and visible
+                       return;
+               }
                if (!getForm().hasError())
                {
                        onSubmit(target);

Modified: 
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java?rev=610593&r1=610592&r2=610593&view=diff
==============================================================================
--- 
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java
 (original)
+++ 
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/Form.java
 Wed Jan  9 13:59:33 2008
@@ -146,8 +146,16 @@
                        if (component instanceof FormComponent)
                        {
                                FormComponent formComponent = 
(FormComponent)component;
+
+                               Form form = formComponent.getForm();
+                               if (!form.isEnabled() || 
!form.isEnableAllowed() || !form.isVisibleInHierarchy())
+                               {
+                                       // do not validate formComponent or any 
of formComponent's children
+                                       return 
Component.IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+                               }
+
                                if (formComponent.isVisibleInHierarchy() && 
formComponent.isValid() &&
-                                               formComponent.isEnabled() && 
formComponent.isEnableAllowed())
+                                       formComponent.isEnabled() && 
formComponent.isEnableAllowed())
                                {
                                        validate(formComponent);
                                }
@@ -381,8 +389,8 @@
                if (removed == null)
                {
                        throw new IllegalStateException(
-                                       "Tried to remove form validator that 
was not previously added. "
-                                                       + "Make sure your 
validator's equals() implementation is sufficient");
+                               "Tried to remove form validator that was not 
previously added. "
+                                       + "Make sure your validator's equals() 
implementation is sufficient");
                }
                addStateChange(new FormValidatorRemovedChange(removed));
        }
@@ -508,31 +516,31 @@
         */
        public final IFormSubmittingComponent findSubmittingButton()
        {
-               IFormSubmittingComponent submittingComponent = 
(IFormSubmittingComponent)getPage()
-                               .visitChildren(IFormSubmittingComponent.class, 
new IVisitor()
+               IFormSubmittingComponent submittingComponent = 
(IFormSubmittingComponent)getPage().visitChildren(
+                       IFormSubmittingComponent.class, new IVisitor()
+                       {
+                               public Object component(final Component 
component)
                                {
-                                       public Object component(final Component 
component)
-                                       {
-                                               // Get submitting component
-                                               final IFormSubmittingComponent 
submittingComponent = (IFormSubmittingComponent)component;
+                                       // Get submitting component
+                                       final IFormSubmittingComponent 
submittingComponent = (IFormSubmittingComponent)component;
 
-                                               // Check for component-name or 
component-name.x request string
-                                               if 
(submittingComponent.getForm() != null &&
-                                                               
submittingComponent.getForm().getRootForm() == Form.this &&
-                                                               
(getRequest().getParameter(submittingComponent.getInputName()) != null || 
getRequest()
-                                                                               
.getParameter(submittingComponent.getInputName() + ".x") != null))
+                                       // Check for component-name or 
component-name.x request string
+                                       if (submittingComponent.getForm() != 
null &&
+                                               
submittingComponent.getForm().getRootForm() == Form.this &&
+                                               
(getRequest().getParameter(submittingComponent.getInputName()) != null || 
getRequest().getParameter(
+                                                       
submittingComponent.getInputName() + ".x") != null))
+                                       {
+                                               if (!component.isVisible())
                                                {
-                                                       if 
(!component.isVisible())
-                                                       {
-                                                               throw new 
WicketRuntimeException("Submit Button " +
-                                                                               
submittingComponent.getInputName() + " (path=" +
-                                                                               
component.getPageRelativePath() + ") is not visible");
-                                                       }
-                                                       return 
submittingComponent;
+                                                       throw new 
WicketRuntimeException("Submit Button " +
+                                                               
submittingComponent.getInputName() + " (path=" +
+                                                               
component.getPageRelativePath() + ") is not visible");
                                                }
-                                               return CONTINUE_TRAVERSAL;
+                                               return submittingComponent;
                                        }
-                               });
+                                       return CONTINUE_TRAVERSAL;
+                               }
+                       });
 
                return submittingComponent;
        }
@@ -579,9 +587,8 @@
        {
                Form root = getRootForm();
                return new 
AppendingStringBuffer("document.getElementById('").append(
-                               
root.getHiddenFieldId()).append("').value='").append(url).append(
-                               
"';document.getElementById('").append(root.getJavascriptId())
-                               .append("').submit();");
+                       
root.getHiddenFieldId()).append("').value='").append(url).append(
+                       
"';document.getElementById('").append(root.getJavascriptId()).append("').submit();");
        }
 
        /**
@@ -728,7 +735,7 @@
         */
        public final void onFormSubmitted()
        {
-               setFlag(FLAG_SUBMITTED, true);
+               markFormsSubmitted();
 
                if (handleMultiPart())
                {
@@ -775,7 +782,7 @@
                // onError
                else if (hasError())
                {
-                       onError();
+                       callOnError();
                }
        }
 
@@ -790,6 +797,13 @@
         */
        public boolean process()
        {
+               if (!isEnabled() || !isEnableAllowed() || 
!isVisibleInHierarchy())
+               {
+                       // since process() can be called outside of the default 
form workflow, an additional
+                       // check is needed
+                       return false;
+               }
+
                // run validation
                validate();
 
@@ -800,14 +814,14 @@
                        markFormComponentsInvalid();
 
                        // let subclass handle error
-                       onError();
+                       callOnError();
 
                        // Form has an error
                        return false;
                }
                else
                {
-                       // mark all childeren as valid
+                       // mark all children as valid
                        markFormComponentsValid();
 
                        // before updating, call the interception method for 
clients
@@ -825,6 +839,55 @@
        }
 
        /**
+        * Calls onError on this [EMAIL PROTECTED] Form} and any enabled and 
visible nested form, if the respective
+        * [EMAIL PROTECTED] Form} actually has errors.
+        */
+       private void callOnError()
+       {
+               onError();
+               // call onError on nested forms
+               visitChildren(Form.class, new IVisitor()
+               {
+                       public Object component(Component component)
+                       {
+                               final Form form = (Form)component;
+                               if (!form.isEnabled() || 
!form.isEnableAllowed() || !form.isVisibleInHierarchy())
+                               {
+                                       return 
IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+                               }
+                               if (form.hasError())
+                               {
+                                       form.onError();
+                               }
+                               return IVisitor.CONTINUE_TRAVERSAL;
+                       }
+               });
+       }
+
+
+       /**
+        * Sets FLAG_SUBMITTED to true on this form and every enabled nested 
form.
+        */
+       private void markFormsSubmitted()
+       {
+               setFlag(FLAG_SUBMITTED, true);
+
+               visitChildren(Form.class, new IVisitor()
+               {
+                       public Object component(Component component)
+                       {
+                               Form form = (Form)component;
+                               if (form.isEnabled() && form.isEnableAllowed() 
&& isVisibleInHierarchy())
+                               {
+                                       form.setFlag(FLAG_SUBMITTED, true);
+                                       return IVisitor.CONTINUE_TRAVERSAL;
+                               }
+                               return 
IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+                       }
+               });
+       }
+
+       /**
         * Removes already persisted data for all FormComponent children and 
disable persistence for the
         * same components.
         * 
@@ -932,7 +995,7 @@
        }
 
        /**
-        * Convenient and typesafe way to visit all the form components on a 
form
+        * Convenient and typesafe way to visit all the form components on a 
form.
         * 
         * @param visitor
         *            The visitor interface to call
@@ -948,26 +1011,7 @@
                        }
                });
 
-               /**
-                * TODO Post 1.2 General: Maybe we should re-think how Borders 
are implemented, because
-                * there are just too many exceptions in the code base because 
of borders. This time it is
-                * to solve the problem tested in BoxBorderTestPage_3 where the 
Form is defined in the box
-                * border and the FormComponents are in the "body". Thus, the 
formComponents are not childs
-                * of the form. They are rather children of the border, as the 
Form itself.
-                */
-               if (getParent() instanceof Border)
-               {
-                       MarkupContainer border = getParent();
-                       Iterator iter = border.iterator();
-                       while (iter.hasNext())
-                       {
-                               Component child = (Component)iter.next();
-                               if (child instanceof FormComponent)
-                               {
-                                       
visitor.formComponent((FormComponent)child);
-                               }
-                       }
-               }
+               visitChildrenInContainingBorder(visitor);
        }
 
        /**
@@ -981,13 +1025,21 @@
        {
                FormComponent.visitFormComponentsPostOrder(this, visitor);
 
-               /**
-                * TODO Post 1.2 General: Maybe we should re-think how Borders 
are implemented, because
-                * there are just too many exceptions in the code base because 
of borders. This time it is
-                * to solve the problem tested in BoxBorderTestPage_3 where the 
Form is defined in the box
-                * border and the FormComponents are in the "body". Thus, the 
formComponents are not
-                * children of the form. They are rather children of the 
border, as the Form itself.
-                */
+               visitChildrenInContainingBorder(visitor);
+       }
+
+       /**
+        * TODO Post 1.2 General: Maybe we should re-think how Borders are 
implemented, because there
+        * are just too many exceptions in the code base because of borders. 
This time it is to solve
+        * the problem tested in BoxBorderTestPage_3 where the Form is defined 
in the box border and the
+        * FormComponents are in the "body". Thus, the formComponents are not 
children of the form. They
+        * are rather children of the border, as the Form itself.
+        * 
+        * @param visitor
+        *            The [EMAIL PROTECTED] [EMAIL PROTECTED] IVisitor} used to 
visit the children.
+        */
+       private void visitChildrenInContainingBorder(final 
FormComponent.IVisitor visitor)
+       {
                if (getParent() instanceof Border)
                {
                        MarkupContainer border = getParent();
@@ -1041,7 +1093,7 @@
                RequestCycle rc = RequestCycle.get();
                IRequestCycleProcessor processor = rc.getProcessor();
                final RequestParameters requestParameters = 
processor.getRequestCodingStrategy().decode(
-                               new FormDispatchRequest(rc.getRequest(), url));
+                       new FormDispatchRequest(rc.getRequest(), url));
                IRequestTarget rt = processor.resolve(rc, requestParameters);
                if (rt instanceof ListenerInterfaceRequestTarget)
                {
@@ -1051,8 +1103,8 @@
                else
                {
                        throw new WicketRuntimeException(
-                                       "Attempt to access unknown request 
listener interface " +
-                                                       
requestParameters.getInterfaceName());
+                               "Attempt to access unknown request listener 
interface " +
+                                       requestParameters.getInterfaceName());
                }
        }
 
@@ -1199,14 +1251,13 @@
         *            The open tag for the body
         */
        protected void appendDefaultButtonField(final MarkupStream markupStream,
-                       final ComponentTag openTag)
+               final ComponentTag openTag)
        {
 
                AppendingStringBuffer buffer = new AppendingStringBuffer();
 
                // div that is not visible (but not display:none either)
-               buffer
-                               .append("<div 
style=\"width:0px;height:0px;position:absolute;left:-100px;top:-100px;overflow:hidden\">");
+               buffer.append("<div 
style=\"width:0px;height:0px;position:absolute;left:-100px;top:-100px;overflow:hidden\">");
 
                // add an empty textfield (otherwise IE doesn't work)
                buffer.append("<input type=\"text\" autocomplete=\"false\"/>");
@@ -1224,8 +1275,7 @@
                }
                buffer.append("\" onclick=\" var b=Wicket.$('");
                buffer.append(submittingComponent.getMarkupId());
-               buffer
-                               .append("'); if (typeof(b.onclick) != 
'undefined') {  var r = b.onclick.bind(b)(); if (r != false) b.click(); } else 
{ b.click(); };  return false;\" ");
+               buffer.append("'); if (typeof(b.onclick) != 'undefined') {  var 
r = b.onclick.bind(b)(); if (r != false) b.click(); } else { b.click(); };  
return false;\" ");
                buffer.append(" />");
 
                // close div
@@ -1266,13 +1316,31 @@
        {
                // when the given submitting component is not null, it means 
that it was the
                // submitting component
+               Form formToProcess = this;
                if (submittingComponent != null)
                {
                        submittingComponent.onSubmit();
+                       // use the form which the submittingComponent has 
submitted for further processing
+                       formToProcess = submittingComponent.getForm();
                }
 
                // Model was successfully updated with valid data
-               onSubmit();
+               formToProcess.onSubmit();
+
+               // call onSubmit on nested forms
+               formToProcess.visitChildren(Form.class, new IVisitor()
+               {
+                       public Object component(Component component)
+                       {
+                               Form form = (Form)component;
+                               if (form.isEnabled() && form.isEnableAllowed() 
&& form.isVisibleInHierarchy())
+                               {
+                                       form.onSubmit();
+                                       return IVisitor.CONTINUE_TRAVERSAL;
+                               }
+                               return 
IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+                       }
+               });
        }
 
        /**
@@ -1343,8 +1411,7 @@
                        // parsed out correctly
                        try
                        {
-                               final WebRequest multipartWebRequest = 
((WebRequest)getRequest())
-                                               
.newMultipartWebRequest(getMaxSize());
+                               final WebRequest multipartWebRequest = 
((WebRequest)getRequest()).newMultipartWebRequest(getMaxSize());
                                
getRequestCycle().setRequest(multipartWebRequest);
                        }
                        catch (WicketRuntimeException wre)
@@ -1365,8 +1432,8 @@
                                        // Resource key should be 
<form-id>.uploadTooLarge to
                                        // override default message
                                        final String defaultValue = "Upload 
must be less than " + getMaxSize();
-                                       String msg = getString(getId() + "." + 
UPLOAD_TOO_LARGE_RESOURCE_KEY, Model
-                                                       .valueOf(model), 
defaultValue);
+                                       String msg = getString(getId() + "." + 
UPLOAD_TOO_LARGE_RESOURCE_KEY,
+                                               Model.valueOf(model), 
defaultValue);
                                        error(msg);
                                }
                                else
@@ -1374,8 +1441,8 @@
                                        // Resource key should be 
<form-id>.uploadFailed to override
                                        // default message
                                        final String defaultValue = "Upload 
failed: " + e.getLocalizedMessage();
-                                       String msg = getString(getId() + "." + 
UPLOAD_FAILED_RESOURCE_KEY, Model
-                                                       .valueOf(model), 
defaultValue);
+                                       String msg = getString(getId() + "." + 
UPLOAD_FAILED_RESOURCE_KEY,
+                                               Model.valueOf(model), 
defaultValue);
                                        error(msg);
 
                                        log.warn(msg, e);
@@ -1426,16 +1493,46 @@
        }
 
        /**
-        * Mark each form component on this form valid.
+        * Mark each form component on this form and on nested forms valid.
         */
        protected final void markFormComponentsValid()
        {
-               // call invalidate methods of all nested form components
+               internalMarkFormComponentsValid();
+               markNestedFormComponentsValid();
+       }
+
+
+       /**
+        * Mark each form component on nested form valid.
+        */
+       private void markNestedFormComponentsValid()
+       {
+               visitChildren(Form.class, new IVisitor()
+               {
+                       public Object component(Component component)
+                       {
+                               Form form = (Form)component;
+                               if (form.isEnableAllowed() && form.isEnabled() 
&& form.isVisibleInHierarchy())
+                               {
+                                       form.internalMarkFormComponentsValid();
+                                       return CONTINUE_TRAVERSAL;
+                               }
+                               return CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+                       }
+               });
+       }
+
+       /**
+        * Mark each form component on this form valid.
+        */
+       private void internalMarkFormComponentsValid()
+       {
+               // call valid methods of all nested form components
                visitFormComponentsPostOrder(new FormComponent.AbstractVisitor()
                {
                        public void onFormComponent(final FormComponent 
formComponent)
                        {
-                               if (formComponent.isVisibleInHierarchy())
+                               if (formComponent.getForm() == Form.this && 
formComponent.isVisibleInHierarchy())
                                {
                                        formComponent.valid();
                                }
@@ -1514,8 +1611,10 @@
 
                        // render the hidden field
                        AppendingStringBuffer buffer = new 
AppendingStringBuffer(
-                                       "<div style=\"display:none\"><input 
type=\"hidden\" name=\"").append(nameAndId)
-                                       .append("\" 
id=\"").append(nameAndId).append("\" />");
+                               "<div style=\"display:none\"><input 
type=\"hidden\" name=\"").append(nameAndId)
+                               .append("\" id=\"")
+                               .append(nameAndId)
+                               .append("\" />");
                        String method = getMethod().toLowerCase();
                        // if it's a get, did put the parameters in the action 
attribute,
                        // and have to write the url parameters as hidden fields
@@ -1528,7 +1627,7 @@
                                {
                                        String[] pair = params[j].split("=");
                                        buffer.append("<input type=\"hidden\" 
name=\"").append(pair[0]).append(
-                                                       "\" 
value=\"").append(pair.length > 1 ? pair[1] : "").append("\" />");
+                                               "\" 
value=\"").append(pair.length > 1 ? pair[1] : "").append("\" />");
                                }
                        }
                        buffer.append("</div>");
@@ -1596,9 +1695,9 @@
        }
 
        /**
-        * Update the model of all form components using the fields that were 
sent with the current
-        * request. This method only updates models when the Form.validate() is 
called first that takes
-        * care of the conversion for the FormComponents.
+        * Update the model of all components on this form and nested forms 
using the fields that were
+        * sent with the current request. This method only updates models when 
the Form.validate() is
+        * called first that takes care of the conversion for the 
FormComponents.
         * 
         * Normally this method will not be called when a validation error 
occurs in one of the form
         * components.
@@ -1607,12 +1706,49 @@
         */
        protected final void updateFormComponentModels()
        {
+               internalUpdateFormComponentModels();
+               updateNestedFormComponentModels();
+       }
+
+       /**
+        * Update the model of all components on nested forms.
+        * 
+        * @see #updateFormComponentModels()
+        */
+       private final void updateNestedFormComponentModels()
+       {
+               visitChildren(Form.class, new IVisitor()
+               {
+                       public Object component(Component component)
+                       {
+                               Form form = (Form)component;
+                               if (form.isEnabled() && form.isEnableAllowed() 
&& form.isVisibleInHierarchy())
+                               {
+                                       
form.internalUpdateFormComponentModels();
+                                       return CONTINUE_TRAVERSAL;
+                               }
+                               return CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+                       }
+               });
+       }
+
+       /**
+        * Update the model of all components on this form.
+        * 
+        * @see #updateFormComponentModels()
+        */
+       private void internalUpdateFormComponentModels()
+       {
                visitFormComponentsPostOrder(new ValidationVisitor()
                {
                        public void validate(FormComponent formComponent)
                        {
-                               // Potentially update the model
-                               formComponent.updateModel();
+                               Form form = formComponent.getForm();
+                               if (form == Form.this)
+                               {
+                                       // Potentially update the model
+                                       formComponent.updateModel();
+                               }
                        }
                });
        }
@@ -1628,8 +1764,13 @@
         */
        protected void validate()
        {
-               validateComponents();
-               validateFormValidators();
+               if (isEnabled() && isEnableAllowed() && isVisibleInHierarchy())
+               {
+                       // since this method can be called directly by users, 
this additional check is needed
+                       validateComponents();
+                       validateFormValidators();
+                       validateNestedForms();
+               }
        }
 
        /**
@@ -1637,11 +1778,16 @@
         */
        protected final void validateComponents()
        {
-               visitFormComponentsPostOrder(new ValidationVisitor()
+               visitFormComponents(new ValidationVisitor()
                {
                        public void validate(final FormComponent formComponent)
                        {
-                               formComponent.validate();
+                               final Form form = formComponent.getForm();
+                               if (form == Form.this && form.isEnabled() && 
form.isEnableAllowed() &&
+                                       form.isVisibleInHierarchy())
+                               {
+                                       formComponent.validate();
+                               }
                        }
                });
        }
@@ -1712,11 +1858,10 @@
                                {
                                        if (log.isWarnEnabled())
                                        {
-                                               log
-                                                               
.warn("IFormValidator in form `" +
-                                                                               
getPageRelativePath() +
-                                                                               
"` depends on a component that has been removed from the page or is no longer 
visible. " +
-                                                                               
"Offending component id `" + dependent.getId() + "`.");
+                                               log.warn("IFormValidator in 
form `" +
+                                                       getPageRelativePath() +
+                                                       "` depends on a 
component that has been removed from the page or is no longer visible. " +
+                                                       "Offending component id 
`" + dependent.getId() + "`.");
                                        }
                                        validate = false;
                                        break;
@@ -1740,20 +1885,27 @@
                {
                        validateFormValidator(formValidators_get(i));
                }
+       }
 
-               // traverse nested forms and invoke the form validators on them
+       /**
+        * Validates [EMAIL PROTECTED] FormComponent}s as well as [EMAIL 
PROTECTED] IFormValidator}s in nested [EMAIL PROTECTED] Form}s.
+        * 
+        * @see #validate()
+        */
+       private void validateNestedForms()
+       {
                visitChildren(Form.class, new IVisitor()
                {
                        public Object component(Component component)
                        {
                                final Form form = (Form)component;
-                               final int count = form.formValidators_size();
-                               for (int i = 0; i < count; i++)
+                               if (form.isEnabled() && form.isEnableAllowed() 
&& form.isVisibleInHierarchy())
                                {
-                                       
form.validateFormValidator(form.formValidators_get(i));
+                                       form.validateComponents();
+                                       form.validateFormValidators();
+                                       return CONTINUE_TRAVERSAL;
                                }
-
-                               return IVisitor.CONTINUE_TRAVERSAL;
+                               return CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
                        }
                });
        }

Modified: 
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java?rev=610593&r1=610592&r2=610593&view=diff
==============================================================================
--- 
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
 (original)
+++ 
wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
 Wed Jan  9 13:59:33 2008
@@ -33,6 +33,7 @@
 import org.apache.wicket.Page;
 import org.apache.wicket.WicketRuntimeException;
 import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.border.Border;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.util.convert.ConversionException;
 import org.apache.wicket.util.convert.IConverter;
@@ -75,8 +76,8 @@
  * @author Igor Vaynberg (ivaynberg)
  */
 public abstract class FormComponent extends LabeledWebMarkupContainer
-               implements
-                       IFormVisitorParticipant
+       implements
+               IFormVisitorParticipant
 {
        /**
         * Visitor for traversing form components
@@ -196,7 +197,8 @@
                public String substitute(String string, Map vars) throws 
IllegalStateException
                {
                        return new MapVariableInterpolator(string, 
addDefaultVars(vars), Application.get()
-                                       
.getResourceSettings().getThrowExceptionOnMissingResource()).toString();
+                               .getResourceSettings()
+                               
.getThrowExceptionOnMissingResource()).toString();
                }
 
                /**
@@ -354,19 +356,19 @@
         *            The visitor to call
         */
        public static final void visitFormComponentsPostOrder(Component 
component,
-                       final FormComponent.IVisitor visitor)
+               final FormComponent.IVisitor visitor)
        {
                if (visitor == null)
                {
                        throw new IllegalArgumentException("Argument `visitor` 
cannot be null");
                }
 
-
                visitFormComponentsPostOrderHelper(component, visitor);
        }
 
+
        private static final Object 
visitFormComponentsPostOrderHelper(Component component,
-                       final FormComponent.IVisitor visitor)
+               final FormComponent.IVisitor visitor)
        {
                if (component instanceof MarkupContainer)
                {
@@ -567,11 +569,32 @@
         */
        public Form getForm()
        {
-               // Look for parent form
-               final Form form = (Form)findParent(Form.class);
+               class FindFormVisitor implements Component.IVisitor
+               {
+                       Form form = null;
+
+                       public Object component(Component component)
+                       {
+                               form = (Form)component;
+                               return Component.IVisitor.STOP_TRAVERSAL;
+                       }
+               }
+
+               Form form = (Form)findParent(Form.class);
                if (form == null)
                {
-                       throw new WicketRuntimeException("Could not find Form 
parent for " + this);
+                       // check whether the form is a child of a surrounding 
border
+                       final Border border = (Border)findParent(Border.class);
+                       if (border != null)
+                       {
+                               FindFormVisitor formVisitor = new 
FindFormVisitor();
+                               border.visitChildren(Form.class, formVisitor);
+                               form = formVisitor.form;
+                       }
+                       if (form == null)
+                       {
+                               throw new WicketRuntimeException("Could not 
find Form parent for " + this);
+                       }
                }
                return form;
        }
@@ -627,6 +650,7 @@
         */
        public String getInputName()
        {
+               // TODO: keep this in sync with AbstractSubmitLink#getInputName
                String id = getId();
                final PrependingStringBuffer inputName = new 
PrependingStringBuffer(id.length());
                Component c = this;
@@ -930,7 +954,7 @@
                else
                {
                        throw new UnsupportedOperationException("FormComponent 
" + getClass() +
-                                       " does not support cookies");
+                               " does not support cookies");
                }
                return this;
        }
@@ -946,7 +970,7 @@
                if (!required && getType() != null && getType().isPrimitive())
                {
                        throw new WicketRuntimeException(
-                                       "FormComponent can't be not required 
when the type is primitive class: " + this);
+                               "FormComponent can't be not required when the 
type is primitive class: " + this);
                }
                if (required != isRequired())
                {
@@ -1222,8 +1246,8 @@
                catch (NumberFormatException e)
                {
                        throw new IllegalArgumentException(
-                                       exceptionMessage("Internal error.  
Request string '" + string +
-                                                       "' not a valid 
integer"));
+                               exceptionMessage("Internal error.  Request 
string '" + string +
+                                       "' not a valid integer"));
                }
        }
 
@@ -1247,7 +1271,7 @@
                        catch (NumberFormatException e)
                        {
                                throw new 
IllegalArgumentException(exceptionMessage("Request string '" + string +
-                                               "' is not a valid integer"));
+                                       "' is not a valid integer"));
                        }
                }
                else
@@ -1404,7 +1428,7 @@
                catch (Exception e)
                {
                        throw new WicketRuntimeException("Exception '" + e + "' 
occurred during validation " +
-                                       validator.getClass().getName() + " on 
component " + getPath(), e);
+                               validator.getClass().getName() + " on component 
" + getPath(), e);
                }
        }
 

Added: 
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/FormSubmitTest.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/FormSubmitTest.java?rev=610593&view=auto
==============================================================================
--- 
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/FormSubmitTest.java
 (added)
+++ 
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/FormSubmitTest.java
 Wed Jan  9 13:59:33 2008
@@ -0,0 +1,265 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.markup.html.form;
+
+import org.apache.wicket.Page;
+import org.apache.wicket.WicketTestCase;
+import org.apache.wicket.markup.html.form.NestedFormsPage.NestableForm;
+import org.apache.wicket.util.tester.FormTester;
+
+/**
+ * @see <a 
href="http://cwiki.apache.org/WICKET/nested-forms.html";>"Specification"</a> of 
nested
+ *      forms handling
+ * @author Gerolf Seitz
+ */
+public class FormSubmitTest extends WicketTestCase
+{
+
+       private Page page;
+       private NestableForm outerForm;
+       private NestableForm middleForm;
+       private NestableForm innerForm;
+
+       protected void setUp() throws Exception
+       {
+               super.setUp();
+               tester.startPage(new NestedFormsPage());
+               page = tester.getLastRenderedPage();
+               outerForm = (NestableForm)page.get("outerForm");
+               middleForm = (NestableForm)page.get("outerForm:middleForm");
+               innerForm = 
(NestableForm)page.get("outerForm:middleForm:innerForm");
+       }
+
+
+       /**
+        * 
+        */
+       public void testAllFormsEnabledSubmitOuterForm()
+       {
+               assertEnabledState(true, true, true);
+
+               FormTester formTester = tester.newFormTester("outerForm");
+               formTester.submit("submit");
+
+               assertOnSubmitCalled(true, true, true);
+               assertOnErrorCalled(false, false, false);
+       }
+
+       /**
+        * 
+        */
+       public void testAllFormsEnabledSubmitMiddleForm()
+       {
+               assertEnabledState(true, true, true);
+
+               FormTester formTester = 
tester.newFormTester("outerForm:middleForm");
+               formTester.submit("submit");
+
+               assertOnSubmitCalled(false, true, true);
+               assertOnErrorCalled(false, false, false);
+       }
+
+       /**
+        * 
+        */
+       public void testAllFormsEnabledSubmitInnerForm()
+       {
+               assertEnabledState(true, true, true);
+
+               FormTester formTester = 
tester.newFormTester("outerForm:middleForm:innerForm");
+               formTester.submit("submit");
+
+               assertOnSubmitCalled(false, false, true);
+               assertOnErrorCalled(false, false, false);
+       }
+
+
+       /**
+        * 
+        */
+       public void testMiddleFormDisabledSubmitOuterForm()
+       {
+               // disable middle form
+               middleForm.setEnabled(false);
+               assertEnabledState(true, false, true);
+
+               // submit outer form
+               FormTester formTester = tester.newFormTester("outerForm");
+               formTester.submit("submit");
+
+               assertOnSubmitCalled(true, false, false);
+               assertOnErrorCalled(false, false, false);
+       }
+
+       /**
+        * 
+        */
+       public void testInnerFormDisabledSubmitOuterForm()
+       {
+               // disable middle form
+               innerForm.setEnabled(false);
+               assertEnabledState(true, true, false);
+
+               // submit outer form
+               FormTester formTester = tester.newFormTester("outerForm");
+               formTester.submit("submit");
+
+               assertOnSubmitCalled(true, true, false);
+               assertOnErrorCalled(false, false, false);
+       }
+
+       /**
+        * 
+        */
+       public void testSubmitDisabledOuterForm()
+       {
+               outerForm.setEnabled(false);
+               assertEnabledState(false, true, true);
+
+               FormTester formTester = tester.newFormTester("outerForm");
+               formTester.submit("submit");
+
+               assertOnSubmitCalled(false, false, false);
+               assertOnErrorCalled(false, false, false);
+       }
+
+       /**
+        * 
+        */
+       public void testErrorOnInnerFormSubmitOuterForm()
+       {
+               assertEnabledState(true, true, true);
+
+               causeValidationErrorAndSubmit("outerForm", 
"middleForm:innerForm:first");
+
+               assertOnSubmitCalled(false, false, false);
+               assertOnErrorCalled(true, true, true);
+       }
+
+       /**
+        * 
+        */
+       public void testErrorOnMiddleFormSubmitOuterForm()
+       {
+               assertEnabledState(true, true, true);
+
+               causeValidationErrorAndSubmit("outerForm", "middleForm:first");
+
+               assertOnSubmitCalled(false, false, false);
+               assertOnErrorCalled(true, true, false);
+       }
+
+       /**
+        * 
+        */
+       public void testErrorOnMiddleFormSubmitMiddleForm()
+       {
+               assertEnabledState(true, true, true);
+
+               causeValidationErrorAndSubmit("outerForm:middleForm", "first");
+
+               assertOnSubmitCalled(false, false, false);
+               assertOnErrorCalled(false, true, false);
+       }
+
+       /**
+        * 
+        */
+       public void testErrorOnInnerFormSubmitMiddleForm()
+       {
+               assertEnabledState(true, true, true);
+
+               causeValidationErrorAndSubmit("outerForm:middleForm", 
"innerForm:first");
+
+               assertOnSubmitCalled(false, false, false);
+               assertOnErrorCalled(false, true, true);
+       }
+
+       /**
+        * 
+        */
+       public void testMiddleFormDisabledErrorOnOuterFormSubmitOuterForm()
+       {
+               middleForm.setEnabled(false);
+               assertEnabledState(true, false, true);
+
+               causeValidationErrorAndSubmit("outerForm", "first");
+
+               assertOnSubmitCalled(false, false, false);
+               assertOnErrorCalled(true, false, false);
+       }
+
+       /**
+        * 
+        */
+       public void testErrorOnInnerFormDisabledMiddleFormSubmitOuterForm()
+       {
+               middleForm.setEnabled(false);
+               assertEnabledState(true, false, true);
+
+               causeValidationErrorAndSubmit("outerForm", 
"middleForm:innerForm:first");
+
+               assertOnSubmitCalled(true, false, false);
+               assertOnErrorCalled(false, false, false);
+       }
+
+
+       private void assertEnabledState(boolean isOuterFormEnabled, boolean 
isMiddleFormEnabled,
+               boolean isInnerFormEnabled)
+       {
+               assertEquals(isOuterFormEnabled, outerForm.isEnabled());
+               assertEquals(isMiddleFormEnabled, middleForm.isEnabled());
+               assertEquals(isInnerFormEnabled, innerForm.isEnabled());
+       }
+
+
+       private void assertOnErrorCalled(boolean isOuterFormOnErrorCalled,
+               boolean isMiddleFormOnErrorCalled, boolean 
isInnerFormOnErrorCalled)
+       {
+               assertEquals(isOuterFormOnErrorCalled, outerForm.onErrorCalled);
+               assertEquals(isMiddleFormOnErrorCalled, 
middleForm.onErrorCalled);
+               assertEquals(isInnerFormOnErrorCalled, innerForm.onErrorCalled);
+       }
+
+
+       private void assertOnSubmitCalled(boolean isOuterFormOnSubmitCalled,
+               boolean isMiddleFormOnSubmitCalled, boolean 
isInnerFormOnSubmitCalled)
+       {
+               assertEquals(isOuterFormOnSubmitCalled, 
outerForm.onSubmitCalled);
+               assertEquals(isMiddleFormOnSubmitCalled, 
middleForm.onSubmitCalled);
+               assertEquals(isInnerFormOnSubmitCalled, 
innerForm.onSubmitCalled);
+       }
+
+
+       /**
+        * @param formToBeSubmitted
+        *            absolute path of the form to be submitted
+        * @param componentToGetError
+        *            relative path to <code>formToBeSumitted</code> of the 
component to be changed
+        * @return a [EMAIL PROTECTED] FormTester} instance
+        */
+       private FormTester causeValidationErrorAndSubmit(String 
formToBeSubmitted,
+               String componentToGetError)
+       {
+               FormTester formTester;
+               formTester = tester.newFormTester(formToBeSubmitted);
+               formTester.setValue(componentToGetError, "");
+               formTester.submit("submit");
+               return formTester;
+       }
+
+}

Propchange: 
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/FormSubmitTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.html
URL: 
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.html?rev=610593&view=auto
==============================================================================
--- 
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.html
 (added)
+++ 
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.html
 Wed Jan  9 13:59:33 2008
@@ -0,0 +1,55 @@
+<html>
+<head>
+       <style>
+               form, div { 
+                       border: 1px solid black;
+                       padding: 20px;
+                       margin: 20px;
+               }
+       </style>
+</head>
+<body>
+       <div wicket:id="feedback"></div>
+       <!-- <a wicket:id="ajaxToggleOuter">ajax enable/disable 
outerForm</a><br/>
+       <a wicket:id="toggleOuter">enable/disable outerForm</a>
+       <form wicket:id="outerForm">
+               <a wicket:id="ajaxToggleInner">ajax enable/disable 
innerForm</a><br/>
+               <a wicket:id="toggleInner">enable/disable innerForm</a>
+               <a wicket:id="ajaxSubmit">submit outerForm</a><br/>
+               <input type="submit" wicket:id="submit"/>
+               <p>
+                       <form wicket:id="innerForm">
+                               <input type="text" wicket:id="first"/>
+                               <input type="text" wicket:id="second"/>
+                               <a wicket:id="ajaxSubmit">submit 
innerForm</a><br/>
+                               <input type="submit" wicket:id="submit"/>
+                       </form>
+               </p>
+       </form>
+       -->
+       
+       <form wicket:id="outerForm">
+               <input type="text" wicket:id="first"/>
+               <input type="text" wicket:id="second"/><br/>
+               <a wicket:id="ajaxSubmit">submit via ajax</a><br/>
+               <a wicket:id="toggle">[toggle]</a><br/>
+               <input type="button" wicket:id="submit"/>
+               
+               <form wicket:id="middleForm">
+                       <input type="text" wicket:id="first"/>
+                       <input type="text" wicket:id="second"/><br/>
+                       <a wicket:id="ajaxSubmit">submit via ajax</a><br/>
+                       <a wicket:id="toggle">[toggle]</a><br/>
+                       <input type="button" wicket:id="submit"/>
+               
+                       <form wicket:id="innerForm">
+                               <input type="text" wicket:id="first"/>
+                               <input type="text" wicket:id="second"/><br/>
+                               <a wicket:id="ajaxSubmit">submit via 
ajax</a><br/>
+                               <a wicket:id="toggle">[toggle]</a><br/>
+                               <input type="button" wicket:id="submit"/>
+                       </form>
+               </form>
+       </form>
+</body>
+</html>
\ No newline at end of file

Propchange: 
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.html
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.java?rev=610593&view=auto
==============================================================================
--- 
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.java
 (added)
+++ 
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.java
 Wed Jan  9 13:59:33 2008
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.markup.html.form;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.MarkupStream;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.html.form.validation.EqualInputValidator;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.FeedbackPanel;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Gerolf Seitz
+ */
+public class NestedFormsPage extends WebPage
+{
+       private static final long serialVersionUID = 1L;
+       static Logger logger = LoggerFactory.getLogger(NestedFormsPage.class);
+
+       private final FeedbackPanel feedback;
+
+       /**
+        * Construct.
+        */
+       public NestedFormsPage()
+       {
+               feedback = new FeedbackPanel("feedback");
+               add(feedback.setOutputMarkupId(true));
+
+               Form outerForm = new NestableForm("outerForm");
+               add(outerForm.setOutputMarkupId(true));
+
+               Form middleForm = new NestableForm("middleForm");
+               outerForm.add(middleForm.setOutputMarkupId(true));
+
+               Form innerForm = new NestableForm("innerForm");
+               middleForm.add(innerForm.setOutputMarkupId(true));
+       }
+
+       public class NestableForm extends Form
+       {
+               private static final long serialVersionUID = 1L;
+
+               private final String first = "test";
+
+               private final String second = "test";
+
+               public boolean onSubmitCalled = false;
+
+               public boolean onErrorCalled = false;
+
+               public NestableForm(String id)
+               {
+                       super(id);
+                       setModel(new CompoundPropertyModel(this));
+
+                       TextField firstField = new RequiredTextField("first");
+                       TextField secondField = new TextField("second");
+                       add(firstField);
+                       add(secondField);
+
+                       add(new EqualInputValidator(firstField, secondField));
+                       add(new AjaxSubmitLink("ajaxSubmit", this)
+                       {
+                               private static final long serialVersionUID = 1L;
+
+                               protected void onSubmit(AjaxRequestTarget 
target, Form form)
+                               {
+                                       target.addComponent(feedback);
+                               }
+
+                               protected void onError(AjaxRequestTarget 
target, Form form)
+                               {
+                                       target.addComponent(feedback);
+                               }
+                       });
+                       add(new ToggleLink("toggle", this));
+                       add(new SubmitLink("submit"));
+               }
+
+               protected void onSubmit()
+               {
+                       super.onSubmit();
+                       onSubmitCalled = true;
+                       logger.info(getId() + ".onSubmit");
+               }
+
+               protected void onError()
+               {
+                       super.onError();
+                       onErrorCalled = true;
+                       logger.info(getId() + ".onError");
+               }
+       }
+
+       private class ToggleLink extends Link
+       {
+               private static final long serialVersionUID = 1L;
+
+               private final Form form;
+
+               public ToggleLink(String id, Form form)
+               {
+                       super(id);
+                       this.form = form;
+               }
+
+               public void onClick()
+               {
+                       form.setEnabled(!form.isEnabled());
+                       form.info(form.getId() + ".isEnabled() == " + 
form.isEnabled());
+               }
+
+               protected void onComponentTagBody(MarkupStream markupStream, 
ComponentTag openTag)
+               {
+                       String state = form.isEnabled() ? "enabled" : 
"disabled";
+                       replaceComponentTagBody(markupStream, openTag, "form is 
" + state);
+               }
+       }
+
+}

Propchange: 
wicket/trunk/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/form/NestedFormsPage.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain


Reply via email to