Author: sabob
Date: Sun Oct 17 12:30:11 2010
New Revision: 1023477
URL: http://svn.apache.org/viewvc?rev=1023477&view=rev
Log:
added stateful support for Form, FieldSet and Field. CLK-715
Modified:
click/trunk/click/framework/src/org/apache/click/control/Field.java
click/trunk/click/framework/src/org/apache/click/control/FieldSet.java
click/trunk/click/framework/src/org/apache/click/control/Form.java
Modified: click/trunk/click/framework/src/org/apache/click/control/Field.java
URL: http://svn.apache.org/viewvc/click/trunk/click/framework/src/org/apache/click/control/Field.java?rev=1023477&r1=1023476&r2=1023477&view=diff
==============================================================================
--- click/trunk/click/framework/src/org/apache/click/control/Field.java (original)
+++ click/trunk/click/framework/src/org/apache/click/control/Field.java Sun Oct 17 12:30:11
2010
@@ -21,6 +21,7 @@ package org.apache.click.control;
import org.apache.click.Context;
import org.apache.click.Control;
import org.apache.click.Page;
+import org.apache.click.Stateful;
import org.apache.commons.lang.StringUtils;
import org.apache.click.util.ClickUtils;
@@ -179,7 +180,7 @@ import org.apache.click.util.HtmlStringB
* </dd>
* </dl>
*/
-public abstract class Field extends AbstractControl {
+public abstract class Field extends AbstractControl implements Stateful {
// Constants --------------------------------------------------------------
@@ -1033,6 +1034,36 @@ public abstract class Field extends Abst
}
/**
+ * Return the Field state. The following state is returned:
+ * <ul>
+ * <li>{@link #getValue() field value}</li>
+ * </ul>
+ *
+ * @return the Field state
+ */
+ public Object getState() {
+ String state = getValue();
+ if (StringUtils.isEmpty(state)) {
+ return null;
+ }
+ return state;
+ }
+
+ /**
+ * Set the Field state.
+ *
+ * @param state the Field state to set
+ */
+ public void setState(Object state) {
+ if (state == null) {
+ return;
+ }
+
+ String fieldState = (String) state;
+ setValue(fieldState);
+ }
+
+ /**
* This method processes the page request returning true to continue
* processing or false otherwise. The Field <tt>onProcess()</tt> method is
* typically invoked by the Form <tt>onProcess()</tt> method when
@@ -1085,6 +1116,48 @@ public abstract class Field extends Abst
}
/**
+ * Remove the Field state from the session for the given request context.
+ *
+ * @see #saveState(org.apache.click.Context)
+ * @see #restoreState(org.apache.click.Context)
+ *
+ * @param context the request context
+ */
+ public void removeState(Context context) {
+ ClickUtils.removeState(this, getName(), context);
+ }
+
+ /**
+ * Restore the Field state from the session for the given request context.
+ * <p/>
+ * This method delegates to {@link #setState(java.lang.Object)} to set the
+ * field restored state.
+ *
+ * @see #saveState(org.apache.click.Context)
+ * @see #removeState(org.apache.click.Context)
+ *
+ * @param context the request context
+ */
+ public void restoreState(Context context) {
+ ClickUtils.restoreState(this, getName(), context);
+ }
+
+ /**
+ * Save the Field state to the session for the given request context.
+ * <p/>
+ * * This method delegates to {@link #getState()} to retrieve the field state
+ * to save.
+ *
+ * @see #restoreState(org.apache.click.Context)
+ * @see #removeState(org.apache.click.Context)
+ *
+ * @param context the request context
+ */
+ public void saveState(Context context) {
+ ClickUtils.saveState(this, getName(), context);
+ }
+
+ /**
* The validate method is invoked by <tt>onProcess()</tt> to validate
* the request submission. Field subclasses should override this method
* to implement request validation logic.
Modified: click/trunk/click/framework/src/org/apache/click/control/FieldSet.java
URL: http://svn.apache.org/viewvc/click/trunk/click/framework/src/org/apache/click/control/FieldSet.java?rev=1023477&r1=1023476&r2=1023477&view=diff
==============================================================================
--- click/trunk/click/framework/src/org/apache/click/control/FieldSet.java (original)
+++ click/trunk/click/framework/src/org/apache/click/control/FieldSet.java Sun Oct 17 12:30:11
2010
@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.apache.click.Context;
import org.apache.click.Control;
import org.apache.click.util.ClickUtils;
import org.apache.click.util.ContainerUtils;
@@ -879,6 +880,55 @@ public class FieldSet extends Field impl
}
/**
+ * Return the FieldSet state. The state will include all the input Field
+ * values and other FieldSets contained in this FieldSet or child containers.
+ *
+ * @return the state of input Fields and FieldSets contained in this FieldSet
+ */
+ @Override
+ public Object getState() {
+ List<Field> fields = new ArrayList<Field>();
+ addStatefulFields(this, fields);
+ Map<String, Object> stateMap = new HashMap<String, Object>();
+ for(Field field : fields) {
+ Object state = field.getState();
+ if(state != null) {
+ stateMap.put(field.getName(), state);
+ }
+ }
+
+ if (stateMap.isEmpty()) {
+ return null;
+ }
+ return stateMap;
+ }
+
+ /**
+ * Set the FieldSet state. The state will be applied to all the input Fields
+ * and FieldSets contained in the FieldSet or child containers.
+ *
+ * @param state the FieldSet state to set
+ */
+ @Override
+ public void setState(Object state) {
+ if (state == null) {
+ return;
+ }
+
+ Map stateMap = (Map) state;
+ List<Field> fields = new ArrayList<Field>();
+ addStatefulFields(this, fields);
+
+ for(Field field : fields) {
+ String fieldName = field.getName();
+ if (stateMap.containsKey(fieldName)) {
+ Object fieldState = stateMap.get(fieldName);
+ field.setState(fieldState);
+ }
+ }
+ }
+
+ /**
* Render the HTML representation of the FieldSet.
* <p/>
* The size of buffer is determined by {@link #getControlSizeEst()}.
@@ -936,6 +986,50 @@ public class FieldSet extends Field impl
}
/**
+ * Remove the FieldSet state from the session for the given request context.
+ *
+ * @see #saveState(org.apache.click.Context)
+ * @see #restoreState(org.apache.click.Context)
+ *
+ * @param context the request context
+ */
+ @Override
+ public void removeState(Context context) {
+ ClickUtils.removeState(this, getName(), context);
+ }
+
+ /**
+ * Restore the FieldSet state from the session for the given request context.
+ * <p/>
+ * This method delegates to {@link #setState(java.lang.Object)} to set the
+ * field restored state.
+ *
+ * @see #saveState(org.apache.click.Context)
+ * @see #removeState(org.apache.click.Context)
+ *
+ * @param context the request context
+ */
+ @Override
+ public void restoreState(Context context) {
+ ClickUtils.restoreState(this, getName(), context);
+ }
+
+ /**
+ * Save the FieldSet state to the session for the given request context.
+ * <p/>
+ * * This method delegates to {@link #getState()} to retrieve the field state
+ * to save.
+ *
+ * @see #restoreState(org.apache.click.Context)
+ * @see #removeState(org.apache.click.Context)
+ *
+ * @param context the request context
+ */
+ public void saveState(Context context) {
+ ClickUtils.saveState(this, getName(), context);
+ }
+
+ /**
* Returns the HTML representation of the FieldSet.
* <p/>
* The rendering of the FieldSet is delegated to
@@ -1253,4 +1347,27 @@ public class FieldSet extends Field impl
return ((Field) control).isHidden();
}
}
+
+ /**
+ * Add fields for the given Container to the specified field list,
+ * recursively including any Fields contained in child containers.
+ *
+ * @param container the container to obtain the fields from
+ * @param fields the list of contained fields
+ */
+ private void addStatefulFields(final Container container, final List<Field> fields)
{
+ for (Control control : container.getControls()) {
+ if (control instanceof Label || control instanceof Button) {
+ // Skip buttons and labels
+ continue;
+ }
+
+ if (control instanceof Field) {
+ fields.add((Field) control);
+ } else if (control instanceof Container) {
+ Container childContainer = (Container) control;
+ addStatefulFields(childContainer, fields);
+ }
+ }
+ }
}
Modified: click/trunk/click/framework/src/org/apache/click/control/Form.java
URL: http://svn.apache.org/viewvc/click/trunk/click/framework/src/org/apache/click/control/Form.java?rev=1023477&r1=1023476&r2=1023477&view=diff
==============================================================================
--- click/trunk/click/framework/src/org/apache/click/control/Form.java (original)
+++ click/trunk/click/framework/src/org/apache/click/control/Form.java Sun Oct 17 12:30:11
2010
@@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletRes
import org.apache.click.Context;
import org.apache.click.Control;
import org.apache.click.Page;
+import org.apache.click.Stateful;
import org.apache.click.element.CssImport;
import org.apache.click.element.Element;
import org.apache.click.element.JsImport;
@@ -504,7 +505,7 @@ import org.apache.commons.lang.StringUti
* @see Field
* @see Submit
*/
-public class Form extends AbstractContainer {
+public class Form extends AbstractContainer implements Stateful {
// Constants --------------------------------------------------------------
@@ -926,6 +927,8 @@ public class Form extends AbstractContai
* the form
* @return the new control that replaced the current control
*
+ * @deprecated this method was used for stateful pages, which have been deprecated
+ *
* @throws IllegalArgumentException if the currentControl or newControl is
* null
* @throws IllegalStateException if the currentControl is not contained in
@@ -1330,6 +1333,7 @@ public class Form extends AbstractContai
}
this.name = name;
+ // TODO: Remove with stateful pages
HiddenField bypassValidationField = (HiddenField) getField(BYPASS_VALIDATION);
if (bypassValidationField == null) {
// Create a hidden field which name and value cannot be change
@@ -1338,10 +1342,11 @@ public class Form extends AbstractContai
insertIndexOffset++;
}
+ // TODO: Remove with stateful pages
HiddenField nameField = (HiddenField) getField(FORM_NAME);
if (nameField == null) {
- // Create a hidden field which name cannot be changed
- nameField = new NonbindableHiddenField(FORM_NAME, String.class);
+ // Create a hidden field that won't be processed and name cannot change
+ nameField = new NonProcessedHiddenField(FORM_NAME, String.class);
add(nameField);
insertIndexOffset++;
}
@@ -1902,6 +1907,53 @@ public class Form extends AbstractContai
}
/**
+ * Return the form state. The state will include all the input Field values
+ * and FieldSets contained in the Form or child containers.
+ *
+ * @return the state of input Fields and FieldSets contained in the form
+ */
+ public Object getState() {
+ List<Field> fields = new ArrayList<Field>();
+ addStatefulFields(this, fields);
+ Map<String, Object> stateMap = new HashMap<String, Object>();
+ for(Field field : fields) {
+ Object state = field.getState();
+ if(state != null) {
+ stateMap.put(field.getName(), state);
+ }
+ }
+
+ if (stateMap.isEmpty()) {
+ return null;
+ }
+ return stateMap;
+ }
+
+ /**
+ * Set the Form state. The state will be applied to all the input Fields
+ * and FieldSets contained in the Form or child containers.
+ *
+ * @param state the Form state to set
+ */
+ public void setState(Object state) {
+ if (state == null) {
+ return;
+ }
+
+ Map stateMap = (Map) state;
+ List<Field> fields = new ArrayList<Field>();
+ addStatefulFields(this, fields);
+
+ for(Field field : fields) {
+ String fieldName = field.getName();
+ if (stateMap.containsKey(fieldName)) {
+ Object fieldState = stateMap.get(fieldName);
+ field.setState(fieldState);
+ }
+ }
+ }
+
+ /**
* Process the Form and its child controls only if the Form was submitted
* by the user.
* <p/>
@@ -2170,6 +2222,48 @@ public class Form extends AbstractContai
}
/**
+ * Remove the Form state from the session for the given request context.
+ *
+ * @see #saveState(org.apache.click.Context)
+ * @see #restoreState(org.apache.click.Context)
+ *
+ * @param context the request context
+ */
+ public void removeState(Context context) {
+ ClickUtils.removeState(this, getName(), context);
+ }
+
+ /**
+ * Restore the Form state from the session for the given request context.
+ * <p/>
+ * This method delegates to {@link #setState(java.lang.Object)} to set the
+ * form restored state.
+ *
+ * @see #saveState(org.apache.click.Context)
+ * @see #removeState(org.apache.click.Context)
+ *
+ * @param context the request context
+ */
+ public void restoreState(Context context) {
+ ClickUtils.restoreState(this, getName(), context);
+ }
+
+ /**
+ * Save the Form state to the session for the given request context.
+ * <p/>
+ * * This method delegates to {@link #getState()} to retrieve the form state
+ * to save.
+ *
+ * @see #restoreState(org.apache.click.Context)
+ * @see #removeState(org.apache.click.Context)
+ *
+ * @param context the request context
+ */
+ public void saveState(Context context) {
+ ClickUtils.saveState(this, getName(), context);
+ }
+
+ /**
* Return the rendered opening form tag and all the forms hidden fields.
*
* @return the rendered form start tag and the forms hidden fields
@@ -2325,7 +2419,7 @@ public class Form extends AbstractContai
// CLK-267: check against adding a duplicate field
HiddenField field = (HiddenField) getField(submitTokenName);
if (field == null) {
- field = new NonbindableHiddenField(submitTokenName, Long.class);
+ field = new NonProcessedHiddenField(submitTokenName, Long.class);
add(field);
insertIndexOffset++;
}
@@ -2983,6 +3077,32 @@ public class Form extends AbstractContai
// Private Methods --------------------------------------------------------
+ /**
+ * Add fields for the given Container to the specified field list,
+ * recursively including any Fields contained in child containers.
+ *
+ * @param container the container to obtain the fields from
+ * @param fields the list of contained fields
+ */
+ private void addStatefulFields(final Container container, final List<Field> fields)
{
+ for (Control control : container.getControls()) {
+ if (control instanceof Label
+ || control instanceof Button
+ || control instanceof NonProcessedHiddenField
+ ) {
+ // Skip buttons and labels and NonProcessedHiddenFields
+ continue;
+ }
+
+ if (control instanceof Field) {
+ fields.add((Field) control);
+ } else if (control instanceof Container) {
+ Container childContainer = (Container) control;
+ addStatefulFields(childContainer, fields);
+ }
+ }
+ }
+
/**
* Return true if the control is hidden, false otherwise.
*
@@ -3001,9 +3121,10 @@ public class Form extends AbstractContai
// Inner Classes ----------------------------------------------------------
/**
- * Provides a HiddenField which does not bind to incoming values.
+ * Provides a HiddenField which does not get processed or bind to its
+ * incoming value. In addition the field name cannot be changed once set.
*/
- private static class NonbindableHiddenField extends HiddenField {
+ private static class NonProcessedHiddenField extends HiddenField {
private static final long serialVersionUID = 1L;
@@ -3013,11 +3134,21 @@ public class Form extends AbstractContai
* @param name the field name
* @param valueClass the Class of the value Object
*/
- public NonbindableHiddenField(String name, Class<?> valueClass) {
+ public NonProcessedHiddenField(String name, Class<?> valueClass) {
super(name, valueClass);
}
/**
+ * Create a field with the given name and value.
+ *
+ * @param name the field name
+ * @param value the value of the field
+ */
+ public NonProcessedHiddenField(String name, Object value) {
+ super(name, value);
+ }
+
+ /**
* This method is overridden to not change the field name once it is set.
*
* @param name the name of the field
@@ -3031,10 +3162,11 @@ public class Form extends AbstractContai
}
/**
- * Overridden to not bind to request value.
+ * Overridden to not process the field or bind to its request value.
*/
@Override
- public void bindRequestValue() {
+ public boolean onProcess() {
+ return true;
}
}
@@ -3042,7 +3174,7 @@ public class Form extends AbstractContai
* Provides a HiddenField which name and value cannot be changed, once it
* is set.
*/
- private static class ImmutableHiddenField extends HiddenField {
+ private static class ImmutableHiddenField extends NonProcessedHiddenField {
private static final long serialVersionUID = 1L;
@@ -3057,19 +3189,6 @@ public class Form extends AbstractContai
}
/**
- * This method is overridden to not change the field name once it is set.
- *
- * @param name the name of the field
- */
- @Override
- public void setName(String name) {
- if (this.name != null) {
- return;
- }
- super.setName(name);
- }
-
- /**
* This method is overridden to not change the field value once it is set.
*
* @param value the field value
|