/** * Copyright (C) 2004-2007 Jive Software. All rights reserved. * * This software is published under the terms of the GNU Public License (GPL), * a copy of which is included in this distribution. */ package org.xmpp.forms; import org.dom4j.Element; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Represents a field of a form. The field could be used to represent a question to complete, * a completed question or a data returned from a search. The exact interpretation of the field * depends on the context where the field is used. * * @author Gaston Dombiak */ public class FormField { private Element element; FormField(Element element) { this.element = element; } /** * Adds a default value to the question if the question is part of a form to fill out. * Otherwise, adds an answered value to the question. * * @param value a default value or an answered value of the question. */ public void addValue(Object value) { element.addElement("value").setText(DataForm.encode(value)); } /** * Removes all the values of the field. */ public void clearValues() { for (Iterator it = element.elementIterator("value"); it.hasNext();) { it.next(); it.remove(); } } /** * Adds an available option to the question that the user has in order to answer * the question. * * @param label a label that represents the option. * @param value the value of the option. */ public void addOption(String label, String value) { Element option = element.addElement("option"); option.addAttribute("label", label); option.addElement("value").setText(value); } /** * Returns the available options to answer for this question. The returned options cannot * be modified but they will be updated if the underlying DOM object gets updated. * * @return the available options to answer for this question. */ public List<Option> getOptions() { List<Option> answer = new ArrayList<Option>(); for (Iterator it = element.elementIterator("option"); it.hasNext();) { answer.add(new Option((Element) it.next())); } return answer; } /** * Sets an indicative of the format for the data to answer. Valid formats are: * <p/> * <ul> * <li>text-single -> single line or word of text * <li>text-private -> instead of showing the user what they typed, you show ***** to * protect it * <li>text-multi -> multiple lines of text entry * <li>list-single -> given a list of choices, pick one * <li>list-multi -> given a list of choices, pick one or more * <li>boolean -> 0 or 1, true or false, yes or no. Default value is 0 * <li>fixed -> fixed for putting in text to show sections, or just advertise your web * site in the middle of the form * <li>hidden -> is not given to the user at all, but returned with the questionnaire * <li>jid-single -> Jabber ID - choosing a JID from your roster, and entering one based * on the rules for a JID. * <li>jid-multi -> multiple entries for JIDs * </ul> * * @param type an indicative of the format for the data to answer. */ public void setType(Type type) { element.addAttribute("type", type==null?null:type.toXMPP()); } /** * Sets the attribute that uniquely identifies the field in the context of the form. If the * field is of type "fixed" then the variable is optional. * * @param var the unique identifier of the field in the context of the form. */ public void setVariable(String var) { element.addAttribute("var", var); } /** * Sets the label of the question which should give enough information to the user to * fill out the form. * * @param label the label of the question. */ public void setLabel(String label) { element.addAttribute("label", label); } /** * Sets if the question must be answered in order to complete the questionnaire. * * @param required if the question must be answered in order to complete the questionnaire. */ public void setRequired(boolean required) { // Remove an existing desc element. if (element.element("required") != null) { element.remove(element.element("required")); } if (required) { element.addElement("required"); } } /** * Sets a description that provides extra clarification about the question. This information * could be presented to the user either in tool-tip, help button, or as a section of text * before the question.<p> * <p/> * If the question is of type FIXED then the description should remain empty. * * @param description provides extra clarification about the question. */ public void setDescription(String description) { // Remove an existing desc element. if (element.element("desc") != null) { element.remove(element.element("desc")); } element.addElement("desc").setText(description); } /** * Returns true if the question must be answered in order to complete the questionnaire. * * @return true if the question must be answered in order to complete the questionnaire. */ public boolean isRequired() { return element.element("required") != null; } /** * Returns the variable name that the question is filling out. * * @return the variable name of the question. */ public String getVariable() { return element.attributeValue("var"); } /** * Returns an Iterator for the default values of the question if the question is part * of a form to fill out. Otherwise, returns an Iterator for the answered values of * the question. * * @return an Iterator for the default values or answered values of the question. */ public List<String> getValues() { List<String> answer = new ArrayList<String>(); for (Iterator it = element.elementIterator("value"); it.hasNext();) { answer.add(((Element) it.next()).getTextTrim()); } return answer; } /** * Returns an indicative of the format for the data to answer. Valid formats are: * <p/> * <ul> * <li>text-single -> single line or word of text * <li>text-private -> instead of showing the user what they typed, you show ***** to * protect it * <li>text-multi -> multiple lines of text entry * <li>list-single -> given a list of choices, pick one * <li>list-multi -> given a list of choices, pick one or more * <li>boolean -> 0 or 1, true or false, yes or no. Default value is 0 * <li>fixed -> fixed for putting in text to show sections, or just advertise your web * site in the middle of the form * <li>hidden -> is not given to the user at all, but returned with the questionnaire * <li>jid-single -> Jabber ID - choosing a JID from your roster, and entering one based * on the rules for a JID. * <li>jid-multi -> multiple entries for JIDs * </ul> * * @return format for the data to answer. */ public Type getType() { String type = element.attributeValue("type"); if (type != null) { Type.fromXMPP(type); } return null; } /** * Returns the label of the question which should give enough information to the user to * fill out the form. * * @return label of the question. */ public String getLabel() { return element.attributeValue("label"); } /** * Returns a description that provides extra clarification about the question. This information * could be presented to the user either in tool-tip, help button, or as a section of text * before the question.<p> * <p/> * If the question is of type FIXED then the description should remain empty. * * @return description that provides extra clarification about the question. */ public String getDescription() { return element.elementTextTrim("desc"); } /** * Represents the available option of a given FormField. * * @author Gaston Dombiak */ public static class Option { private Element element; private Option(Element element) { this.element = element; } /** * Returns the label that represents the option. * * @return the label that represents the option. */ public String getLabel() { return element.attributeValue("label"); } /** * Returns the value of the option. * * @return the value of the option. */ public String getValue() { return element.elementTextTrim("value"); } } /** * Type-safe enumeration to represent the field type of the Data forms.<p> * * Implementation note: XMPP error conditions use "-" characters in * their names such as "jid-multi". Because "-" characters are not valid * identifier parts in Java, they have been converted to "_" characters in * the enumeration names, such as <tt>jid_multi</tt>. The {@link #toXMPP()} and * {@link #fromXMPP(String)} methods can be used to convert between the * enumertation values and Type code strings. */ public enum Type { /** * The field enables an entity to gather or provide an either-or choice between two * options. The allowable values are 1 for yes/true/assent and 0 for no/false/decline. * The default value is 0. */ boolean_type("boolean"), /** * The field is intended for data description (e.g., human-readable text such as * "section" headers) rather than data gathering or provision. The <value/> child * SHOULD NOT contain newlines (the \n and \r characters); instead an application * SHOULD generate multiple fixed fields, each with one <value/> child. */ fixed("fixed"), /** * The field is not shown to the entity providing information, but instead is * returned with the form. */ hidden("hidden"), /** * The field enables an entity to gather or provide multiple Jabber IDs. */ jid_multi("jid-multi"), /** * The field enables an entity to gather or provide multiple Jabber IDs. */ jid_single("jid-single"), /** * The field enables an entity to gather or provide one or more options from * among many. */ list_multi("list-multi"), /** * The field enables an entity to gather or provide one option from among many. */ list_single("list-single"), /** * The field enables an entity to gather or provide multiple lines of text. */ text_multi("text-multi"), /** * The field enables an entity to gather or provide a single line or word of text, * which shall be obscured in an interface (e.g., *****). */ text_private("text-private"), /** * The field enables an entity to gather or provide a single line or word of text, * which may be shown in an interface. This field type is the default and MUST be * assumed if an entity receives a field type it does not understand. */ text_single("text-single"); /** * Converts a String value into its Type representation. * * @param type the String value. * @return the type corresponding to the String. */ public static Type fromXMPP(String type) { if (type == null) { throw new NullPointerException(); } type = type.toLowerCase(); if (boolean_type.toXMPP().equals(type)) { return boolean_type; } else if (fixed.toXMPP().equals(type)) { return fixed; } else if (hidden.toXMPP().equals(type)) { return hidden; } else if (jid_multi.toXMPP().equals(type)) { return jid_multi; } else if (jid_single.toXMPP().equals(type)) { return jid_single; } else if (list_multi.toXMPP().equals(type)) { return list_multi; } else if (list_single.toXMPP().equals(type)) { return list_single; } else if (text_multi.toXMPP().equals(type)) { return text_multi; } else if (text_private.toXMPP().equals(type)) { return text_private; } else if (text_single.toXMPP().equals(type)) { return text_single; } else { throw new IllegalArgumentException("Type invalid:" + type); } } private String value; private Type(String value) { this.value = value; } /** * Returns the Field Type as a valid Field Type code string. * * @return the Field Type value. */ public String toXMPP() { return value; } } }