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.packet; 22 23 import org.jivesoftware.smack.packet.PacketExtension; 24 import org.jivesoftware.smackx.Form; 25 import org.jivesoftware.smackx.FormField; 26 27 import java.util.ArrayList; 28 import java.util.Collections; 29 import java.util.Iterator; 30 import java.util.List; 31 32 /** 33 * Represents a form that could be use for gathering data as well as for reporting data 34 * returned from a search. 35 * 36 * @author Gaston Dombiak 37 */ 38 public class DataForm implements PacketExtension { 39 40 private String type; 41 private String title; 42 private List<String> instructions = new ArrayList<String>(); 43 private ReportedData reportedData; 44 private final List<Item> items = new ArrayList<Item>(); 45 private final List<FormField> fields = new ArrayList<FormField>(); 46 47 public DataForm(String type) { 48 this.type = type; 49 } 50 51 /** 52 * Returns the meaning of the data within the context. The data could be part of a form 53 * to fill out, a form submission or data results.<p> 54 * 55 * Possible form types are: 56 * <ul> 57 * <li>form -> This packet contains a form to fill out. Display it to the user (if your 58 * program can).</li> 59 * <li>submit -> The form is filled out, and this is the data that is being returned from 60 * the form.</li> 61 * <li>cancel -> The form was cancelled. Tell the asker that piece of information.</li> 62 * <li>result -> Data results being returned from a search, or some other query.</li> 63 * </ul> 64 * 65 * @return the form's type. 66 */ 67 public String getType() { 68 return type; 69 } 70 71 /** 72 * Returns the description of the data. It is similar to the title on a web page or an X 73 * window. You can put a <title/> on either a form to fill out, or a set of data results. 74 * 75 * @return description of the data. 76 */ 77 public String getTitle() { 78 return title; 79 } 80 81 /** 82 * Returns an Iterator for the list of instructions that explain how to fill out the form and 83 * what the form is about. The dataform could include multiple instructions since each 84 * instruction could not contain newlines characters. Join the instructions together in order 85 * to show them to the user. 86 * 87 * @return an Iterator for the list of instructions that explain how to fill out the form. 88 */ 89 public Iterator<String> getInstructions() { 90 synchronized (instructions) { 91 return Collections.unmodifiableList(new ArrayList<String>(instructions)).iterator(); 92 } 93 } 94 95 /** 96 * Returns the fields that will be returned from a search. 97 * 98 * @return fields that will be returned from a search. 99 */ 100 public ReportedData getReportedData() { 101 return reportedData; 102 } 103 104 /** 105 * Returns an Iterator for the items returned from a search. 106 * 107 * @return an Iterator for the items returned from a search. 108 */ 109 public Iterator<Item> getItems() { 110 synchronized (items) { 111 return Collections.unmodifiableList(new ArrayList<Item>(items)).iterator(); 112 } 113 } 114 115 /** 116 * Returns an Iterator for the fields that are part of the form. 117 * 118 * @return an Iterator for the fields that are part of the form. 119 */ 120 public Iterator<FormField> getFields() { 121 synchronized (fields) { 122 return Collections.unmodifiableList(new ArrayList<FormField>(fields)).iterator(); 123 } 124 } 125 126 public String getElementName() { 127 return Form.ELEMENT; 128 } 129 130 public String getNamespace() { 131 return Form.NAMESPACE; 132 } 133 134 /** 135 * Sets the description of the data. It is similar to the title on a web page or an X window. 136 * You can put a <title/> on either a form to fill out, or a set of data results. 137 * 138 * @param title description of the data. 139 */ 140 public void setTitle(String title) { 141 this.title = title; 142 } 143 144 /** 145 * Sets the list of instructions that explain how to fill out the form and what the form is 146 * about. The dataform could include multiple instructions since each instruction could not 147 * contain newlines characters. 148 * 149 * @param instructions list of instructions that explain how to fill out the form. 150 */ 151 public void setInstructions(List<String> instructions) { 152 this.instructions = instructions; 153 } 154 155 /** 156 * Sets the fields that will be returned from a search. 157 * 158 * @param reportedData the fields that will be returned from a search. 159 */ 160 public void setReportedData(ReportedData reportedData) { 161 this.reportedData = reportedData; 162 } 163 164 /** 165 * Adds a new field as part of the form. 166 * 167 * @param field the field to add to the form. 168 */ 169 public void addField(FormField field) { 170 synchronized (fields) { 171 fields.add(field); 172 } 173 } 174 175 /** 176 * Adds a new instruction to the list of instructions that explain how to fill out the form 177 * and what the form is about. The dataform could include multiple instructions since each 178 * instruction could not contain newlines characters. 179 * 180 * @param instruction the new instruction that explain how to fill out the form. 181 */ 182 public void addInstruction(String instruction) { 183 synchronized (instructions) { 184 instructions.add(instruction); 185 } 186 } 187 188 /** 189 * Adds a new item returned from a search. 190 * 191 * @param item the item returned from a search. 192 */ 193 public void addItem(Item item) { 194 synchronized (items) { 195 items.add(item); 196 } 197 } 198 199 /** 200 * Returns true if this DataForm has at least one FORM_TYPE field which is 201 * hidden. This method is used for sanity checks. 202 * 203 * @return 204 */ 205 public boolean hasHiddenFormTypeField() { 206 boolean found = false; 207 for (FormField f : fields) { 208 if (f.getVariable().equals("FORM_TYPE") && f.getType() != null && f.getType().equals("hidden")) 209 found = true; 210 } 211 return found; 212 } 213 214 public String toXML() { 215 StringBuilder buf = new StringBuilder(); 216 buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append( 217 "\" type=\"" + getType() +"\">"); 218 if (getTitle() != null) { 219 buf.append("<title>").append(getTitle()).append("</title>"); 220 } 221 for (Iterator<String> it=getInstructions(); it.hasNext();) { 222 buf.append("<instructions>").append(it.next()).append("</instructions>"); 223 } 224 // Append the list of fields returned from a search 225 if (getReportedData() != null) { 226 buf.append(getReportedData().toXML()); 227 } 228 // Loop through all the items returned from a search and append them to the string buffer 229 for (Iterator<Item> i = getItems(); i.hasNext();) { 230 Item item = i.next(); 231 buf.append(item.toXML()); 232 } 233 // Loop through all the form fields and append them to the string buffer 234 for (Iterator<FormField> i = getFields(); i.hasNext();) { 235 FormField field = i.next(); 236 buf.append(field.toXML()); 237 } 238 buf.append("</").append(getElementName()).append(">"); 239 return buf.toString(); 240 } 241 242 /** 243 * 244 * Represents the fields that will be returned from a search. This information is useful when 245 * you try to use the jabber:iq:search namespace to return dynamic form information. 246 * 247 * @author Gaston Dombiak 248 */ 249 public static class ReportedData { 250 private List<FormField> fields = new ArrayList<FormField>(); 251 252 public ReportedData(List<FormField> fields) { 253 this.fields = fields; 254 } 255 256 /** 257 * Returns the fields returned from a search. 258 * 259 * @return the fields returned from a search. 260 */ 261 public Iterator<FormField> getFields() { 262 return Collections.unmodifiableList(new ArrayList<FormField>(fields)).iterator(); 263 } 264 265 public String toXML() { 266 StringBuilder buf = new StringBuilder(); 267 buf.append("<reported>"); 268 // Loop through all the form items and append them to the string buffer 269 for (Iterator<FormField> i = getFields(); i.hasNext();) { 270 FormField field = i.next(); 271 buf.append(field.toXML()); 272 } 273 buf.append("</reported>"); 274 return buf.toString(); 275 } 276 } 277 278 /** 279 * 280 * Represents items of reported data. 281 * 282 * @author Gaston Dombiak 283 */ 284 public static class Item { 285 private List<FormField> fields = new ArrayList<FormField>(); 286 287 public Item(List<FormField> fields) { 288 this.fields = fields; 289 } 290 291 /** 292 * Returns the fields that define the data that goes with the item. 293 * 294 * @return the fields that define the data that goes with the item. 295 */ 296 public Iterator<FormField> getFields() { 297 return Collections.unmodifiableList(new ArrayList<FormField>(fields)).iterator(); 298 } 299 300 public String toXML() { 301 StringBuilder buf = new StringBuilder(); 302 buf.append("<item>"); 303 // Loop through all the form items and append them to the string buffer 304 for (Iterator<FormField> i = getFields(); i.hasNext();) { 305 FormField field = i.next(); 306 buf.append(field.toXML()); 307 } 308 buf.append("</item>"); 309 return buf.toString(); 310 } 311 } 312 } 313