cvs commit: jakarta-tapestry/framework/src/test/org/apache/tapestry/junit/form TestLabeledPropertySelectionModel.java TestListEditMap.java

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

cvs commit: jakarta-tapestry/framework/src/test/org/apache/tapestry/junit/form TestLabeledPropertySelectionModel.java TestListEditMap.java

hlship
hlship      2005/05/09 07:45:17

  Modified:    .        status.xml
               framework/src/java/org/apache/tapestry/form ImageSubmit.jwc
                        Submit.jwc FormSupportImpl.java Form.java
                        ImageSubmit.java Submit.java
               framework/src/documentation/content/xdocs/tapestry/ComponentReference
                        ImageSubmit.xml Submit.xml
               framework/src/test/org/apache/tapestry/describe
                        BaseDescribeTestCase.java
               framework/src/test/org/apache/tapestry/form MockForm.java
                        TestFormSupport.java
               framework/src/test/org/apache/tapestry/valid
                        BaseValidatorTestCase.java
               src/documentation/content/xdocs links.ent
               framework/src/test/org/apache/tapestry/binding
                        BindingTestCase.java
               framework/src/test/org/apache/tapestry/components
                        BaseComponentTestCase.java
               framework/src/java/org/apache/tapestry FormBehavior.java
               framework/src/test/org/apache/tapestry/junit
                        TapestryTestCase.java
               framework/src/test/org/apache/tapestry/web
                        BaseWebTestCase.java
               portlet/src/test/org/apache/tapestry/portlet
                        BasePortletWebTestCase.java
               framework/src/test/org/apache/tapestry/resolver
                        AbstractSpecificationResolverTestCase.java
  Added:       framework/src/test/org/apache/tapestry/form
                        BaseFormComponentTest.java TestImageSubmit.java
                        TestSubmit.java TestListEditMap.java
                        TestLabeledPropertySelectionModel.java
  Removed:     doc/src/ComponentReference ImageSubmit.html Submit.html
               framework/src/test/org/apache/tapestry/junit/form
                        TestLabeledPropertySelectionModel.java
                        TestListEditMap.java
  Log:
  TAPESTRY-166: Allow Submits to defer invoking their listener
 
  Revision  Changes    Path
  1.98      +1 -0      jakarta-tapestry/status.xml
 
  Index: status.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/status.xml,v
  retrieving revision 1.97
  retrieving revision 1.98
  diff -u -r1.97 -r1.98
  --- status.xml 8 May 2005 00:29:54 -0000 1.97
  +++ status.xml 9 May 2005 14:45:14 -0000 1.98
  @@ -55,6 +55,7 @@
       <release version="4.0-alpha-3-snapshot" date="unrelease">
         <action type="add" dev="HLS">Add initial support for the validator: binding prefix.</action>
         <action type="add" dev="PF" fixes-bug="TAPESTRY-317">Fixed workbench build script so that generated war file will include the required ognl jar.</action>
  +      <action type="fix" dev="HLS" fixes-bug="TAPESTRY-166">Allow Submits to defer invoking their listener.</action>
       </release>
       <release version="4.0-alpha-2" date="May 5 2005">
         <action type="update" dev="HLS"> Coordinate Locale changes with the hivemind.ThreadLocale service. </action>
 
 
 
  1.6       +9 -0      jakarta-tapestry/framework/src/java/org/apache/tapestry/form/ImageSubmit.jwc
 
  Index: ImageSubmit.jwc
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/form/ImageSubmit.jwc,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- ImageSubmit.jwc 18 Apr 2005 17:06:41 -0000 1.5
  +++ ImageSubmit.jwc 9 May 2005 14:45:15 -0000 1.6
  @@ -61,6 +61,15 @@
      </description>
     </parameter>
     
  +  <parameter name="defer" default-binding="ognl" default-value="true">
  +      <description>
  +          If true (the default), then the listener (if any)
  +          is not notified until just before the form's listener,
  +          after all components enclosed by the Form have had
  +          a chance to update properties.
  +       </description>
  +  </parameter>
  +  
     <reserved-parameter name="type"/>
     <reserved-parameter name="src"/>
     <reserved-parameter name="border"/>
 
 
 
  1.6       +29 -4     jakarta-tapestry/framework/src/java/org/apache/tapestry/form/Submit.jwc
 
  Index: Submit.jwc
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/form/Submit.jwc,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- Submit.jwc 18 Apr 2005 17:06:41 -0000 1.5
  +++ Submit.jwc 9 May 2005 14:45:15 -0000 1.6
  @@ -26,10 +26,35 @@
     </description>
   
     <parameter name="label" default-binding="literal"/>
  -  <parameter name="disabled" default-binding="ognl"/>
  -  <parameter name="selected" default-binding="ognl"/>
  -  <parameter name="tag" default-binding="ognl"/>
  -  <parameter name="listener" default-binding="listener"/>
  +  <parameter name="disabled" default-binding="ognl">
  +      <description>
  +          If true, then the component is disabled, which will be reflected in the
  +          output submit element. Additionally, the component will not respond
  +          during the form submission.
  +      </description>
  +  </parameter>
  +  <parameter name="selected" default-binding="ognl">
  +      <description>
  +          If bound, then this parameter will be updated with the value of the
  +          tag parameter, if the Submit is triggered.
  +       </description>
  +  </parameter>
  +  <parameter name="tag" default-binding="ognl">
  +      <description>
  +          A tag value used to identify this Submit as the triggered component.
  +      </description>
  +  <parameter>
  +  <parameter name="listener" default-binding="listener">
  +      <description>
  +          A listener that is notified if this component is triggered.
  +      </description>
  +  </parameter>
  +  <parameter name="defer" default-binding="ognl" default-value="true">
  +      <description>
  +          If true (the default), then any listener notification is deferred
  +          until just before the form's listener is invoked.
  +      </description>
  +  </parameter>
     
     <reserved-parameter name="name"/>
     <reserved-parameter name="type"/>
 
 
 
  1.4       +24 -0     jakarta-tapestry/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java
 
  Index: FormSupportImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- FormSupportImpl.java 3 May 2005 17:41:27 -0000 1.3
  +++ FormSupportImpl.java 9 May 2005 14:45:15 -0000 1.4
  @@ -100,6 +100,8 @@
   
       private String _encodingType;
   
  +    private final List _deferredRunnables = new ArrayList();
  +
       /**
        * Map keyed on extended component id, value is the pre-rendered markup for that component.
        */
  @@ -445,6 +447,8 @@
   
           _form.renderBody(nested, _cycle);
   
  +        runDeferredRunnables();
  +        
           writeTag(_writer, method, link.getURL(null, false));
   
           _writer.attribute("name", _form.getName());
  @@ -493,6 +497,19 @@
               throw new StaleLinkException(FormMessages.formTooFewIds(_form, expected
                       - _allocatedIdIndex, nextExpectedId), _form);
           }
  +
  +        runDeferredRunnables();
  +    }
  +
  +    private void runDeferredRunnables()
  +    {
  +        Iterator i = _deferredRunnables.iterator();
  +        while (i.hasNext())
  +        {
  +            Runnable r = (Runnable) i.next();
  +
  +            r.run();
  +        }
       }
   
       public void setEncodingType(String encodingType)
  @@ -596,4 +613,11 @@
   
           return true;
       }
  +
  +    public void addDeferredRunnable(Runnable runnable)
  +    {
  +        Defense.notNull(runnable, "runnable");
  +
  +        _deferredRunnables.add(runnable);
  +    }
   }
  \ No newline at end of file
 
 
 
  1.17      +7 -0      jakarta-tapestry/framework/src/java/org/apache/tapestry/form/Form.java
 
  Index: Form.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/form/Form.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- Form.java 3 May 2005 17:41:27 -0000 1.16
  +++ Form.java 9 May 2005 14:45:15 -0000 1.17
  @@ -382,4 +382,11 @@
       {
           return _formSupport.wasPrerendered(writer, field);
       }
  +
  +    /** @since 4.0 */
  +
  +    public void addDeferredRunnable(Runnable runnable)
  +    {
  +        _formSupport.addDeferredRunnable(runnable);
  +    }
   }
  \ No newline at end of file
 
 
 
  1.8       +29 -43    jakarta-tapestry/framework/src/java/org/apache/tapestry/form/ImageSubmit.java
 
  Index: ImageSubmit.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/form/ImageSubmit.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- ImageSubmit.java 3 May 2005 17:41:27 -0000 1.7
  +++ ImageSubmit.java 9 May 2005 14:45:15 -0000 1.8
  @@ -16,9 +16,7 @@
   
   import java.awt.Point;
   
  -import org.apache.tapestry.IActionListener;
   import org.apache.tapestry.IAsset;
  -import org.apache.tapestry.IBinding;
   import org.apache.tapestry.IForm;
   import org.apache.tapestry.IMarkupWriter;
   import org.apache.tapestry.IRequestCycle;
  @@ -34,7 +32,7 @@
    * @author Howard Lewis Ship
    */
   
  -public abstract class ImageSubmit extends AbstractFormComponent
  +public abstract class ImageSubmit extends Submit
   {
       protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
       {
  @@ -51,6 +49,8 @@
                   this,
                   nameOverride);
   
  +        setName(name);
  +
           if (rewinding)
           {
               // If disabled, do nothing.
  @@ -65,41 +65,8 @@
   
               String value = cycle.getParameter(parameterName);
   
  -            if (value == null)
  -                return;
  -
  -            // The point parameter is not really used, unless the
  -            // ImageButton is used for its original purpose (as a kind
  -            // of image map). In modern usage, we only care about
  -            // whether the user clicked on the image (and thus submitted
  -            // the form), not where in the image the user actually clicked.
  -
  -            IBinding pointBinding = getBinding("point");
  -
  -            if (pointBinding != null)
  -            {
  -                int x = Integer.parseInt(value);
  -
  -                parameterName = name + ".y";
  -                value = cycle.getParameter(parameterName);
  -
  -                int y = Integer.parseInt(value);
  -
  -                pointBinding.setObject(new Point(x, y));
  -            }
  -
  -            // Notify the application, by setting the select parameter
  -            // to the tag parameter.
  -
  -            IBinding selectedBinding = getBinding("selected");
  -
  -            if (selectedBinding != null)
  -                selectedBinding.setObject(getTag());
  -
  -            IActionListener listener = getListener();
  -
  -            if (listener != null)
  -                listener.actionTriggered(this, cycle);
  +            if (value != null)
  +                handleClick(cycle, form);
   
               return;
           }
  @@ -132,18 +99,37 @@
           writer.closeTag();
       }
   
  -    public abstract boolean isDisabled();
  +    void handleClick(IRequestCycle cycle, IForm form)
  +    {
  +        // The point parameter is not really used, unless the
  +        // ImageButton is used for its original purpose (as a kind
  +        // of image map). In modern usage, we only care about
  +        // whether the user clicked on the image (and thus submitted
  +        // the form), not where in the image the user actually clicked.
   
  -    public abstract IAsset getDisabledImage();
  +        if (isParameterBound("point"))
  +        {
  +            int x = Integer.parseInt(cycle.getParameter(getName() + ".x"));
  +            int y = Integer.parseInt(cycle.getParameter(getName() + ".y"));
   
  -    public abstract IAsset getImage();
  +            setPoint(new Point(x, y));
  +        }
   
  -    public abstract IActionListener getListener();
  +        super.handleClick(cycle, form);
  +    }
   
  -    public abstract Object getTag();
  +    /** parameter */
  +    public abstract IAsset getDisabledImage();
   
  +    /** parameter */
  +    public abstract IAsset getImage();
  +
  +    /** parameter */
       public abstract String getNameOverride();
   
  +    /** parameter */
  +    public abstract void setPoint(Point point);
  +
       protected void prepareForRender(IRequestCycle cycle)
       {
           super.prepareForRender(cycle);
 
 
 
  1.7       +43 -11    jakarta-tapestry/framework/src/java/org/apache/tapestry/form/Submit.java
 
  Index: Submit.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/form/Submit.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- Submit.java 3 May 2005 17:41:27 -0000 1.6
  +++ Submit.java 9 May 2005 14:45:15 -0000 1.7
  @@ -15,7 +15,6 @@
   package org.apache.tapestry.form;
   
   import org.apache.tapestry.IActionListener;
  -import org.apache.tapestry.IBinding;
   import org.apache.tapestry.IForm;
   import org.apache.tapestry.IMarkupWriter;
   import org.apache.tapestry.IRequestCycle;
  @@ -36,7 +35,6 @@
   
       protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
       {
  -
           IForm form = getForm(cycle);
   
           if (form.wasPrerendered(writer, this))
  @@ -46,6 +44,8 @@
   
           String name = form.getElementId(this);
   
  +        setName(name);
  +
           if (rewinding)
           {
               // Don't bother doing anything if disabled.
  @@ -66,15 +66,7 @@
               if (value == null)
                   return;
   
  -            IBinding selectedBinding = getBinding("selected");
  -
  -            if (selectedBinding != null)
  -                selectedBinding.setObject(getTag());
  -
  -            IActionListener listener = getListener();
  -
  -            if (listener != null)
  -                listener.actionTriggered(this, cycle);
  +            handleClick(cycle, form);
   
               return;
           }
  @@ -96,12 +88,52 @@
           writer.closeTag();
       }
   
  +    void handleClick(final IRequestCycle cycle, IForm form)
  +    {
  +        if (isParameterBound("selected"))
  +            setSelected(getTag());
  +
  +        final IActionListener listener = getListener();
  +
  +        if (listener == null)
  +            return;
  +
  +        // Have a listener; notify it now, or defer for later?
  +
  +        Runnable notify = new Runnable()
  +        {
  +            public void run()
  +            {
  +                listener.actionTriggered(Submit.this, cycle);
  +            }
  +        };
  +
  +        if (getDefer())
  +            form.addDeferredRunnable(notify);
  +        else
  +            notify.run();
  +    }
  +
  +    /** parameter */
  +
       public abstract String getLabel();
   
  +    /** parameter */
  +
       public abstract boolean isDisabled();
   
  +    /** parameter */
  +
       public abstract IActionListener getListener();
   
  +    /** parameter */
  +
       public abstract Object getTag();
   
  +    /** parameter */
  +
  +    public abstract void setSelected(Object tag);
  +
  +    /** parameter */
  +    public abstract boolean getDefer();
   }
  \ No newline at end of file
 
 
 
  1.3       +170 -5    jakarta-tapestry/framework/src/documentation/content/xdocs/tapestry/ComponentReference/ImageSubmit.xml
 
  Index: ImageSubmit.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/documentation/content/xdocs/tapestry/ComponentReference/ImageSubmit.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ImageSubmit.xml 6 Jan 2005 02:17:15 -0000 1.2
  +++ ImageSubmit.xml 9 May 2005 14:45:15 -0000 1.3
  @@ -28,11 +28,14 @@
     
     <body>
   
  -<p> <strong>THIS PAGE UNDER CONSTRUCTION</strong>
  +<p> A component that generates a clickable image that will cause the enclosing form to submit.  The &lt;input type="image"&gt; form element
  +  was originally designed for use as a way to select a pixel within an image that was presumable a map; it has been co-opted by web applications
  +  as a way to decorate a form submit button using a custom image instead of ordinary clickable buttons.  This component is simply an enhanced version of the &Submit; component that will display an image
  +  instead of a text label.
   </p>
   
   <p>
  -  <strong>See also:</strong>
  +  <strong>See also: &Form;, &Submit;</strong>
   </p>
   
   <section>
  @@ -45,21 +48,140 @@
     <th>Direction</th>
       <th>Required</th>
       <th>Default</th>
  +    <th>Default Binding</th>
       <th>Description</th>
     </tr>
   
  +  <tr>
  +    <td>image</td>
  +    <td>&IAsset;</td>
  +    <td>in</td>
  +    <td>yes</td>
  +    <td>&nbsp;</td>
  +    <td>asset</td>
  +    <td>
  +      The normal image to display for the button.
  +    </td>
  +  </tr>
  +  
  +  <tr>
  +    <td>name</td>
  +    <td>String</td>
  +    <td>in</td>
  +    <td>no</td>
  +    <td>&nbsp;</td>
  +    <td>literal</td>
  +    <td>
  +      Overrides the default mechanism for selecting the form element id; this allows the name attribute of the rendered
  +      &lt;input&gt; tag to be controlled, which is necessary is some browsers to control the tooltip help message for the
  +      control.
  +    </td>
  +  </tr>
  +
  +  <tr>
  +  <td>disabled</td>
  +  <td>boolean</td>
  +    <td>in</td>
  +    <td>no</td>
  +  <td>false</td>
  +    <td>ognl</td>
  +    <td>
  +    If set to true, the button will be disabled (will not respond to
  +    the mouse); the browser should provide a "greyed out" appearance.
  +    </td>
  +   </tr>
  +      
  +  <tr>
  +    <td>disabledImage</td>
  +    <td>&IAsset;</td>
  +    <td>in</td>
  +    <td>no</td>
  +    <td>&nbsp;</td>
  +    <td>asset</td>
  +    <td>
  +      If specified, and if the component is disabled, then this image is used rather than the normal image
  +      parameter. This allows an alternate image to be used to indicate to the user that the option is not available.
  +    </td>
  +  </tr>    
  +  
  +  <tr>
  +    <td>point</td>
  +    <td>java.awt.Point</td>
  +    <td>out</td>
  +    <td>no</td>
  +    <td>&nbsp;</td>
  +    <td>ognl</td>
  +    <td>
  +      Set to the coordinates of the clicked point within the image.
  +    </td>
  +  </tr>
  +  
  +  <tr>
  +    <td>selected</td>
  +    <td>Object</td>
  +    <td>out</td>
  +    <td>no</td>
  +    <td>&nbsp;</td>
  +    <td>ognl</td>
  +    <td>
  +    This parameter is bound to a property that is updated when the submit
  +    button is clicked by the user. The property is updated to match the tag
  +    parameter.
  +    </td>
  +   </tr>    
  +  <tr>
  +    <td>tag</td>
  +    <td>Object</td>
  +    <td>in</td>
  +    <td>no</td>
  +    <td>&nbsp;</td>
  +    <td>ognl</td>
  +    <td>
  +    Tag used with the selected parameter to indicate which Submit button
  +    on a form was clicked.
  +    </td>
  +   </tr>    
  +  
  + <tr>
  + <td>listener</td>
  + <td>
  +    &IActionListener;
  +    </td>
  + <td>in</td>
  + <td>no</td>
  + <td>&nbsp;</td>
  +    <td>listener</td>
  + <td>
  +    An optional listener (typically specified as the name of a listener method), notified
  +    when the Submit is triggered.
  + </td>
  +   </tr>  
  +   <tr>
  +    <td>defer</td>
  +    <td>boolean</td>
  +    <td>in</td>
  +    <td>no</td>
  +    <td>true</td>
  +    <td>ognl</td>
  +    <td>
  +      If true (the default), then the listener (if any) will not
  +      be notified immediately but will be notified just
  +      before the enclosing &Form;'s listener.
  +    </td>
  +   </tr>
  +  
    </table>
     
   <p>
  -  Body: <strong>removed / allowed</strong>
  +  Body: <strong>removed</strong>
   </p>  
   
   <p>
  -  Informal parameters: <strong>allowed  / forbidden</strong>
  +  Informal parameters: <strong>allowed</strong>
   </p>
   
   <p>
  -  Reserved parameters: <em>none</em>
  +  Reserved parameters: <em>type, src, border</em>
   </p>
   
   </section>
  @@ -67,6 +189,49 @@
   <section>
     <title>Examples</title>
   
  +<p>
  +HTML template:
  +</p>
  +
  +<source><![CDATA[
  +<form jwcid="form@Form" listener="doSubmit">
  +<table>
  +  <tr>
  +    <th>User name:</th>
  +    <td><input jwcid="userName@TextField" value="userName" size="12"/></td>
  +  </tr>
  +  <tr>
  +    <th>Password:</th>
  +    <td><input jwcid="password@TextField" value="password" hidden="true" size="12"/></td>
  +  </tr>
  +  <tr>
  +    <td colspan="2">
  +      <input type="image" src="images/login.png"/>
  +      <input type="image" jwcid="help@ImageSubmit" listener="doHelp" image="help/>
  +    </td>
  +  </tr>
  +</table>
  +</form>]]></source>
  +
  +<p>
  +Page specification:
  +</p>
  +
  +<source><![CDATA[
  +
  +. . .
  +
  +  <asset name="help" path="images/help.png"/>
  +
  +. . .
  +
  +]]></source>
  +
  +
  +<p>
  +This is a variation of the example for the &Submit; component; it uses images instead of ordinary clickable buttons for the
  +help and login actions.
  +</p>
   </section>
   </body>
   </document>
  \ No newline at end of file
 
 
 
  1.3       +133 -6    jakarta-tapestry/framework/src/documentation/content/xdocs/tapestry/ComponentReference/Submit.xml
 
  Index: Submit.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/documentation/content/xdocs/tapestry/ComponentReference/Submit.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Submit.xml 6 Jan 2005 02:17:15 -0000 1.2
  +++ Submit.xml 9 May 2005 14:45:15 -0000 1.3
  @@ -28,11 +28,34 @@
     
     <body>
   
  -<p> <strong>THIS PAGE UNDER CONSTRUCTION</strong>
  +<p>Provides an HTML form submission element, &lt;input type="submit"&gt;.  The
  +  Submit component must be enclosed by a &Form; component.  A Submit
  +  component is used when a single form has multiple form submission buttons,
  +  and the application needs to know which one is the trigger for the
  +  form submission.</p>
  +
  +<p>
  +The application can use two techniques to determine which
  +Submit component (if any) caused the form to be submitted:
   </p>
   
  +<ul>
  +  <li>A property may be set to some value; this uses the selected and
  +  tag parameters.</li>
  +  <li>A listener may be notified.</li>
  +</ul>
  +  
   <p>
  -  <strong>See also:</strong>
  +It is even possible to combine the two, in which case the property is set first,
  +then the listener is notified.  The listener may be notified immediately
  +(i.e., in the middle of processing the form submission), but by default,
  +the listener will be notified later, just before the form's listener (if any)
  +is notified.
  +</p>
  +  
  +
  +<p>
  +  <strong>See also: &Form;, &ImageSubmit;</strong>
   </p>
   
   <section>
  @@ -45,27 +68,131 @@
     <th>Direction</th>
       <th>Required</th>
       <th>Default</th>
  +    <th>Default Binding</th>
       <th>Description</th>
     </tr>
   
  +   <tr>
  + <td>label</td>
  + <td>String</td>
  + <td>in</td>
  + <td>no</td>
  + <td>&nbsp;</td>
  +    <td>literal</td>
  + <td>The label put on the button (this becomes the HTML value attribute). Alternately,
  +      the value attribute may simply be specified as an informal parameter.
  + </td>
  + </tr>
  +  
  +  <tr>
  +  <td>disabled</td>
  +  <td>boolean</td>
  +    <td>in</td>
  +    <td>no</td>
  +  <td>false</td>
  +    <td>ognl</td>
  +    <td>
  +    If set to true, the button will be disabled (will not respond to
  +    the mouse); the browser should provide a "greyed out" appearance.
  +    </td>
  +   </tr>
  +      
  +  <tr>
  +    <td>selected</td>
  +    <td>Object</td>
  +    <td>out</td>
  +    <td>no</td>
  +    <td>&nbsp;</td>
  +    <td>ognl</td>
  +    <td>
  +    This parameter is bound to a property that is updated when the submit
  +    button is clicked by the user. The property is updated to match the tag
  +    parameter.
  +    </td>
  +   </tr>    
  +  <tr>
  +    <td>tag</td>
  +    <td>Object</td>
  +    <td>in</td>
  +    <td>no</td>
  +    <td>&nbsp;</td>
  +    <td>ognl</td>
  +    <td>
  +    Tag used with the selected parameter to indicate which Submit button
  +    on a form was clicked.
  +    </td>
  +   </tr>    
  +  
  + <tr>
  + <td>listener</td>
  + <td>
  +    &IActionListener;
  +    </td>
  + <td>in</td>
  + <td>no</td>
  + <td>&nbsp;</td>
  +    <td>listener</td>
  + <td>
  +    An optional listener (typically specified as the name of a listener method), notified
  +    when the Submit is triggered.
  + </td>
  +   </tr>  
  +   <tr>
  +    <td>defer</td>
  +    <td>boolean</td>
  +    <td>in</td>
  +    <td>no</td>
  +    <td>true</td>
  +    <td>ognl</td>
  +    <td>
  +      If true (the default), then the listener (if any) will not
  +      be notified immediately but will be notified just
  +      before the enclosing &Form;'s listener.
  +    </td>
  +   </tr>
    </table>
     
   <p>
  -  Body: <strong>removed / allowed</strong>
  +  Body: <strong>removed</strong>
   </p>  
   
   <p>
  -  Informal parameters: <strong>allowed  / forbidden</strong>
  +  Informal parameters: <strong>allowed</strong>
   </p>
   
   <p>
  -  Reserved parameters: <em>none</em>
  +  Reserved parameters: <em>name, type</em>
   </p>
   
   </section>
   
   <section>
  -  <title>Examples</title>
  +  <title>Example</title>
  +
  +<source><![CDATA[
  +<form jwcid="form@Form" listener="doSubmit">
  +<table>
  +  <tr>
  +    <th>User name:</th>
  +    <td><input jwcid="userName@TextField" value="userName" size="12"/></td>
  +  </tr>
  +  <tr>
  +    <th>Password:</th>
  +    <td><input jwcid="password@TextField" value="password" hidden="true" size="12"/></td>
  +  </tr>
  +  <tr>
  +    <td colspan="2">
  +      <input type="submit" value="Login"/>
  +      <input type="submit" jwcid="help@Submit" listener="doHelp" value="Help"/>
  +    </td>
  +  </tr>
  +</table>
  +</form>]]></source>
  +
  +<p>
  +Here, the page class will have <em>two</em> listener methods: doHelp() and doSubmit().  doHelp() will be
  +invoked if the user clicks the Help button, then doSubmit() will be invoked either way.
  +</p>
   
   </section>
   </body>
 
 
 
  1.3       +1 -1      jakarta-tapestry/framework/src/test/org/apache/tapestry/describe/BaseDescribeTestCase.java
 
  Index: BaseDescribeTestCase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/test/org/apache/tapestry/describe/BaseDescribeTestCase.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- BaseDescribeTestCase.java 18 Apr 2005 17:07:53 -0000 1.2
  +++ BaseDescribeTestCase.java 9 May 2005 14:45:15 -0000 1.3
  @@ -22,7 +22,7 @@
    * @author Howard M. Lewis Ship
    * @since 4.0
    */
  -public class BaseDescribeTestCase extends HiveMindTestCase
  +public abstract class BaseDescribeTestCase extends HiveMindTestCase
   {
   
       protected IMarkupWriter newWriter()
 
 
 
  1.4       +21 -0     jakarta-tapestry/framework/src/test/org/apache/tapestry/form/MockForm.java
 
  Index: MockForm.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/test/org/apache/tapestry/form/MockForm.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- MockForm.java 3 May 2005 17:41:28 -0000 1.3
  +++ MockForm.java 9 May 2005 14:45:15 -0000 1.4
  @@ -14,7 +14,10 @@
   
   package org.apache.tapestry.form;
   
  +import java.util.ArrayList;
   import java.util.Collection;
  +import java.util.Iterator;
  +import java.util.List;
   import java.util.Map;
   
   import org.apache.hivemind.Location;
  @@ -46,6 +49,8 @@
   
       private IRender _body;
   
  +    private List _deferredRunnable = new ArrayList();
  +
       public MockForm()
       {
       }
  @@ -277,4 +282,20 @@
       {
           return false;
       }
  +
  +    public void addDeferredRunnable(Runnable runnable)
  +    {
  +        _deferredRunnable.add(runnable);
  +    }
  +
  +    void runDeferred()
  +    {
  +        Iterator i = _deferredRunnable.iterator();
  +        while (i.hasNext())
  +        {
  +            Runnable r = (Runnable) i.next();
  +
  +            r.run();
  +        }
  +    }
   }
  \ No newline at end of file
 
 
 
  1.4       +139 -0    jakarta-tapestry/framework/src/test/org/apache/tapestry/form/TestFormSupport.java
 
  Index: TestFormSupport.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/test/org/apache/tapestry/form/TestFormSupport.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- TestFormSupport.java 3 May 2005 17:41:28 -0000 1.3
  +++ TestFormSupport.java 9 May 2005 14:45:15 -0000 1.4
  @@ -911,6 +911,96 @@
           verifyControls();
       }
   
  +    public void testSimpleRenderWithDeferredRunnable()
  +    {
  +        MockControl writerc = newControl(IMarkupWriter.class);
  +        IMarkupWriter writer = (IMarkupWriter) writerc.getMock();
  +
  +        NestedMarkupWriter nested = newNestedWriter();
  +
  +        MockControl cyclec = newControl(IRequestCycle.class);
  +        IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
  +
  +        MockForm form = new MockForm();
  +
  +        cycle.isRewound(form);
  +        cyclec.setReturnValue(false);
  +
  +        replayControls();
  +
  +        final FormSupport fs = new FormSupportImpl(writer, cycle, form);
  +
  +        verifyControls();
  +
  +        IRender body = new IRender()
  +        {
  +
  +            public void render(final IMarkupWriter writer, IRequestCycle cycle)
  +            {
  +                fs.addDeferredRunnable(new Runnable()
  +                {
  +
  +                    public void run()
  +                    {
  +                        writer.print("DEFERRED");
  +                    }
  +
  +                });
  +            }
  +
  +        };
  +
  +        form.setBody(body);
  +
  +        MockControl linkc = newControl(ILink.class);
  +        ILink link = (ILink) linkc.getMock();
  +
  +        IRender render = (IRender) newMock(IRender.class);
  +
  +        link.getParameterNames();
  +        linkc.setReturnValue(new String[]
  +        { "service" });
  +
  +        link.getParameterValues("service");
  +        linkc.setReturnValue(new String[]
  +        { "fred" });
  +
  +        writer.getNestedWriter();
  +        writerc.setReturnValue(nested);
  +
  +        link.getURL(null, false);
  +        linkc.setReturnValue("/app");
  +
  +        writer.begin("form");
  +        writer.attribute("method", "post");
  +        writer.attribute("action", "/app");
  +
  +        writer.attribute("name", "myform");
  +
  +        render.render(writer, cycle);
  +
  +        writer.println();
  +
  +        trainHidden(writer, "formids", "");
  +        trainHidden(writer, "service", "fred");
  +
  +        // EasyMock can't fully verify that this gets called at the right moment, nor can we truly
  +        // prove (well, except by looking at the code), that the deferred runnables execute at the
  +        // right time.
  +
  +        nested.print("DEFERRED");
  +
  +        nested.close();
  +
  +        writer.end();
  +
  +        replayControls();
  +
  +        fs.render("post", render, link);
  +
  +        verifyControls();
  +    }
  +
       public void testSimpleRewind()
       {
           IMarkupWriter writer = newWriter();
  @@ -944,6 +1034,55 @@
           verifyControls();
       }
   
  +    public void testSimpleRewindWithDeferredRunnable()
  +    {
  +        IMarkupWriter writer = newWriter();
  +
  +        MockControl cyclec = newControl(IRequestCycle.class);
  +        IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
  +
  +        MockForm form = new MockForm();
  +
  +        cycle.isRewound(form);
  +        cyclec.setReturnValue(true);
  +
  +        replayControls();
  +
  +        final FormSupport fs = new FormSupportImpl(writer, cycle, form);
  +
  +        verifyControls();
  +
  +        trainCycleForRewind(cyclec, cycle, "", null);
  +
  +        writer.print("DEFERRED");
  +
  +        replayControls();
  +
  +        IRender body = new IRender()
  +        {
  +
  +            public void render(final IMarkupWriter writer, IRequestCycle cycle)
  +            {
  +                fs.addDeferredRunnable(new Runnable()
  +                {
  +
  +                    public void run()
  +                    {
  +                        writer.print("DEFERRED");
  +                    }
  +
  +                });
  +            }
  +
  +        };
  +
  +        form.setBody(body);
  +
  +        fs.rewind();
  +
  +        verifyControls();
  +    }
  +
       public void testSimpleSubmitEventHandler()
       {
           MockControl writerc = newControl(IMarkupWriter.class);
 
 
 
  1.1                  jakarta-tapestry/framework/src/test/org/apache/tapestry/form/BaseFormComponentTest.java
 
  Index: BaseFormComponentTest.java
  ===================================================================
  // Copyright 2005 The Apache Software Foundation
  //
  // 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 org.apache.tapestry.form;
 
  import org.apache.hivemind.test.HiveMindTestCase;
  import org.apache.tapestry.IActionListener;
  import org.apache.tapestry.IBinding;
  import org.apache.tapestry.IForm;
  import org.apache.tapestry.IMarkupWriter;
  import org.apache.tapestry.IRequestCycle;
  import org.apache.tapestry.TapestryUtils;
  import org.apache.tapestry.valid.IValidationDelegate;
  import org.easymock.MockControl;
 
  /**
   * Base class for tests of implementations of {@link org.apache.tapestry.form.IFormComponent}.
   *
   * @author Howard M. Lewis Ship
   * @since 4.0
   */
  public abstract class BaseFormComponentTest extends HiveMindTestCase
  {
 
      protected IValidationDelegate newDelegate()
      {
          return (IValidationDelegate) newMock(IValidationDelegate.class);
      }
 
      protected IForm newForm()
      {
          return (IForm) newMock(IForm.class);
      }
 
      protected IRequestCycle newCycle()
      {
          return (IRequestCycle) newMock(IRequestCycle.class);
      }
 
      protected void train(MockControl control, IRequestCycle cycle, IForm form)
      {
          cycle.getAttribute(TapestryUtils.FORM_ATTRIBUTE);
          control.setReturnValue(form);
      }
 
      protected void train(MockControl control, IRequestCycle cycle, String parameterName,
              String parameterValue)
      {
          cycle.getParameter(parameterName);
          control.setReturnValue(parameterValue);
      }
 
      protected void trainWasPrerendered(MockControl control, IForm form, IMarkupWriter writer,
              Submit submit, boolean wasPrerendered)
      {
          form.wasPrerendered(writer, submit);
          control.setReturnValue(wasPrerendered);
      }
 
      protected void trainIsRewinding(MockControl control, IForm form, boolean isRewinding)
      {
          form.isRewinding();
          control.setReturnValue(isRewinding);
      }
 
      protected void trainGetElementId(MockControl control, IForm form, IFormComponent component,
              String name)
      {
          form.getElementId(component);
          control.setReturnValue(name);
      }
 
      protected IMarkupWriter newWriter()
      {
          return (IMarkupWriter) newMock(IMarkupWriter.class);
      }
 
      protected IBinding newBinding()
      {
          return (IBinding) newMock(IBinding.class);
      }
 
      protected IActionListener newListener()
      {
          return (IActionListener) newMock(IActionListener.class);
      }
  }
 
 
 
  1.1                  jakarta-tapestry/framework/src/test/org/apache/tapestry/form/TestImageSubmit.java
 
  Index: TestImageSubmit.java
  ===================================================================
  // Copyright 2005 The Apache Software Foundation
  //
  // 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 org.apache.tapestry.form;
 
  import java.awt.Point;
 
  import org.apache.hivemind.util.PropertyUtils;
  import org.apache.tapestry.IAsset;
  import org.apache.tapestry.IBinding;
  import org.apache.tapestry.IForm;
  import org.apache.tapestry.IMarkupWriter;
  import org.apache.tapestry.IRequestCycle;
  import org.apache.tapestry.test.Creator;
  import org.apache.tapestry.valid.IValidationDelegate;
  import org.easymock.MockControl;
 
  /**
   * Tests for {@link org.apache.tapestry.form.ImageSubmit}.
   *
   * @author Howard M. Lewis Ship
   * @since 4.0
   */
  public class TestImageSubmit extends BaseFormComponentTest
  {
      protected IAsset newAsset(IRequestCycle cycle, String imageURL)
      {
          MockControl control = newControl(IAsset.class);
          IAsset asset = (IAsset) control.getMock();
 
          asset.buildURL(cycle);
          control.setReturnValue(imageURL);
 
          return asset;
      }
 
      public void testPrerendered()
      {
          Creator creator = new Creator();
          ImageSubmit submit = (ImageSubmit) creator.newInstance(ImageSubmit.class);
 
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, true);
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          verifyControls();
      }
 
      public void testRender()
      {
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
          IAsset image = newAsset(cycle, "image-url");
 
          Creator creator = new Creator();
          ImageSubmit submit = (ImageSubmit) creator.newInstance(ImageSubmit.class, new Object[]
          { "image", image });
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, false);
 
          trainGetElementId(formc, form, submit, "fred");
 
          writer.beginEmpty("input");
          writer.attribute("type", "image");
          writer.attribute("name", "fred");
          writer.attribute("border", 0);
          writer.attribute("src", "image-url");
          writer.closeTag();
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
 
          verifyControls();
      }
 
      public void testRenderDisabled()
      {
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
          IAsset image = newAsset(cycle, "disabled-image-url");
 
          Creator creator = new Creator();
          ImageSubmit submit = (ImageSubmit) creator.newInstance(ImageSubmit.class, new Object[]
          { "disabledImage", image, "disabled", Boolean.TRUE });
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, false);
 
          trainGetElementId(formc, form, submit, "fred");
 
          writer.beginEmpty("input");
          writer.attribute("type", "image");
          writer.attribute("name", "fred");
          writer.attribute("disabled", "disabled");
          writer.attribute("border", 0);
          writer.attribute("src", "disabled-image-url");
          writer.closeTag();
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
 
          verifyControls();
      }
 
      public void testRenderDisabledNoDisabledImage()
      {
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
          IAsset image = newAsset(cycle, "image-url");
 
          Creator creator = new Creator();
          ImageSubmit submit = (ImageSubmit) creator.newInstance(ImageSubmit.class, new Object[]
          { "image", image, "disabled", Boolean.TRUE });
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, false);
 
          trainGetElementId(formc, form, submit, "fred");
 
          writer.beginEmpty("input");
          writer.attribute("type", "image");
          writer.attribute("name", "fred");
          writer.attribute("disabled", "disabled");
          writer.attribute("border", 0);
          writer.attribute("src", "image-url");
          writer.closeTag();
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
 
          verifyControls();
      }
 
      public void testRenderWithNameOverride()
      {
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
          IAsset image = newAsset(cycle, "image-url");
 
          Creator creator = new Creator();
          ImageSubmit submit = (ImageSubmit) creator.newInstance(ImageSubmit.class, new Object[]
          { "image", image, "nameOverride", "barney" });
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, false);
 
          form.getElementId(submit, "barney");
          formc.setReturnValue("barney$0");
 
          writer.beginEmpty("input");
          writer.attribute("type", "image");
          writer.attribute("name", "barney$0");
          writer.attribute("border", 0);
          writer.attribute("src", "image-url");
          writer.closeTag();
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("barney$0", submit.getName());
 
          verifyControls();
      }
 
      public void testRewindingDisabled()
      {
          Creator creator = new Creator();
          ImageSubmit submit = (ImageSubmit) creator.newInstance(ImageSubmit.class, new Object[]
          { "disabled", Boolean.TRUE });
 
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, true);
 
          trainGetElementId(formc, form, submit, "fred");
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
 
          verifyControls();
      }
 
      public void testRewindNotTrigger()
      {
          Creator creator = new Creator();
          ImageSubmit submit = (ImageSubmit) creator.newInstance(ImageSubmit.class);
 
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, true);
 
          trainGetElementId(formc, form, submit, "fred");
 
          train(cyclec, cycle, "fred.x", null);
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
 
          verifyControls();
      }
 
      public void testRewindTrigger()
      {
          Creator creator = new Creator();
          ImageSubmit submit = (ImageSubmit) creator.newInstance(ImageSubmit.class, new Object[]
          { "tag", "clicked" });
 
          IBinding binding = newBinding();
          submit.setBinding("selected", binding);
 
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, true);
 
          trainGetElementId(formc, form, submit, "fred");
 
          train(cyclec, cycle, "fred.x", "33");
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
          assertEquals("clicked", PropertyUtils.read(submit, "selected"));
 
          // Note: we rely on the fact that ImageSubmit subclasses
          // from Submit to test some of the extra logic about
          // notifying listeners (deferred or not).
          // This test "proves" that Submit.handleClick() is invoked.
 
          verifyControls();
      }
 
      public void testRewindTriggeredWithPointBound()
      {
          Creator creator = new Creator();
          ImageSubmit submit = (ImageSubmit) creator.newInstance(ImageSubmit.class, new Object[]
          { "tag", "clicked" });
 
          IBinding binding = newBinding();
          submit.setBinding("selected", binding);
          submit.setBinding("point", binding);
 
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, true);
 
          trainGetElementId(formc, form, submit, "fred");
 
          train(cyclec, cycle, "fred.x", "33");
          train(cyclec, cycle, "fred.x", "33");
          train(cyclec, cycle, "fred.y", "19");
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
          assertEquals("clicked", PropertyUtils.read(submit, "selected"));
          assertEquals(new Point(33, 19), PropertyUtils.read(submit, "point"));
 
          verifyControls();
      }
  }
 
 
 
  1.1                  jakarta-tapestry/framework/src/test/org/apache/tapestry/form/TestSubmit.java
 
  Index: TestSubmit.java
  ===================================================================
  // Copyright 2005 The Apache Software Foundation
  //
  // 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 org.apache.tapestry.form;
 
  import org.apache.hivemind.util.PropertyUtils;
  import org.apache.tapestry.IActionListener;
  import org.apache.tapestry.IBinding;
  import org.apache.tapestry.IForm;
  import org.apache.tapestry.IMarkupWriter;
  import org.apache.tapestry.IRequestCycle;
  import org.apache.tapestry.test.Creator;
  import org.apache.tapestry.valid.IValidationDelegate;
  import org.easymock.MockControl;
 
  /**
   * Tests for {@link org.apache.tapestry.form.Submit}.
   *
   * @author Howard M. Lewis Ship
   * @since 4.0
   */
  public class TestSubmit extends BaseFormComponentTest
  {
      public void testPrerendered()
      {
          Creator creator = new Creator();
          Submit submit = (Submit) creator.newInstance(Submit.class);
 
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, true);
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          verifyControls();
      }
 
      public void testRender()
      {
          Creator creator = new Creator();
          Submit submit = (Submit) creator.newInstance(Submit.class);
 
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, false);
 
          trainGetElementId(formc, form, submit, "fred");
 
          writer.beginEmpty("input");
          writer.attribute("type", "submit");
          writer.attribute("name", "fred");
          writer.closeTag();
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
 
          verifyControls();
      }
 
      public void testRenderDisabled()
      {
          Creator creator = new Creator();
          Submit submit = (Submit) creator.newInstance(Submit.class, new Object[]
          { "disabled", Boolean.TRUE });
 
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, false);
 
          trainGetElementId(formc, form, submit, "fred");
 
          writer.beginEmpty("input");
          writer.attribute("type", "submit");
          writer.attribute("name", "fred");
          writer.attribute("disabled", "disabled");
          writer.closeTag();
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
 
          verifyControls();
      }
 
      public void testRenderWithLabel()
      {
          Creator creator = new Creator();
          Submit submit = (Submit) creator.newInstance(Submit.class, new Object[]
          { "label", "flintstone" });
 
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, false);
 
          trainGetElementId(formc, form, submit, "fred");
 
          writer.beginEmpty("input");
          writer.attribute("type", "submit");
          writer.attribute("name", "fred");
          writer.attribute("value", "flintstone");
          writer.closeTag();
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
 
          verifyControls();
      }
 
      public void testRewindingDisabled()
      {
          Creator creator = new Creator();
          Submit submit = (Submit) creator.newInstance(Submit.class, new Object[]
          { "disabled", Boolean.TRUE });
 
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, true);
 
          trainGetElementId(formc, form, submit, "fred");
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
 
          verifyControls();
      }
 
      public void testRewindNotTrigger()
      {
          Creator creator = new Creator();
          Submit submit = (Submit) creator.newInstance(Submit.class);
 
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, true);
 
          trainGetElementId(formc, form, submit, "fred");
 
          train(cyclec, cycle, "fred", null);
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
 
          verifyControls();
      }
 
      public void testRewindTriggered()
      {
          Creator creator = new Creator();
          Submit submit = (Submit) creator.newInstance(Submit.class, new Object[]
          { "tag", "clicked" });
 
          IBinding binding = newBinding();
          submit.setBinding("selected", binding);
 
          IValidationDelegate delegate = newDelegate();
          MockControl formc = newControl(IForm.class);
          IForm form = (IForm) formc.getMock();
          MockControl cyclec = newControl(IRequestCycle.class);
          IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
          IMarkupWriter writer = newWriter();
 
          train(cyclec, cycle, form);
 
          form.getDelegate();
          formc.setReturnValue(delegate);
 
          delegate.setFormComponent(submit);
 
          trainWasPrerendered(formc, form, writer, submit, false);
 
          trainIsRewinding(formc, form, true);
 
          trainGetElementId(formc, form, submit, "fred");
 
          train(cyclec, cycle, "fred", "flintstone");
 
          replayControls();
 
          submit.renderComponent(writer, cycle);
 
          assertEquals("fred", submit.getName());
          assertEquals("clicked", PropertyUtils.read(submit, "selected"));
 
          verifyControls();
      }
 
      public void testTriggerWithListener()
      {
          IActionListener listener = newListener();
          IForm form = newForm();
          IRequestCycle cycle = newCycle();
 
          Creator creator = new Creator();
          Submit submit = (Submit) creator.newInstance(Submit.class, new Object[]
          { "listener", listener });
 
          listener.actionTriggered(submit, cycle);
 
          replayControls();
 
          submit.handleClick(cycle, form);
 
          verifyControls();
      }
 
      public void testTriggerWithDeferredListener()
      {
          IActionListener listener = newListener();
          MockForm form = new MockForm();
          IRequestCycle cycle = newCycle();
 
          Creator creator = new Creator();
          Submit submit = (Submit) creator.newInstance(Submit.class, new Object[]
          { "listener", listener, "defer", Boolean.TRUE });
 
          replayControls();
 
          submit.handleClick(cycle, form);
 
          verifyControls();
 
          listener.actionTriggered(submit, cycle);