diff options
Diffstat (limited to 'events/eventcontent.h')
-rw-r--r-- | events/eventcontent.h | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/events/eventcontent.h b/events/eventcontent.h new file mode 100644 index 00000000..60437995 --- /dev/null +++ b/events/eventcontent.h @@ -0,0 +1,295 @@ +/****************************************************************************** + * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +// This file contains generic event content definitions, applicable to room +// message events as well as other events (e.g., avatars). + +#include "converters.h" + +#include <QtCore/QJsonObject> +#include <QtCore/QMimeType> +#include <QtCore/QUrl> +#include <QtCore/QSize> + +namespace QMatrixClient +{ + namespace EventContent + { + /** + * A base class for all content types that can be stored + * in a RoomMessageEvent + * + * Each content type class should have a constructor taking + * a QJsonObject and override fillJson() with an implementation + * that will fill the target QJsonObject with stored values. It is + * assumed but not required that a content object can also be created + * from plain data. fillJson() should only fill the main JSON object + * but not the "info" subobject if it exists for a certain content type; + * use \p InfoBase to de/serialize "info" parts with an optional URL + * on the top level. + */ + class Base + { + public: + virtual ~Base() = default; + + QJsonObject toJson() const; + + protected: + virtual void fillJson(QJsonObject* o) const = 0; + }; + + class TypedBase: public Base + { + public: + virtual QMimeType type() const = 0; + }; + + template <typename T = QString> + class SimpleContent: public Base + { + public: + using value_type = T; + + // The constructor is templated to enable perfect forwarding + template <typename TT> + SimpleContent(QString keyName, TT&& value) + : value(std::forward<TT>(value)), key(std::move(keyName)) + { } + SimpleContent(const QJsonObject& json, QString keyName) + : value(QMatrixClient::fromJson<T>(json[keyName])) + , key(std::move(keyName)) + { } + + T value; + + protected: + QString key; + + private: + void fillJson(QJsonObject* json) const override + { + Q_ASSERT(json); + json->insert(key, QMatrixClient::toJson(value)); + } + }; + + /** + * A base class for content types that have an "info" object in their + * JSON representation + * + * These include most multimedia types currently in the CS API spec. + * Derived classes should override fillInfoJson() to fill the "info" + * subobject, BUT NOT the main JSON object. Most but not all "info" + * classes (specifically, those deriving from FileInfo) should also + * have a constructor that accepts two parameters, QUrl and QJsonObject, + * in order to load the URL+info part from JSON. + */ + class InfoBase + { + public: + virtual ~InfoBase() = default; + + QJsonObject toInfoJson() const; + + QMimeType mimeType; + + protected: + InfoBase() = default; + explicit InfoBase(const QMimeType& type) : mimeType(type) { } + + virtual void fillInfoJson(QJsonObject* /*infoJson*/) const = 0; + }; + + // The below structures fairly follow CS spec 11.2.1.6. The overall + // set of attributes for each content types is a superset of the spec + // but specific aggregation structure is altered. See doc comments to + // each type for the list of available attributes. + + /** + * Base class for content types that consist of a URL along with + * additional information. Most of message types except textual fall + * under this category. + */ + class FileInfo: public InfoBase + { + public: + explicit FileInfo(const QUrl& u, int payloadSize = -1, + const QMimeType& mimeType = {}, + const QString& originalFilename = {}); + FileInfo(const QUrl& u, const QJsonObject& infoJson, + const QString& originalFilename = {}); + + QUrl url; + int payloadSize; + QString originalName; + + protected: + void fillInfoJson(QJsonObject* infoJson) const override; + }; + + /** + * A base class for image info types: image, thumbnail, video + * + * \tparam InfoT base info class; should derive from \p InfoBase + */ + template <class InfoT = FileInfo> + class ImageInfo : public InfoT + { + public: + explicit ImageInfo(const QUrl& u, int fileSize = -1, + QMimeType mimeType = {}, + const QSize& imageSize = {}) + : InfoT(u, fileSize, mimeType), imageSize(imageSize) + { } + ImageInfo(const QUrl& u, const QJsonObject& infoJson, + const QString& originalFilename = {}) + : InfoT(u, infoJson, originalFilename) + , imageSize(infoJson["w"].toInt(), infoJson["h"].toInt()) + { } + + QSize imageSize; + + protected: + void fillInfoJson(QJsonObject* infoJson) const override + { + InfoT::fillInfoJson(infoJson); + infoJson->insert("w", imageSize.width()); + infoJson->insert("h", imageSize.height()); + } + }; + + /** + * A base class for an info type that carries a thumbnail + * + * This class decorates the underlying type, adding ability to save/load + * a thumbnail to/from "info" subobject of the JSON representation of + * event content; namely, "info/thumbnail_url" and "info/thumbnail_info" + * fields are used. + * + * \tparam InfoT base info class; should derive from \p InfoBase + */ + template <class InfoT = InfoBase> + class Thumbnailed : public InfoT + { + public: + template <typename... ArgTs> + explicit Thumbnailed(const ImageInfo<>& thumbnail, + ArgTs&&... infoArgs) + : InfoT(std::forward<ArgTs>(infoArgs)...) + , thumbnail(thumbnail) + { } + + explicit Thumbnailed(const QJsonObject& infoJson) + : thumbnail(infoJson["thumbnail_url"].toString(), + infoJson["thumbnail_info"].toObject()) + { } + + Thumbnailed(const QUrl& u, const QJsonObject& infoJson, + const QString& originalFilename = {}) + : InfoT(u, infoJson, originalFilename) + , thumbnail(infoJson["thumbnail_url"].toString(), + infoJson["thumbnail_info"].toObject()) + { } + + ImageInfo<> thumbnail; + + protected: + void fillInfoJson(QJsonObject* infoJson) const override + { + InfoT::fillInfoJson(infoJson); + infoJson->insert("thumbnail_url", thumbnail.url.toString()); + infoJson->insert("thumbnail_info", thumbnail.toInfoJson()); + } + }; + + /** + * One more facility base class for content types that have a URL and + * additional info + * + * Types that derive from UrlWith<InfoT> take "url" and, optionally, + * "filename" values from the top-level JSON object and the rest of + * information from the "info" subobject. + * + * \tparam InfoT base info class; should derive from \p FileInfo or + * provide a constructor with a compatible signature + */ + template <class InfoT> // InfoT : public FileInfo + class UrlWith : public TypedBase, public InfoT + { + public: + using InfoT::InfoT; + explicit UrlWith(const QJsonObject& json) + : InfoT(json["url"].toString(), json["info"].toObject(), + json["filename"].toString()) + { } + + QMimeType type() const override { return InfoT::mimeType; } + + protected: + void fillJson(QJsonObject* json) const override + { + Q_ASSERT(json); + json->insert("url", InfoT::url.toString()); + if (!InfoT::originalName.isEmpty()) + json->insert("filename", InfoT::originalName); + json->insert("info", InfoT::toInfoJson()); + } + }; + + /** + * Content class for m.image + * + * Available fields: + * - corresponding to the top-level JSON: + * - url + * - filename (extension to the spec) + * - corresponding to the "info" subobject: + * - payloadSize ("size" in JSON) + * - mimeType ("mimetype" in JSON) + * - imageSize (QSize for a combination of "h" and "w" in JSON) + * - thumbnail.url ("thumbnail_url" in JSON) + * - corresponding to the "info/thumbnail_info" subobject: contents of + * thumbnail field, in the same vein as for the main image: + * - payloadSize + * - mimeType + * - imageSize + */ + using ImageContent = UrlWith<Thumbnailed<ImageInfo<>>>; + + /** + * Content class for m.file + * + * Available fields: + * - corresponding to the top-level JSON: + * - url + * - filename + * - corresponding to the "info" subobject: + * - payloadSize ("size" in JSON) + * - mimeType ("mimetype" in JSON) + * - thumbnail.url ("thumbnail_url" in JSON) + * - corresponding to the "info/thumbnail_info" subobject: + * - thumbnail.payloadSize + * - thumbnail.mimeType + * - thumbnail.imageSize (QSize for "h" and "w" in JSON) + */ + using FileContent = UrlWith<Thumbnailed<FileInfo>>; + } // namespace EventContent +} // namespace QMatrixClient |