aboutsummaryrefslogtreecommitdiff
path: root/lib/events
diff options
context:
space:
mode:
Diffstat (limited to 'lib/events')
-rw-r--r--lib/events/event.h12
-rw-r--r--lib/events/eventcontent.cpp32
-rw-r--r--lib/events/eventcontent.h11
-rw-r--r--lib/events/roomevent.cpp5
-rw-r--r--lib/events/roommessageevent.cpp65
-rw-r--r--lib/events/roommessageevent.h21
-rw-r--r--lib/events/stateevent.cpp13
-rw-r--r--lib/events/stateevent.h9
8 files changed, 137 insertions, 31 deletions
diff --git a/lib/events/event.h b/lib/events/event.h
index c51afcc4..d7ac4292 100644
--- a/lib/events/event.h
+++ b/lib/events/event.h
@@ -208,6 +208,9 @@ namespace QMatrixClient
template <typename EventT>
inline auto registerEventType()
{
+ // Initialise exactly once, even if this function is called twice for
+ // the same type (for whatever reason - you never know the ways of
+ // static initialisation is done).
static const auto _ = setupFactory<EventT>();
return _; // Only to facilitate usage in static initialisation
}
@@ -337,7 +340,8 @@ namespace QMatrixClient
-> decltype(static_cast<EventT*>(&*eptr))
{
Q_ASSERT(eptr);
- return is<EventT>(*eptr) ? static_cast<EventT*>(&*eptr) : nullptr;
+ return is<std::decay_t<EventT>>(*eptr)
+ ? static_cast<EventT*>(&*eptr) : nullptr;
}
// A single generic catch-all visitor
@@ -369,7 +373,7 @@ namespace QMatrixClient
visit(const BaseEventT& event, FnT&& visitor)
{
using event_type = fn_arg_t<FnT>;
- if (is<event_type>(event))
+ if (is<std::decay_t<event_type>>(event))
visitor(static_cast<event_type>(event));
}
@@ -383,7 +387,7 @@ namespace QMatrixClient
fn_return_t<FnT>&& defaultValue = {})
{
using event_type = fn_arg_t<FnT>;
- if (is<event_type>(event))
+ if (is<std::decay_t<event_type>>(event))
return visitor(static_cast<event_type>(event));
return std::forward<fn_return_t<FnT>>(defaultValue);
}
@@ -396,7 +400,7 @@ namespace QMatrixClient
FnTs&&... visitors)
{
using event_type1 = fn_arg_t<FnT1>;
- if (is<event_type1>(event))
+ if (is<std::decay_t<event_type1>>(event))
return visitor1(static_cast<event_type1&>(event));
return visit(event, std::forward<FnT2>(visitor2),
std::forward<FnTs>(visitors)...);
diff --git a/lib/events/eventcontent.cpp b/lib/events/eventcontent.cpp
index a6b1c763..9a5e872c 100644
--- a/lib/events/eventcontent.cpp
+++ b/lib/events/eventcontent.cpp
@@ -17,6 +17,8 @@
*/
#include "eventcontent.h"
+
+#include "converters.h"
#include "util.h"
#include <QtCore/QMimeDatabase>
@@ -30,7 +32,7 @@ QJsonObject Base::toJson() const
return o;
}
-FileInfo::FileInfo(const QUrl& u, int payloadSize, const QMimeType& mimeType,
+FileInfo::FileInfo(const QUrl& u, qint64 payloadSize, const QMimeType& mimeType,
const QString& originalFilename)
: mimeType(mimeType), url(u), payloadSize(payloadSize)
, originalName(originalFilename)
@@ -41,7 +43,7 @@ FileInfo::FileInfo(const QUrl& u, const QJsonObject& infoJson,
: originalInfoJson(infoJson)
, mimeType(QMimeDatabase().mimeTypeForName(infoJson["mimetype"_ls].toString()))
, url(u)
- , payloadSize(infoJson["size"_ls].toInt())
+ , payloadSize(fromJson<qint64>(infoJson["size"_ls]))
, originalName(originalFilename)
{
if (!mimeType.isValid())
@@ -51,13 +53,15 @@ FileInfo::FileInfo(const QUrl& u, const QJsonObject& infoJson,
void FileInfo::fillInfoJson(QJsonObject* infoJson) const
{
Q_ASSERT(infoJson);
- infoJson->insert(QStringLiteral("size"), payloadSize);
- infoJson->insert(QStringLiteral("mimetype"), mimeType.name());
+ if (payloadSize != -1)
+ infoJson->insert(QStringLiteral("size"), payloadSize);
+ if (mimeType.isValid())
+ infoJson->insert(QStringLiteral("mimetype"), mimeType.name());
}
-ImageInfo::ImageInfo(const QUrl& u, int fileSize, QMimeType mimeType,
- const QSize& imageSize)
- : FileInfo(u, fileSize, mimeType), imageSize(imageSize)
+ImageInfo::ImageInfo(const QUrl& u, qint64 fileSize, QMimeType mimeType,
+ const QSize& imageSize, const QString& originalFilename)
+ : FileInfo(u, fileSize, mimeType, originalFilename), imageSize(imageSize)
{ }
ImageInfo::ImageInfo(const QUrl& u, const QJsonObject& infoJson,
@@ -69,8 +73,10 @@ ImageInfo::ImageInfo(const QUrl& u, const QJsonObject& infoJson,
void ImageInfo::fillInfoJson(QJsonObject* infoJson) const
{
FileInfo::fillInfoJson(infoJson);
- infoJson->insert(QStringLiteral("w"), imageSize.width());
- infoJson->insert(QStringLiteral("h"), imageSize.height());
+ if (imageSize.width() != -1)
+ infoJson->insert(QStringLiteral("w"), imageSize.width());
+ if (imageSize.height() != -1)
+ infoJson->insert(QStringLiteral("h"), imageSize.height());
}
Thumbnail::Thumbnail(const QJsonObject& infoJson)
@@ -80,7 +86,9 @@ Thumbnail::Thumbnail(const QJsonObject& infoJson)
void Thumbnail::fillInfoJson(QJsonObject* infoJson) const
{
- infoJson->insert(QStringLiteral("thumbnail_url"), url.toString());
- infoJson->insert(QStringLiteral("thumbnail_info"),
- toInfoJson<ImageInfo>(*this));
+ if (url.isValid())
+ infoJson->insert(QStringLiteral("thumbnail_url"), url.toString());
+ if (!imageSize.isEmpty())
+ infoJson->insert(QStringLiteral("thumbnail_info"),
+ toInfoJson<ImageInfo>(*this));
}
diff --git a/lib/events/eventcontent.h b/lib/events/eventcontent.h
index ea321fb6..0588c0e2 100644
--- a/lib/events/eventcontent.h
+++ b/lib/events/eventcontent.h
@@ -88,7 +88,7 @@ namespace QMatrixClient
class FileInfo
{
public:
- explicit FileInfo(const QUrl& u, int payloadSize = -1,
+ explicit FileInfo(const QUrl& u, qint64 payloadSize = -1,
const QMimeType& mimeType = {},
const QString& originalFilename = {});
FileInfo(const QUrl& u, const QJsonObject& infoJson,
@@ -109,7 +109,7 @@ namespace QMatrixClient
QJsonObject originalInfoJson;
QMimeType mimeType;
QUrl url;
- int payloadSize;
+ qint64 payloadSize;
QString originalName;
};
@@ -127,9 +127,10 @@ namespace QMatrixClient
class ImageInfo : public FileInfo
{
public:
- explicit ImageInfo(const QUrl& u, int fileSize = -1,
+ explicit ImageInfo(const QUrl& u, qint64 fileSize = -1,
QMimeType mimeType = {},
- const QSize& imageSize = {});
+ const QSize& imageSize = {},
+ const QString& originalFilename = {});
ImageInfo(const QUrl& u, const QJsonObject& infoJson,
const QString& originalFilename = {});
@@ -167,6 +168,7 @@ namespace QMatrixClient
explicit TypedBase(const QJsonObject& o = {}) : Base(o) { }
virtual QMimeType type() const = 0;
virtual const FileInfo* fileInfo() const { return nullptr; }
+ virtual FileInfo* fileInfo() { return nullptr; }
virtual const Thumbnail* thumbnailInfo() const { return nullptr; }
};
@@ -196,6 +198,7 @@ namespace QMatrixClient
QMimeType type() const override { return InfoT::mimeType; }
const FileInfo* fileInfo() const override { return this; }
+ FileInfo* fileInfo() override { return this; }
protected:
void fillJson(QJsonObject* json) const override
diff --git a/lib/events/roomevent.cpp b/lib/events/roomevent.cpp
index 80d121de..3d03509f 100644
--- a/lib/events/roomevent.cpp
+++ b/lib/events/roomevent.cpp
@@ -42,10 +42,6 @@ RoomEvent::RoomEvent(Type type, const QJsonObject& json)
_redactedBecause = makeEvent<RedactionEvent>(redaction.toObject());
return;
}
-
- const auto& txnId = transactionId();
- if (!txnId.isEmpty())
- qCDebug(EVENTS) << "Event transactionId:" << txnId;
}
RoomEvent::~RoomEvent() = default; // Let the smart pointer do its job
@@ -90,7 +86,6 @@ void RoomEvent::setTransactionId(const QString& txnId)
auto unsignedData = fullJson()[UnsignedKeyL].toObject();
unsignedData.insert(QStringLiteral("transaction_id"), txnId);
editJson().insert(UnsignedKey, unsignedData);
- qCDebug(EVENTS) << "New event transactionId:" << txnId;
Q_ASSERT(transactionId() == txnId);
}
diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp
index 1c5cf058..c3007fa0 100644
--- a/lib/events/roommessageevent.cpp
+++ b/lib/events/roommessageevent.cpp
@@ -21,6 +21,9 @@
#include "logging.h"
#include <QtCore/QMimeDatabase>
+#include <QtCore/QFileInfo>
+#include <QtGui/QImageReader>
+#include <QtMultimedia/QMediaResource>
using namespace QMatrixClient;
using namespace EventContent;
@@ -71,8 +74,8 @@ MsgType jsonToMsgType(const QString& matrixType)
return MsgType::Unknown;
}
-inline QJsonObject toMsgJson(const QString& plainBody, const QString& jsonMsgType,
- TypedBase* content)
+QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody,
+ const QString& jsonMsgType, TypedBase* content)
{
auto json = content ? content->toJson() : QJsonObject();
json.insert(QStringLiteral("msgtype"), jsonMsgType);
@@ -86,7 +89,7 @@ static const auto BodyKey = "body"_ls;
RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
const QString& jsonMsgType, TypedBase* content)
: RoomEvent(typeId(), matrixTypeId(),
- toMsgJson(plainBody, jsonMsgType, content))
+ assembleContentJson(plainBody, jsonMsgType, content))
, _content(content)
{ }
@@ -95,6 +98,40 @@ RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
: RoomMessageEvent(plainBody, msgTypeToJson(msgType), content)
{ }
+TypedBase* contentFromFile(const QFileInfo& file, bool asGenericFile)
+{
+ auto filePath = file.absoluteFilePath();
+ auto localUrl = QUrl::fromLocalFile(filePath);
+ auto mimeType = QMimeDatabase().mimeTypeForFile(file);
+ if (!asGenericFile)
+ {
+ auto mimeTypeName = mimeType.name();
+ if (mimeTypeName.startsWith("image/"))
+ return new ImageContent(localUrl, file.size(), mimeType,
+ QImageReader(filePath).size(),
+ file.fileName());
+
+ // duration can only be obtained asynchronously and can only be reliably
+ // done by starting to play the file. Left for a future implementation.
+ if (mimeTypeName.startsWith("video/"))
+ return new VideoContent(localUrl, file.size(), mimeType,
+ QMediaResource(localUrl).resolution(),
+ file.fileName());
+
+ if (mimeTypeName.startsWith("audio/"))
+ return new AudioContent(localUrl, file.size(), mimeType,
+ file.fileName());
+ }
+ return new FileContent(localUrl, file.size(), mimeType, file.fileName());
+}
+
+RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
+ const QFileInfo& file, bool asGenericFile)
+ : RoomMessageEvent(plainBody,
+ asGenericFile ? QStringLiteral("m.file") : rawMsgTypeForFile(file),
+ contentFromFile(file, asGenericFile))
+{ }
+
RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj)
: RoomEvent(typeId(), obj), _content(nullptr)
{
@@ -162,6 +199,25 @@ bool RoomMessageEvent::hasThumbnail() const
return content() && content()->thumbnailInfo();
}
+QString rawMsgTypeForMimeType(const QMimeType& mimeType)
+{
+ auto name = mimeType.name();
+ return name.startsWith("image/") ? QStringLiteral("m.image") :
+ name.startsWith("video/") ? QStringLiteral("m.video") :
+ name.startsWith("audio/") ? QStringLiteral("m.audio") :
+ QStringLiteral("m.file");
+}
+
+QString RoomMessageEvent::rawMsgTypeForUrl(const QUrl& url)
+{
+ return rawMsgTypeForMimeType(QMimeDatabase().mimeTypeForUrl(url));
+}
+
+QString RoomMessageEvent::rawMsgTypeForFile(const QFileInfo& fi)
+{
+ return rawMsgTypeForMimeType(QMimeDatabase().mimeTypeForFile(fi));
+}
+
TextContent::TextContent(const QString& text, const QString& contentType)
: mimeType(QMimeDatabase().mimeTypeForName(contentType)), body(text)
{
@@ -200,7 +256,8 @@ void TextContent::fillJson(QJsonObject* json) const
}
}
-LocationContent::LocationContent(const QString& geoUri, const ImageInfo& thumbnail)
+LocationContent::LocationContent(const QString& geoUri,
+ const Thumbnail& thumbnail)
: geoUri(geoUri), thumbnail(thumbnail)
{ }
diff --git a/lib/events/roommessageevent.h b/lib/events/roommessageevent.h
index 4c29a93e..d5b570f5 100644
--- a/lib/events/roommessageevent.h
+++ b/lib/events/roommessageevent.h
@@ -21,6 +21,8 @@
#include "roomevent.h"
#include "eventcontent.h"
+class QFileInfo;
+
namespace QMatrixClient
{
namespace MessageEventContent = EventContent; // Back-compatibility
@@ -49,6 +51,9 @@ namespace QMatrixClient
explicit RoomMessageEvent(const QString& plainBody,
MsgType msgType = MsgType::Text,
EventContent::TypedBase* content = nullptr);
+ explicit RoomMessageEvent(const QString& plainBody,
+ const QFileInfo& file,
+ bool asGenericFile = false);
explicit RoomMessageEvent(const QJsonObject& obj);
MsgType msgtype() const;
@@ -56,14 +61,27 @@ namespace QMatrixClient
QString plainBody() const;
EventContent::TypedBase* content() const
{ return _content.data(); }
+ template <typename VisitorT>
+ void editContent(VisitorT visitor)
+ {
+ visitor(*_content);
+ editJson()[ContentKeyL] =
+ assembleContentJson(plainBody(), rawMsgtype(), content());
+ }
QMimeType mimeType() const;
bool hasTextContent() const;
bool hasFileContent() const;
bool hasThumbnail() const;
+ static QString rawMsgTypeForUrl(const QUrl& url);
+ static QString rawMsgTypeForFile(const QFileInfo& fi);
+
private:
QScopedPointer<EventContent::TypedBase> _content;
+ static QJsonObject assembleContentJson(const QString& plainBody,
+ const QString& jsonMsgType, EventContent::TypedBase* content);
+
REGISTER_ENUM(MsgType)
};
REGISTER_EVENT_TYPE(RoomMessageEvent)
@@ -112,7 +130,7 @@ namespace QMatrixClient
{
public:
LocationContent(const QString& geoUri,
- const ImageInfo& thumbnail);
+ const Thumbnail& thumbnail = {});
explicit LocationContent(const QJsonObject& json);
QMimeType type() const override;
@@ -132,6 +150,7 @@ namespace QMatrixClient
class PlayableContent : public ContentT
{
public:
+ using ContentT::ContentT;
PlayableContent(const QJsonObject& json)
: ContentT(json)
, duration(ContentT::originalInfoJson["duration"_ls].toInt())
diff --git a/lib/events/stateevent.cpp b/lib/events/stateevent.cpp
index fd8079be..c4151676 100644
--- a/lib/events/stateevent.cpp
+++ b/lib/events/stateevent.cpp
@@ -20,8 +20,19 @@
using namespace QMatrixClient;
+// Aside from the normal factory to instantiate StateEventBase inheritors
+// StateEventBase itself can be instantiated if there's a state_key JSON key
+// but the event type is unknown.
[[gnu::unused]] static auto stateEventTypeInitialised =
- RoomEvent::factory_t::chainFactory<StateEventBase>();
+ RoomEvent::factory_t::addMethod(
+ [] (const QJsonObject& json, const QString& matrixType)
+ {
+ if (auto e = StateEventBase::factory_t::make(json, matrixType))
+ return e;
+ return json.contains("state_key")
+ ? makeEvent<StateEventBase>(unknownEventTypeId(), json)
+ : nullptr;
+ });
bool StateEventBase::repeatsState() const
{
diff --git a/lib/events/stateevent.h b/lib/events/stateevent.h
index d82de7e1..dc017b11 100644
--- a/lib/events/stateevent.h
+++ b/lib/events/stateevent.h
@@ -38,6 +38,9 @@ namespace QMatrixClient {
using StateEventPtr = event_ptr_tt<StateEventBase>;
using StateEvents = EventsArray<StateEventBase>;
+ template <>
+ inline bool is<StateEventBase>(const Event& e) { return e.isStateEvent(); }
+
/**
* A combination of event type and state key uniquely identifies a piece
* of state in Matrix.
@@ -88,6 +91,12 @@ namespace QMatrixClient {
}
const ContentT& content() const { return _content; }
+ template <typename VisitorT>
+ void editContent(VisitorT&& visitor)
+ {
+ visitor(_content);
+ editJson()[ContentKeyL] = _content.toJson();
+ }
[[deprecated("Use prevContent instead")]]
const ContentT* prev_content() const { return prevContent(); }
const ContentT* prevContent() const