Home | History | Annotate | Download | only in smackx
      1 /**
      2  * $RCSfile$
      3  * $Revision$
      4  * $Date$
      5  *
      6  * Copyright 2003-2007 Jive Software.
      7  *
      8  * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *     http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  */
     20 
     21 package org.jivesoftware.smackx;
     22 
     23 import org.jivesoftware.smack.util.StringUtils;
     24 
     25 import java.util.ArrayList;
     26 import java.util.Collections;
     27 import java.util.Iterator;
     28 import java.util.List;
     29 
     30 /**
     31  * Represents a field of a form. The field could be used to represent a question to complete,
     32  * a completed question or a data returned from a search. The exact interpretation of the field
     33  * depends on the context where the field is used.
     34  *
     35  * @author Gaston Dombiak
     36  */
     37 public class FormField {
     38 
     39     public static final String TYPE_BOOLEAN = "boolean";
     40     public static final String TYPE_FIXED = "fixed";
     41     public static final String TYPE_HIDDEN = "hidden";
     42     public static final String TYPE_JID_MULTI = "jid-multi";
     43     public static final String TYPE_JID_SINGLE = "jid-single";
     44     public static final String TYPE_LIST_MULTI = "list-multi";
     45     public static final String TYPE_LIST_SINGLE = "list-single";
     46     public static final String TYPE_TEXT_MULTI = "text-multi";
     47     public static final String TYPE_TEXT_PRIVATE = "text-private";
     48     public static final String TYPE_TEXT_SINGLE = "text-single";
     49 
     50     private String description;
     51     private boolean required = false;
     52     private String label;
     53     private String variable;
     54     private String type;
     55     private final List<Option> options = new ArrayList<Option>();
     56     private final List<String> values = new ArrayList<String>();
     57 
     58     /**
     59      * Creates a new FormField with the variable name that uniquely identifies the field
     60      * in the context of the form.
     61      *
     62      * @param variable the variable name of the question.
     63      */
     64     public FormField(String variable) {
     65         this.variable = variable;
     66     }
     67 
     68     /**
     69      * Creates a new FormField of type FIXED. The fields of type FIXED do not define a variable
     70      * name.
     71      */
     72     public FormField() {
     73         this.type = FormField.TYPE_FIXED;
     74     }
     75 
     76     /**
     77      * Returns a description that provides extra clarification about the question. This information
     78      * could be presented to the user either in tool-tip, help button, or as a section of text
     79      * before the question.<p>
     80      * <p/>
     81      * If the question is of type FIXED then the description should remain empty.
     82      *
     83      * @return description that provides extra clarification about the question.
     84      */
     85     public String getDescription() {
     86         return description;
     87     }
     88 
     89     /**
     90      * Returns the label of the question which should give enough information to the user to
     91      * fill out the form.
     92      *
     93      * @return label of the question.
     94      */
     95     public String getLabel() {
     96         return label;
     97     }
     98 
     99     /**
    100      * Returns an Iterator for the available options that the user has in order to answer
    101      * the question.
    102      *
    103      * @return Iterator for the available options.
    104      */
    105     public Iterator<Option> getOptions() {
    106         synchronized (options) {
    107             return Collections.unmodifiableList(new ArrayList<Option>(options)).iterator();
    108         }
    109     }
    110 
    111     /**
    112      * Returns true if the question must be answered in order to complete the questionnaire.
    113      *
    114      * @return true if the question must be answered in order to complete the questionnaire.
    115      */
    116     public boolean isRequired() {
    117         return required;
    118     }
    119 
    120     /**
    121      * Returns an indicative of the format for the data to answer. Valid formats are:
    122      * <p/>
    123      * <ul>
    124      * <li>text-single -> single line or word of text
    125      * <li>text-private -> instead of showing the user what they typed, you show ***** to
    126      * protect it
    127      * <li>text-multi -> multiple lines of text entry
    128      * <li>list-single -> given a list of choices, pick one
    129      * <li>list-multi -> given a list of choices, pick one or more
    130      * <li>boolean -> 0 or 1, true or false, yes or no. Default value is 0
    131      * <li>fixed -> fixed for putting in text to show sections, or just advertise your web
    132      * site in the middle of the form
    133      * <li>hidden -> is not given to the user at all, but returned with the questionnaire
    134      * <li>jid-single -> Jabber ID - choosing a JID from your roster, and entering one based
    135      * on the rules for a JID.
    136      * <li>jid-multi -> multiple entries for JIDs
    137      * </ul>
    138      *
    139      * @return format for the data to answer.
    140      */
    141     public String getType() {
    142         return type;
    143     }
    144 
    145     /**
    146      * Returns an Iterator for the default values of the question if the question is part
    147      * of a form to fill out. Otherwise, returns an Iterator for the answered values of
    148      * the question.
    149      *
    150      * @return an Iterator for the default values or answered values of the question.
    151      */
    152     public Iterator<String> getValues() {
    153         synchronized (values) {
    154             return Collections.unmodifiableList(new ArrayList<String>(values)).iterator();
    155         }
    156     }
    157 
    158     /**
    159      * Returns the variable name that the question is filling out.
    160      *
    161      * @return the variable name of the question.
    162      */
    163     public String getVariable() {
    164         return variable;
    165     }
    166 
    167     /**
    168      * Sets a description that provides extra clarification about the question. This information
    169      * could be presented to the user either in tool-tip, help button, or as a section of text
    170      * before the question.<p>
    171      * <p/>
    172      * If the question is of type FIXED then the description should remain empty.
    173      *
    174      * @param description provides extra clarification about the question.
    175      */
    176     public void setDescription(String description) {
    177         this.description = description;
    178     }
    179 
    180     /**
    181      * Sets the label of the question which should give enough information to the user to
    182      * fill out the form.
    183      *
    184      * @param label the label of the question.
    185      */
    186     public void setLabel(String label) {
    187         this.label = label;
    188     }
    189 
    190     /**
    191      * Sets if the question must be answered in order to complete the questionnaire.
    192      *
    193      * @param required if the question must be answered in order to complete the questionnaire.
    194      */
    195     public void setRequired(boolean required) {
    196         this.required = required;
    197     }
    198 
    199     /**
    200      * Sets an indicative of the format for the data to answer. Valid formats are:
    201      * <p/>
    202      * <ul>
    203      * <li>text-single -> single line or word of text
    204      * <li>text-private -> instead of showing the user what they typed, you show ***** to
    205      * protect it
    206      * <li>text-multi -> multiple lines of text entry
    207      * <li>list-single -> given a list of choices, pick one
    208      * <li>list-multi -> given a list of choices, pick one or more
    209      * <li>boolean -> 0 or 1, true or false, yes or no. Default value is 0
    210      * <li>fixed -> fixed for putting in text to show sections, or just advertise your web
    211      * site in the middle of the form
    212      * <li>hidden -> is not given to the user at all, but returned with the questionnaire
    213      * <li>jid-single -> Jabber ID - choosing a JID from your roster, and entering one based
    214      * on the rules for a JID.
    215      * <li>jid-multi -> multiple entries for JIDs
    216      * </ul>
    217      *
    218      * @param type an indicative of the format for the data to answer.
    219      */
    220     public void setType(String type) {
    221         this.type = type;
    222     }
    223 
    224     /**
    225      * Adds a default value to the question if the question is part of a form to fill out.
    226      * Otherwise, adds an answered value to the question.
    227      *
    228      * @param value a default value or an answered value of the question.
    229      */
    230     public void addValue(String value) {
    231         synchronized (values) {
    232             values.add(value);
    233         }
    234     }
    235 
    236     /**
    237      * Adds a default values to the question if the question is part of a form to fill out.
    238      * Otherwise, adds an answered values to the question.
    239      *
    240      * @param newValues default values or an answered values of the question.
    241      */
    242     public void addValues(List<String> newValues) {
    243         synchronized (values) {
    244             values.addAll(newValues);
    245         }
    246     }
    247 
    248     /**
    249      * Removes all the values of the field.
    250      */
    251     protected void resetValues() {
    252         synchronized (values) {
    253             values.removeAll(new ArrayList<String>(values));
    254         }
    255     }
    256 
    257     /**
    258      * Adss an available options to the question that the user has in order to answer
    259      * the question.
    260      *
    261      * @param option a new available option for the question.
    262      */
    263     public void addOption(Option option) {
    264         synchronized (options) {
    265             options.add(option);
    266         }
    267     }
    268 
    269     public String toXML() {
    270         StringBuilder buf = new StringBuilder();
    271         buf.append("<field");
    272         // Add attributes
    273         if (getLabel() != null) {
    274             buf.append(" label=\"").append(getLabel()).append("\"");
    275         }
    276         if (getVariable() != null) {
    277             buf.append(" var=\"").append(getVariable()).append("\"");
    278         }
    279         if (getType() != null) {
    280             buf.append(" type=\"").append(getType()).append("\"");
    281         }
    282         buf.append(">");
    283         // Add elements
    284         if (getDescription() != null) {
    285             buf.append("<desc>").append(getDescription()).append("</desc>");
    286         }
    287         if (isRequired()) {
    288             buf.append("<required/>");
    289         }
    290         // Loop through all the values and append them to the string buffer
    291         for (Iterator<String> i = getValues(); i.hasNext();) {
    292             buf.append("<value>").append(i.next()).append("</value>");
    293         }
    294         // Loop through all the values and append them to the string buffer
    295         for (Iterator<Option> i = getOptions(); i.hasNext();) {
    296             buf.append((i.next()).toXML());
    297         }
    298         buf.append("</field>");
    299         return buf.toString();
    300     }
    301 
    302     @Override
    303     public boolean equals(Object obj) {
    304         if (obj == null)
    305             return false;
    306         if (obj == this)
    307             return true;
    308         if (!(obj instanceof FormField))
    309             return false;
    310 
    311         FormField other = (FormField) obj;
    312 
    313         return toXML().equals(other.toXML());
    314     }
    315 
    316     @Override
    317     public int hashCode() {
    318         return toXML().hashCode();
    319     }
    320 
    321     /**
    322      * Represents the available option of a given FormField.
    323      *
    324      * @author Gaston Dombiak
    325      */
    326     public static class Option {
    327 
    328         private String label;
    329         private String value;
    330 
    331         public Option(String value) {
    332             this.value = value;
    333         }
    334 
    335         public Option(String label, String value) {
    336             this.label = label;
    337             this.value = value;
    338         }
    339 
    340         /**
    341          * Returns the label that represents the option.
    342          *
    343          * @return the label that represents the option.
    344          */
    345         public String getLabel() {
    346             return label;
    347         }
    348 
    349         /**
    350          * Returns the value of the option.
    351          *
    352          * @return the value of the option.
    353          */
    354         public String getValue() {
    355             return value;
    356         }
    357 
    358         @Override
    359         public String toString() {
    360             return getLabel();
    361         }
    362 
    363         public String toXML() {
    364             StringBuilder buf = new StringBuilder();
    365             buf.append("<option");
    366             // Add attribute
    367             if (getLabel() != null) {
    368                 buf.append(" label=\"").append(getLabel()).append("\"");
    369             }
    370             buf.append(">");
    371             // Add element
    372             buf.append("<value>").append(StringUtils.escapeForXML(getValue())).append("</value>");
    373 
    374             buf.append("</option>");
    375             return buf.toString();
    376         }
    377 
    378         @Override
    379         public boolean equals(Object obj) {
    380             if (obj == null)
    381                 return false;
    382             if (obj == this)
    383                 return true;
    384             if (obj.getClass() != getClass())
    385                 return false;
    386 
    387             Option other = (Option) obj;
    388 
    389             if (!value.equals(other.value))
    390                 return false;
    391 
    392             String thisLabel = label == null ? "" : label;
    393             String otherLabel = other.label == null ? "" : other.label;
    394 
    395             if (!thisLabel.equals(otherLabel))
    396                 return false;
    397 
    398             return true;
    399         }
    400 
    401         @Override
    402         public int hashCode() {
    403             int result = 1;
    404             result = 37 * result + value.hashCode();
    405             result = 37 * result + (label == null ? 0 : label.hashCode());
    406             return result;
    407         }
    408     }
    409 }
    410