aboutsummaryrefslogtreecommitdiff
path: root/src/base/QXmppDataFormBase.cpp
blob: 1dfb04298a83acfa630d731be2ab3713e9eeeac8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// SPDX-FileCopyrightText: 2021 Linus Jahn <lnj@kaidan.im>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

#include "QXmppDataFormBase.h"

#include "QXmppDataForm.h"

#include <QDateTime>

///
/// \class QXmppDataFormBase
///
/// QXmppDataFormBase is an abstract class types that can be serialized to data
/// forms.
///
/// QXmppDataFormBase based types can easily be converted to QXmppDataForms, it
/// is as simple as this:
/// \code
/// MyDataFormBase foo;
/// QXmppDataForm dataForm(foo);
/// \endcode
///
/// To make this work, you will need to at least implement the toDataForm()
/// method. For parsing your type you should also create a static creator
/// method, like this:
/// \code
/// static std::optional<MyType> fromDataForm(const QXmppDataForm &);
/// \endcode
///
/// \since QXmpp 1.5
///

///
/// Serializes all fields to a QXmppDataForm.
///
QXmppDataForm QXmppDataFormBase::toDataForm() const
{
    QXmppDataForm form(QXmppDataForm::Form);

    // add FORM_TYPE
    serializeNullable(form, QXmppDataForm::Field::HiddenField, QStringLiteral("FORM_TYPE"), formType());

    // manual serialization parts
    serializeForm(form);

    return form;
}

///
/// Parses the QXmppDataForm.
///
bool QXmppDataFormBase::fromDataForm(const QXmppDataForm &form, QXmppDataFormBase &output)
{
    output.parseForm(form);
    return true;
}

///
/// \fn QXmppDataFormBase::formType
///
/// Returns the 'FORM_TYPE' value of the parsed form.
///

///
/// \fn QXmppDataFormBase::parseForm
///
/// This is called when a QXmppDataForm is parsed. You can parse all values from
/// the given form and its fields.
///

///
/// \fn QXmppDataFormBase::serializeForm
///
/// This is called the object is serialized to a QXmppDataForm. You need to
/// create a new QXmppDataForm and serialize all fields and values.
///

///
/// \fn QXmppDataFormBase::parseUInt
///
/// Parses an unsigned int from a QVariant (QString). Returns std::nullopt if
/// the no number could be parsed.
///

///
/// \fn QXmppDataFormBase::parseULongLong
///
/// Parses an unsigned long long from a QVariant (QString). Returns std::nullopt
/// if the no number could be parsed.
///

///
/// \fn QXmppDataFormBase::parseBool
///
/// Returns the contained boolean value if the QVariant contains a bool.
///

///
/// \fn QXmppDataFormBase::serializeValue
///
/// Adds a new field to the form with the given field type, field name and value.
///

///
/// \fn QXmppDataFormBase::serializeNullable
///
/// Adds a new field to the form if \code !value.isNull() \endcode.
///

///
/// \fn QXmppDataFormBase::serializeEmptyable
///
/// Adds a new field to the form if \code !value.isEmpty() \endcode.
///

///
/// \fn QXmppDataFormBase::serializeOptional
///
/// Adds a new field to the form if \code optional.has_value() \endcode.
///

///
/// \fn QXmppDataFormBase::serializeOptionalNumber
///
/// Adds a new field to the form if \code optional.has_value() \endcode.
/// Converts the optional's value to QString using QString::number().
///

///
/// Adds a new field to the form if the passed QDateTime is valid and formats it
/// as ISO timestamp and always uses UTC.
///
void QXmppDataFormBase::serializeDatetime(QXmppDataForm &form, const QString &name, const QDateTime &datetime, QXmppDataForm::Field::Type type)
{
    if (datetime.isValid()) {
        serializeValue(form, type, name, datetime.toUTC().toString(Qt::ISODate));
    }
}

///
/// \class QXmppExtensibleDataFormBase
///
/// This class is used for parsing a QXmppDataForm in an extensible way with
/// inheritance and keeping additional unknown fields.
///
/// When inheriting you need to reimplement parseField(), serializeForm() and
/// formType(). Also you should add a static parsing function (e.g.
/// QXmppPubSubMetadata::fromDataForm()).
///
/// \since QXmpp 1.5
///

class QXmppExtensibleDataFormBasePrivate : public QSharedData
{
public:
    QList<QXmppDataForm::Field> unknownFields;
};

QXmppExtensibleDataFormBase::QXmppExtensibleDataFormBase()
    : d(new QXmppExtensibleDataFormBasePrivate)
{
}

/// \cond
QXmppExtensibleDataFormBase::QXmppExtensibleDataFormBase(const QXmppExtensibleDataFormBase &) = default;
QXmppExtensibleDataFormBase::QXmppExtensibleDataFormBase(QXmppExtensibleDataFormBase &&) = default;
QXmppExtensibleDataFormBase::~QXmppExtensibleDataFormBase() = default;
QXmppExtensibleDataFormBase &QXmppExtensibleDataFormBase::operator=(const QXmppExtensibleDataFormBase &) = default;
QXmppExtensibleDataFormBase &QXmppExtensibleDataFormBase::operator=(QXmppExtensibleDataFormBase &&) = default;
/// \endcond

///
/// Returns all fields that couldn't be parsed.
///
QList<QXmppDataForm::Field> QXmppExtensibleDataFormBase::unknownFields() const
{
    return d->unknownFields;
}

///
/// Sets all additional fields to be serialized.
///
void QXmppExtensibleDataFormBase::setUnknownFields(const QList<QXmppDataForm::Field> &unknownFields)
{
    d->unknownFields = unknownFields;
}

void QXmppExtensibleDataFormBase::parseForm(const QXmppDataForm &form)
{
    const auto fields = form.fields();
    for (const auto &field : fields) {
        // FORM_TYPE fields are not saved (override this function to save them)
        if (!parseField(field) &&
            !(field.type() == QXmppDataForm::Field::HiddenField &&
              field.key() == QStringLiteral("FORM_TYPE"))) {
            d->unknownFields << field;
        }
    }
}

void QXmppExtensibleDataFormBase::serializeForm(QXmppDataForm &form) const
{
    form.fields() << d->unknownFields;
}

///
/// Returns true if a field has been parsed.
///
/// Should be reimplemented to do actual parsing. All fields that can't be
/// parsed end up as unknownFields().
///
bool QXmppExtensibleDataFormBase::parseField(const QXmppDataForm::Field &)
{
    return false;
}