Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/tapestry/form/Form.java


1   /* $$ Clover has instrumented this file $$ */// Copyright 2004 The Apache Software Foundation
2   //
3   // Licensed under the Apache License, Version 2.0 (the "License");
4   // you may not use this file except in compliance with the License.
5   // You may obtain a copy of the License at
6   //
7   //     http://www.apache.org/licenses/LICENSE-2.0
8   //
9   // Unless required by applicable law or agreed to in writing, software
10  // distributed under the License is distributed on an "AS IS" BASIS,
11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  // See the License for the specific language governing permissions and
13  // limitations under the License.
14  
15  package org.apache.tapestry.form;
16  
17  import java.util.ArrayList;
18  import java.util.HashMap;
19  import java.util.Iterator;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.apache.tapestry.AbstractComponent;
24  import org.apache.hivemind.ApplicationRuntimeException;
25  import org.apache.tapestry.IActionListener;
26  import org.apache.tapestry.IBinding;
27  import org.apache.tapestry.IDirect;
28  import org.apache.tapestry.IEngine;
29  import org.apache.tapestry.IForm;
30  import org.apache.tapestry.IMarkupWriter;
31  import org.apache.tapestry.IRequestCycle;
32  import org.apache.tapestry.RenderRewoundException;
33  import org.apache.tapestry.StaleLinkException;
34  import org.apache.tapestry.Tapestry;
35  import org.apache.tapestry.engine.IEngineService;
36  import org.apache.tapestry.engine.ILink;
37  import org.apache.tapestry.html.Body;
38  import org.apache.tapestry.util.IdAllocator;
39  import org.apache.tapestry.util.StringSplitter;
40  import org.apache.tapestry.valid.IValidationDelegate;
41  
42  /**
43   *  Component which contains form element components.  Forms use the
44   *  action or direct services to handle the form submission.  A Form will wrap
45   *  other components and static HTML, including
46   *  form components such as {@link TextArea}, {@link TextField}, {@link Checkbox}, etc.
47   * 
48   *  [<a href="../../../../../ComponentReference/Form.html">Component Reference</a>]
49   * 
50   *  <p>When a form is submitted, it continues through the rewind cycle until
51   *  <em>after</em> all of its wrapped elements have renderred.  As the form
52   *  component render (in the rewind cycle), they will be updating
53   *  properties of the containing page and notifying thier listeners.  Again:
54   *  each form component is responsible not only for rendering HTML (to present the
55   *  form), but for handling it's share of the form submission.
56   *
57   *  <p>Only after all that is done will the Form notify its listener.
58   *
59   *  <p>Starting in release 1.0.2, a Form can use either the direct service or
60   *  the action service.  The default is the direct service, even though
61   *  in earlier releases, only the action service was available.
62   *
63   *  @author Howard Lewis Ship, David Solis
64   **/
65  
66  public abstract class Form extends AbstractComponent implements IForm, IDirect
67  {public static com.cortexeb.tools.clover.d __CLOVER_130_0 = com.cortexeb.tools.clover.aq.getRecorder(new char[] {67,58,92,119,111,114,107,115,112,97,99,101,92,106,97,107,97,114,116,97,45,116,97,112,101,115,116,114,121,92,102,114,97,109,101,119,111,114,107,92,116,97,114,103,101,116,92,99,108,111,118,101,114,45,100,98},1096998272901L);
68      private static class HiddenValue
69      {
70          String _name;
71          String _value;
72          String _id;
73  
74          private HiddenValue(String name, String value)
75          {
76        this(name, null, value);__CLOVER_130_0.S[3037]++;try { __CLOVER_130_0.M[687]++;
77          } finally { }}
78  
79      private HiddenValue(String name, String id, String value)
80      {try { __CLOVER_130_0.M[688]++;
81        __CLOVER_130_0.S[3038]++;_name  = name;
82        __CLOVER_130_0.S[3039]++;_id    = id;
83        __CLOVER_130_0.S[3040]++;_value  = value;
84      } finally { }}
85      }
86  
87      private boolean _rewinding;
88      private boolean _rendering;
89      private String _name;
90  
91      /**
92       *  Used when rewinding the form to figure to match allocated ids (allocated during
93       *  the rewind) against expected ids (allocated in the previous request cycle, when
94       *  the form was rendered).
95       * 
96       *  @since 3.0
97       * 
98       **/
99  
100     private int _allocatedIdIndex;
101 
102     /**
103      *  The list of allocated ids for form elements within this form.  This list
104      *  is constructed when a form renders, and is validated against when the
105      *  form is rewound.
106      * 
107      *  @since 3.0
108      * 
109      **/
110 
111     private List _allocatedIds = new ArrayList();
112 
113     /**
114      *  {@link Map}, keyed on {@link FormEventType}.  Values are either a String (the name
115      *  of a single event), or a {@link List} of Strings.
116      *
117      *  @since 1.0.2
118      **/
119 
120     private Map _events;
121 
122     private static final int EVENT_MAP_SIZE = 3;
123 
124     private IdAllocator _elementIdAllocator = new IdAllocator();
125 
126     private String _encodingType;
127 
128     private List _hiddenValues;
129 
130     /**
131      *  Returns the currently active {@link IForm}, or null if no form is
132      *  active.  This is a convienience method, the result will be
133      *  null, or an instance of {@link IForm}, but not necessarily a
134      *  <code>Form</code>.
135      *
136      **/
137 
138     public static IForm get(IRequestCycle cycle)
139     {try { __CLOVER_130_0.M[689]++;
140         __CLOVER_130_0.S[3041]++;return (IForm) cycle.getAttribute(ATTRIBUTE_NAME);
141     } finally { }}
142 
143     /**
144      *  Indicates to any wrapped form components that they should respond to the form
145      *  submission.
146      *
147      *  @throws ApplicationRuntimeException if not rendering.
148      **/
149 
150     public boolean isRewinding()
151     {try { __CLOVER_130_0.M[690]++;
152         __CLOVER_130_0.S[3042]++;if ((((!_rendering) && (++__CLOVER_130_0.CT[552] != 0)) || (++__CLOVER_130_0.CF[552] == 0))){
153             __CLOVER_130_0.S[3043]++;throw Tapestry.createRenderOnlyPropertyException(this, "rewinding");}
154 
155         __CLOVER_130_0.S[3044]++;return _rewinding;
156     } finally { }}
157 
158     /**
159      *  Returns true if this Form is configured to use the direct
160      *  service.
161      *
162      *  <p>This is derived from the direct parameter, and defaults
163      *  to true if not bound.
164      *
165      *  @since 1.0.2
166      **/
167 
168     public abstract boolean isDirect();
169 
170     /**
171      *  Returns true if the stateful parameter is bound to
172      *  a true value.  If stateful is not bound, also returns
173      *  the default, true.
174      *
175      *  @since 1.0.1
176      **/
177 
178     public boolean getRequiresSession()
179     {try { __CLOVER_130_0.M[691]++;
180         __CLOVER_130_0.S[3045]++;return isStateful();
181     } finally { }}
182 
183     /**
184      *  Constructs a unique identifier (within the Form).  The identifier
185      *  consists of the component's id, with an index number added to
186      *  ensure uniqueness.
187      *
188      *  <p>Simply invokes {@link #getElementId(org.apache.tapestry.form.IFormComponent, java.lang.String)}
189      *  with the component's id.
190      *
191      *
192      *  @since 1.0.2
193      **/
194 
195     public String getElementId(IFormComponent component)
196     {try { __CLOVER_130_0.M[692]++;
197         __CLOVER_130_0.S[3046]++;return getElementId(component, component.getId());
198     } finally { }}
199 
200     /**
201      *  Constructs a unique identifier from the base id.  If possible, the
202      *  id is used as-is.  Otherwise, a unique identifier is appended
203      *  to the id.
204      *
205      *  <p>This method is provided simply so that some components
206      * ({@link ImageSubmit}) have more specific control over
207      *  their names.
208      *
209      *  @since 1.0.3
210      *
211      **/
212 
213     public String getElementId(IFormComponent component, String baseId)
214     {try { __CLOVER_130_0.M[693]++;
215         __CLOVER_130_0.S[3047]++;String result = _elementIdAllocator.allocateId(baseId);
216 
217         __CLOVER_130_0.S[3048]++;if ((((_rewinding) && (++__CLOVER_130_0.CT[553] != 0)) || (++__CLOVER_130_0.CF[553] == 0))){
218         {
219             __CLOVER_130_0.S[3049]++;if ((((_allocatedIdIndex >= _allocatedIds.size()) && (++__CLOVER_130_0.CT[554] != 0)) || (++__CLOVER_130_0.CF[554] == 0))){
220             {
221                 __CLOVER_130_0.S[3050]++;throw new StaleLinkException(
222                     Tapestry.format(
223                         "Form.too-many-ids",
224                         getExtendedId(),
225                         Integer.toString(_allocatedIds.size()),
226                         component.getExtendedId()),
227                     this);
228             }}
229 
230             __CLOVER_130_0.S[3051]++;String expected = (String) _allocatedIds.get(_allocatedIdIndex);
231 
232             __CLOVER_130_0.S[3052]++;if ((((!result.equals(expected)) && (++__CLOVER_130_0.CT[555] != 0)) || (++__CLOVER_130_0.CF[555] == 0))){
233                 __CLOVER_130_0.S[3053]++;throw new StaleLinkException(
234                     Tapestry.format(
235                         "Form.id-mismatch",
236                         new Object[] {
237                             getExtendedId(),
238                             Integer.toString(_allocatedIdIndex + 1),
239                             expected,
240                             result,
241                             component.getExtendedId()}),
242                     this);}
243         }}
244         else{
245         {
246             __CLOVER_130_0.S[3054]++;_allocatedIds.add(result);
247         }}
248 
249         __CLOVER_130_0.S[3055]++;_allocatedIdIndex++;
250 
251         __CLOVER_130_0.S[3056]++;component.setName(result);
252 
253         __CLOVER_130_0.S[3057]++;return result;
254     } finally { }}
255 
256     /**
257      *  Returns the name generated for the form.  This is used to faciliate
258      *  components that write JavaScript and need to access the form or
259      *  its contents.
260      *
261      *  <p>This value is generated when the form renders, and is not cleared.
262      *  If the Form is inside a {@link org.apache.tapestry.components.Foreach}, 
263      *  this will be the most recently
264      *  generated name for the Form.
265      *
266      *  <p>This property is exposed so that sophisticated applications can write
267      *  JavaScript handlers for the form and components within the form.
268      *
269      *  @see AbstractFormComponent#getName()
270      *
271      **/
272 
273     public String getName()
274     {try { __CLOVER_130_0.M[694]++;
275         __CLOVER_130_0.S[3058]++;return _name;
276     } finally { }}
277 
278     /** @since 3.0 **/
279 
280     protected void prepareForRender(IRequestCycle cycle)
281     {try { __CLOVER_130_0.M[695]++;
282         __CLOVER_130_0.S[3059]++;super.prepareForRender(cycle);
283 
284         __CLOVER_130_0.S[3060]++;if ((((cycle.getAttribute(ATTRIBUTE_NAME) != null) && (++__CLOVER_130_0.CT[556] != 0)) || (++__CLOVER_130_0.CF[556] == 0))){
285             __CLOVER_130_0.S[3061]++;throw new ApplicationRuntimeException(
286                 Tapestry.getMessage("Form.forms-may-not-nest"),
287                 this,
288                 null,
289                 null);}
290 
291         __CLOVER_130_0.S[3062]++;cycle.setAttribute(ATTRIBUTE_NAME, this);
292     } finally { }}
293 
294     protected void cleanupAfterRender(IRequestCycle cycle)
295     {try { __CLOVER_130_0.M[696]++;
296         __CLOVER_130_0.S[3063]++;_rendering = false;
297 
298         __CLOVER_130_0.S[3064]++;_allocatedIdIndex = 0;
299         __CLOVER_130_0.S[3065]++;_allocatedIds.clear();
300 
301         __CLOVER_130_0.S[3066]++;_events = null;
302 
303         __CLOVER_130_0.S[3067]++;_elementIdAllocator.clear();
304 
305         __CLOVER_130_0.S[3068]++;if ((((_hiddenValues != null) && (++__CLOVER_130_0.CT[557] != 0)) || (++__CLOVER_130_0.CF[557] == 0))){
306             __CLOVER_130_0.S[3069]++;_hiddenValues.clear();}
307 
308         __CLOVER_130_0.S[3070]++;cycle.removeAttribute(ATTRIBUTE_NAME);
309 
310         __CLOVER_130_0.S[3071]++;_encodingType = null;
311 
312         __CLOVER_130_0.S[3072]++;IValidationDelegate delegate = getDelegate();
313 
314         __CLOVER_130_0.S[3073]++;if ((((delegate != null) && (++__CLOVER_130_0.CT[558] != 0)) || (++__CLOVER_130_0.CF[558] == 0))){
315             __CLOVER_130_0.S[3074]++;delegate.setFormComponent(null);}
316 
317         __CLOVER_130_0.S[3075]++;super.cleanupAfterRender(cycle);
318     } finally { }}
319 
320     protected void writeAttributes(IMarkupWriter writer, ILink link)
321     {try { __CLOVER_130_0.M[697]++;
322         __CLOVER_130_0.S[3076]++;String method = getMethod();
323 
324         __CLOVER_130_0.S[3077]++;writer.begin(getTag());
325         __CLOVER_130_0.S[3078]++;writer.attribute("method", ((((method == null) ) && (++__CLOVER_130_0.CT[559] != 0)) || (++__CLOVER_130_0.CF[559] == 0))? "post" : method);
326         __CLOVER_130_0.S[3079]++;writer.attribute("name", _name);
327         __CLOVER_130_0.S[3080]++;writer.attribute("action", link.getURL(null, false));
328 
329         __CLOVER_130_0.S[3081]++;if ((((_encodingType != null) && (++__CLOVER_130_0.CT[560] != 0)) || (++__CLOVER_130_0.CF[560] == 0))){
330             __CLOVER_130_0.S[3082]++;writer.attribute("enctype", _encodingType);}
331     } finally { }}
332 
333     protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
334     {try { __CLOVER_130_0.M[698]++;
335         __CLOVER_130_0.S[3083]++;String actionId = cycle.getNextActionId();
336         __CLOVER_130_0.S[3084]++;_name = getDisplayName() + actionId;
337 
338         __CLOVER_130_0.S[3085]++;boolean renderForm = !cycle.isRewinding();
339         __CLOVER_130_0.S[3086]++;boolean rewound = cycle.isRewound(this);
340 
341         __CLOVER_130_0.S[3087]++;_rewinding = rewound;
342 
343         __CLOVER_130_0.S[3088]++;_allocatedIdIndex = 0;
344 
345         __CLOVER_130_0.S[3089]++;_rendering = true;
346 
347         __CLOVER_130_0.S[3090]++;if ((((rewound) && (++__CLOVER_130_0.CT[561] != 0)) || (++__CLOVER_130_0.CF[561] == 0))){
348         {
349             __CLOVER_130_0.S[3091]++;String storedIdList = cycle.getRequestContext().getParameter(_name);
350 
351             __CLOVER_130_0.S[3092]++;reconstructAllocatedIds(storedIdList);
352         }}
353 
354         __CLOVER_130_0.S[3093]++;ILink link = getLink(cycle, actionId);
355 
356         // When rendering, use a nested writer so that an embedded Upload
357         // component can force the encoding type.
358 
359         __CLOVER_130_0.S[3094]++;IMarkupWriter nested = writer.getNestedWriter();
360 
361         __CLOVER_130_0.S[3095]++;renderBody(nested, cycle);
362 
363         __CLOVER_130_0.S[3096]++;if ((((renderForm) && (++__CLOVER_130_0.CT[562] != 0)) || (++__CLOVER_130_0.CF[562] == 0))){
364         {
365             __CLOVER_130_0.S[3097]++;writeAttributes(writer, link);
366 
367             __CLOVER_130_0.S[3098]++;renderInformalParameters(writer, cycle);
368             __CLOVER_130_0.S[3099]++;writer.println();
369         }}
370 
371         // Write the hidden's, or at least, reserve the query parameters
372         // required by the Gesture.
373 
374         __CLOVER_130_0.S[3100]++;writeLinkParameters(writer, link, !renderForm);
375 
376         __CLOVER_130_0.S[3101]++;if ((((renderForm) && (++__CLOVER_130_0.CT[563] != 0)) || (++__CLOVER_130_0.CF[563] == 0))){
377         {
378             // What's this for?  It's part of checking for stale links.  
379             // We record the list of allocated ids.
380             // On rewind, we check that the stored list against which
381             // ids were allocated.  If the persistent state of the page or
382             // application changed between render (previous request cycle)
383             // and rewind (current request cycle), then the list
384             // of ids will change as well.
385 
386             __CLOVER_130_0.S[3102]++;writeHiddenField(writer, _name, buildAllocatedIdList());
387             __CLOVER_130_0.S[3103]++;writeHiddenValues(writer);
388 
389             __CLOVER_130_0.S[3104]++;nested.close();
390 
391             __CLOVER_130_0.S[3105]++;writer.end(getTag());
392 
393             // Write out event handlers collected during the rendering.
394 
395             __CLOVER_130_0.S[3106]++;emitEventHandlers(writer, cycle);
396         }}
397 
398         __CLOVER_130_0.S[3107]++;if ((((rewound) && (++__CLOVER_130_0.CT[564] != 0)) || (++__CLOVER_130_0.CF[564] == 0))){
399         {
400             __CLOVER_130_0.S[3108]++;int expected = _allocatedIds.size();
401 
402             // The other case, _allocatedIdIndex > expected, is
403             // checked for inside getElementId().  Remember that
404             // _allocatedIdIndex is incremented after allocating.
405 
406             __CLOVER_130_0.S[3109]++;if ((((_allocatedIdIndex < expected) && (++__CLOVER_130_0.CT[565] != 0)) || (++__CLOVER_130_0.CF[565] == 0))){
407             {
408                 __CLOVER_130_0.S[3110]++;String nextExpectedId = (String) _allocatedIds.get(_allocatedIdIndex);
409 
410                 __CLOVER_130_0.S[3111]++;throw new StaleLinkException(
411                     Tapestry.format(
412                         "Form.too-few-ids",
413                         getExtendedId(),
414                         Integer.toString(expected - _allocatedIdIndex),
415                         nextExpectedId),
416                     this);
417             }}
418 
419             __CLOVER_130_0.S[3112]++;IActionListener listener = getListener();
420 
421             __CLOVER_130_0.S[3113]++;if ((((listener != null) && (++__CLOVER_130_0.CT[566] != 0)) || (++__CLOVER_130_0.CF[566] == 0))){
422                 __CLOVER_130_0.S[3114]++;listener.actionTriggered(this, cycle);}
423 
424             // Abort the rewind render.
425 
426             __CLOVER_130_0.S[3115]++;throw new RenderRewoundException(this);
427         }}
428     } finally { }}
429 
430     /**
431      *  Adds an additional event handler.
432      *
433      *  @since 1.0.2
434      * 
435      **/
436 
437     public void addEventHandler(FormEventType type, String functionName)
438     {try { __CLOVER_130_0.M[699]++;
439         __CLOVER_130_0.S[3116]++;if ((((_events == null) && (++__CLOVER_130_0.CT[567] != 0)) || (++__CLOVER_130_0.CF[567] == 0))){
440             __CLOVER_130_0.S[3117]++;_events = new HashMap(EVENT_MAP_SIZE);}
441 
442         __CLOVER_130_0.S[3118]++;Object value = _events.get(type);
443 
444         // The value can either be a String, or a List of String.  Since
445         // it is rare for there to be more than one event handling function,
446         // we start with just a String.
447 
448         __CLOVER_130_0.S[3119]++;if ((((value == null) && (++__CLOVER_130_0.CT[568] != 0)) || (++__CLOVER_130_0.CF[568] == 0))){
449         {
450             __CLOVER_130_0.S[3120]++;_events.put(type, functionName);
451             __CLOVER_130_0.S[3121]++;return;
452         }}
453 
454         // The second function added converts it to a List.
455 
456         __CLOVER_130_0.S[3122]++;if ((((value instanceof String) && (++__CLOVER_130_0.CT[569] != 0)) || (++__CLOVER_130_0.CF[569] == 0))){
457         {
458             __CLOVER_130_0.S[3123]++;List list = new ArrayList();
459             __CLOVER_130_0.S[3124]++;list.add(value);
460             __CLOVER_130_0.S[3125]++;list.add(functionName);
461 
462             __CLOVER_130_0.S[3126]++;_events.put(type, list);
463             __CLOVER_130_0.S[3127]++;return;
464         }}
465 
466         // The third and subsequent function just
467         // adds to the List.
468 
469         __CLOVER_130_0.S[3128]++;List list = (List) value;
470         __CLOVER_130_0.S[3129]++;list.add(functionName);
471     } finally { }}
472 
473     protected void emitEventHandlers(IMarkupWriter writer, IRequestCycle cycle)
474     {try { __CLOVER_130_0.M[700]++;
475 
476         __CLOVER_130_0.S[3130]++;if ((((_events == null || _events.isEmpty()) && (++__CLOVER_130_0.CT[570] != 0)) || (++__CLOVER_130_0.CF[570] == 0))){
477             __CLOVER_130_0.S[3131]++;return;}
478 
479         __CLOVER_130_0.S[3132]++;Body body = Body.get(cycle);
480 
481         __CLOVER_130_0.S[3133]++;if ((((body == null) && (++__CLOVER_130_0.CT[571] != 0)) || (++__CLOVER_130_0.CF[571] == 0))){
482             __CLOVER_130_0.S[3134]++;throw new ApplicationRuntimeException(
483                 Tapestry.getMessage("Form.needs-body-for-event-handlers"),
484                 this,
485                 null,
486                 null);}
487 
488         __CLOVER_130_0.S[3135]++;StringBuffer buffer = new StringBuffer();
489 
490         __CLOVER_130_0.S[3136]++;Iterator i = _events.entrySet().iterator();
491         __CLOVER_130_0.S[3137]++;while ((((i.hasNext()) && (++__CLOVER_130_0.CT[572] != 0)) || (++__CLOVER_130_0.CF[572] == 0))){
492         {
493 
494             __CLOVER_130_0.S[3138]++;Map.Entry entry = (Map.Entry) i.next();
495             __CLOVER_130_0.S[3139]++;FormEventType type = (FormEventType) entry.getKey();
496             __CLOVER_130_0.S[3140]++;Object value = entry.getValue();
497 
498             __CLOVER_130_0.S[3141]++;buffer.append("document.");
499             __CLOVER_130_0.S[3142]++;buffer.append(_name);
500             __CLOVER_130_0.S[3143]++;buffer.append(".");
501             __CLOVER_130_0.S[3144]++;buffer.append(type.getPropertyName());
502             __CLOVER_130_0.S[3145]++;buffer.append(" = ");
503 
504             // The typical case; one event one event handler.  Easy enough.
505 
506             __CLOVER_130_0.S[3146]++;if ((((value instanceof String) && (++__CLOVER_130_0.CT[573] != 0)) || (++__CLOVER_130_0.CF[573] == 0))){
507             {
508                 __CLOVER_130_0.S[3147]++;buffer.append(value.toString());
509                 __CLOVER_130_0.S[3148]++;buffer.append(";");
510             }}
511             else{
512             {
513                 // Build a composite function in-place
514 
515                 __CLOVER_130_0.S[3149]++;buffer.append("function ()\n{\n");
516 
517                 __CLOVER_130_0.S[3150]++;boolean combineWithAnd = type.getCombineUsingAnd();
518 
519                 __CLOVER_130_0.S[3151]++;List l = (List) value;
520                 __CLOVER_130_0.S[3152]++;int count = l.size();
521 
522                 __CLOVER_130_0.S[3153]++;for (int j = 0; (((j < count) && (++__CLOVER_130_0.CT[574] != 0)) || (++__CLOVER_130_0.CF[574] == 0)); j++){
523                 {
524                     __CLOVER_130_0.S[3154]++;String functionName = (String) l.get(j);
525 
526                     __CLOVER_130_0.S[3155]++;if ((((j > 0) && (++__CLOVER_130_0.CT[575] != 0)) || (++__CLOVER_130_0.CF[575] == 0))){
527                     {
528 
529                         __CLOVER_130_0.S[3156]++;if ((((combineWithAnd) && (++__CLOVER_130_0.CT[576] != 0)) || (++__CLOVER_130_0.CF[576] == 0))){
530                             __CLOVER_130_0.S[3157]++;buffer.append(" &&");}
531                         else{
532                             __CLOVER_130_0.S[3158]++;buffer.append(";");}
533                     }}
534 
535                     __CLOVER_130_0.S[3159]++;buffer.append("\n  ");
536 
537                     __CLOVER_130_0.S[3160]++;if ((((combineWithAnd) && (++__CLOVER_130_0.CT[577] != 0)) || (++__CLOVER_130_0.CF[577] == 0))){
538                     {
539                         __CLOVER_130_0.S[3161]++;if ((((j == 0) && (++__CLOVER_130_0.CT[578] != 0)) || (++__CLOVER_130_0.CF[578] == 0))){
540                             __CLOVER_130_0.S[3162]++;buffer.append("return ");}
541                         else{
542                             __CLOVER_130_0.S[3163]++;buffer.append("  ");}
543                     }}
544 
545                     __CLOVER_130_0.S[3164]++;buffer.append(functionName);
546                     __CLOVER_130_0.S[3165]++;buffer.append("()");
547                 }}
548 
549                 __CLOVER_130_0.S[3166]++;buffer.append(";\n}");
550             }}
551 
552             __CLOVER_130_0.S[3167]++;buffer.append("\n\n");
553         }}
554 
555         __CLOVER_130_0.S[3168]++;body.addInitializationScript(buffer.toString());
556     } finally { }}
557 
558     /**
559      *  Simply invokes {@link #render(IMarkupWriter, IRequestCycle)}.
560      *
561      *  @since 1.0.2
562      * 
563      **/
564 
565     public void rewind(IMarkupWriter writer, IRequestCycle cycle)
566     {try { __CLOVER_130_0.M[701]++;
567         __CLOVER_130_0.S[3169]++;render(writer, cycle);
568     } finally { }}
569 
570     /**
571      *  Method invoked by the direct service.
572      *
573      *  @since 1.0.2
574      *
575      **/
576 
577     public void trigger(IRequestCycle cycle)
578     {try { __CLOVER_130_0.M[702]++;
579         __CLOVER_130_0.S[3170]++;Object[] parameters = cycle.getServiceParameters();
580 
581         __CLOVER_130_0.S[3171]++;cycle.rewindForm(this, (String) parameters[0]);
582     } finally { }}
583 
584     /**
585      *  Builds the EngineServiceLink for the form, using either the direct or
586      *  action service. 
587      *
588      *  @since 1.0.3
589      *
590      **/
591 
592     private ILink getLink(IRequestCycle cycle, String actionId)
593     {try { __CLOVER_130_0.M[703]++;
594         __CLOVER_130_0.S[3172]++;String serviceName = null;
595 
596         __CLOVER_130_0.S[3173]++;if ((((isDirect()) && (++__CLOVER_130_0.CT[579] != 0)) || (++__CLOVER_130_0.CF[579] == 0))){
597             __CLOVER_130_0.S[3174]++;serviceName = Tapestry.DIRECT_SERVICE;}
598         else{
599             __CLOVER_130_0.S[3175]++;serviceName = Tapestry.ACTION_SERVICE;}
600 
601         __CLOVER_130_0.S[3176]++;IEngine engine = cycle.getEngine();
602         __CLOVER_130_0.S[3177]++;IEngineService service = engine.getService(serviceName);
603 
604         // A single service parameter is used to store the actionId.
605 
606         __CLOVER_130_0.S[3178]++;return service.getLink(cycle, this, new String[] { actionId });
607     } finally { }}
608 
609     private void writeLinkParameters(IMarkupWriter writer, ILink link, boolean reserveOnly)
610     {try { __CLOVER_130_0.M[704]++;
611         __CLOVER_130_0.S[3179]++;String[] names = link.getParameterNames();
612         __CLOVER_130_0.S[3180]++;int count = Tapestry.size(names);
613 
614         __CLOVER_130_0.S[3181]++;for (int i = 0; (((i < count) && (++__CLOVER_130_0.CT[580] != 0)) || (++__CLOVER_130_0.CF[580] == 0)); i++){
615         {
616             __CLOVER_130_0.S[3182]++;String name = names[i];
617 
618             // Reserve the name.
619 
620             __CLOVER_130_0.S[3183]++;_elementIdAllocator.allocateId(name);
621 
622             __CLOVER_130_0.S[3184]++;if ((((!reserveOnly) && (++__CLOVER_130_0.CT[581] != 0)) || (++__CLOVER_130_0.CF[581] == 0))){
623                 __CLOVER_130_0.S[3185]++;writeHiddenFieldsForParameter(writer, link, name);}
624         }}
625     } finally { }}
626 
627     /**
628      *  @since 3.0
629      *
630      **/
631 
632     protected void writeHiddenField(IMarkupWriter writer, String name, String value)
633     {try { __CLOVER_130_0.M[705]++;
634     __CLOVER_130_0.S[3186]++;writeHiddenField(writer, name, null, value);
635     } finally { }}
636 
637   protected void writeHiddenField(IMarkupWriter writer, String name, String id, String value)
638   {try { __CLOVER_130_0.M[706]++;
639     __CLOVER_130_0.S[3187]++;writer.beginEmpty("input");
640     __CLOVER_130_0.S[3188]++;writer.attribute("type", "hidden");
641     __CLOVER_130_0.S[3189]++;writer.attribute("name", name);
642 
643     __CLOVER_130_0.S[3190]++;if((((id != null && id.length() != 0) && (++__CLOVER_130_0.CT[582] != 0)) || (++__CLOVER_130_0.CF[582] == 0))){
644       __CLOVER_130_0.S[3191]++;writer.attribute("id", id);}
645     
646     __CLOVER_130_0.S[3192]++;writer.attribute("value", value);
647     __CLOVER_130_0.S[3193]++;writer.println();
648   } finally { }}
649 
650     /**
651      *  @since 2.2
652      * 
653      **/
654 
655     private void writeHiddenFieldsForParameter(
656         IMarkupWriter writer,
657         ILink link,
658         String parameterName)
659     {try { __CLOVER_130_0.M[707]++;
660         __CLOVER_130_0.S[3194]++;String[] values = link.getParameterValues(parameterName);
661 
662         __CLOVER_130_0.S[3195]++;for (int i = 0; (((i < values.length) && (++__CLOVER_130_0.CT[583] != 0)) || (++__CLOVER_130_0.CF[583] == 0)); i++){
663         {
664             __CLOVER_130_0.S[3196]++;writeHiddenField(writer, parameterName, values[i]);
665         }}
666     } finally { }}
667 
668     /**
669      *  Converts the allocateIds property into a string, a comma-separated list of ids.
670      *  This is included as a hidden field in the form and is used to identify
671      *  discrepencies when the form is submitted.
672      * 
673      *  @since 3.0
674      * 
675      **/
676 
677     protected String buildAllocatedIdList()
678     {try { __CLOVER_130_0.M[708]++;
679         __CLOVER_130_0.S[3197]++;StringBuffer buffer = new StringBuffer();
680         __CLOVER_130_0.S[3198]++;int count = _allocatedIds.size();
681 
682         __CLOVER_130_0.S[3199]++;for (int i = 0; (((i < count) && (++__CLOVER_130_0.CT[584] != 0)) || (++__CLOVER_130_0.CF[584] == 0)); i++){
683         {
684             __CLOVER_130_0.S[3200]++;if ((((i > 0) && (++__CLOVER_130_0.CT[585] != 0)) || (++__CLOVER_130_0.CF[585] == 0))){
685                 __CLOVER_130_0.S[3201]++;buffer.append(',');}
686 
687             __CLOVER_130_0.S[3202]++;buffer.append(_allocatedIds.get(i));
688         }}
689 
690         __CLOVER_130_0.S[3203]++;return buffer.toString();
691     } finally { }}
692 
693     /**
694      *  Converts a string passed as a parameter (and containing a comma
695      *  separated list of ids) back into the allocateIds property.
696      * 
697      *  @see #buildAllocatedIdList()
698      * 
699      *  @since 3.0
700      * 
701      **/
702 
703     protected void reconstructAllocatedIds(String storedIdList)
704     {try { __CLOVER_130_0.M[709]++;
705         __CLOVER_130_0.S[3204]++;if ((((Tapestry.isBlank(storedIdList)) && (++__CLOVER_130_0.CT[586] != 0)) || (++__CLOVER_130_0.CF[586] == 0))){
706             __CLOVER_130_0.S[3205]++;return;}
707 
708         __CLOVER_130_0.S[3206]++;StringSplitter splitter = new StringSplitter(',');
709 
710         __CLOVER_130_0.S[3207]++;String[] ids = splitter.splitToArray(storedIdList);
711 
712         __CLOVER_130_0.S[3208]++;for (int i = 0; (((i < ids.length) && (++__CLOVER_130_0.CT[587] != 0)) || (++__CLOVER_130_0.CF[587] == 0)); i++){
713             __CLOVER_130_0.S[3209]++;_allocatedIds.add(ids[i]);}
714     } finally { }}
715 
716     public abstract IValidationDelegate getDelegate();
717 
718     public abstract void setDelegate(IValidationDelegate delegate);
719 
720     public abstract void setDirect(boolean direct);
721 
722     public abstract IActionListener getListener();
723 
724     public abstract String getMethod();
725 
726     /**
727      *  Invoked when not rendering, so it uses the stateful binding.
728      *  If not bound, returns true.
729      * 
730      **/
731 
732     public boolean isStateful()
733     {try { __CLOVER_130_0.M[710]++;
734         __CLOVER_130_0.S[3210]++;IBinding statefulBinding = getStatefulBinding();
735 
736         __CLOVER_130_0.S[3211]++;if ((((statefulBinding == null) && (++__CLOVER_130_0.CT[588] != 0)) || (++__CLOVER_130_0.CF[588] == 0))){
737             __CLOVER_130_0.S[3212]++;return true;}
738 
739         __CLOVER_130_0.S[3213]++;return statefulBinding.getBoolean();
740     } finally { }}
741 
742     public abstract IBinding getStatefulBinding();
743 
744     protected void finishLoad()
745     {try { __CLOVER_130_0.M[711]++;
746         __CLOVER_130_0.S[3214]++;setDirect(true);
747     } finally { }}
748 
749     public void setEncodingType(String encodingType)
750     {try { __CLOVER_130_0.M[712]++;
751         __CLOVER_130_0.S[3215]++;if ((((_encodingType != null && !_encodingType.equals(encodingType)) && (++__CLOVER_130_0.CT[589] != 0)) || (++__CLOVER_130_0.CF[589] == 0))){
752             __CLOVER_130_0.S[3216]++;throw new ApplicationRuntimeException(
753                 Tapestry.format(
754                     "Form.encoding-type-contention",
755                     getExtendedId(),
756                     _encodingType,
757                     encodingType),
758                 this,
759                 null,
760                 null);}
761 
762         __CLOVER_130_0.S[3217]++;_encodingType = encodingType;
763     } finally { }}
764 
765     /**
766      *  Returns the tag of the form.
767      *
768      *  @since 3.0
769      *
770      **/
771 
772     protected String getTag()
773     {try { __CLOVER_130_0.M[713]++;
774         __CLOVER_130_0.S[3218]++;return "form";
775     } finally { }}
776 
777     /**
778      * Returns the name of the element.
779      *
780      *
781      *  @since 3.0
782      **/
783 
784     protected String getDisplayName()
785     {try { __CLOVER_130_0.M[714]++;
786         __CLOVER_130_0.S[3219]++;return "Form";
787     } finally { }}
788 
789     /** @since 3.0 */
790 
791     public void addHiddenValue(String name, String value)
792     {try { __CLOVER_130_0.M[715]++;
793     __CLOVER_130_0.S[3220]++;if ((((_hiddenValues == null) && (++__CLOVER_130_0.CT[590] != 0)) || (++__CLOVER_130_0.CF[590] == 0))){
794       __CLOVER_130_0.S[3221]++;_hiddenValues = new ArrayList();}
795 
796     __CLOVER_130_0.S[3222]++;_hiddenValues.add(new HiddenValue(name, value));
797     } finally { }}
798 
799   /** @since 3.0 */
800 
801   public void addHiddenValue(String name, String id, String value)
802   {try { __CLOVER_130_0.M[716]++;
803     __CLOVER_130_0.S[3223]++;if ((((_hiddenValues == null) && (++__CLOVER_130_0.CT[591] != 0)) || (++__CLOVER_130_0.CF[591] == 0))){
804       __CLOVER_130_0.S[3224]++;_hiddenValues = new ArrayList();}
805 
806     __CLOVER_130_0.S[3225]++;_hiddenValues.add(new HiddenValue(name, id, value));
807   } finally { }}
808 
809     /** 
810      * Writes hidden values accumulated during the render
811      * (by components invoking {@link #addHiddenValue(String, String)}.
812      * 
813      * @since 3.0
814      */
815 
816     protected void writeHiddenValues(IMarkupWriter writer)
817     {try { __CLOVER_130_0.M[717]++;
818         __CLOVER_130_0.S[3226]++;int count = Tapestry.size(_hiddenValues);
819 
820         __CLOVER_130_0.S[3227]++;for (int i = 0; (((i < count) && (++__CLOVER_130_0.CT[592] != 0)) || (++__CLOVER_130_0.CF[592] == 0)); i++){
821         {
822             __CLOVER_130_0.S[3228]++;HiddenValue hv = (HiddenValue) _hiddenValues.get(i);
823 
824             __CLOVER_130_0.S[3229]++;writeHiddenField(writer, hv._name, hv._id, hv._value);
825         }}
826     } finally { }}
827 }