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.packet; 019 020import org.jivesoftware.smack.packet.PacketExtension; 021import org.jivesoftware.smack.util.XmlStringBuilder; 022import org.jivesoftware.smackx.xdata.FormField; 023 024import java.util.ArrayList; 025import java.util.Collections; 026import java.util.List; 027 028/** 029 * Represents a form that could be use for gathering data as well as for reporting data 030 * returned from a search. 031 * 032 * @author Gaston Dombiak 033 */ 034public class DataForm implements PacketExtension { 035 036 public static final String NAMESPACE = "jabber:x:data"; 037 public static final String ELEMENT = "x"; 038 039 private String type; 040 private String title; 041 private List<String> instructions = new ArrayList<String>(); 042 private ReportedData reportedData; 043 private final List<Item> items = new ArrayList<Item>(); 044 private final List<FormField> fields = new ArrayList<FormField>(); 045 046 public DataForm(String type) { 047 this.type = type; 048 } 049 050 /** 051 * Returns the meaning of the data within the context. The data could be part of a form 052 * to fill out, a form submission or data results.<p> 053 * 054 * Possible form types are: 055 * <ul> 056 * <li>form -> This packet contains a form to fill out. Display it to the user (if your 057 * program can).</li> 058 * <li>submit -> The form is filled out, and this is the data that is being returned from 059 * the form.</li> 060 * <li>cancel -> The form was cancelled. Tell the asker that piece of information.</li> 061 * <li>result -> Data results being returned from a search, or some other query.</li> 062 * </ul> 063 * 064 * @return the form's type. 065 */ 066 public String getType() { 067 return type; 068 } 069 070 /** 071 * Returns the description of the data. It is similar to the title on a web page or an X 072 * window. You can put a <title/> on either a form to fill out, or a set of data results. 073 * 074 * @return description of the data. 075 */ 076 public String getTitle() { 077 return title; 078 } 079 080 /** 081 * Returns a List of the list of instructions that explain how to fill out the form and 082 * what the form is about. The dataform could include multiple instructions since each 083 * instruction could not contain newlines characters. Join the instructions together in order 084 * to show them to the user. 085 * 086 * @return a List of the list of instructions that explain how to fill out the form. 087 */ 088 public List<String> getInstructions() { 089 synchronized (instructions) { 090 return Collections.unmodifiableList(new ArrayList<String>(instructions)); 091 } 092 } 093 094 /** 095 * Returns the fields that will be returned from a search. 096 * 097 * @return fields that will be returned from a search. 098 */ 099 public ReportedData getReportedData() { 100 return reportedData; 101 } 102 103 /** 104 * Returns a List of the items returned from a search. 105 * 106 * @return a List of the items returned from a search. 107 */ 108 public List<Item> getItems() { 109 synchronized (items) { 110 return Collections.unmodifiableList(new ArrayList<Item>(items)); 111 } 112 } 113 114 /** 115 * Returns a List of the fields that are part of the form. 116 * 117 * @return a List of the fields that are part of the form. 118 */ 119 public List<FormField> getFields() { 120 synchronized (fields) { 121 return Collections.unmodifiableList(new ArrayList<FormField>(fields)); 122 } 123 } 124 125 public String getElementName() { 126 return ELEMENT; 127 } 128 129 public String getNamespace() { 130 return NAMESPACE; 131 } 132 133 /** 134 * Sets the description of the data. It is similar to the title on a web page or an X window. 135 * You can put a <title/> on either a form to fill out, or a set of data results. 136 * 137 * @param title description of the data. 138 */ 139 public void setTitle(String title) { 140 this.title = title; 141 } 142 143 /** 144 * Sets the list of instructions that explain how to fill out the form and what the form is 145 * about. The dataform could include multiple instructions since each instruction could not 146 * contain newlines characters. 147 * 148 * @param instructions list of instructions that explain how to fill out the form. 149 */ 150 public void setInstructions(List<String> instructions) { 151 this.instructions = instructions; 152 } 153 154 /** 155 * Sets the fields that will be returned from a search. 156 * 157 * @param reportedData the fields that will be returned from a search. 158 */ 159 public void setReportedData(ReportedData reportedData) { 160 this.reportedData = reportedData; 161 } 162 163 /** 164 * Adds a new field as part of the form. 165 * 166 * @param field the field to add to the form. 167 */ 168 public void addField(FormField field) { 169 synchronized (fields) { 170 fields.add(field); 171 } 172 } 173 174 /** 175 * Adds a new instruction to the list of instructions that explain how to fill out the form 176 * and what the form is about. The dataform could include multiple instructions since each 177 * instruction could not contain newlines characters. 178 * 179 * @param instruction the new instruction that explain how to fill out the form. 180 */ 181 public void addInstruction(String instruction) { 182 synchronized (instructions) { 183 instructions.add(instruction); 184 } 185 } 186 187 /** 188 * Adds a new item returned from a search. 189 * 190 * @param item the item returned from a search. 191 */ 192 public void addItem(Item item) { 193 synchronized (items) { 194 items.add(item); 195 } 196 } 197 198 /** 199 * Returns true if this DataForm has at least one FORM_TYPE field which is 200 * hidden. This method is used for sanity checks. 201 * 202 * @return true if there is at least one field which is hidden. 203 */ 204 public boolean hasHiddenFormTypeField() { 205 boolean found = false; 206 for (FormField f : fields) { 207 if (f.getVariable().equals("FORM_TYPE") && f.getType() != null && f.getType().equals("hidden")) 208 found = true; 209 } 210 return found; 211 } 212 213 @Override 214 public XmlStringBuilder toXML() { 215 XmlStringBuilder buf = new XmlStringBuilder(this); 216 buf.attribute("type", getType()); 217 buf.rightAngelBracket(); 218 219 buf.optElement("title", getTitle()); 220 for (String instruction : getInstructions()) { 221 buf.element("instructions", instruction); 222 } 223 // Append the list of fields returned from a search 224 if (getReportedData() != null) { 225 buf.append(getReportedData().toXML()); 226 } 227 // Loop through all the items returned from a search and append them to the string buffer 228 for (Item item : getItems()) { 229 buf.append(item.toXML()); 230 } 231 // Loop through all the form fields and append them to the string buffer 232 for (FormField field : getFields()) { 233 buf.append(field.toXML()); 234 } 235 buf.closeElement(this); 236 return buf; 237 } 238 239 /** 240 * 241 * Represents the fields that will be returned from a search. This information is useful when 242 * you try to use the jabber:iq:search namespace to return dynamic form information. 243 * 244 * @author Gaston Dombiak 245 */ 246 public static class ReportedData { 247 public static final String ELEMENT = "reported"; 248 249 private List<FormField> fields = new ArrayList<FormField>(); 250 251 public ReportedData(List<FormField> fields) { 252 this.fields = fields; 253 } 254 255 /** 256 * Returns the fields returned from a search. 257 * 258 * @return the fields returned from a search. 259 */ 260 public List<FormField> getFields() { 261 return Collections.unmodifiableList(new ArrayList<FormField>(fields)); 262 } 263 264 public CharSequence toXML() { 265 XmlStringBuilder buf = new XmlStringBuilder(); 266 buf.openElement(ELEMENT); 267 // Loop through all the form items and append them to the string buffer 268 for (FormField field : getFields()) { 269 buf.append(field.toXML()); 270 } 271 buf.closeElement(ELEMENT); 272 return buf; 273 } 274 } 275 276 /** 277 * 278 * Represents items of reported data. 279 * 280 * @author Gaston Dombiak 281 */ 282 public static class Item { 283 public static final String ELEMENT = "item"; 284 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 List<FormField> getFields() { 297 return Collections.unmodifiableList(new ArrayList<FormField>(fields)); 298 } 299 300 public CharSequence toXML() { 301 XmlStringBuilder buf = new XmlStringBuilder(); 302 buf.openElement(ELEMENT); 303 // Loop through all the form items and append them to the string buffer 304 for (FormField field : getFields()) { 305 buf.append(field.toXML()); 306 } 307 buf.closeElement(ELEMENT); 308 return buf; 309 } 310 } 311}