aboutsummaryrefslogtreecommitdiff
path: root/events/roommessageevent.h
diff options
context:
space:
mode:
Diffstat (limited to 'events/roommessageevent.h')
-rw-r--r--events/roommessageevent.h335
1 files changed, 287 insertions, 48 deletions
diff --git a/events/roommessageevent.h b/events/roommessageevent.h
index 299b1b19..74e0defb 100644
--- a/events/roommessageevent.h
+++ b/events/roommessageevent.h
@@ -24,122 +24,361 @@
#include <QtCore/QMimeType>
#include <QtCore/QSize>
-#include <memory>
-
namespace QMatrixClient
{
namespace MessageEventContent
{
+ /**
+ * 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
{
- Q_GADGET
public:
- enum class Type
- {
- Text, Emote, Notice, Image, File, Location, Video, Audio, Unknown
- };
-
virtual ~Base() = default;
- REGISTER_ENUM(Type)
+ QJsonObject toJson() const;
+
+ QMimeType mimeType;
+
+ protected:
+ Base() = default;
+ explicit Base(const QMimeType& type) : mimeType(type) { }
+
+ virtual void fillJson(QJsonObject* o) const = 0;
+ };
+
+ /**
+ * 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 UrlInfo) 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 Base
+ {
+ public:
+ QJsonObject toInfoJson() const;
+
+ protected:
+ using Base::Base;
+
+ virtual void fillInfoJson(QJsonObject* infoJson) const { }
};
- using CType = Base::Type;
} // namespace MessageEventContent
- using MessageEventType = MessageEventContent::CType;
+ /**
+ * The event class corresponding to m.room.message events
+ */
class RoomMessageEvent: public RoomEvent
{
+ Q_GADGET
public:
+ enum class MsgType
+ {
+ Text, Emote, Notice, Image, File, Location, Video, Audio, Unknown
+ };
+
+ RoomMessageEvent(const QString& plainBody,
+ const QString& jsonMsgType,
+ MessageEventContent::Base* content = nullptr)
+ : RoomEvent(Type::RoomMessage)
+ , _msgtype(jsonMsgType), _plainBody(plainBody), _content(content)
+ { }
+ explicit RoomMessageEvent(const QString& plainBody,
+ MsgType msgType = MsgType::Text,
+ MessageEventContent::Base* content = nullptr);
explicit RoomMessageEvent(const QJsonObject& obj);
- ~RoomMessageEvent();
- MessageEventType msgtype() const { return _msgtype; }
- const QString& plainBody() const { return _plainBody; }
- const MessageEventContent::Base* content() const { return _content; }
+ MsgType msgtype() const;
+ QString rawMsgtype() const { return _msgtype; }
+ const QString& plainBody() const { return _plainBody; }
+ const MessageEventContent::Base* content() const
+ { return _content.data(); }
+ QMimeType mimeType() const;
+
+ QJsonObject toJson() const;
+
+ static constexpr const char* TypeId = "m.room.message";
private:
- MessageEventType _msgtype;
+ QString _msgtype;
QString _plainBody;
- MessageEventContent::Base* _content;
+ QScopedPointer<MessageEventContent::Base> _content;
+
+ REGISTER_ENUM(MsgType)
};
+ using MessageEventType = RoomMessageEvent::MsgType;
namespace MessageEventContent
{
// 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.
+ // but specific aggregation structure is altered. See doc comments to
+ // each type for the list of available attributes.
+ /**
+ * Rich text content for m.text, m.emote, m.notice
+ *
+ * Available fields: mimeType, body. The body can be either rich text
+ * or plain text, depending on what mimeType specifies.
+ */
class TextContent: public Base
{
public:
+ TextContent(const QString& text, const QString& contentType);
explicit TextContent(const QJsonObject& json);
- QMimeType mimeType;
+ void fillJson(QJsonObject* json) const override;
+
QString body;
};
- class FileInfo: public Base
+ /**
+ * Base class for content types that consist of a URL along with
+ * additional information
+ *
+ * All message types except the (hyper)text mentioned above and
+ * m.location fall under this category.
+ */
+ class FileInfo: public InfoBase
{
public:
- FileInfo(QUrl u, const QJsonObject& infoJson,
- QString originalFilename = QString());
+ 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 fileSize;
- QMimeType mimetype;
+ int payloadSize;
QString originalName;
+
+ protected:
+ void fillJson(QJsonObject* json) const override;
+ void fillInfoJson(QJsonObject* infoJson) const override;
};
- class ImageInfo: public FileInfo
+ /**
+ * 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:
- ImageInfo(QUrl u, const QJsonObject& infoJson);
+ 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())
+ { }
+
+ void fillInfoJson(QJsonObject* infoJson) const /* override */
+ {
+ InfoT::fillInfoJson(infoJson);
+ infoJson->insert("w", imageSize.width());
+ infoJson->insert("h", imageSize.height());
+ }
QSize imageSize;
};
- template <class ContentInfoT>
- class ThumbnailedContent: public ContentInfoT
+ /**
+ * A base class for an info type that carries a thumbnail
+ *
+ * This class provides a means to save/load a thumbnail to/from "info"
+ * subobject of the JSON representation of a message; 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:
- explicit ThumbnailedContent(const QJsonObject& json)
- : ContentInfoT(json["url"].toString(), json["info"].toObject())
- , thumbnail(json["thumbnail_url"].toString(),
- json["thumbnail_info"].toObject())
+ template <typename... ArgTs>
+ explicit Thumbnailed(const ImageInfo<>& thumbnail,
+ ArgTs&&... infoArgs)
+ : InfoT(std::forward<ArgTs>(infoArgs)...)
+ , thumbnail(thumbnail)
{ }
- ImageInfo 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())
+ { }
+
+ void fillInfoJson(QJsonObject* infoJson) const /* override */
+ {
+ InfoT::fillInfoJson(infoJson);
+ infoJson->insert("thumbnail_url", thumbnail.url.toString());
+ infoJson->insert("thumbnail_info", thumbnail.toInfoJson());
+ }
+
+ ImageInfo<> thumbnail;
+ };
+
+ /**
+ * One more facility base class for content types that have a URL and
+ * additional info
+ *
+ * The assumed layout for types enabled by a combination of UrlInfo and
+ * UrlWith<> is the following: "url" and, optionally, "filename" in the
+ * top-level JSON and the rest of information inside the "info" subobject.
+ *
+ * \tparam InfoT base info class; should derive from \p UrlInfo or
+ * provide a constructor with a compatible signature
+ */
+ template <class InfoT> // InfoT : public FileInfo
+ class UrlWith : public InfoT
+ {
+ public:
+ using InfoT::InfoT;
+ explicit UrlWith(const QJsonObject& json)
+ : InfoT(json["url"].toString(), json["info"].toObject(),
+ json["filename"].toString())
+ { }
};
- using ImageContent = ThumbnailedContent<ImageInfo>;
- using FileContent = ThumbnailedContent<FileInfo>;
+ /**
+ * 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<>>>;
- class LocationContent: public Base
+ /**
+ * 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>>;
+
+ /**
+ * Content class for m.location
+ *
+ * Available fields:
+ * - corresponding to the top-level JSON:
+ * - geoUri ("geo_uri" in JSON)
+ * - corresponding to the "info" subobject:
+ * - thumbnail.url ("thumbnail_url" in JSON)
+ * - corresponding to the "info/thumbnail_info" subobject:
+ * - thumbnail.payloadSize
+ * - thumbnail.mimeType
+ * - thumbnail.imageSize
+ */
+ class LocationContent: public Thumbnailed<>
{
public:
+ LocationContent(const QString& geoUri,
+ const ImageInfo<>& thumbnail);
explicit LocationContent(const QJsonObject& json);
+ void fillJson(QJsonObject* o) const override;
+
QString geoUri;
- ImageInfo thumbnail;
};
- class VideoInfo: public FileInfo
+ /**
+ * A base class for "playable" info types: audio and video
+ */
+ class PlayableInfo : public FileInfo
{
public:
- VideoInfo(QUrl u, const QJsonObject& infoJson);
+ explicit PlayableInfo(const QUrl& u, int fileSize,
+ const QMimeType& mimeType, int duration,
+ const QString& originalFilename = {});
+ PlayableInfo(const QUrl& u, const QJsonObject& infoJson,
+ const QString& originalFilename = {});
+
+ void fillInfoJson(QJsonObject* infoJson) const override;
int duration;
- QSize imageSize;
};
- using VideoContent = ThumbnailedContent<VideoInfo>;
- class AudioInfo: public FileInfo
- {
- public:
- AudioInfo(QUrl u, const QJsonObject& infoJson);
+ /**
+ * Content class for m.video
+ *
+ * Available fields:
+ * - corresponding to the top-level JSON:
+ * - url
+ * - filename (extension to the CS API spec)
+ * - corresponding to the "info" subobject:
+ * - payloadSize ("size" in JSON)
+ * - mimeType ("mimetype" in JSON)
+ * - duration
+ * - 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 "info":
+ * - payloadSize
+ * - mimeType
+ * - imageSize
+ */
+ using VideoContent = UrlWith<Thumbnailed<ImageInfo<PlayableInfo>>>;
- int duration;
- };
- using AudioContent = ThumbnailedContent<AudioInfo>;
+ /**
+ * Content class for m.audio
+ *
+ * Available fields:
+ * - corresponding to the top-level JSON:
+ * - url
+ * - filename (extension to the CS API spec)
+ * - corresponding to the "info" subobject:
+ * - payloadSize ("size" in JSON)
+ * - mimeType ("mimetype" in JSON)
+ * - duration
+ */
+ using AudioContent = UrlWith<PlayableInfo>;
} // namespace MessageEventContent
} // namespace QMatrixClient