001/** 002 * 003 * Copyright 2003-2007 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.jivesoftware.smackx.xdata; 019 020import org.jivesoftware.smack.util.XmlStringBuilder; 021 022import java.util.ArrayList; 023import java.util.Collections; 024import java.util.List; 025 026/** 027 * Represents a field of a form. The field could be used to represent a question to complete, 028 * a completed question or a data returned from a search. The exact interpretation of the field 029 * depends on the context where the field is used. 030 * 031 * @author Gaston Dombiak 032 */ 033public class FormField { 034 035 public static final String ELEMENT = "field"; 036 037 public static final String TYPE_BOOLEAN = "boolean"; 038 public static final String TYPE_FIXED = "fixed"; 039 public static final String TYPE_HIDDEN = "hidden"; 040 public static final String TYPE_JID_MULTI = "jid-multi"; 041 public static final String TYPE_JID_SINGLE = "jid-single"; 042 public static final String TYPE_LIST_MULTI = "list-multi"; 043 public static final String TYPE_LIST_SINGLE = "list-single"; 044 public static final String TYPE_TEXT_MULTI = "text-multi"; 045 public static final String TYPE_TEXT_PRIVATE = "text-private"; 046 public static final String TYPE_TEXT_SINGLE = "text-single"; 047 048 private String description; 049 private boolean required = false; 050 private String label; 051 private String variable; 052 private String type; 053 private final List<Option> options = new ArrayList<Option>(); 054 private final List<String> values = new ArrayList<String>(); 055 056 /** 057 * Creates a new FormField with the variable name that uniquely identifies the field 058 * in the context of the form. 059 * 060 * @param variable the variable name of the question. 061 */ 062 public FormField(String variable) { 063 this.variable = variable; 064 } 065 066 /** 067 * Creates a new FormField of type FIXED. The fields of type FIXED do not define a variable 068 * name. 069 */ 070 public FormField() { 071 this.type = FormField.TYPE_FIXED; 072 } 073 074 /** 075 * Returns a description that provides extra clarification about the question. This information 076 * could be presented to the user either in tool-tip, help button, or as a section of text 077 * before the question.<p> 078 * <p/> 079 * If the question is of type FIXED then the description should remain empty. 080 * 081 * @return description that provides extra clarification about the question. 082 */ 083 public String getDescription() { 084 return description; 085 } 086 087 /** 088 * Returns the label of the question which should give enough information to the user to 089 * fill out the form. 090 * 091 * @return label of the question. 092 */ 093 public String getLabel() { 094 return label; 095 } 096 097 /** 098 * Returns a List of the available options that the user has in order to answer 099 * the question. 100 * 101 * @return List of the available options. 102 */ 103 public List<Option> getOptions() { 104 synchronized (options) { 105 return Collections.unmodifiableList(new ArrayList<Option>(options)); 106 } 107 } 108 109 /** 110 * Returns true if the question must be answered in order to complete the questionnaire. 111 * 112 * @return true if the question must be answered in order to complete the questionnaire. 113 */ 114 public boolean isRequired() { 115 return required; 116 } 117 118 /** 119 * Returns an indicative of the format for the data to answer. Valid formats are: 120 * <p/> 121 * <ul> 122 * <li>text-single -> single line or word of text 123 * <li>text-private -> instead of showing the user what they typed, you show ***** to 124 * protect it 125 * <li>text-multi -> multiple lines of text entry 126 * <li>list-single -> given a list of choices, pick one 127 * <li>list-multi -> given a list of choices, pick one or more 128 * <li>boolean -> 0 or 1, true or false, yes or no. Default value is 0 129 * <li>fixed -> fixed for putting in text to show sections, or just advertise your web 130 * site in the middle of the form 131 * <li>hidden -> is not given to the user at all, but returned with the questionnaire 132 * <li>jid-single -> Jabber ID - choosing a JID from your roster, and entering one based 133 * on the rules for a JID. 134 * <li>jid-multi -> multiple entries for JIDs 135 * </ul> 136 * 137 * @return format for the data to answer. 138 */ 139 public String getType() { 140 return type; 141 } 142 143 /** 144 * Returns a List of the default values of the question if the question is part 145 * of a form to fill out. Otherwise, returns a List of the answered values of 146 * the question. 147 * 148 * @return a List of the default values or answered values of the question. 149 */ 150 public List<String> getValues() { 151 synchronized (values) { 152 return Collections.unmodifiableList(new ArrayList<String>(values)); 153 } 154 } 155 156 /** 157 * Returns the variable name that the question is filling out. 158 * 159 * @return the variable name of the question. 160 */ 161 public String getVariable() { 162 return variable; 163 } 164 165 /** 166 * Sets a description that provides extra clarification about the question. This information 167 * could be presented to the user either in tool-tip, help button, or as a section of text 168 * before the question.<p> 169 * <p/> 170 * If the question is of type FIXED then the description should remain empty. 171 * 172 * @param description provides extra clarification about the question. 173 */ 174 public void setDescription(String description) { 175 this.description = description; 176 } 177 178 /** 179 * Sets the label of the question which should give enough information to the user to 180 * fill out the form. 181 * 182 * @param label the label of the question. 183 */ 184 public void setLabel(String label) { 185 this.label = label; 186 } 187 188 /** 189 * Sets if the question must be answered in order to complete the questionnaire. 190 * 191 * @param required if the question must be answered in order to complete the questionnaire. 192 */ 193 public void setRequired(boolean required) { 194 this.required = required; 195 } 196 197 /** 198 * Sets an indicative of the format for the data to answer. Valid formats are: 199 * <p/> 200 * <ul> 201 * <li>text-single -> single line or word of text 202 * <li>text-private -> instead of showing the user what they typed, you show ***** to 203 * protect it 204 * <li>text-multi -> multiple lines of text entry 205 * <li>list-single -> given a list of choices, pick one 206 * <li>list-multi -> given a list of choices, pick one or more 207 * <li>boolean -> 0 or 1, true or false, yes or no. Default value is 0 208 * <li>fixed -> fixed for putting in text to show sections, or just advertise your web 209 * site in the middle of the form 210 * <li>hidden -> is not given to the user at all, but returned with the questionnaire 211 * <li>jid-single -> Jabber ID - choosing a JID from your roster, and entering one based 212 * on the rules for a JID. 213 * <li>jid-multi -> multiple entries for JIDs 214 * </ul> 215 * 216 * @param type an indicative of the format for the data to answer. 217 */ 218 public void setType(String type) { 219 this.type = type; 220 } 221 222 /** 223 * Adds a default value to the question if the question is part of a form to fill out. 224 * Otherwise, adds an answered value to the question. 225 * 226 * @param value a default value or an answered value of the question. 227 */ 228 public void addValue(String value) { 229 synchronized (values) { 230 values.add(value); 231 } 232 } 233 234 /** 235 * Adds a default values to the question if the question is part of a form to fill out. 236 * Otherwise, adds an answered values to the question. 237 * 238 * @param newValues default values or an answered values of the question. 239 */ 240 public void addValues(List<String> newValues) { 241 synchronized (values) { 242 values.addAll(newValues); 243 } 244 } 245 246 /** 247 * Removes all the values of the field. 248 */ 249 protected void resetValues() { 250 synchronized (values) { 251 values.removeAll(new ArrayList<String>(values)); 252 } 253 } 254 255 /** 256 * Adss an available options to the question that the user has in order to answer 257 * the question. 258 * 259 * @param option a new available option for the question. 260 */ 261 public void addOption(Option option) { 262 synchronized (options) { 263 options.add(option); 264 } 265 } 266 267 public XmlStringBuilder toXML() { 268 XmlStringBuilder buf = new XmlStringBuilder(); 269 buf.halfOpenElement(ELEMENT); 270 // Add attributes 271 buf.optAttribute("label", getLabel()); 272 buf.optAttribute("var", getVariable()); 273 buf.optAttribute("type", getType()); 274 buf.rightAngelBracket(); 275 // Add elements 276 buf.optElement("desc", getDescription()); 277 buf.condEmptyElement(isRequired(), "required"); 278 // Loop through all the values and append them to the string buffer 279 for (String value : getValues()) { 280 buf.element("value", value); 281 } 282 // Loop through all the values and append them to the string buffer 283 for (Option option : getOptions()) { 284 buf.append(option.toXML()); 285 } 286 buf.closeElement(ELEMENT); 287 return buf; 288 } 289 290 @Override 291 public boolean equals(Object obj) { 292 if (obj == null) 293 return false; 294 if (obj == this) 295 return true; 296 if (!(obj instanceof FormField)) 297 return false; 298 299 FormField other = (FormField) obj; 300 301 return toXML().equals(other.toXML()); 302 } 303 304 @Override 305 public int hashCode() { 306 return toXML().hashCode(); 307 } 308 309 /** 310 * Represents the available option of a given FormField. 311 * 312 * @author Gaston Dombiak 313 */ 314 public static class Option { 315 316 public static final String ELEMNT = "option"; 317 318 private final String value; 319 private String label; 320 321 public Option(String value) { 322 this.value = value; 323 } 324 325 public Option(String label, String value) { 326 this.label = label; 327 this.value = value; 328 } 329 330 /** 331 * Returns the label that represents the option. 332 * 333 * @return the label that represents the option. 334 */ 335 public String getLabel() { 336 return label; 337 } 338 339 /** 340 * Returns the value of the option. 341 * 342 * @return the value of the option. 343 */ 344 public String getValue() { 345 return value; 346 } 347 348 @Override 349 public String toString() { 350 return getLabel(); 351 } 352 353 public XmlStringBuilder toXML() { 354 XmlStringBuilder xml = new XmlStringBuilder(); 355 xml.halfOpenElement(ELEMNT); 356 // Add attribute 357 xml.optAttribute("label", getLabel()); 358 xml.rightAngelBracket(); 359 360 // Add element 361 xml.element("value", getValue()); 362 363 xml.closeElement(ELEMENT); 364 return xml; 365 } 366 367 @Override 368 public boolean equals(Object obj) { 369 if (obj == null) 370 return false; 371 if (obj == this) 372 return true; 373 if (obj.getClass() != getClass()) 374 return false; 375 376 Option other = (Option) obj; 377 378 if (!value.equals(other.value)) 379 return false; 380 381 String thisLabel = label == null ? "" : label; 382 String otherLabel = other.label == null ? "" : other.label; 383 384 if (!thisLabel.equals(otherLabel)) 385 return false; 386 387 return true; 388 } 389 390 @Override 391 public int hashCode() { 392 int result = 1; 393 result = 37 * result + value.hashCode(); 394 result = 37 * result + (label == null ? 0 : label.hashCode()); 395 return result; 396 } 397 } 398}