// SPDX-FileCopyrightText: 2021 Linus Jahn // // SPDX-License-Identifier: LGPL-2.1-or-later #include "QXmppDataFormBase.h" #include "QXmppDataForm.h" #include /// /// \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 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 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 QXmppExtensibleDataFormBase::unknownFields() const { return d->unknownFields; } /// /// Sets all additional fields to be serialized. /// void QXmppExtensibleDataFormBase::setUnknownFields(const QList &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; }