/*
* Field.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 18:02:24 +0100 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
* Institute of Technology. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.app.xmlui.wing.element;
/**
* A class representing an an abstract input control (which is just a fancy name
* for a field :) )
*
* The field element is a container for all information necessary to create a
* form field. The required "type" attribute determines the type of the field,
* while the children tags carry the information on how to build it. Fields can
* only occur in divisions of type "interactive".
*
* There are several types of possible fields and each of these field types
* determine the appropriate parameters on the parameter object. This is the
* only place in the schema where this design pattern is used. It limits the
* proliferation of elements, such as a special element for textarea, select
* lists, text fields etc... as HTML does. It also forces us to treat all fields
* the same.
*
* text: A single-line text input control.
*
* textarea: A multi-line text input control.
*
* password: A single-line text input control where the input text is rendered
* in such a way as to hide the characters from the user.
*
* hidden: An input control that is not rendered on the screen and hidden from
* the user.
*
* button: A button input control that when activated by the user will submit
* the form, including all the fields, back to the server for processing.
*
* checkbox: A boolean input control which may be toggled by the user. A
* checkbox may have several fields which share the same name and each of those
* fields may be toggled independently. This is distinct from a radio button
* where only one field may be toggled.
*
* file: An input control that allows the user to select files to be submitted
* with the form. Note that a form which uses a file field must use the
* multipart method.
*
* radio: A boolean input control which may be toggled by the user. Multiple
* radio button fields may share the same name. When this occurs only one field
* may be selected to be true. This is distinct from a checkbox where multiple
* fields may be toggled.
*
* select: A menu input control which allows the user to select from a list of
* available options.
*
* composite: A combination of multile fields into one input control.
*
* @author Scott Phillips
*/
import java.util.ArrayList;
import java.util.List;
import org.dspace.app.xmlui.wing.AttributeMap;
import org.dspace.app.xmlui.wing.Message;
import org.dspace.app.xmlui.wing.WingContext;
import org.dspace.app.xmlui.wing.WingException;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.NamespaceSupport;
public abstract class Field extends AbstractWingElement implements
StructuralElement
{
/** The name of the field element */
public static final String E_FIELD = "field";
/** The name of the field type attribute */
public static final String A_FIELD_TYPE = "type";
/** The name of the disabled attribute */
public static final String A_DISABLED = "disabled";
/** The name of the required attribute */
public static final String A_REQUIRED = "required";
/** The possible field types */
public static final String TYPE_BUTTON = "button";
public static final String TYPE_CHECKBOX = "checkbox";
public static final String TYPE_FILE = "file";
public static final String TYPE_HIDDEN = "hidden";
public static final String TYPE_PASSWORD = "password";
public static final String TYPE_RADIO = "radio";
public static final String TYPE_SELECT = "select";
public static final String TYPE_TEXT = "text";
public static final String TYPE_TEXTAREA = "textarea";
public static final String TYPE_COMPOSITE = "composite";
/** All the possible field types collected into one array. */
public static final String[] TYPES = { TYPE_BUTTON, TYPE_CHECKBOX,
TYPE_FILE, TYPE_HIDDEN, TYPE_PASSWORD, TYPE_RADIO, TYPE_SELECT,
TYPE_TEXT, TYPE_TEXTAREA, TYPE_COMPOSITE };
/** Possible field behavioral operations */
public static final String OPERATION_ADD = "add";
public static final String OPERATION_DELETE = "delete";
public static final String[] OPERATIONS = {OPERATION_ADD, OPERATION_DELETE};
/** The field's name */
protected String name;
/** The type of field, see TYPES above */
protected String type;
/** Weather this field is disabled */
protected boolean disabled;
/** Weather this field is required */
protected boolean required;
/** Any special rendering instructions */
protected String rend;
/** Additional field parameters */
protected Params params;
/** The fields Label */
protected Label label;
/** Help instructions for this field */
protected Help help;
/** Help link to instructions for this field */
protected HelpLink helpLink;
/** Error instructions for this field */
protected List<Error> errors = new ArrayList<Error>();
/** All sub fields contained within a composite field */
protected List<Field> fields = new ArrayList<Field>();
/** The value of this field */
protected List<Option> options = new ArrayList<Option>();
/** The value of this field */
protected List<Value> values = new ArrayList<Value>();
/** The set of stored values */
protected List<Instance> instances = new ArrayList<Instance>();
/**
* Construct a new field.
*
* @param context
* (Required) The context this element is contained in, such as
* where to route SAX events and what i18n catalogue to use.
*
* @param name
* (Required) a non-unique local identifier used to differentiate
* the element from its siblings within an interactive division.
* This is the name of the field use when data is submitted back
* to the server.
* @param type
* (Required) Specify the type of field, must be one of the field
* types defined in the static variable TYPES.
* @param rend
* (May be null) a rendering hint used to override the default
* display of the element.
*/
protected Field(WingContext context, String name, String type,
String rend) throws WingException
{
super(context);
require(name, "The 'name' parameter is required for all fields.");
require(type, "The 'type' parameter is required for all fields.");
restrict(
type,
TYPES,
"The 'type' parameter must be one of these values: 'button', 'checkbox', 'file', 'hidden', 'password', 'radio', 'select', 'text', 'textarea'.");
this.name = name;
this.type = type;
this.disabled = false;
this.required = false;
this.rend = rend;
}
/** Parameters available on all fields */
/**
* Set this field as required.
*/
public void setRequired()
{
this.required = true;
}
/**
* Set this field to either be required or not required as determined by the
* required parameter.
*
* @param requeired
* Determine if the field is required or not.
*/
public void setRequired(boolean required)
{
this.required = required;
}
/**
* Set this field to be disabled.
*
*/
public void setDisabled()
{
this.disabled = true;
}
/**
* Set this field to either be disabled or enabled as determined by the
* disabled parameter.
*
* @param disabled
* Determine if the field is required or not.
*/
public void setDisabled(boolean disabled)
{
this.disabled = disabled;
}
/** ******************************************************************** */
/** Help * */
/** ******************************************************************** */
/**
* The help element provides help instructions to assist the user in using
* this field.
*
*/
public Help setHelp() throws WingException
{
this.help = new Help(context);
return this.help;
}
/**
* The help element provides help instructions to assist the user in using
* this field.
*
* @param characters
* (May be null) Direct content or a dictionary tag to be
* inserted into the element.
*/
public void setHelp(String characters) throws WingException
{
this.help = new Help(context);
this.help.addContent(characters);
}
/**
* The help element provides help instructions to assist the user in using
* this field.
*
* @param message
* (Required) A key into the i18n catalogue for translation into
* the user's preferred language.
*/
public void setHelp(Message message) throws WingException
{
this.help = new Help(context);
this.help.addContent(message);
}
/**
* The help element provides help instructions to assist the user in using
* this field.
*
*/
public HelpLink createAndSetHelpLink() throws WingException
{
this.helpLink = new HelpLink(context);
return this.helpLink;
}
/** ******************************************************************** */
/** Errors * */
/** ******************************************************************** */
/**
* The error elements denotes that the fields value is invalid for the given
* context. The message contained within the error message will provide
* assistance to the user in correcting the problem.
*
*/
public Error addError() throws WingException
{
Error error = new Error(context);
errors.add(error);
return error;
}
/**
* The error elements denotes that the fields value is invalid for the given
* context. The message contained within the error message will provide
* assistance to the user in correcting the problem.
*
* @param characters
* (May be null) Direct content or a dictionary tag to be
* inserted into the element.
*/
public void addError(String characters) throws WingException
{
Error error = new Error(context);
error.addContent(characters);
errors.add(error);
}
/**
* The error elements denotes that the fields value is invalid for the given
* context. The message contained within the error message will provide
* assistance to the user in correcting the problem.
*
* @param message
* (Required) A key into the i18n catalogue for translation into
* the user's preferred language.
*/
public void addError(Message message) throws WingException
{
Error error = new Error(context);
error.addContent(message);
errors.add(error);
}
/** ******************************************************************** */
/** Label * */
/** ******************************************************************** */
/**
* The help element provides help instructions to assist the user in using
* this field.
*
*/
public Label setLabel() throws WingException
{
this.label = new Label(context,null,null);
return this.label;
}
/**
* The help element provides help instructions to assist the user in using
* this field.
*
* @param characters
* (May be null) Direct content or a dictionary tag to be
* inserted into the element.
*/
public void setLabel(String characters) throws WingException
{
this.label = new Label(context,null,null);
this.label.addContent(characters);
}
/**
* The help element provides help instructions to assist the user in using
* this field.
*
* @param message
* (Required) A key into the i18n catalogue for translation into
* the user's preferred language.
*/
public void setLabel(Message message) throws WingException
{
this.label = new Label(context,null,null);
this.label.addContent(message);
}
/**
* Private function to remove all values of a particular type.
*
* @param removeType
* The type to be removed.
*/
protected void removeValueOfType(String removeType)
{
List<Value> found = new ArrayList<Value>();
for (Value value : values)
if (value.getType().equals(removeType))
found.add(value);
for (Value remove : found)
{
values.remove(remove);
remove.dispose();
}
}
/**
* Translate this element and all contained elements into SAX events. The
* events should be routed to the contentHandler found in the WingContext.
*
* @param contentHandler
* (Required) The registered contentHandler where SAX events
* should be routed too.
* @param lexicalHandler
* (Required) The registered lexicalHandler where lexical events
* (such as CDATA, DTD, etc) should be routed too.
* @param namespaces
* (Required) SAX Helper class to keep track of namespaces able
* to determine the correct prefix for a given namespace URI.
*/
public void toSAX(ContentHandler contentHandler,
LexicalHandler lexicalHandler, NamespaceSupport namespaces)
throws SAXException
{
AttributeMap attributes = new AttributeMap();
attributes.put(A_NAME, this.name);
attributes.put(A_ID, this.context.generateID(E_FIELD, this.name));
attributes.put(A_FIELD_TYPE, this.type);
if (this.disabled)
attributes.put(A_DISABLED, this.disabled);
if (this.required)
attributes.put(A_REQUIRED, this.required);
if (this.rend != null)
attributes.put(A_RENDER, this.rend);
startElement(contentHandler, namespaces, E_FIELD, attributes);
if (params != null)
params.toSAX(contentHandler, lexicalHandler, namespaces);
if (label != null)
label.toSAX(contentHandler, lexicalHandler, namespaces);
if (help != null)
help.toSAX(contentHandler, lexicalHandler, namespaces);
if (helpLink != null)
helpLink.toSAX(contentHandler, lexicalHandler, namespaces);
for (Error error : errors)
error.toSAX(contentHandler, lexicalHandler, namespaces);
for (Field field : fields)
field.toSAX(contentHandler, lexicalHandler, namespaces);
for (Option option : options)
option.toSAX(contentHandler, lexicalHandler, namespaces);
for (Value value : values)
value.toSAX(contentHandler, lexicalHandler, namespaces);
for (Instance instance : instances)
instance.toSAX(contentHandler, lexicalHandler, namespaces);
endElement(contentHandler, namespaces, E_FIELD);
}
/**
* Dispose
*/
public void dispose()
{
if (params != null)
params.dispose();
if (label != null)
label.dispose();
if (help != null)
help.dispose();
if (helpLink != null)
helpLink.dispose();
for (Error error : errors)
error.dispose();
if (errors != null)
errors.clear();
for (Field field : fields)
field.dispose();
if (fields != null)
fields.clear();
for (Option option : options)
option.dispose();
if (options != null)
options.clear();
for (Value value : values)
value.dispose();
if (values != null)
values.clear();
for (Instance instance : instances)
instance.dispose();
if (instances != null)
instances.clear();
params = null;
label = null;
help = null;
helpLink = null;
errors = null;
fields = null;
options = null;
values = null;
instances = null;
super.dispose();
}
}