diff options
-rw-r--r-- | events/roommessageevent.cpp | 181 | ||||
-rw-r--r-- | events/roommessageevent.h | 77 |
2 files changed, 135 insertions, 123 deletions
diff --git a/events/roommessageevent.cpp b/events/roommessageevent.cpp index 0da35527..513534ad 100644 --- a/events/roommessageevent.cpp +++ b/events/roommessageevent.cpp @@ -70,6 +70,18 @@ MessageEventContent::Base* RoomMessageEvent::content() const return d->content; } +template <class ContentT> +MessageEventContent::Base* make(const QJsonObject& json) +{ + return new ContentT(json); +} + +template <class ContentT> +MessageEventContent::Base* make2(const QJsonObject& json) +{ + return new ContentT(json["url"].toString(), json["info"].toObject()); +}; + RoomMessageEvent* RoomMessageEvent::fromJson(const QJsonObject& obj) { RoomMessageEvent* e = new RoomMessageEvent(); @@ -82,104 +94,53 @@ RoomMessageEvent* RoomMessageEvent::fromJson(const QJsonObject& obj) } if( obj.contains("content") ) { - using namespace MessageEventContent; - - QJsonObject content = obj.value("content").toObject(); - QString msgtype = content.value("msgtype").toString(); - - if( msgtype == "m.text" ) - { - e->d->msgtype = MessageEventType::Text; - e->d->content = new TextContent(obj); - } - else if( msgtype == "m.emote" ) - { - e->d->msgtype = MessageEventType::Emote; - e->d->content = new TextContent(obj); - } - else if( msgtype == "m.notice" ) - { - e->d->msgtype = MessageEventType::Notice; - e->d->content = new TextContent(obj); - } - else if( msgtype == "m.image" ) - { - e->d->msgtype = MessageEventType::Image; - ImageContent* c = new ImageContent; - c->url = QUrl(content.value("url").toString()); - QJsonObject info = content.value("info").toObject(); - c->height = info.value("h").toInt(); - c->width = info.value("w").toInt(); - c->size = info.value("size").toInt(); - c->mimetype = info.value("mimetype").toString(); - e->d->content = c; - } - else if( msgtype == "m.file" ) - { - e->d->msgtype = MessageEventType::File; - FileContent* c = new FileContent; - c->filename = content.value("filename").toString(); - c->url = QUrl(content.value("url").toString()); - QJsonObject info = content.value("info").toObject(); - c->size = info.value("size").toInt(); - c->mimetype = info.value("mimetype").toString(); - e->d->content = c; - } - else if( msgtype == "m.location" ) + const QJsonObject content = obj["content"].toObject(); + if ( content.contains("msgtype") && content.contains("body") ) { - e->d->msgtype = MessageEventType::Location; - LocationContent* c = new LocationContent; - c->geoUri = content.value("geo_uri").toString(); - c->thumbnailUrl = QUrl(content.value("thumbnail_url").toString()); - QJsonObject info = content.value("thumbnail_info").toObject(); - c->thumbnailHeight = info.value("h").toInt(); - c->thumbnailWidth = info.value("w").toInt(); - c->thumbnailSize = info.value("size").toInt(); - c->thumbnailMimetype = info.value("mimetype").toString(); - e->d->content = c; - } - else if( msgtype == "m.video" ) - { - e->d->msgtype = MessageEventType::Video; - VideoContent* c = new VideoContent; - c->url = QUrl(content.value("url").toString()); - QJsonObject info = content.value("info").toObject(); - c->height = info.value("h").toInt(); - c->width = info.value("w").toInt(); - c->duration = info.value("duration").toInt(); - c->size = info.value("size").toInt(); - c->thumbnailUrl = QUrl(info.value("thumnail_url").toString()); - QJsonObject thumbnailInfo = content.value("thumbnail_info").toObject(); - c->thumbnailHeight = thumbnailInfo.value("h").toInt(); - c->thumbnailWidth = thumbnailInfo.value("w").toInt(); - c->thumbnailSize = thumbnailInfo.value("size").toInt(); - c->thumbnailMimetype = thumbnailInfo.value("mimetype").toString(); - e->d->content = c; - } - else if( msgtype == "m.audio" ) - { - e->d->msgtype = MessageEventType::Audio; - AudioContent* c = new AudioContent; - c->url = QUrl(content.value("url").toString()); - QJsonObject info = content.value("info").toObject(); - c->duration = info.value("duration").toInt(); - c->mimetype = info.value("mimetype").toString(); - c->size = info.value("size").toInt(); - e->d->content = c; + using namespace MessageEventContent; + + e->d->plainBody = content["body"].toString(); + + struct Factory + { + QString jsonTag; + MessageEventType enumTag; + MessageEventContent::Base*(*make)(const QJsonObject& json); + }; + + const Factory factories[] { + { "m.text", MessageEventType::Text, make<TextContent> }, + { "m.emote", MessageEventType::Emote, make<TextContent> }, + { "m.notice", MessageEventType::Notice, make<TextContent> }, + { "m.image", MessageEventType::Image, make<ImageContent> }, + { "m.file", MessageEventType::File, make<FileContent> }, + { "m.location", MessageEventType::Location, make<LocationContent> }, + { "m.video", MessageEventType::Video, make2<VideoContent> }, + { "m.audio", MessageEventType::Audio, make2<AudioContent> }, + // Insert new message types before this line + }; + + QString msgtype = content.value("msgtype").toString(); + for (auto f: factories) + { + if (msgtype == f.jsonTag) + { + e->d->msgtype = f.enumTag; + e->d->content = f.make(content); + break; + } + } + if (e->d->msgtype == MessageEventType::Unknown) + { + qDebug() << "RoomMessageEvent: unknown msgtype: " << msgtype; + qDebug() << obj; + e->d->content = new Base; + } } else { - qDebug() << "RoomMessageEvent: unknown msgtype: " << msgtype; + qWarning() << "RoomMessageEvent(" << e->id() << "): no body or msgtype"; qDebug() << obj; - e->d->msgtype = MessageEventType::Unknown; - e->d->content = new Base; - } - - if( content.contains("body") ) - { - e->d->plainBody = content.value("body").toString(); - } else { - qDebug() << "RoomMessageEvent: body not found"; } } return e; @@ -203,3 +164,37 @@ TextContent::TextContent(const QJsonObject& json) mimeType = db.mimeTypeForData(body.toUtf8()); } } + +FileInfo::FileInfo(QUrl u, const QJsonObject& infoJson, QString originalFilename) + : url(u) + , fileSize(infoJson["size"].toInt()) + , mimetype(QMimeDatabase().mimeTypeForName(infoJson["mimetype"].toString())) + , originalName(originalFilename) +{ + if (!mimetype.isValid()) + mimetype = QMimeDatabase().mimeTypeForData(QByteArray()); +} + +ImageInfo::ImageInfo(QUrl u, const QJsonObject& infoJson) + : FileInfo(u, infoJson) + , imageSize(infoJson["w"].toInt(), infoJson["h"].toInt()) +{ } + +LocationContent::LocationContent(const QJsonObject& json) + : geoUri(json["geo_uri"].toString()) + , thumbnail(json["thumbnail_url"].toString(), + json["thumbnail_info"].toObject()) +{ } + +VideoContent::VideoContent(QUrl u, const QJsonObject& infoJson) + : FileInfo(u, infoJson) + , duration(infoJson["duration"].toInt()) + , imageSize(infoJson["w"].toInt(), infoJson["h"].toInt()) + , thumbnail(infoJson["thumbnail_url"].toString(), + infoJson["thumbnail_info"].toObject()) +{ } + +AudioContent::AudioContent(QUrl u, const QJsonObject& infoJson) + : FileInfo(u, infoJson) + , duration(infoJson["duration"].toInt()) +{ } diff --git a/events/roommessageevent.h b/events/roommessageevent.h index 7b6394ba..83022b4d 100644 --- a/events/roommessageevent.h +++ b/events/roommessageevent.h @@ -21,6 +21,7 @@ #include <QtCore/QUrl> #include <QtCore/QMimeType> +#include <QtCore/QSize> #include "event.h" @@ -66,6 +67,10 @@ namespace QMatrixClient 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. + class TextContent: public Base { public: @@ -75,59 +80,71 @@ namespace QMatrixClient QString body; }; - class ImageContent: public Base + class FileInfo: public Base { public: + FileInfo(QUrl u, const QJsonObject& infoJson, + QString originalFilename = QString()); + QUrl url; - int height; - int width; - int size; - QString mimetype; + int fileSize; + QMimeType mimetype; + QString originalName; }; - class FileContent: public Base + class ImageInfo: public FileInfo { public: - QString filename; - QString mimetype; - int size; - QUrl url; + ImageInfo(QUrl u, const QJsonObject& infoJson); + + QSize imageSize; }; + template <class ContentInfoT> + class ThumbnailedContent: public ContentInfoT + { + public: + ThumbnailedContent(const QJsonObject& json) + : ContentInfoT(json["url"].toString(), json["info"].toObject()) + , thumbnail(json["thumbnail_url"].toString(), + json["thumbnail_info"].toObject()) + { } + + ImageInfo thumbnail; + }; + + using ImageContent = ThumbnailedContent<ImageInfo>; + using FileContent = ThumbnailedContent<FileInfo>; + class LocationContent: public Base { public: + LocationContent(const QJsonObject& json); + QString geoUri; - int thumbnailHeight; - int thumbnailWidth; - QString thumbnailMimetype; - int thumbnailSize; - QUrl thumbnailUrl; + ImageInfo thumbnail; }; - class VideoContent: public Base + // The spec structures m.video messages differently for some reason - + // instead of putting a thumbnail block on the top level, as with + // file and image, it puts it inside "info" key. So instead of + // using ThumbnailContent<> base, we add the thumbnail into VideoInfo explicitly. + class VideoContent: public FileInfo { public: - QUrl url; + VideoContent(QUrl u, const QJsonObject& infoJson); + int duration; - int width; - int height; - int size; - QString mimetype; - int thumbnailWidth; - int thumbnailHeight; - int thumbnailSize; - QString thumbnailMimetype; - QUrl thumbnailUrl; + QSize imageSize; + ImageInfo thumbnail; }; - class AudioContent: public Base + class AudioContent: public FileInfo { public: - QUrl url; - int size; + AudioContent(QUrl u, const QJsonObject& infoJson); + int duration; - QString mimetype; }; } } |