001: /*
002: * Field.java
003: *
004: * Version: $Revision: 1.15 $
005: *
006: * Date: $Date: 2006/07/20 21:47:44 $
007: *
008: * Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
009: * Institute of Technology. All rights reserved.
010: *
011: * Redistribution and use in source and binary forms, with or without
012: * modification, are permitted provided that the following conditions are
013: * met:
014: *
015: * - Redistributions of source code must retain the above copyright
016: * notice, this list of conditions and the following disclaimer.
017: *
018: * - Redistributions in binary form must reproduce the above copyright
019: * notice, this list of conditions and the following disclaimer in the
020: * documentation and/or other materials provided with the distribution.
021: *
022: * - Neither the name of the Hewlett-Packard Company nor the name of the
023: * Massachusetts Institute of Technology nor the names of their
024: * contributors may be used to endorse or promote products derived from
025: * this software without specific prior written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
030: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031: * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
032: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
033: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
034: * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
035: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
036: * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
037: * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
038: * DAMAGE.
039: */
040:
041: package org.dspace.app.xmlui.wing.element;
042:
043: /**
044: * A class representing an an abstract input control (which is just a fancy name
045: * for a field :) )
046: *
047: * The field element is a container for all information necessary to create a
048: * form field. The required "type" attribute determines the type of the field,
049: * while the children tags carry the information on how to build it. Fields can
050: * only occur in divisions of type "interactive".
051: *
052: * There are several types of possible fields and each of these field types
053: * determine the appropriate parameters on the parameter object. This is the
054: * only place in the schema where this design pattern is used. It limits the
055: * proliferation of elements, such as a special element for textarea, select
056: * lists, text fields etc... as HTML does. It also forces us to treat all fields
057: * the same.
058: *
059: * text: A single-line text input control.
060: *
061: * textarea: A multi-line text input control.
062: *
063: * password: A single-line text input control where the input text is rendered
064: * in such a way as to hide the characters from the user.
065: *
066: * hidden: An input control that is not rendered on the screen and hidden from
067: * the user.
068: *
069: * button: A button input control that when activated by the user will submit
070: * the form, including all the fields, back to the server for processing.
071: *
072: * checkbox: A boolean input control which may be toggled by the user. A
073: * checkbox may have several fields which share the same name and each of those
074: * fields may be toggled independently. This is distinct from a radio button
075: * where only one field may be toggled.
076: *
077: * file: An input control that allows the user to select files to be submitted
078: * with the form. Note that a form which uses a file field must use the
079: * multipart method.
080: *
081: * radio: A boolean input control which may be toggled by the user. Multiple
082: * radio button fields may share the same name. When this occurs only one field
083: * may be selected to be true. This is distinct from a checkbox where multiple
084: * fields may be toggled.
085: *
086: * select: A menu input control which allows the user to select from a list of
087: * available options.
088: *
089: * composite: A combination of multile fields into one input control.
090: *
091: * @author Scott Phillips
092: */
093:
094: import java.util.ArrayList;
095: import java.util.List;
096:
097: import org.dspace.app.xmlui.wing.AttributeMap;
098: import org.dspace.app.xmlui.wing.Message;
099: import org.dspace.app.xmlui.wing.WingContext;
100: import org.dspace.app.xmlui.wing.WingException;
101: import org.xml.sax.ContentHandler;
102: import org.xml.sax.SAXException;
103: import org.xml.sax.ext.LexicalHandler;
104: import org.xml.sax.helpers.NamespaceSupport;
105:
106: public abstract class Field extends AbstractWingElement implements
107: StructuralElement {
108: /** The name of the field element */
109: public static final String E_FIELD = "field";
110:
111: /** The name of the field type attribute */
112: public static final String A_FIELD_TYPE = "type";
113:
114: /** The name of the disabled attribute */
115: public static final String A_DISABLED = "disabled";
116:
117: /** The name of the required attribute */
118: public static final String A_REQUIRED = "required";
119:
120: /** The possible field types */
121: public static final String TYPE_BUTTON = "button";
122:
123: public static final String TYPE_CHECKBOX = "checkbox";
124:
125: public static final String TYPE_FILE = "file";
126:
127: public static final String TYPE_HIDDEN = "hidden";
128:
129: public static final String TYPE_PASSWORD = "password";
130:
131: public static final String TYPE_RADIO = "radio";
132:
133: public static final String TYPE_SELECT = "select";
134:
135: public static final String TYPE_TEXT = "text";
136:
137: public static final String TYPE_TEXTAREA = "textarea";
138:
139: public static final String TYPE_COMPOSITE = "composite";
140:
141: /** All the possible field types collected into one array. */
142: public static final String[] TYPES = { TYPE_BUTTON, TYPE_CHECKBOX,
143: TYPE_FILE, TYPE_HIDDEN, TYPE_PASSWORD, TYPE_RADIO,
144: TYPE_SELECT, TYPE_TEXT, TYPE_TEXTAREA, TYPE_COMPOSITE };
145:
146: /** Possible field behavioral operations */
147: public static final String OPERATION_ADD = "add";
148:
149: public static final String OPERATION_DELETE = "delete";
150:
151: public static final String[] OPERATIONS = { OPERATION_ADD,
152: OPERATION_DELETE };
153:
154: /** The field's name */
155: protected String name;
156:
157: /** The type of field, see TYPES above */
158: protected String type;
159:
160: /** Weather this field is disabled */
161: protected boolean disabled;
162:
163: /** Weather this field is required */
164: protected boolean required;
165:
166: /** Any special rendering instructions */
167: protected String rend;
168:
169: /** Additional field parameters */
170: protected Params params;
171:
172: /** The fields Label */
173: protected Label label;
174:
175: /** Help instructions for this field */
176: protected Help help;
177:
178: /** Error instructions for this field */
179: protected List<Error> errors = new ArrayList<Error>();
180:
181: /** All sub fields contained within a composite field */
182: protected List<Field> fields = new ArrayList<Field>();
183:
184: /** The value of this field */
185: protected List<Option> options = new ArrayList<Option>();
186:
187: /** The value of this field */
188: protected List<Value> values = new ArrayList<Value>();
189:
190: /** The set of stored values */
191: protected List<Instance> instances = new ArrayList<Instance>();
192:
193: /**
194: * Construct a new field.
195: *
196: * @param context
197: * (Required) The context this element is contained in, such as
198: * where to route SAX events and what i18n catalogue to use.
199: *
200: * @param name
201: * (Required) a non-unique local identifier used to differentiate
202: * the element from its siblings within an interactive division.
203: * This is the name of the field use when data is submitted back
204: * to the server.
205: * @param type
206: * (Required) Specify the type of field, must be one of the field
207: * types defined in the static variable TYPES.
208: * @param rend
209: * (May be null) a rendering hint used to override the default
210: * display of the element.
211: */
212: protected Field(WingContext context, String name, String type,
213: String rend) throws WingException {
214: super (context);
215: require(name,
216: "The 'name' parameter is required for all fields.");
217: require(type,
218: "The 'type' parameter is required for all fields.");
219: restrict(
220: type,
221: TYPES,
222: "The 'type' parameter must be one of these values: 'button', 'checkbox', 'file', 'hidden', 'password', 'radio', 'select', 'text', 'textarea'.");
223:
224: this .name = name;
225: this .type = type;
226: this .disabled = false;
227: this .required = false;
228: this .rend = rend;
229: }
230:
231: /** Parameters available on all fields */
232:
233: /**
234: * Set this field as required.
235: */
236: public void setRequired() {
237: this .required = true;
238: }
239:
240: /**
241: * Set this field to either be required or not required as determined by the
242: * required parameter.
243: *
244: * @param requeired
245: * Determine if the field is required or not.
246: */
247: public void setRequired(boolean required) {
248: this .required = required;
249: }
250:
251: /**
252: * Set this field to be disabled.
253: *
254: */
255: public void setDisabled() {
256: this .disabled = true;
257: }
258:
259: /**
260: * Set this field to either be disabled or enabled as determined by the
261: * disabled parameter.
262: *
263: * @param disabled
264: * Determine if the field is required or not.
265: */
266: public void setDisabled(boolean disabled) {
267: this .disabled = disabled;
268: }
269:
270: /** ******************************************************************** */
271: /** Help * */
272: /** ******************************************************************** */
273:
274: /**
275: * The help element provides help instructions to assist the user in using
276: * this field.
277: *
278: */
279: public Help setHelp() throws WingException {
280: this .help = new Help(context);
281: return this .help;
282: }
283:
284: /**
285: * The help element provides help instructions to assist the user in using
286: * this field.
287: *
288: * @param characters
289: * (May be null) Direct content or a dictionary tag to be
290: * inserted into the element.
291: */
292: public void setHelp(String characters) throws WingException {
293: this .help = new Help(context);
294: this .help.addContent(characters);
295: }
296:
297: /**
298: * The help element provides help instructions to assist the user in using
299: * this field.
300: *
301: * @param message
302: * (Required) A key into the i18n catalogue for translation into
303: * the user's preferred language.
304: */
305: public void setHelp(Message message) throws WingException {
306: this .help = new Help(context);
307: this .help.addContent(message);
308: }
309:
310: /** ******************************************************************** */
311: /** Errors * */
312: /** ******************************************************************** */
313:
314: /**
315: * The error elements denotes that the fields value is invalid for the given
316: * context. The message contained within the error message will provide
317: * assistance to the user in correcting the problem.
318: *
319: */
320: public Error addError() throws WingException {
321: Error error = new Error(context);
322: errors.add(error);
323: return error;
324: }
325:
326: /**
327: * The error elements denotes that the fields value is invalid for the given
328: * context. The message contained within the error message will provide
329: * assistance to the user in correcting the problem.
330: *
331: * @param characters
332: * (May be null) Direct content or a dictionary tag to be
333: * inserted into the element.
334: */
335: public void addError(String characters) throws WingException {
336: Error error = new Error(context);
337: error.addContent(characters);
338: errors.add(error);
339: }
340:
341: /**
342: * The error elements denotes that the fields value is invalid for the given
343: * context. The message contained within the error message will provide
344: * assistance to the user in correcting the problem.
345: *
346: * @param message
347: * (Required) A key into the i18n catalogue for translation into
348: * the user's preferred language.
349: */
350: public void addError(Message message) throws WingException {
351: Error error = new Error(context);
352: error.addContent(message);
353: errors.add(error);
354: }
355:
356: /** ******************************************************************** */
357: /** Label * */
358: /** ******************************************************************** */
359:
360: /**
361: * The help element provides help instructions to assist the user in using
362: * this field.
363: *
364: */
365: public Label setLabel() throws WingException {
366: this .label = new Label(context, null, null);
367: return this .label;
368: }
369:
370: /**
371: * The help element provides help instructions to assist the user in using
372: * this field.
373: *
374: * @param characters
375: * (May be null) Direct content or a dictionary tag to be
376: * inserted into the element.
377: */
378: public void setLabel(String characters) throws WingException {
379: this .label = new Label(context, null, null);
380: this .label.addContent(characters);
381: }
382:
383: /**
384: * The help element provides help instructions to assist the user in using
385: * this field.
386: *
387: * @param message
388: * (Required) A key into the i18n catalogue for translation into
389: * the user's preferred language.
390: */
391: public void setLabel(Message message) throws WingException {
392: this .label = new Label(context, null, null);
393: this .label.addContent(message);
394: }
395:
396: /**
397: * Private function to remove all values of a particular type.
398: *
399: * @param removeType
400: * The type to be removed.
401: */
402: protected void removeValueOfType(String removeType) {
403: List<Value> found = new ArrayList<Value>();
404: for (Value value : values)
405: if (value.getType().equals(removeType))
406: found.add(value);
407:
408: for (Value remove : found) {
409: values.remove(remove);
410: remove.dispose();
411: }
412: }
413:
414: /**
415: * Translate this element and all contained elements into SAX events. The
416: * events should be routed to the contentHandler found in the WingContext.
417: *
418: * @param contentHandler
419: * (Required) The registered contentHandler where SAX events
420: * should be routed too.
421: * @param lexicalHandler
422: * (Required) The registered lexicalHandler where lexical events
423: * (such as CDATA, DTD, etc) should be routed too.
424: * @param namespaces
425: * (Required) SAX Helper class to keep track of namespaces able
426: * to determine the correct prefix for a given namespace URI.
427: */
428: public void toSAX(ContentHandler contentHandler,
429: LexicalHandler lexicalHandler, NamespaceSupport namespaces)
430: throws SAXException {
431: AttributeMap attributes = new AttributeMap();
432:
433: attributes.put(A_NAME, this .name);
434: attributes.put(A_ID, this .context
435: .generateID(E_FIELD, this .name));
436: attributes.put(A_FIELD_TYPE, this .type);
437: if (this .disabled)
438: attributes.put(A_DISABLED, this .disabled);
439: if (this .required)
440: attributes.put(A_REQUIRED, this .required);
441: if (this .rend != null)
442: attributes.put(A_RENDER, this .rend);
443:
444: startElement(contentHandler, namespaces, E_FIELD, attributes);
445:
446: if (params != null)
447: params.toSAX(contentHandler, lexicalHandler, namespaces);
448:
449: if (label != null)
450: label.toSAX(contentHandler, lexicalHandler, namespaces);
451:
452: if (help != null)
453: help.toSAX(contentHandler, lexicalHandler, namespaces);
454:
455: for (Error error : errors)
456: error.toSAX(contentHandler, lexicalHandler, namespaces);
457:
458: for (Field field : fields)
459: field.toSAX(contentHandler, lexicalHandler, namespaces);
460:
461: for (Option option : options)
462: option.toSAX(contentHandler, lexicalHandler, namespaces);
463:
464: for (Value value : values)
465: value.toSAX(contentHandler, lexicalHandler, namespaces);
466:
467: for (Instance instance : instances)
468: instance.toSAX(contentHandler, lexicalHandler, namespaces);
469:
470: endElement(contentHandler, namespaces, E_FIELD);
471: }
472:
473: /**
474: * Dispose
475: */
476: public void dispose() {
477: if (params != null)
478: params.dispose();
479:
480: if (label != null)
481: label.dispose();
482:
483: if (help != null)
484: help.dispose();
485:
486: for (Error error : errors)
487: error.dispose();
488: if (errors != null)
489: errors.clear();
490:
491: for (Field field : fields)
492: field.dispose();
493: if (fields != null)
494: fields.clear();
495:
496: for (Option option : options)
497: option.dispose();
498: if (options != null)
499: options.clear();
500:
501: for (Value value : values)
502: value.dispose();
503: if (values != null)
504: values.clear();
505:
506: for (Instance instance : instances)
507: instance.dispose();
508: if (instances != null)
509: instances.clear();
510:
511: params = null;
512: label = null;
513: help = null;
514: errors = null;
515: fields = null;
516: options = null;
517: values = null;
518: instances = null;
519: super.dispose();
520: }
521: }
|