/* * DescribeStep.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.aspect.submission.submit; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Locale; import javax.servlet.ServletException; import org.apache.log4j.Logger; import org.dspace.app.util.DCInput; import org.dspace.app.util.DCInputSet; import org.dspace.app.util.DCInputsReader; import org.dspace.app.xmlui.utils.UIException; import org.dspace.app.xmlui.aspect.submission.AbstractSubmissionStep; import org.dspace.app.xmlui.aspect.submission.FlowUtils; import org.dspace.app.xmlui.wing.Message; import org.dspace.app.xmlui.wing.WingException; import org.dspace.app.xmlui.wing.element.Body; import org.dspace.app.xmlui.wing.element.CheckBox; import org.dspace.app.xmlui.wing.element.Composite; import org.dspace.app.xmlui.wing.element.Division; import org.dspace.app.xmlui.wing.element.Field; import org.dspace.app.xmlui.wing.element.List; import org.dspace.app.xmlui.wing.element.Radio; import org.dspace.app.xmlui.wing.element.Select; import org.dspace.app.xmlui.wing.element.Text; import org.dspace.app.xmlui.wing.element.TextArea; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; import org.dspace.content.DCDate; import org.dspace.content.DCPersonName; import org.dspace.content.DCSeriesNumber; import org.dspace.content.DCValue; import org.dspace.content.Item; import org.xml.sax.SAXException; import uk.ac.jorum.dspace.utils.StringUtils; /** * This is a step of the item submission processes. The describe step queries * the user for various metadata items about the item. For the most part all the * questions queried are completely configurable via the input-sets.xml file. * This system allows for multiple pages to be defined so this step is different * from all other stages in that it may represent multiple stages within the * submission processes. * * @author Scott Phillips * @author Tim Donohue (updated for Configurable Submission) */ public class DescribeStep extends AbstractSubmissionStep { private static Logger log = Logger.getLogger(DescribeStep.class); /** Language Strings **/ protected static final Message T_head = message("xmlui.Submission.submit.DescribeStep.head"); protected static final Message T_unknown_field= message("xmlui.Submission.submit.DescribeStep.unknown_field"); protected static final Message T_required_field= message("xmlui.Submission.submit.DescribeStep.required_field"); protected static final Message T_last_name_help= message("xmlui.Submission.submit.DescribeStep.last_name_help"); protected static final Message T_first_name_help= message("xmlui.Submission.submit.DescribeStep.first_name_help"); protected static final Message T_year= message("xmlui.Submission.submit.DescribeStep.year"); protected static final Message T_month= message("xmlui.Submission.submit.DescribeStep.month"); protected static final Message T_day= message("xmlui.Submission.submit.DescribeStep.day"); protected static final Message T_series_name= message("xmlui.Submission.submit.DescribeStep.series_name"); protected static final Message T_report_no= message("xmlui.Submission.submit.DescribeStep.report_no"); /** * The scope of the input sets, this restricts hidden metadata fields from * view by the end user during submission. */ private static String SUBMISSION_SCOPE = "submit"; /** * The scope of the input sets, this restricts hidden metadata fields from * view during workflow processing. */ private static String WORKFLOW_SCOPE = "workflow"; /** * A shared resource of the inputs reader. The 'inputs' are the * questions we ask the user to describe an item during the * submission process. The reader is a utility class to read * that configuration file. */ private static DCInputsReader INPUTS_READER = null; /** * Ensure that the inputs reader has been initialized, this method may be * called multiple times with no ill-effect. */ private static void initializeInputsReader() throws ServletException { if (INPUTS_READER == null) INPUTS_READER = new DCInputsReader(); } /** * Return the inputs reader. Note, the reader must have been * initialized before the reader can be accessed. * * @return The input reader. */ private static DCInputsReader getInputsReader() { return INPUTS_READER; } /** * Establish our required parameters, abstractStep will enforce these. */ public DescribeStep() throws ServletException { this.requireSubmission = true; this.requireStep = true; //Ensure that the InputsReader is initialized. initializeInputsReader(); } public void addBody(Body body) throws SAXException, WingException, UIException, SQLException, IOException, AuthorizeException { // Obtain the inputs (i.e. metadata fields we are going to display) Item item = submission.getItem(); Collection collection = submission.getCollection(); String actionURL = contextPath + "/handle/"+collection.getHandle() + "/submit/" + knot.getId() + ".continue"; DCInputSet inputSet = null; DCInput[] inputs = {}; try { inputSet = getInputsReader().getInputs(submission.getCollection().getHandle()); inputs = inputSet.getPageRows(getPage()-1, submission.hasMultipleTitles(), submission.isPublishedBefore()); } catch (ServletException se) { throw new UIException(se); } Division div = body.addInteractiveDivision("submit-describe",actionURL,Division.METHOD_POST,"primary submission"); div.setHead(T_submission_head); addSubmissionProgressList(div); List form = div.addList("submit-describe",List.TYPE_FORM); form.setHead(T_head); // Iterate over all inputs and add it to the form. for(DCInput dcInput : inputs) { // If the input is invisible in this scope, then skip it. if (!dcInput.isVisible(submissionInfo.isInWorkflow() ? WORKFLOW_SCOPE : SUBMISSION_SCOPE)) continue; String schema = dcInput.getSchema(); String element = dcInput.getElement(); String qualifier = dcInput.getQualifier(); DCValue[] dcValues = item.getMetadata(schema, element, qualifier, Item.ANY); String fieldName = FlowUtils.getFieldName(dcInput); String inputType = dcInput.getInputType(); if (inputType.equals("name")) { renderNameField(form, fieldName, dcInput, dcValues); } else if (inputType.equals("date")) { renderDateField(form, fieldName, dcInput, dcValues); } else if (inputType.equals("series")) { renderSeriesField(form, fieldName, dcInput, dcValues); } else if (inputType.equals("twobox")) { // We don't have a twobox field, instead it's just a // one box field that the theme can render in two columns. renderOneboxField(form, fieldName, dcInput, dcValues); } else if (inputType.equals("qualdrop_value")) { // Determine the real field's values. Since the qualifier is // selected we need to search through all the metadata and see // if any match for another field, if not we assume that this field // should handle it. DCValue[] unfiltered = item.getMetadata(dcInput.getSchema(), dcInput.getElement(), Item.ANY, Item.ANY); ArrayList<DCValue> filtered = new ArrayList<DCValue>(); for (DCValue dcValue : unfiltered) { String unfilteredFieldName = dcValue.element + "." + dcValue.qualifier; if ( ! inputSet.isFieldPresent(unfilteredFieldName) ) { filtered.add( dcValue ); } } renderQualdropField(form, fieldName, dcInput, filtered.toArray(new DCValue[filtered.size()])); } else if (inputType.equals("textarea")) { renderTextArea(form, fieldName, dcInput, dcValues); } else if (inputType.equals("dropdown")) { renderDropdownField(form, fieldName, dcInput, dcValues); } else if (inputType.equals("list")) { renderSelectFromListField(form, fieldName, dcInput, dcValues); } else if (inputType.equals("onebox")) { renderOneboxField(form, fieldName, dcInput, dcValues); } else if (inputType.equals("multivalue")) { renderMultivalueField(form, fieldName, dcInput, dcValues); } else { form.addItem(T_unknown_field); } } // add standard control/paging buttons addControlButtons(form); } /** * Each submission step must define its own information to be reviewed * during the final Review/Verify Step in the submission process. * <P> * The information to review should be tacked onto the passed in * List object. * <P> * NOTE: To remain consistent across all Steps, you should first * add a sub-List object (with this step's name as the heading), * by using a call to reviewList.addList(). This sublist is * the list you return from this method! * * @param reviewList * The List to which all reviewable information should be added * @return * The new sub-List object created by this step, which contains * all the reviewable information. If this step has nothing to * review, then return null! */ public List addReviewSection(List reviewList) throws SAXException, WingException, UIException, SQLException, IOException, AuthorizeException { //Create a new list section for this step (and set its heading) List describeSection = reviewList.addList("submit-review-" + this.stepAndPage, List.TYPE_FORM); describeSection.setHead(T_head); //Review the values assigned to all inputs //on this page of the Describe step. DCInputSet inputSet = null; try { inputSet = getInputsReader().getInputs(submission.getCollection().getHandle()); } catch (ServletException se) { throw new UIException(se); } DCInput[] inputs = inputSet.getPageRows(getPage()-1, submission.hasMultipleTitles(), submission.isPublishedBefore()); for (DCInput input : inputs) { // If the input is invisible in this scope, then skip it. if (!input.isVisible(submissionInfo.isInWorkflow() ? WORKFLOW_SCOPE : SUBMISSION_SCOPE)) continue; String inputType = input.getInputType(); String pairsName = input.getPairsType(); DCValue[] values = new DCValue[0]; if (inputType.equals("qualdrop_value")) { values = submission.getItem().getMetadata(input.getSchema(), input.getElement(), Item.ANY, Item.ANY); } else { values = submission.getItem().getMetadata(input.getSchema(), input.getElement(), input.getQualifier(), Item.ANY); } if (values.length > 0) { for (DCValue value : values) { String displayValue = null; if (inputType.equals("date")) { DCDate date = new DCDate(value.value); displayValue = date.toString(); } else if (inputType.equals("dropdown")) { displayValue = input.getDisplayString(pairsName,value.value); } else if (inputType.equals("qualdrop_value")) { String qualifier = value.qualifier; String displayQual = input.getDisplayString(pairsName,qualifier); if (displayQual!=null && displayQual.length()>0) { displayValue = displayQual + ":" + value.value; } } else { displayValue = value.value; } //Only display this field if we have a value to display if (displayValue!=null && displayValue.length()>0) { describeSection.addLabel(input.getLabel()); describeSection.addItem(displayValue); } } // For each DCValue } // If values exist }// For each input //return this new "describe" section return describeSection; } /** * Render a Name field to the DRI document. The name field consists of two * text fields, one for the last name and the other for a first name (plus * all other names). * * @param form * The form list to add the field too * @param fieldName * The field's name. * @param dcInput * The field's input deffinition * @param dcValues * The field's pre-existing values. */ private void renderNameField(List form, String fieldName, DCInput dcInput, DCValue[] dcValues) throws WingException { // The name field is a composite field containing two text fields, one // for first name the other for last name. Composite fullName = form.addItem().addComposite(fieldName, "submit-name"); Text lastName = fullName.addText(fieldName+"_last"); Text firstName = fullName.addText(fieldName+"_first"); // Setup the full name fullName.setLabel(dcInput.getLabel()); fullName.setHelp(cleanHints(dcInput.getHints())); if (dcInput.isRequired()) fullName.setRequired(); if (isFieldInError(fieldName)) fullName.addError(T_required_field); if (dcInput.isRepeatable()) fullName.enableAddOperation(); if (dcInput.isRepeatable() || dcValues.length > 1) fullName.enableDeleteOperation(); // Setup the first and last name lastName.setLabel(T_last_name_help); firstName.setLabel(T_first_name_help); // Setup the field's values if (dcInput.isRepeatable() || dcValues.length > 1) { for (DCValue dcValue : dcValues) { DCPersonName dpn = new DCPersonName(dcValue.value); lastName.addInstance().setValue(dpn.getLastName()); firstName.addInstance().setValue(dpn.getFirstNames()); fullName.addInstance().setValue(dcValue.value); } } else if (dcValues.length == 1) { DCPersonName dpn = new DCPersonName(dcValues[0].value); lastName.setValue(dpn.getLastName()); firstName.setValue(dpn.getFirstNames()); } } /** * Render a date field to the DRI document. The date field consists of * three component fields, a 4 character text field for the year, a select * box for the month, and a 2 character text field for the day. * * @param form * The form list to add the field too * @param fieldName * The field's name. * @param dcInput * The field's input deffinition * @param dcValues * The field's pre-existing values. */ private void renderDateField(List form, String fieldName, DCInput dcInput, DCValue[] dcValues) throws WingException { // The date field consists of three primitive fields: a text field // for the year, followed by a select box of the months, follewed // by a text box for the day. Composite fullDate = form.addItem().addComposite(fieldName, "submit-date"); Text year = fullDate.addText(fieldName+"_year"); Select month = fullDate.addSelect(fieldName+"_month"); Text day = fullDate.addText(fieldName+"_day"); // Set up the full field fullDate.setLabel(dcInput.getLabel()); fullDate.setHelp(cleanHints(dcInput.getHints())); if (dcInput.isRequired()) fullDate.setRequired(); if (isFieldInError(fieldName)) fullDate.addError(T_required_field); if (dcInput.isRepeatable()) fullDate.enableAddOperation(); if (dcInput.isRepeatable() || dcValues.length > 1) fullDate.enableDeleteOperation(); // Setup the year field year.setLabel(T_year); year.setSize(4,4); // Setup the month field month.setLabel(T_month); month.addOption(0,""); for (int i = 1; i < 13; i++) { month.addOption(i,org.dspace.content.DCDate.getMonthName(i,Locale.getDefault())); } // Setup the day field day.setLabel(T_day); day.setSize(2,2); // Setup the field's values if (dcInput.isRepeatable() || dcValues.length > 1) { for (DCValue dcValue : dcValues) { DCDate dcDate = new DCDate(dcValue.value); year.addInstance().setValue(String.valueOf(dcDate.getYear())); month.addInstance().setOptionSelected(dcDate.getMonth()); day.addInstance().setValue(String.valueOf(dcDate.getDay())); fullDate.addInstance().setValue(dcDate.toString()); } } else if (dcValues.length == 1) { DCDate dcDate = new DCDate(dcValues[0].value); year.setValue(String.valueOf(dcDate.getYear())); month.setOptionSelected(dcDate.getMonth()); // Check if the day field is not specified, if so then just // put a blank value in instead of the wiered looking -1. if (dcDate.getDay() == -1) day.setValue(""); else day.setValue(String.valueOf(dcDate.getDay())); } } /** * Render a series field to the DRI document. The series field conist of * two component text fields. When interpreted each of these fields are * combined back together to be a single value joined together by a * semicolen. The primary use case is for the journal or report number * the left hand side is the journal and the right hand side in a * unique number within the journal. * * @param form * The form list to add the field too * @param fieldName * The field's name. * @param dcInput * The field's input deffinition * @param dcValues * The field's pre-existing values. */ private void renderSeriesField(List form, String fieldName, DCInput dcInput, DCValue[] dcValues) throws WingException { // The seiries field consists of two parts, a series name (text field) // and report or paper number (also a text field). Composite fullSeries = form.addItem().addComposite(fieldName,"submit-"+dcInput.getInputType()); Text series = fullSeries.addText(fieldName+"_series"); Text number = fullSeries.addText(fieldName+"_number"); // Setup the full field. fullSeries.setLabel(dcInput.getLabel()); fullSeries.setHelp(cleanHints(dcInput.getHints())); if (dcInput.isRequired()) fullSeries.setRequired(); if (isFieldInError(fieldName)) fullSeries.addError(T_required_field); if (dcInput.isRepeatable()) fullSeries.enableAddOperation(); if (dcInput.isRepeatable() || dcValues.length > 1) fullSeries.enableDeleteOperation(); series.setLabel(T_series_name); number.setLabel(T_report_no); // Setup the field's values if (dcInput.isRepeatable() || dcValues.length > 1) { for (DCValue dcValue : dcValues) { DCSeriesNumber dcSeriesNumber = new DCSeriesNumber(dcValue.value); series.addInstance().setValue(dcSeriesNumber.getSeries()); number.addInstance().setValue(dcSeriesNumber.getNumber()); fullSeries.addInstance().setValue(dcSeriesNumber.toString()); } } else if (dcValues.length == 1) { DCSeriesNumber dcSeriesNumber = new DCSeriesNumber(dcValues[0].value); series.setValue(dcSeriesNumber.getSeries()); number.setValue(dcSeriesNumber.getNumber()); } } /** * Render a qualdrop field to the DRI document. Qualdrop fields are complicated, * widget wise they are composed of two fields, a select and text box field. * The select field selects the metedata's qualifier and the text box is the * value. This means that that there is not just one metadata element that is * represented so the confusing part is that the name can change. * * @param form * The form list to add the field too * @param fieldName * The field's name. * @param dcInput * The field's input deffinition * @param dcValues * The field's pre-existing values. */ private void renderQualdropField(List form, String fieldName, DCInput dcInput, DCValue[] dcValues) throws WingException { Composite qualdrop = form.addItem().addComposite(fieldName,"submit-qualdrop"); Select qual = qualdrop.addSelect(fieldName+"_qualifier"); Text value = qualdrop.addText(fieldName+"_value"); // Setup the full field. qualdrop.setLabel(dcInput.getLabel()); qualdrop.setHelp(cleanHints(dcInput.getHints())); if (dcInput.isRequired()) qualdrop.setRequired(); if (isFieldInError(fieldName)) qualdrop.addError(T_required_field); if (dcInput.isRepeatable()) qualdrop.enableAddOperation(); // Update delete based upon the filtered values. if (dcInput.isRepeatable() || dcValues.length > 1) qualdrop.enableDeleteOperation(); // Setup the possible options @SuppressWarnings("unchecked") // This cast is correct java.util.List<String> pairs = dcInput.getPairs(); for (int i = 0; i < pairs.size(); i += 2) { String display = pairs.get(i); String returnValue = pairs.get(i+1); qual.addOption(returnValue,display); } // Setup the field's values if (dcInput.isRepeatable() || dcValues.length > 1) { for (DCValue dcValue : dcValues) { qual.addInstance().setOptionSelected(dcValue.qualifier); value.addInstance().setValue(dcValue.value); qualdrop.addInstance().setValue(dcValue.qualifier + ":" + dcValue.value); } } else if (dcValues.length == 1) { qual.setOptionSelected(dcValues[0].qualifier); value.setValue(dcValues[0].value); } } /** * Render a Text Area field to the DRI document. The text area is a simple * multi row and column text field. * * @param form * The form list to add the field too * @param fieldName * The field's name. * @param dcInput * The field's input deffinition * @param dcValues * The field's pre-existing values. */ private void renderTextArea(List form, String fieldName, DCInput dcInput, DCValue[] dcValues) throws WingException { // Plain old Textarea TextArea textArea = form.addItem().addTextArea(fieldName,"submit-textarea"); // Setup the text area textArea.setLabel(dcInput.getLabel()); textArea.setHelp(cleanHints(dcInput.getHints())); if (dcInput.isRequired()) textArea.setRequired(); if (isFieldInError(fieldName)) textArea.addError(T_required_field); if (dcInput.isRepeatable()) textArea.enableAddOperation(); if (dcInput.isRepeatable() || dcValues.length > 1) textArea.enableDeleteOperation(); // Setup the field's values if (dcInput.isRepeatable() || dcValues.length > 1) { for (DCValue dcValue : dcValues) { textArea.addInstance().setValue(dcValue.value); } } else if (dcValues.length == 1) { textArea.setValue(dcValues[0].value); } } /** * Render a dropdown field to the DRI document. The dropdown field consists * of an HTML select box. * * @param form * The form list to add the field too * @param fieldName * The field's name. * @param dcInput * The field's input deffinition * @param dcValues * The field's pre-existing values. */ private void renderDropdownField(List form, String fieldName, DCInput dcInput, DCValue[] dcValues) throws WingException { // Plain old select list. Select select = form.addItem().addSelect(fieldName,"submit-select"); //Setup the select field select.setLabel(dcInput.getLabel()); select.setHelp(cleanHints(dcInput.getHints())); if (dcInput.isRequired()) select.setRequired(); if (isFieldInError(fieldName)) select.addError(T_required_field); if (dcInput.isRepeatable() || dcValues.length > 1) { // Use the multiple functionality from the HTML // widget instead of DRI's version. select.setMultiple(); select.setSize(6); } // Setup the possible options @SuppressWarnings("unchecked") // This cast is correct java.util.List<String> pairs = dcInput.getPairs(); for (int i = 0; i < pairs.size(); i += 2) { String display = pairs.get(i); String value = pairs.get(i+1); select.addOption(value,display); } // Setup the field's pre-selected values for (DCValue dcValue : dcValues) { select.setOptionSelected(dcValue.value); } } /** * Render a select-from-list field to the DRI document. * This field consists of either a series of checkboxes * (if repeatable) or a series of radio buttons (if not repeatable). * <P> * Note: This is NOT the same as a List element * (org.dspace.app.xmlui.wing.element.List). It's just unfortunately * similarly named. * * @param form * The form list to add the field too * @param fieldName * The field's name. * @param dcInput * The field's input deffinition * @param dcValues * The field's pre-existing values. */ private void renderSelectFromListField(List form, String fieldName, DCInput dcInput, DCValue[] dcValues) throws WingException { Field listField = null; //if repeatable, this list of fields should be checkboxes if (dcInput.isRepeatable()) { listField = form.addItem().addCheckBox(fieldName); } else //otherwise this is a list of radio buttons { listField = form.addItem().addRadio(fieldName); } // Setup the field listField.setLabel(dcInput.getLabel()); listField.setHelp(cleanHints(dcInput.getHints())); if (dcInput.isRequired()) listField.setRequired(); if (isFieldInError(fieldName)) listField.addError(T_required_field); //Setup each of the possible options java.util.List<String> pairs = dcInput.getPairs(); for (int i = 0; i < pairs.size(); i += 2) { String display = pairs.get(i); String value = pairs.get(i+1); if(listField instanceof CheckBox) { ((CheckBox)listField).addOption(value, display); } else if(listField instanceof Radio) { ((Radio)listField).addOption(value, display); } } // Setup the field's pre-selected values for (DCValue dcValue : dcValues) { if(listField instanceof CheckBox) { ((CheckBox)listField).setOptionSelected(dcValue.value); } else if(listField instanceof Radio) { ((Radio)listField).setOptionSelected(dcValue.value); } } } /** * Render a simple text field to the DRI document * * @param form * The form list to add the field too * @param fieldName * The field's name. * @param dcInput * The field's input deffinition * @param dcValues * The field's pre-existing values. */ private void renderOneboxField(List form, String fieldName, DCInput dcInput, DCValue[] dcValues) throws WingException { // Both onebox and twobox consist a free form text field // that the user may enter any value. The difference between // the two is that a onebox should be rendered in one column // as twobox should be listed in a two column format. Since this // decision is not something the Aspect can effect we merely place // as a render hint. Text text = form.addItem().addText(fieldName,"submit-text"); // Setup the select field text.setLabel(dcInput.getLabel()); text.setHelp(cleanHints(dcInput.getHints())); if (dcInput.isRequired()) text.setRequired(); if (isFieldInError(fieldName)) text.addError(T_required_field); if (dcInput.isRepeatable()) text.enableAddOperation(); if (dcInput.isRepeatable() || dcValues.length > 1) text.enableDeleteOperation(); // Setup the field's values if (dcInput.isRepeatable() || dcValues.length > 1) { for (DCValue dcValue : dcValues) { text.addInstance().setValue(dcValue.value); } } else if (dcValues.length == 1) { text.setValue(dcValues[0].value); } } /* An exact copy of renderOneboxField(...) but tweaked to check for comma separated values. Arguably I should have integrated this with the readText code but i wanted to keep it separate so it can be easily removed in the future. */ private void renderMultivalueField(List form, String fieldName, DCInput dcInput, DCValue[] dcValues) throws WingException { // Both onebox and twobox consist a free form text field // that the user may enter any value. The difference between // the two is that a onebox should be rendered in one column // as twobox should be listed in a two column format. Since this // decision is not something the Aspect can effect we merely place // as a render hint. Text text = form.addItem().addText(fieldName,"submit-text"); // Setup the select field text.setLabel(dcInput.getLabel()); text.setHelp(cleanHints(dcInput.getHints())); if (dcInput.isRequired()) text.setRequired(); if (isFieldInError(fieldName)) text.addError(T_required_field); if (dcInput.isRepeatable()) text.enableAddOperation(); if (dcInput.isRepeatable() || dcValues.length > 1) text.enableDeleteOperation(); // Setup the field's values if (dcInput.isRepeatable() || dcValues.length > 1) { for (DCValue dcValue : dcValues) { text.addInstance().setValue(StringUtils.encloseInQuotes(dcValue.value)); } } else if (dcValues.length == 1) { text.setValue(StringUtils.encloseInQuotes(dcValues[0].value)); } } /** * Check if the given fieldname is listed as being in error. * * @param fieldName * @return */ private boolean isFieldInError(String fieldName) { if(this.errorFields.contains(fieldName)) return true; else return false; } /** * There is a problem with the way hints are handled. The class that we use to * read the input-forms.xml configuration will append and prepend HTML to hints. * This causes all sorts of confusion when inserting into the DRI page, so this * method will strip that extra HTML and just leave the cleaned comments. * * * However this method will not remove naughty or sexual innuendoes from the * field's hints. * * * @param dirtyHints HTML-ized hints * @return Hints without HTML. */ private static final String HINT_HTML_PREFIX = "<tr><td colspan=\"4\" class=\"submitFormHelp\">"; private static final String HINT_HTML_POSTFIX = "</td></tr>"; private String cleanHints(String dirtyHints) { String clean = (dirtyHints!=null ? dirtyHints : ""); if (clean.startsWith(HINT_HTML_PREFIX)) { clean = clean.substring(HINT_HTML_PREFIX.length()); } if (clean.endsWith(HINT_HTML_POSTFIX)) { clean = clean.substring(0,clean.length() - HINT_HTML_POSTFIX.length()); } return clean; } }