source: psi/trunk/src/xmpp_xdata.cpp@ 59

Last change on this file since 59 was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 9.7 KB
Line 
1/*
2 * xmpp_xdata.cpp - a class for jabber:x:data forms
3 * Copyright (C) 2003-2004 Michail Pishchagin
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include "xmpp_xdata.h"
22
23#include <qshared.h>
24
25#include "im.h" // for JID validation
26#include "xmpp_xmlcommon.h"
27
28using namespace XMPP;
29using namespace XMLHelper;
30
31// TODO: report, item
32
33//----------------------------------------------------------------------------
34// XData::Field
35//----------------------------------------------------------------------------
36XData::Field::Field()
37{
38}
39
40XData::Field::~Field()
41{
42}
43
44QString XData::Field::desc() const
45{
46 return _desc;
47}
48
49void XData::Field::setDesc(const QString &d)
50{
51 _desc = d;
52}
53
54XData::Field::OptionList XData::Field::options() const
55{
56 return _options;
57}
58
59void XData::Field::setOptions(XData::Field::OptionList o)
60{
61 _options = o;
62}
63
64bool XData::Field::required() const
65{
66 return _required;
67}
68
69void XData::Field::setRequired(bool r)
70{
71 _required = r;
72}
73
74QString XData::Field::label() const
75{
76 return _label;
77}
78
79void XData::Field::setLabel(const QString &l)
80{
81 _label = l;
82}
83
84QString XData::Field::var() const
85{
86 return _var;
87}
88
89void XData::Field::setVar(const QString &v)
90{
91 _var = v;
92}
93
94QStringList XData::Field::value() const
95{
96 return _value;
97}
98
99void XData::Field::setValue(const QStringList &v)
100{
101 _value = v;
102}
103
104XData::Field::Type XData::Field::type() const
105{
106 return _type;
107}
108
109void XData::Field::setType(XData::Field::Type t)
110{
111 _type = t;
112}
113
114bool XData::Field::isValid() const
115{
116 if ( _required && _value.isEmpty() )
117 return false;
118
119 if ( _type == Field_Boolean ) {
120 if ( _value.count() != 1 )
121 return false;
122
123 QString str = _value.first();
124 if ( str == "0" || str == "1" || str == "true" || str == "false" || str == "yes" || str == "no" )
125 return true;
126 }
127 if ( _type == Field_TextSingle || _type == Field_TextPrivate ) {
128 if ( _value.count() == 1 )
129 return true;
130 }
131 if ( _type == Field_JidSingle ) {
132 if ( _value.count() != 1 )
133 return false;
134
135 Jid j( _value.first() );
136 return j.isValid();
137 }
138 if ( _type == Field_JidMulti ) {
139 QStringList::ConstIterator it = _value.begin();
140 bool allValid = true;
141 for ( ; it != _value.end(); ++it) {
142 Jid j(*it);
143 if ( !j.isValid() ) {
144 allValid = false;
145 break;
146 }
147 }
148 return allValid;
149 }
150
151 return false;
152}
153
154void XData::Field::fromXml(const QDomElement &e)
155{
156 if ( e.tagName() != "field" )
157 return;
158
159 _var = e.attribute("var");
160 _label = e.attribute("label");
161
162 QString type = e.attribute("type");
163 if ( type == "boolean" )
164 _type = Field_Boolean;
165 else if ( type == "fixed" )
166 _type = Field_Fixed;
167 else if ( type == "hidden" )
168 _type = Field_Hidden;
169 else if ( type == "jid-multi" )
170 _type = Field_JidMulti;
171 else if ( type == "jid-single" )
172 _type = Field_JidSingle;
173 else if ( type == "list-multi" )
174 _type = Field_ListMulti;
175 else if ( type == "list-single" )
176 _type = Field_ListSingle;
177 else if ( type == "text-multi" )
178 _type = Field_TextMulti;
179 else if ( type == "text-private" )
180 _type = Field_TextPrivate;
181 else
182 _type = Field_TextSingle;
183
184 _required = false;
185 _desc = QString::null;
186 _options.clear();
187 _value.clear();
188
189 QDomNode n = e.firstChild();
190 for ( ; !n.isNull(); n = n.nextSibling() ) {
191 QDomElement i = n.toElement();
192 if ( i.isNull() )
193 continue;
194
195 QString tag = i.tagName();
196 if ( tag == "required" )
197 _required = true;
198 else if ( tag == "desc" )
199 _desc = i.text().simplifyWhiteSpace();
200 else if ( tag == "option" ) {
201 Option o;
202 bool found;
203 o.label = i.attribute("label");
204
205 QDomElement e = findSubTag( i, "value", &found );
206 o.value = ( found ? e.text() : QString("") );
207 _options.append(o);
208 }
209 else if ( tag == "value" ) {
210 _value.append(i.text());
211 }
212 }
213}
214
215QDomElement XData::Field::toXml(QDomDocument *doc, bool submitForm) const
216{
217 QDomElement f = doc->createElement("field");
218
219 // setting attributes...
220 if ( !_var.isEmpty() )
221 f.setAttribute("var", _var);
222 if ( !submitForm && !_label.isEmpty() )
223 f.setAttribute("label", _label);
224
225 // now we're gonna get the 'type'
226 QString type = "text-single";
227 if ( _type == Field_Boolean )
228 type = "boolean";
229 else if ( _type == Field_Fixed )
230 type = "fixed";
231 else if ( _type == Field_Hidden )
232 type = "hidden";
233 else if ( _type == Field_JidMulti )
234 type = "jid-multi";
235 else if ( _type == Field_JidSingle )
236 type = "jid-single";
237 else if ( _type == Field_ListMulti )
238 type = "list-multi";
239 else if ( _type == Field_ListSingle )
240 type = "list-single";
241 else if ( _type == Field_TextMulti )
242 type = "text-multi";
243 else if ( _type == Field_TextPrivate )
244 type = "text-private";
245
246 f.setAttribute("type", type);
247
248 // now, setting nested tags...
249 if ( !submitForm && _required )
250 f.appendChild( emptyTag(doc, "required") );
251
252 if ( !submitForm && !_desc.isEmpty() )
253 f.appendChild( textTag(doc, "desc", _desc) );
254
255 if ( !submitForm && !_options.isEmpty() ) {
256 OptionList::ConstIterator it = _options.begin();
257 for ( ; it != _options.end(); ++it) {
258 QDomElement o = doc->createElement("option");
259 o.appendChild(textTag(doc, "value", (*it).value));
260 if ( !(*it).label.isEmpty() )
261 o.setAttribute("label", (*it).label);
262 f.appendChild(o);
263 }
264 }
265
266 if ( !_value.isEmpty() ) {
267 QStringList::ConstIterator it = _value.begin();
268 for ( ; it != _value.end(); ++it)
269 f.appendChild( textTag(doc, "value", *it) );
270 }
271
272 return f;
273}
274
275//----------------------------------------------------------------------------
276// XData
277//----------------------------------------------------------------------------
278class XData::Private : public QShared {
279public:
280 QString title, instructions;
281 XData::Type type;
282 FieldList fields;
283 QValueList<ReportField> report;
284 QValueList<ReportItem> reportItems;
285};
286
287XData::XData()
288{
289 d = new Private;
290}
291
292XData::~XData()
293{
294 if ( d->deref() )
295 delete d;
296}
297
298XData::XData(const XData &x)
299{
300 d = x.d;
301 d->ref();
302}
303
304QString XData::title() const
305{
306 return d->title;
307}
308
309void XData::setTitle(const QString &t)
310{
311 detach();
312 d->title = t;
313}
314
315QString XData::instructions() const
316{
317 return d->instructions;
318}
319
320void XData::setInstructions(const QString &i)
321{
322 detach();
323 d->instructions = i;
324}
325
326XData::Type XData::type() const
327{
328 return d->type;
329}
330
331void XData::setType(Type t)
332{
333 detach();
334 d->type = t;
335}
336
337XData::FieldList XData::fields() const
338{
339 return d->fields;
340}
341
342void XData::setFields(const FieldList &f)
343{
344 detach();
345 d->fields = f;
346}
347
348void XData::fromXml(const QDomElement &e)
349{
350 if ( e.attribute("xmlns") != "jabber:x:data" )
351 return;
352
353 detach();
354
355 QString type = e.attribute("type");
356 if ( type == "result" )
357 d->type = Data_Result;
358 else if ( type == "submit" )
359 d->type = Data_Submit;
360 else if ( type == "cancel" )
361 d->type = Data_Cancel;
362 else
363 d->type = Data_Form;
364
365 d->title = subTagText(e, "title");
366 d->instructions = subTagText(e, "instructions");
367
368 d->fields.clear();
369
370 QDomNode n = e.firstChild();
371 for ( ; !n.isNull(); n = n.nextSibling() ) {
372 QDomElement i = n.toElement();
373 if ( i.isNull() )
374 continue;
375
376 if ( i.tagName() == "field" ) {
377 Field f;
378 f.fromXml(i);
379 d->fields.append(f);
380 }
381 else if ( i.tagName() == "reported" ) {
382 d->report.clear();
383 d->reportItems.clear();
384
385 QDomNode nn = i.firstChild();
386 for ( ; !nn.isNull(); nn = nn.nextSibling() ) {
387 QDomElement ii = nn.toElement();
388 if ( ii.isNull() )
389 continue;
390
391 if ( ii.tagName() == "field" ) {
392 d->report.append( ReportField( ii.attribute("label"), ii.attribute("var") ) );
393 }
394 }
395 }
396 else if ( i.tagName() == "item" ) {
397 ReportItem item;
398
399 QDomNode nn = i.firstChild();
400 for ( ; !nn.isNull(); nn = nn.nextSibling() ) {
401 QDomElement ii = nn.toElement();
402 if ( ii.isNull() )
403 continue;
404
405 if ( ii.tagName() == "field" ) {
406 QString name = ii.attribute("var");
407 QString value;
408
409 bool found;
410 QDomElement e = findSubTag( ii, "value", &found );
411 if ( found )
412 value = e.text();
413
414 item[name] = value;
415 }
416 }
417
418 d->reportItems.append( item );
419 }
420 }
421}
422
423QDomElement XData::toXml(QDomDocument *doc, bool submitForm) const
424{
425 QDomElement x = doc->createElement("x");
426 x.setAttribute("xmlns", "jabber:x:data");
427
428 QString type = "form";
429 if ( d->type == Data_Result )
430 type = "result";
431 else if ( d->type == Data_Submit )
432 type = "submit";
433 else if ( d->type == Data_Cancel )
434 type = "cancel";
435
436 x.setAttribute("type", type);
437
438 if ( !submitForm && !d->title.isEmpty() )
439 x.appendChild( textTag(doc, "title", d->title) );
440 if ( !submitForm && !d->instructions.isEmpty() )
441 x.appendChild( textTag(doc, "instructions", d->instructions) );
442
443 if ( !d->fields.isEmpty() ) {
444 FieldList::ConstIterator it = d->fields.begin();
445 for ( ; it != d->fields.end(); ++it) {
446 Field f = *it;
447 if ( !(submitForm && f.var().isEmpty()) )
448 x.appendChild( f.toXml(doc, submitForm) );
449 }
450 }
451
452 return x;
453}
454
455XData &XData::operator= (const XData &from)
456{
457 if ( d->deref() )
458 delete d;
459
460 d = from.d;
461 d->ref();
462
463 return *this;
464}
465
466XData XData::copy() const
467{
468 XData foo;
469 delete foo.d;
470 foo.d = new Private( *this->d );
471
472 return foo;
473}
474
475void XData::detach()
476{
477 if ( d->count != 1 ) // only if >1 reference
478 *this = copy();
479}
480
481const QValueList<XData::ReportField> &XData::report() const
482{
483 return d->report;
484}
485
486const QValueList<XData::ReportItem> &XData::reportItems() const
487{
488 return d->reportItems;
489}
Note: See TracBrowser for help on using the repository browser.