You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by eh...@apache.org on 2006/10/20 13:59:53 UTC
svn commit: r466081 -
/incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/FormComponent.java
Author: ehillenius
Date: Fri Oct 20 04:59:52 2006
New Revision: 466081
URL: http://svn.apache.org/viewvc?view=rev&rev=466081
Log:
backported 2.0 change: rather then using an attribute modifier, put the disabled bit in the tag in onComponentTag
Modified:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/FormComponent.java
Modified: incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/FormComponent.java
URL: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/FormComponent.java?view=diff&rev=466081&r1=466080&r2=466081
==============================================================================
--- incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/FormComponent.java (original)
+++ incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/markup/html/form/FormComponent.java Fri Oct 20 04:59:52 2006
@@ -75,15 +75,6 @@
*/
public abstract class FormComponent extends WebMarkupContainer
{
- private static final long serialVersionUID = 1L;
-
- private static final String[] EMPTY_STRING_ARRAY = new String[] { "" };
-
- /**
- * The value separator
- */
- public static String VALUE_SEPARATOR = ";";
-
/**
* Typesafe interface to code that is called when visiting a form component.
*/
@@ -99,26 +90,6 @@
}
/**
- * Change object to capture the required flag change
- *
- * @author Igor Vaynberg (ivaynberg)
- */
- private final class RequiredStateChange extends Change
- {
- private static final long serialVersionUID = 1L;
-
- private final boolean required = isRequired();
-
- /**
- * @see wicket.version.undo.Change#undo()
- */
- public void undo()
- {
- setRequired(required);
- }
- }
-
- /**
* Attribute modifier model that returns 'disabled' if a form component is
* disabled or null otherwise (resulting in no attribute being appended).
*/
@@ -157,9 +128,29 @@
}
/**
- * Type that the raw input string will be converted to
+ * Change object to capture the required flag change
+ *
+ * @author Igor Vaynberg (ivaynberg)
*/
- private Class type;
+ private final class RequiredStateChange extends Change
+ {
+ private static final long serialVersionUID = 1L;
+
+ private final boolean required = isRequired();
+
+ /**
+ * @see wicket.version.undo.Change#undo()
+ */
+ public void undo()
+ {
+ setRequired(required);
+ }
+ }
+
+ /**
+ * The value separator
+ */
+ public static String VALUE_SEPARATOR = ";";
/**
* Make empty strings null values boolean. Used by AbstractTextComponent
@@ -167,36 +158,45 @@
*/
protected static final short FLAG_CONVERT_EMPTY_INPUT_STRING_TO_NULL = FLAG_RESERVED1;
+ private static final String[] EMPTY_STRING_ARRAY = new String[] { "" };
+
/**
* Whether this form component should save and restore state between
* sessions. This is false by default.
*/
private static final short FLAG_PERSISTENT = FLAG_RESERVED2;
-
/** Whether or not this component's value is required (non-empty) */
private static final short FLAG_REQUIRED = FLAG_RESERVED3;
private static final String NO_RAW_INPUT = "[-NO-RAW-INPUT-]";
+
+ private static final long serialVersionUID = 1L;
+
+ private transient Object convertedInput;
+
+ /**
+ * The value will be made available to the validator property by means of
+ * ${label}. It does not have any specific meaning to FormComponent itself.
+ */
+ private IModel labelModel = null;
+
/**
* Raw Input entered by the user or NO_RAW_INPUT if nothing is filled in.
*/
private String rawInput = NO_RAW_INPUT;
/**
- * The list of validators for this form component as either an IValidator
- * instance or an array of IValidator instances.
+ * Type that the raw input string will be converted to
*/
- private Object validators = null;
+ private Class type;
/**
- * The value will be made available to the validator property by means of
- * ${label}. It does not have any specific meaning to FormComponent itself.
+ * The list of validators for this form component as either an IValidator
+ * instance or an array of IValidator instances.
*/
- private IModel labelModel = null;
-
- private transient Object convertedInput;
+ private Object validators = null;
/**
* @see wicket.Component#Component(String)
@@ -204,7 +204,6 @@
public FormComponent(final String id)
{
super(id);
- add(new DisabledAttributeModifier(new DisabledAttributeModel()));
// the form decides whether form components are versioned or not
// see Form.setVersioned
setVersioned(false);
@@ -216,7 +215,6 @@
public FormComponent(final String id, IModel model)
{
super(id, model);
- add(new DisabledAttributeModifier(new DisabledAttributeModel()));
// the form decides whether form components are versioned or not
// see Form.setVersioned
setVersioned(false);
@@ -244,369 +242,626 @@
}
/**
- * @return The parent form for this form component
+ * Checks if the form component's 'required' requirement is met
+ *
+ * @return true if the 'required' requirement is met, false otherwise
*/
- public Form getForm()
+ public final boolean checkRequired()
{
- // Look for parent form
- final Form form = (Form)findParent(Form.class);
- if (form == null)
+ if (isRequired())
{
- throw new WicketRuntimeException("Could not find Form parent for " + this);
+ final String input = getInput();
+
+ // when null, check whether this is natural for that component, or
+ // whether - as is the case with text fields - this can only happen
+ // when the component was disabled
+ if (input == null && !isInputNullable())
+ {
+ // this value must have come from a disabled field
+ // do not perform validation
+ return true;
+ }
+
+ // peform validation by looking whether the value is null or empty
+ if (Strings.isEmpty(input))
+ {
+ return false;
+ }
}
- return form;
+ return true;
}
/**
- * The value will be made available to the validator property by means of
- * ${label}. It does not have any specific meaning to FormComponent itself.
- *
- * @param labelModel
- * @return this for chaining
+ * Clears the user input.
*/
- public FormComponent setLabel(final IModel labelModel)
+ public final void clearInput()
{
- this.labelModel = labelModel;
- return this;
+ rawInput = NO_RAW_INPUT;
}
/**
- * The value will be made available to the validator property by means of
- * ${label}. It does not have any specific meaning to FormComponent itself.
+ * Builds and reports an error message. Typically called from a validator.
+ * <p>
+ * This function will iterate over the list of resource keys and try to find
+ * a resource message that matches. Each key is first tried verbatim, and
+ * then a key of form prefix.key is tried; prefix comes from
+ * {@link #getValidatorKeyPrefix()}.
+ * <p>
+ * If a message is found, any variables in it with form ${varname} will be
+ * interpolated given the arguments in the args parameter.
+ * <p>
+ * This method will add a few default arguments to the args map if they are
+ * not already present:
+ * <ul>
+ * <li>input - the raw string value entered by the user</li>
+ * <li>name - the id of the this form component</li>
+ * <li>label - string value of object returned from the {@link #getLabel()}
+ * model</li>
+ * </ul>
*
- * @return labelModel
- */
- public IModel getLabel()
- {
- return this.labelModel;
- }
-
- /**
- * Gets the request parameter for this component as a string.
*
- * @return The value in the request for this component
+ * @param resourceKeys
+ * list of resource keys to try
+ * @param args
+ * argument substituion map with format map:varname->varvalue
*/
- // TODO Post 1.2: make this final, if the users want to override this they
- // should really be overriding #getInputAsArray()
- public String getInput()
+ public final void error(List/* <String> */resourceKeys, Map/* <String,String> */args)
{
- String[] input = getInputAsArray();
- if (input == null || input.length == 0)
+ String prefix = getValidatorKeyPrefix();
+ if (Strings.isEmpty(prefix))
{
- return null;
+ prefix = "";
}
- else
+
+ // prepare the arguments map by adding default arguments such as input,
+ // name, and label
+ final Map fullArgs;
+ if (args == null)
{
- return input[0];
+ fullArgs = new HashMap(6);
}
- }
-
- /**
- * Gets the request parameters for this component as strings.
- *
- * @return The values in the request for this component
- */
- public String[] getInputAsArray()
- {
- String[] values = getRequest().getParameters(getInputName());
- if (!isInputNullable())
+ else
{
- if (values != null && values.length == 1 && values[0] == null)
- {
- // we the key got passed in (otherwise values would be null),
- // but the value was set to null.
- // As the servlet spec isn't clear on what to do with 'empty'
- // request values - most return an empty string, but some null -
- // we have to workaround here and deliberately set to an empty
- // string if the the component is not nullable (text components)
- return EMPTY_STRING_ARRAY;
- }
+ fullArgs = new HashMap(args.size() + 6);
+ fullArgs.putAll(args);
}
- return values;
- }
- /**
- * Gets the string to be used for the <tt>name</tt> attribute of the form
- * element. Generated using the path from the form to the component,
- * excluding the form itself. Override it if you want even a smaller name.
- * E.g. if you know for sure that the id is unique within a form.
- *
- * @return The string to use as the form element's name attribute
- */
- public String getInputName()
- {
- String id = getId();
- final PrependingStringBuffer inputName = new PrependingStringBuffer(id.length());
- Component c = this;
- while (true)
+ if (!fullArgs.containsKey("input"))
{
- inputName.prepend(id);
- c = c.getParent();
- if (c == null || c instanceof Form || c instanceof Page)
- {
- break;
- }
- inputName.prepend(Component.PATH_SEPARATOR);
- id = c.getId();
+ fullArgs.put("input", getInput());
}
- return inputName.toString();
- }
-
- /**
- * Gets an unmodifiable list of validators for this FormComponent.
- *
- * @return List of validators
- */
- public final List getValidators()
- {
- final int size = validators_size();
- if (size == 0)
+ if (!fullArgs.containsKey("name"))
{
- return Collections.EMPTY_LIST;
+ fullArgs.put("name", getId());
}
- else
+ if (!fullArgs.containsKey("label"))
{
- final List list = new ArrayList();
- for (int i = 0; i < size; i++)
+ Object label = null;
+ if (getLabel() != null)
{
- list.add(validators_get(i));
+ label = getLabel().getObject(this);
+ }
+ if (label != null)
+ {
+ fullArgs.put("label", label);
+ }
+ else
+ {
+ // apply default value (component id) if key/value can not be
+ // found
+ fullArgs.put("label", getLocalizer().getString(getId(), getParent(), getId()));
}
- return Collections.unmodifiableList(list);
- }
- }
-
- /**
- * Gets current value for a form component.
- *
- * @return The value
- */
- public final String getValue()
- {
- if (NO_RAW_INPUT.equals(rawInput))
- {
- return getModelValue();
}
- else
+
+ final IModel argsModel = new Model((Serializable)fullArgs);
+
+ // iterate through keys in order they were provided
+
+ final Localizer localizer = getLocalizer();
+ final Iterator keys = resourceKeys.iterator();
+
+ String message = null;
+
+ while (keys.hasNext())
{
- if (getEscapeModelStrings() && rawInput != null)
+ final String key = (String)keys.next();
+
+ String resource = prefix + getId() + "." + key;
+
+ // Note: It is important that the default value of "" is provided
+ // to getString() not to throw a MissingResourceException or to
+ // return a default string like "[Warning: String ..."
+ message = localizer.getString(resource, getParent(), argsModel, "");
+
+ // If not found, than ..
+ if (Strings.isEmpty(message))
{
- return Strings.escapeMarkup(rawInput).toString();
+ // Have a 2nd try with the class name as the key. This makes for
+ // keys like "RequiredValidator" in any of the properties files
+ // along the path.
+
+ resource = prefix + key;
+
+ if (keys.hasNext())
+ {
+ message = localizer.getString(resource, this, argsModel, "");
+ }
+ else
+ {
+ /*
+ * Note: This is the last key we are going to try. It is
+ * important that the default value of "" is NOT provided to
+ * getString() throw either MissingResourceException or to
+ * to return a default string like "[Warning: String ..." in
+ * case the property could not be found.
+ */
+ message = localizer.getString(resource, this, argsModel);
+ }
}
- return rawInput;
+
+ if (!Strings.isEmpty(message))
+ {
+ break;
+ }
+
}
- }
- /**
- * Use hasRawInput() to check if this component has raw input because null
- * can mean 2 things: It doesn't have rawinput or the rawinput is really
- * null.
- *
- * @return The raw form input that is stored for this formcomponent
- */
- public final String getRawInput()
- {
- return rawInput == NO_RAW_INPUT ? null : rawInput;
+ error(message);
}
/**
- * This method can be called to know if this component really has raw input.
- *
- * @return boolean if this form component has rawinput.
+ * @return value of input converted into appropriate type if any was set
*/
- public final boolean hasRawInput()
+ public final Object getConvertedInput()
{
- return rawInput != NO_RAW_INPUT;
+ return convertedInput;
}
-
/**
- * Called to indicate that
+ * @return The parent form for this form component
*/
- public final void invalid()
+ public Form getForm()
{
- onInvalid();
+ // Look for parent form
+ final Form form = (Form)findParent(Form.class);
+ if (form == null)
+ {
+ throw new WicketRuntimeException("Could not find Form parent for " + this);
+ }
+ return form;
}
/**
- * @return True if this component encodes data in a multipart form submit
+ * Gets the request parameter for this component as a string.
+ *
+ * @return The value in the request for this component
*/
- public boolean isMultiPart()
+ // TODO Post 1.2: make this final, if the users want to override this they
+ // should really be overriding #getInputAsArray()
+ public String getInput()
{
- return false;
+ String[] input = getInputAsArray();
+ if (input == null || input.length == 0)
+ {
+ return null;
+ }
+ else
+ {
+ return input[0];
+ }
}
/**
- * @return True if this component supports persistence AND it has been asked
- * to persist itself with setPersistent().
+ * Gets the request parameters for this component as strings.
+ *
+ * @return The values in the request for this component
*/
- public final boolean isPersistent()
+ public String[] getInputAsArray()
{
- return supportsPersistence() && getFlag(FLAG_PERSISTENT);
+ String[] values = getRequest().getParameters(getInputName());
+ if (!isInputNullable())
+ {
+ if (values != null && values.length == 1 && values[0] == null)
+ {
+ // we the key got passed in (otherwise values would be null),
+ // but the value was set to null.
+ // As the servlet spec isn't clear on what to do with 'empty'
+ // request values - most return an empty string, but some null -
+ // we have to workaround here and deliberately set to an empty
+ // string if the the component is not nullable (text components)
+ return EMPTY_STRING_ARRAY;
+ }
+ }
+ return values;
}
/**
- * Gets whether this component is 'valid'. Valid in this context means that
- * no validation errors were reported the last time the form component was
- * processed. This variable not only is convenient for 'business' use, but
- * is also nescesarry as we don't want the form component models updated
- * with invalid input.
+ * Gets the string to be used for the <tt>name</tt> attribute of the form
+ * element. Generated using the path from the form to the component,
+ * excluding the form itself. Override it if you want even a smaller name.
+ * E.g. if you know for sure that the id is unique within a form.
*
- * @return valid whether this component is 'valid'
+ * @return The string to use as the form element's name attribute
*/
- public final boolean isValid()
+ public String getInputName()
{
- return !hasErrorMessage();
+ String id = getId();
+ final PrependingStringBuffer inputName = new PrependingStringBuffer(id.length());
+ Component c = this;
+ while (true)
+ {
+ inputName.prepend(id);
+ c = c.getParent();
+ if (c == null || c instanceof Form || c instanceof Page)
+ {
+ break;
+ }
+ inputName.prepend(Component.PATH_SEPARATOR);
+ id = c.getId();
+ }
+ return inputName.toString();
}
/**
- * Gets whether this component is to be validated.
+ * The value will be made available to the validator property by means of
+ * ${label}. It does not have any specific meaning to FormComponent itself.
*
- * @return True if this component has one or more validators
+ * @return labelModel
*/
- public final boolean isValidated()
+ public IModel getLabel()
{
- return this.validators != null;
+ return this.labelModel;
}
/**
- * Gets whether this component's input can be null. By default, components
- * that do not get input will have null values passed in for input. However,
- * component TextField is an example (possibly the only one) that never gets
- * a null passed in, even if the field is left empty UNLESS it had attribute
- * <code>disabled="disabled"</code> set.
+ * Use hasRawInput() to check if this component has raw input because null
+ * can mean 2 things: It doesn't have rawinput or the rawinput is really
+ * null.
*
- * @return True if this component's input can be null. Returns true by
- * default.
+ * @return The raw form input that is stored for this formcomponent
*/
- public boolean isInputNullable()
+ public final String getRawInput()
{
- return true;
+ return rawInput == NO_RAW_INPUT ? null : rawInput;
}
/**
- * Sets the value for a form component this value will be split the string
- * with {@link FormComponent#VALUE_SEPARATOR} and calls
- * setModelValue(String[]) with that.
- *
- * @param value
- * The value
- *
- * @depricated call or override setModelValue(String[])
+ * @return the type to use when updating the model for this form component
*/
- public void setModelValue(final String value)
+ public final Class getType()
{
- setModelValue(value.split(VALUE_SEPARATOR));
+ return type;
}
+
/**
- * Sets the value for a form component.
- *
- * @param value
- * The value
+ * @see Form#getValidatorKeyPrefix()
+ * @return prefix used when constructing validator key messages
*/
- public void setModelValue(final String[] value)
+ public String getValidatorKeyPrefix()
{
- convertedInput = convertValue(value);
- updateModel();
+ Form form = (Form)findParent(Form.class);
+ if (form != null)
+ {
+ return getForm().getValidatorKeyPrefix();
+ }
+ return null;
}
/**
- * Sets whether this component is to be persisted.
+ * Gets an unmodifiable list of validators for this FormComponent.
*
- * @param persistent
- * True if this component is to be persisted.
- * @return this for chaining
+ * @return List of validators
*/
- public final FormComponent setPersistent(final boolean persistent)
+ public final List getValidators()
{
- if (supportsPersistence())
+ final int size = validators_size();
+ if (size == 0)
{
- setFlag(FLAG_PERSISTENT, persistent);
+ return Collections.EMPTY_LIST;
}
else
{
- throw new UnsupportedOperationException("FormComponent " + getClass()
- + " does not support cookies");
+ final List list = new ArrayList();
+ for (int i = 0; i < size; i++)
+ {
+ list.add(validators_get(i));
+ }
+ return Collections.unmodifiableList(list);
}
- return this;
}
/**
- * Updates this components' model from the request, it expect that the
- * object is already converted through the convert() call. By default it
- * just does this:
- *
- * <pre>
- * setModelObject(getConvertedInput());
- * </pre>
+ * Gets current value for a form component.
*
- * DO NOT CALL THIS METHOD DIRECTLY UNLESS YOU ARE SURE WHAT YOU ARE DOING.
- * USUALLY UPDATING YOUR MODEL IS HANDLED BY THE FORM, NOT DIRECTLY BY YOU.
+ * @return The value
*/
- public void updateModel()
+ public final String getValue()
{
- setModelObject(getConvertedInput());
+ if (NO_RAW_INPUT.equals(rawInput))
+ {
+ return getModelValue();
+ }
+ else
+ {
+ if (getEscapeModelStrings() && rawInput != null)
+ {
+ return Strings.escapeMarkup(rawInput).toString();
+ }
+ return rawInput;
+ }
}
/**
- * Called to indicate that the user input is valid.
+ * This method can be called to know if this component really has raw input.
+ *
+ * @return boolean if this form component has rawinput.
*/
- public final void valid()
+ public final boolean hasRawInput()
{
- clearInput();
+ return rawInput != NO_RAW_INPUT;
+ }
- onValid();
+ /**
+ * Used by Form to tell the FormComponent that a new user input is available
+ */
+ public final void inputChanged()
+ {
+ if (isVisibleInHierarchy() && isEnabled())
+ {
+ // Get input as String array
+ final String[] input = getInputAsArray();
+
+ // If there is any input
+ if (input != null && input.length > 0 && input[0] != null)
+ {
+ // join the values together with ";", for example, "id1;id2;id3"
+ rawInput = StringList.valueOf(input).join(VALUE_SEPARATOR);
+ }
+ else if (isInputNullable())
+ {
+ // no input
+ rawInput = null;
+ }
+ else
+ {
+ rawInput = NO_RAW_INPUT;
+ }
+ }
}
/**
- * Clears the user input.
+ * Called to indicate that
*/
- public final void clearInput()
+ public final void invalid()
{
- rawInput = NO_RAW_INPUT;
+ onInvalid();
}
/**
- * Checks if the form component's 'required' requirement is met
+ * Gets whether this component's input can be null. By default, components
+ * that do not get input will have null values passed in for input. However,
+ * component TextField is an example (possibly the only one) that never gets
+ * a null passed in, even if the field is left empty UNLESS it had attribute
+ * <code>disabled="disabled"</code> set.
*
- * @return true if the 'required' requirement is met, false otherwise
+ * @return True if this component's input can be null. Returns true by
+ * default.
*/
- public final boolean checkRequired()
+ public boolean isInputNullable()
{
- if (isRequired())
+ return true;
+ }
+
+ /**
+ * @return True if this component encodes data in a multipart form submit
+ */
+ public boolean isMultiPart()
+ {
+ return false;
+ }
+
+ /**
+ * @return True if this component supports persistence AND it has been asked
+ * to persist itself with setPersistent().
+ */
+ public final boolean isPersistent()
+ {
+ return supportsPersistence() && getFlag(FLAG_PERSISTENT);
+ }
+
+ /**
+ * @return whether or not this component's value is required
+ */
+ public boolean isRequired()
+ {
+ return getFlag(FLAG_REQUIRED);
+ }
+
+ /**
+ * Gets whether this component is 'valid'. Valid in this context means that
+ * no validation errors were reported the last time the form component was
+ * processed. This variable not only is convenient for 'business' use, but
+ * is also nescesarry as we don't want the form component models updated
+ * with invalid input.
+ *
+ * @return valid whether this component is 'valid'
+ */
+ public final boolean isValid()
+ {
+ return !hasErrorMessage();
+ }
+
+ /**
+ * Gets whether this component is to be validated.
+ *
+ * @return True if this component has one or more validators
+ */
+ public final boolean isValidated()
+ {
+ return this.validators != null;
+ }
+
+ /**
+ * This method will retrieve the request parameter, validate it, and if
+ * valid update the model. These are the same steps as would be performed by
+ * the form.
+ *
+ * This is useful when a formcomponent is used outside a form.
+ *
+ */
+ public final void processInput()
+ {
+ inputChanged();
+ validate();
+ if (hasErrorMessage())
{
- final String input = getInput();
+ invalid();
+ }
+ else
+ {
+ valid();
+ updateModel();
+ }
+ }
- // when null, check whether this is natural for that component, or
- // whether - as is the case with text fields - this can only happen
- // when the component was disabled
- if (input == null && !isInputNullable())
- {
- // this value must have come from a disabled field
- // do not perform validation
- return true;
- }
+ /**
+ * The value will be made available to the validator property by means of
+ * ${label}. It does not have any specific meaning to FormComponent itself.
+ *
+ * @param labelModel
+ * @return this for chaining
+ */
+ public FormComponent setLabel(final IModel labelModel)
+ {
+ this.labelModel = labelModel;
+ return this;
+ }
- // peform validation by looking whether the value is null or empty
- if (Strings.isEmpty(input))
- {
- return false;
- }
+
+ /**
+ * Sets the value for a form component this value will be split the string
+ * with {@link FormComponent#VALUE_SEPARATOR} and calls
+ * setModelValue(String[]) with that.
+ *
+ * @param value
+ * The value
+ *
+ * @depricated call or override setModelValue(String[])
+ */
+ public void setModelValue(final String value)
+ {
+ setModelValue(value.split(VALUE_SEPARATOR));
+ }
+
+ /**
+ * Sets the value for a form component.
+ *
+ * @param value
+ * The value
+ */
+ public void setModelValue(final String[] value)
+ {
+ convertedInput = convertValue(value);
+ updateModel();
+ }
+
+ /**
+ * Sets whether this component is to be persisted.
+ *
+ * @param persistent
+ * True if this component is to be persisted.
+ * @return this for chaining
+ */
+ public final FormComponent setPersistent(final boolean persistent)
+ {
+ if (supportsPersistence())
+ {
+ setFlag(FLAG_PERSISTENT, persistent);
}
- return true;
+ else
+ {
+ throw new UnsupportedOperationException("FormComponent " + getClass()
+ + " does not support cookies");
+ }
+ return this;
}
/**
- * Checks if the raw input value is not null if this component is required
+ * Sets the required flag
+ *
+ * @param required
+ * @return this for chaining
*/
- protected final void validateRequired()
+ public final FormComponent setRequired(final boolean required)
{
- if (!checkRequired())
+ if (!required && type != null && type.isPrimitive())
{
- error(Collections.singletonList("RequiredValidator"), new HashMap());
+ throw new WicketRuntimeException(
+ "FormComponent can't be not required when the type is primitive class: " + this);
}
+ if (required != isRequired())
+ {
+ addStateChange(new RequiredStateChange());
+ }
+ setFlag(FLAG_REQUIRED, required);
+ return this;
+ }
+
+ /**
+ * Sets the type that will be used when updating the model for this
+ * component. If no type is specified String type is assumed.
+ *
+ * @param type
+ * @return this for chaining
+ */
+ public final FormComponent setType(Class type)
+ {
+ this.type = type;
+ if (type != null && type.isPrimitive())
+ setRequired(true);
+ return this;
+ }
+
+ /**
+ * Updates this components' model from the request, it expect that the
+ * object is already converted through the convert() call. By default it
+ * just does this:
+ *
+ * <pre>
+ * setModelObject(getConvertedInput());
+ * </pre>
+ *
+ * DO NOT CALL THIS METHOD DIRECTLY UNLESS YOU ARE SURE WHAT YOU ARE DOING.
+ * USUALLY UPDATING YOUR MODEL IS HANDLED BY THE FORM, NOT DIRECTLY BY YOU.
+ */
+ public void updateModel()
+ {
+ setModelObject(getConvertedInput());
}
+ /**
+ * Called to indicate that the user input is valid.
+ */
+ public final void valid()
+ {
+ clearInput();
+
+ onValid();
+ }
+
+ /**
+ * Performs full validation of the form component, which consists of calling
+ * validateRequired(), validateTypeConversion(), and validateValidators().
+ * This method should only be used if the form component needs to be fully
+ * validated outside the form process.
+ */
+ public final void validate()
+ {
+ validateRequired();
+ convert();
+ validateValidators();
+ }
/**
* Converts and validates the conversion of the raw input string into the
@@ -711,51 +966,6 @@
return value != null && value.length > 0 && value[0] != null ? value[0].trim() : null;
}
- /**
- * Performs full validation of the form component, which consists of calling
- * validateRequired(), validateTypeConversion(), and validateValidators().
- * This method should only be used if the form component needs to be fully
- * validated outside the form process.
- */
- public final void validate()
- {
- validateRequired();
- convert();
- validateValidators();
- }
-
- /**
- * Validates this component using the component's validators.
- */
- protected final void validateValidators()
- {
- final int size = validators_size();
-
- int i = 0;
- IValidator validator = null;
- try
- {
- for (i = 0; i < size; i++)
- {
- validator = validators_get(i);
- validator.validate(this);
- if (!isValid())
- {
- break;
- }
- }
- }
- catch (Exception e)
- {
- String name = "<null>";
- if (validator != null)
- {
- name = validator.getClass().getName();
- }
- throw new WicketRuntimeException("Exception '" + e + "' occurred during validation "
- + name + " on component " + this.getPath(), e);
- }
- }
/**
* @return Value to return when model value is needed
@@ -840,192 +1050,39 @@
* @return The values in the request for this component
* @deprecated Use {@link #getInputAsArray()} instead
*/
- // TODO Post 1.2: remove
- protected final String[] inputAsStringArray()
- {
- return getInputAsArray();
- }
-
- /**
- * Processes the component tag.
- *
- * @param tag
- * Tag to modify
- * @see wicket.Component#onComponentTag(ComponentTag)
- */
- protected void onComponentTag(final ComponentTag tag)
- {
- tag.put("name", getInputName());
- super.onComponentTag(tag);
- }
-
- /**
- * Handle invalidation
- */
- protected void onInvalid()
- {
- }
-
-
- /**
- * @see wicket.Component#internalOnModelChanged()
- */
- protected void internalOnModelChanged()
- {
- // If the model for this form component changed, we should make it
- // valid again because there can't be any invalid input for it anymore.
- valid();
- }
-
- /**
- * Handle validation
- */
- protected void onValid()
- {
- }
-
- /**
- * @return True if this type of FormComponent can be persisted.
- */
- protected boolean supportsPersistence()
- {
- return false;
- }
-
- /**
- * @param validator
- * The validator to add to the validators Object (which may be an
- * array of IValidators or a single instance, for efficiency)
- */
- private void validators_add(final IValidator validator)
- {
- if (this.validators == null)
- {
- this.validators = validator;
- }
- else
- {
- // Get current list size
- final int size = validators_size();
-
- // Create array that holds size + 1 elements
- final IValidator[] validators = new IValidator[size + 1];
-
- // Loop through existing validators copying them
- for (int i = 0; i < size; i++)
- {
- validators[i] = validators_get(i);
- }
-
- // Add new validator to the end
- validators[size] = validator;
-
- // Save new validator list
- this.validators = validators;
- }
- }
-
- /**
- * Gets validator from validators Object (which may be an array of
- * IValidators or a single instance, for efficiency) at the given index
- *
- * @param index
- * The index of the validator to get
- * @return The validator
- */
- private IValidator validators_get(int index)
- {
- if (this.validators == null)
- {
- throw new IndexOutOfBoundsException();
- }
- if (this.validators instanceof IValidator[])
- {
- return ((IValidator[])validators)[index];
- }
- return (IValidator)validators;
- }
-
- /**
- * @return The number of validators in the validators Object (which may be
- * an array of IValidators or a single instance, for efficiency)
- */
- private int validators_size()
- {
- if (this.validators == null)
- {
- return 0;
- }
- if (this.validators instanceof IValidator[])
- {
- return ((IValidator[])validators).length;
- }
- return 1;
- }
-
- /**
- * Used by Form to tell the FormComponent that a new user input is available
- */
- public final void inputChanged()
- {
- if (isVisibleInHierarchy() && isEnabled())
- {
- // Get input as String array
- final String[] input = getInputAsArray();
-
- // If there is any input
- if (input != null && input.length > 0 && input[0] != null)
- {
- // join the values together with ";", for example, "id1;id2;id3"
- rawInput = StringList.valueOf(input).join(VALUE_SEPARATOR);
- }
- else if (isInputNullable())
- {
- // no input
- rawInput = null;
- }
- else
- {
- rawInput = NO_RAW_INPUT;
- }
- }
- }
-
- /**
- * Sets the required flag
- *
- * @param required
- * @return this for chaining
- */
- public final FormComponent setRequired(final boolean required)
- {
- if (!required && type != null && type.isPrimitive())
- {
- throw new WicketRuntimeException(
- "FormComponent can't be not required when the type is primitive class: " + this);
- }
- if (required != isRequired())
- {
- addStateChange(new RequiredStateChange());
- }
- setFlag(FLAG_REQUIRED, required);
- return this;
+ // TODO Post 1.2: remove
+ protected final String[] inputAsStringArray()
+ {
+ return getInputAsArray();
}
/**
- * @return whether or not this component's value is required
+ * @see wicket.Component#internalOnModelChanged()
*/
- public boolean isRequired()
+ protected void internalOnModelChanged()
{
- return getFlag(FLAG_REQUIRED);
+ // If the model for this form component changed, we should make it
+ // valid again because there can't be any invalid input for it anymore.
+ valid();
}
/**
- * @return value of input converted into appropriate type if any was set
+ * Processes the component tag.
+ *
+ * @param tag
+ * Tag to modify
+ * @see wicket.Component#onComponentTag(ComponentTag)
*/
- public final Object getConvertedInput()
+ protected void onComponentTag(final ComponentTag tag)
{
- return convertedInput;
+ tag.put("name", getInputName());
+
+ if (!isEnabled() || !isEnableAllowed())
+ {
+ tag.put("disabled", "disabled");
+ }
+
+ super.onComponentTag(tag);
}
protected void onDetach()
@@ -1035,193 +1092,140 @@
}
/**
- * @return the type to use when updating the model for this form component
+ * Handle invalidation
*/
- public final Class getType()
+ protected void onInvalid()
{
- return type;
}
/**
- * Sets the type that will be used when updating the model for this
- * component. If no type is specified String type is assumed.
- *
- * @param type
- * @return this for chaining
+ * Handle validation
*/
- public final FormComponent setType(Class type)
+ protected void onValid()
{
- this.type = type;
- if (type != null && type.isPrimitive())
- setRequired(true);
- return this;
}
/**
- * @see Form#getValidatorKeyPrefix()
- * @return prefix used when constructing validator key messages
+ * @return True if this type of FormComponent can be persisted.
*/
- public String getValidatorKeyPrefix()
+ protected boolean supportsPersistence()
{
- Form form = (Form)findParent(Form.class);
- if (form != null)
- {
- return getForm().getValidatorKeyPrefix();
- }
- return null;
+ return false;
}
/**
- * Builds and reports an error message. Typically called from a validator.
- * <p>
- * This function will iterate over the list of resource keys and try to find
- * a resource message that matches. Each key is first tried verbatim, and
- * then a key of form prefix.key is tried; prefix comes from
- * {@link #getValidatorKeyPrefix()}.
- * <p>
- * If a message is found, any variables in it with form ${varname} will be
- * interpolated given the arguments in the args parameter.
- * <p>
- * This method will add a few default arguments to the args map if they are
- * not already present:
- * <ul>
- * <li>input - the raw string value entered by the user</li>
- * <li>name - the id of the this form component</li>
- * <li>label - string value of object returned from the {@link #getLabel()}
- * model</li>
- * </ul>
- *
- *
- * @param resourceKeys
- * list of resource keys to try
- * @param args
- * argument substituion map with format map:varname->varvalue
+ * Checks if the raw input value is not null if this component is required
*/
- public final void error(List/* <String> */resourceKeys, Map/* <String,String> */args)
+ protected final void validateRequired()
{
- String prefix = getValidatorKeyPrefix();
- if (Strings.isEmpty(prefix))
+ if (!checkRequired())
{
- prefix = "";
+ error(Collections.singletonList("RequiredValidator"), new HashMap());
}
+ }
- // prepare the arguments map by adding default arguments such as input,
- // name, and label
- final Map fullArgs;
- if (args == null)
- {
- fullArgs = new HashMap(6);
- }
- else
- {
- fullArgs = new HashMap(args.size() + 6);
- fullArgs.putAll(args);
- }
+ /**
+ * Validates this component using the component's validators.
+ */
+ protected final void validateValidators()
+ {
+ final int size = validators_size();
- if (!fullArgs.containsKey("input"))
- {
- fullArgs.put("input", getInput());
- }
- if (!fullArgs.containsKey("name"))
- {
- fullArgs.put("name", getId());
- }
- if (!fullArgs.containsKey("label"))
+ int i = 0;
+ IValidator validator = null;
+ try
{
- Object label = null;
- if (getLabel() != null)
- {
- label = getLabel().getObject(this);
- }
- if (label != null)
+ for (i = 0; i < size; i++)
{
- fullArgs.put("label", label);
+ validator = validators_get(i);
+ validator.validate(this);
+ if (!isValid())
+ {
+ break;
+ }
}
- else
+ }
+ catch (Exception e)
+ {
+ String name = "<null>";
+ if (validator != null)
{
- // apply default value (component id) if key/value can not be
- // found
- fullArgs.put("label", getLocalizer().getString(getId(), getParent(), getId()));
+ name = validator.getClass().getName();
}
+ throw new WicketRuntimeException("Exception '" + e + "' occurred during validation "
+ + name + " on component " + this.getPath(), e);
}
+ }
- final IModel argsModel = new Model((Serializable)fullArgs);
-
- // iterate through keys in order they were provided
-
- final Localizer localizer = getLocalizer();
- final Iterator keys = resourceKeys.iterator();
-
- String message = null;
-
- while (keys.hasNext())
+ /**
+ * @param validator
+ * The validator to add to the validators Object (which may be an
+ * array of IValidators or a single instance, for efficiency)
+ */
+ private void validators_add(final IValidator validator)
+ {
+ if (this.validators == null)
{
- final String key = (String)keys.next();
-
- String resource = prefix + getId() + "." + key;
+ this.validators = validator;
+ }
+ else
+ {
+ // Get current list size
+ final int size = validators_size();
- // Note: It is important that the default value of "" is provided
- // to getString() not to throw a MissingResourceException or to
- // return a default string like "[Warning: String ..."
- message = localizer.getString(resource, getParent(), argsModel, "");
+ // Create array that holds size + 1 elements
+ final IValidator[] validators = new IValidator[size + 1];
- // If not found, than ..
- if (Strings.isEmpty(message))
+ // Loop through existing validators copying them
+ for (int i = 0; i < size; i++)
{
- // Have a 2nd try with the class name as the key. This makes for
- // keys like "RequiredValidator" in any of the properties files
- // along the path.
-
- resource = prefix + key;
-
- if (keys.hasNext())
- {
- message = localizer.getString(resource, this, argsModel, "");
- }
- else
- {
- /*
- * Note: This is the last key we are going to try. It is
- * important that the default value of "" is NOT provided to
- * getString() throw either MissingResourceException or to
- * to return a default string like "[Warning: String ..." in
- * case the property could not be found.
- */
- message = localizer.getString(resource, this, argsModel);
- }
+ validators[i] = validators_get(i);
}
- if (!Strings.isEmpty(message))
- {
- break;
- }
+ // Add new validator to the end
+ validators[size] = validator;
+ // Save new validator list
+ this.validators = validators;
}
+ }
- error(message);
+ /**
+ * Gets validator from validators Object (which may be an array of
+ * IValidators or a single instance, for efficiency) at the given index
+ *
+ * @param index
+ * The index of the validator to get
+ * @return The validator
+ */
+ private IValidator validators_get(int index)
+ {
+ if (this.validators == null)
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ if (this.validators instanceof IValidator[])
+ {
+ return ((IValidator[])validators)[index];
+ }
+ return (IValidator)validators;
}
/**
- * This method will retrieve the request parameter, validate it, and if
- * valid update the model. These are the same steps as would be performed by
- * the form.
- *
- * This is useful when a formcomponent is used outside a form.
- *
+ * @return The number of validators in the validators Object (which may be
+ * an array of IValidators or a single instance, for efficiency)
*/
- public final void processInput()
+ private int validators_size()
{
- inputChanged();
- validate();
- if (hasErrorMessage())
+ if (this.validators == null)
{
- invalid();
+ return 0;
}
- else
+ if (this.validators instanceof IValidator[])
{
- valid();
- updateModel();
+ return ((IValidator[])validators).length;
}
+ return 1;
}
}