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 */ FormField(String variable)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 */ FormField()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 */ getDescription()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 */ getLabel()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 */ getOptions()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 */ isRequired()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 */ getType()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 */ getValues()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 */ getVariable()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 */ setDescription(String description)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 */ setLabel(String label)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 */ setRequired(boolean required)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 */ setType(String type)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 */ addValue(String value)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 */ addValues(List<String> newValues)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 */ resetValues()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 */ addOption(Option option)263 public void addOption(Option option) { 264 synchronized (options) { 265 options.add(option); 266 } 267 } 268 toXML()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 equals(Object obj)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 hashCode()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 Option(String value)331 public Option(String value) { 332 this.value = value; 333 } 334 Option(String label, String value)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 */ getLabel()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 */ getValue()354 public String getValue() { 355 return value; 356 } 357 358 @Override toString()359 public String toString() { 360 return getLabel(); 361 } 362 toXML()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 equals(Object obj)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 hashCode()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