From e5bf7c2fa64716de0b75a67acc5f8620e8dc1704 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Mon, 28 Dec 2020 18:22:29 +0100 Subject: Add support for sticker events --- lib/events/stickerevent.h | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 lib/events/stickerevent.h (limited to 'lib/events/stickerevent.h') diff --git a/lib/events/stickerevent.h b/lib/events/stickerevent.h new file mode 100644 index 00000000..93671086 --- /dev/null +++ b/lib/events/stickerevent.h @@ -0,0 +1,38 @@ +// SDPX-FileCopyrightText: 2020 Carl Schwan +// SPDX-License-Identifier: LGPL-2.1-or-later + +#pragma once + +#include "roomevent.h" +#include "eventcontent.h" + +namespace Quotient { + +/// Sticker messages are specialised image messages that are displayed without +/// controls (e.g. no "download" link, or light-box view on click, as would be +/// displayed for for m.image events). +class StickerEvent : public RoomEvent +{ +public: + DEFINE_EVENT_TYPEID("m.sticker", StickerEvent) + + explicit StickerEvent(const QJsonObject &obj); + + /// \brief A textual representation or associated description of the + /// sticker image. + /// + /// This could be the alt text of the original image, or a message to + /// accompany and further describe the sticker. + QString body() const; + + /// \brief Metadata about the image referred to in url including a + /// thumbnail representation. + const EventContent::ImageContent &image() const; + + /// \brief The URL to the sticker image. This must be a valid mxc:// URI. + QUrl url() const; +private: + EventContent::ImageContent m_imageContent; +}; +REGISTER_EVENT_TYPE(StickerEvent) +} // namespace Quotient -- cgit v1.2.3 From 7350fe82953cf6274b8845a890eafb21a09b9931 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Wed, 29 Dec 2021 15:59:58 +0100 Subject: Add QUOTIENT_API throughout non-generated code This include all (hopefully) classes/structures and functions that have non-inline definitions, as well as namespaces with Q_NAMESPACE since those have non-inline (as of Qt 5.15) QMetaObject - for that a new macro, QUO_NAMESPACE, has been devised to accommodate the lack of Q_NAMESPACE_EXPORT in Qt before 5.14. --- lib/accountregistry.h | 4 +++- lib/avatar.h | 4 +++- lib/connection.h | 2 +- lib/converters.h | 6 +++--- lib/eventitem.cpp | 4 ++++ lib/eventitem.h | 9 +++++---- lib/events/accountdataevents.h | 2 +- lib/events/callanswerevent.h | 3 +-- lib/events/callhangupevent.h | 2 +- lib/events/callinviteevent.h | 2 +- lib/events/directchatevent.h | 2 +- lib/events/encryptedevent.h | 2 +- lib/events/encryptionevent.h | 5 ++--- lib/events/event.h | 23 +++++++++++++---------- lib/events/eventcontent.h | 19 ++++++++++--------- lib/events/reactionevent.h | 6 +++--- lib/events/receiptevent.h | 2 +- lib/events/roomavatarevent.h | 3 ++- lib/events/roomcreateevent.h | 2 +- lib/events/roomevent.h | 4 ++-- lib/events/roomkeyevent.h | 2 +- lib/events/roommemberevent.h | 5 ++--- lib/events/roommessageevent.h | 8 ++++---- lib/events/roompowerlevelsevent.h | 8 +++----- lib/events/roomtombstoneevent.h | 2 +- lib/events/simplestateevents.h | 3 ++- lib/events/stateevent.h | 2 +- lib/events/stickerevent.h | 2 +- lib/events/typingevent.h | 2 +- lib/eventstats.h | 4 ++-- lib/jobs/basejob.h | 4 ++-- lib/jobs/downloadfilejob.h | 2 +- lib/jobs/mediathumbnailjob.h | 2 +- lib/jobs/requestdata.h | 4 +++- lib/mxcreply.h | 4 +++- lib/networkaccessmanager.h | 4 +++- lib/networksettings.h | 2 +- lib/quotient_common.h | 17 ++++++++++++++++- lib/room.h | 8 ++++---- lib/settings.h | 8 +++++--- lib/ssosession.h | 4 +++- lib/syncdata.h | 2 +- lib/uri.h | 2 +- lib/uriresolver.h | 6 +++--- lib/user.h | 3 ++- lib/util.h | 22 ++++++++++++---------- 46 files changed, 138 insertions(+), 100 deletions(-) (limited to 'lib/events/stickerevent.h') diff --git a/lib/accountregistry.h b/lib/accountregistry.h index 5efda459..f7a864df 100644 --- a/lib/accountregistry.h +++ b/lib/accountregistry.h @@ -4,6 +4,8 @@ #pragma once +#include "quotient_export.h" + #include #include #include @@ -11,7 +13,7 @@ namespace Quotient { class Connection; -class AccountRegistry : public QAbstractListModel { +class QUOTIENT_API AccountRegistry : public QAbstractListModel { Q_OBJECT public: enum EventRoles { diff --git a/lib/avatar.h b/lib/avatar.h index d4634aea..93f43948 100644 --- a/lib/avatar.h +++ b/lib/avatar.h @@ -3,6 +3,8 @@ #pragma once +#include "quotient_export.h" + #include #include @@ -12,7 +14,7 @@ namespace Quotient { class Connection; -class Avatar { +class QUOTIENT_API Avatar { public: explicit Avatar(); explicit Avatar(QUrl url); diff --git a/lib/connection.h b/lib/connection.h index 0713af16..d669462e 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -105,7 +105,7 @@ using DirectChatsMap = QMultiHash; using DirectChatUsersMap = QMultiHash; using IgnoredUsersList = IgnoredUsersEvent::content_type; -class Connection : public QObject { +class QUOTIENT_API Connection : public QObject { Q_OBJECT Q_PROPERTY(User* localUser READ user NOTIFY stateChanged) diff --git a/lib/converters.h b/lib/converters.h index 9c3d5749..a6028f1b 100644 --- a/lib/converters.h +++ b/lib/converters.h @@ -183,7 +183,7 @@ struct JsonConverter { }; template <> -struct JsonConverter { +struct QUOTIENT_API JsonConverter { static QJsonValue dump(const QVariant& v); static QVariant load(const QJsonValue& jv); }; @@ -281,9 +281,9 @@ template struct JsonObjectConverter> : public HashMapFromJson> {}; -QJsonObject toJson(const QVariantHash& vh); +QJsonObject QUOTIENT_API toJson(const QVariantHash& vh); template <> -QVariantHash fromJson(const QJsonValue& jv); +QVariantHash QUOTIENT_API fromJson(const QJsonValue& jv); // Conditional insertion into a QJsonObject diff --git a/lib/eventitem.cpp b/lib/eventitem.cpp index 4f1595bc..a2d65d8d 100644 --- a/lib/eventitem.cpp +++ b/lib/eventitem.cpp @@ -25,3 +25,7 @@ void PendingEventItem::setFileUploaded(const QUrl& remoteUrl) } setStatus(EventStatus::FileUploaded); } + +// Not exactly sure why but this helps with the linker not finding +// Quotient::EventStatus::staticMetaObject when building Quaternion +#include "moc_eventitem.cpp" diff --git a/lib/eventitem.h b/lib/eventitem.h index 0ab1a01d..2f1e72cc 100644 --- a/lib/eventitem.h +++ b/lib/eventitem.h @@ -4,6 +4,7 @@ #pragma once #include "events/stateevent.h" +#include "quotient_common.h" #include #include @@ -11,7 +12,7 @@ namespace Quotient { namespace EventStatus { - Q_NAMESPACE + QUO_NAMESPACE /** Special marks an event can assume * @@ -33,7 +34,7 @@ namespace EventStatus { Q_ENUM_NS(Code) } // namespace EventStatus -class EventItemBase { +class QUOTIENT_API EventItemBase { public: explicit EventItemBase(RoomEventPtr&& e) : evt(std::move(e)) { @@ -74,7 +75,7 @@ private: std::any data; }; -class TimelineItem : public EventItemBase { +class QUOTIENT_API TimelineItem : public EventItemBase { public: // For compatibility with Qt containers, even though we use // a std:: container now for the room timeline @@ -103,7 +104,7 @@ inline const CallEventBase* EventItemBase::viewAs() const return evt->isCallEvent() ? weakPtrCast(evt) : nullptr; } -class PendingEventItem : public EventItemBase { +class QUOTIENT_API PendingEventItem : public EventItemBase { public: using EventItemBase::EventItemBase; diff --git a/lib/events/accountdataevents.h b/lib/events/accountdataevents.h index 9cf77be3..c0f2202d 100644 --- a/lib/events/accountdataevents.h +++ b/lib/events/accountdataevents.h @@ -50,7 +50,7 @@ struct JsonObjectConverter { using TagsMap = QHash; #define DEFINE_SIMPLE_EVENT(_Name, _TypeId, _ContentType, _ContentKey) \ - class _Name : public Event { \ + class QUOTIENT_API _Name : public Event { \ public: \ using content_type = _ContentType; \ DEFINE_EVENT_TYPEID(_TypeId, _Name) \ diff --git a/lib/events/callanswerevent.h b/lib/events/callanswerevent.h index 4c01c941..8ffe60f2 100644 --- a/lib/events/callanswerevent.h +++ b/lib/events/callanswerevent.h @@ -7,7 +7,7 @@ #include "roomevent.h" namespace Quotient { -class CallAnswerEvent : public CallEventBase { +class QUOTIENT_API CallAnswerEvent : public CallEventBase { public: DEFINE_EVENT_TYPEID("m.call.answer", CallAnswerEvent) @@ -26,6 +26,5 @@ public: return contentPart("answer"_ls).value("sdp"_ls).toString(); } }; - REGISTER_EVENT_TYPE(CallAnswerEvent) } // namespace Quotient diff --git a/lib/events/callhangupevent.h b/lib/events/callhangupevent.h index f3f82833..b0017c59 100644 --- a/lib/events/callhangupevent.h +++ b/lib/events/callhangupevent.h @@ -7,7 +7,7 @@ #include "roomevent.h" namespace Quotient { -class CallHangupEvent : public CallEventBase { +class QUOTIENT_API CallHangupEvent : public CallEventBase { public: DEFINE_EVENT_TYPEID("m.call.hangup", CallHangupEvent) diff --git a/lib/events/callinviteevent.h b/lib/events/callinviteevent.h index 80b7d651..47362b5c 100644 --- a/lib/events/callinviteevent.h +++ b/lib/events/callinviteevent.h @@ -7,7 +7,7 @@ #include "roomevent.h" namespace Quotient { -class CallInviteEvent : public CallEventBase { +class QUOTIENT_API CallInviteEvent : public CallEventBase { public: DEFINE_EVENT_TYPEID("m.call.invite", CallInviteEvent) diff --git a/lib/events/directchatevent.h b/lib/events/directchatevent.h index e2143779..2018d3d6 100644 --- a/lib/events/directchatevent.h +++ b/lib/events/directchatevent.h @@ -6,7 +6,7 @@ #include "event.h" namespace Quotient { -class DirectChatEvent : public Event { +class QUOTIENT_API DirectChatEvent : public Event { public: DEFINE_EVENT_TYPEID("m.direct", DirectChatEvent) diff --git a/lib/events/encryptedevent.h b/lib/events/encryptedevent.h index de89a7c6..81343a29 100644 --- a/lib/events/encryptedevent.h +++ b/lib/events/encryptedevent.h @@ -25,7 +25,7 @@ namespace Quotient { * in general. It's possible, because RoomEvent interface is similar to Event's * one and doesn't add new restrictions, just provides additional features. */ -class EncryptedEvent : public RoomEvent { +class QUOTIENT_API EncryptedEvent : public RoomEvent { public: DEFINE_EVENT_TYPEID("m.room.encrypted", EncryptedEvent) diff --git a/lib/events/encryptionevent.h b/lib/events/encryptionevent.h index 14439fcc..dfb28b2f 100644 --- a/lib/events/encryptionevent.h +++ b/lib/events/encryptionevent.h @@ -8,7 +8,7 @@ #include "stateevent.h" namespace Quotient { -class EncryptionEventContent : public EventContent::Base { +class QUOTIENT_API EncryptionEventContent : public EventContent::Base { public: enum EncryptionType : size_t { MegolmV1AesSha2 = 0, Undefined }; @@ -26,7 +26,7 @@ protected: using EncryptionType = EncryptionEventContent::EncryptionType; -class EncryptionEvent : public StateEvent { +class QUOTIENT_API EncryptionEvent : public StateEvent { Q_GADGET public: DEFINE_EVENT_TYPEID("m.room.encryption", EncryptionEvent) @@ -51,6 +51,5 @@ public: int rotationPeriodMs() const { return content().rotationPeriodMs; } int rotationPeriodMsgs() const { return content().rotationPeriodMsgs; } }; - REGISTER_EVENT_TYPE(EncryptionEvent) } // namespace Quotient diff --git a/lib/events/event.h b/lib/events/event.h index 8f62872d..8a0076d0 100644 --- a/lib/events/event.h +++ b/lib/events/event.h @@ -60,14 +60,14 @@ inline QJsonObject basicEventJson(const QString& matrixType, using event_type_t = size_t; using event_mtype_t = const char*; -class EventTypeRegistry { +class QUOTIENT_API EventTypeRegistry { public: ~EventTypeRegistry() = default; static event_type_t initializeTypeId(event_mtype_t matrixTypeId); template - static inline event_type_t initializeTypeId() + static event_type_t initializeTypeId() { return initializeTypeId(EventT::matrixTypeId()); } @@ -190,7 +190,7 @@ namespace _impl { // === Event === -class Event { +class QUOTIENT_API Event { public: using Type = event_type_t; static inline _impl::EventFactory factory { "Event" }; @@ -243,7 +243,7 @@ public: return fromJson(unsignedJson()[std::forward(key)]); } - friend QDebug operator<<(QDebug dbg, const Event& e) + friend QUOTIENT_API QDebug operator<<(QDebug dbg, const Event& e) { QDebugStateSaver _dss { dbg }; dbg.noquote().nospace() << e.matrixType() << '(' << e.type() << "): "; @@ -272,17 +272,20 @@ using Events = EventsArray; // This macro should be used in a public section of an event class to // provide matrixTypeId() and typeId(). -#define DEFINE_EVENT_TYPEID(_Id, _Type) \ - static constexpr event_mtype_t matrixTypeId() { return _Id; } \ - static auto typeId() { return Quotient::typeId<_Type>(); } \ +#define DEFINE_EVENT_TYPEID(_Id, _Type) \ + static QUOTIENT_EXPORT constexpr event_mtype_t matrixTypeId() \ + { \ + return _Id; \ + } \ + static QUOTIENT_EXPORT auto typeId() { return Quotient::typeId<_Type>(); } \ // End of macro // This macro should be put after an event class definition (in .h or .cpp) // to enable its deserialisation from a /sync and other // polymorphic event arrays -#define REGISTER_EVENT_TYPE(_Type) \ - [[maybe_unused]] inline const auto _factoryAdded##_Type = \ - _Type::factory.addMethod<_Type>(); \ +#define REGISTER_EVENT_TYPE(_Type) \ + [[maybe_unused]] QUOTIENT_API inline const auto _factoryAdded##_Type = \ + _Type::factory.addMethod<_Type>(); \ // End of macro // === Event loading === diff --git a/lib/events/eventcontent.h b/lib/events/eventcontent.h index f609a603..bfa7d926 100644 --- a/lib/events/eventcontent.h +++ b/lib/events/eventcontent.h @@ -6,14 +6,15 @@ // This file contains generic event content definitions, applicable to room // message events as well as other events (e.g., avatars). +#include "encryptedfile.h" +#include "quotient_export.h" + #include #include #include #include #include -#include "encryptedfile.h" - class QFileInfo; namespace Quotient { @@ -28,7 +29,7 @@ namespace EventContent { * assumed but not required that a content object can also be created * from plain data. */ - class Base { + class QUOTIENT_API Base { public: explicit Base(QJsonObject o = {}) : originalJson(std::move(o)) {} virtual ~Base() = default; @@ -76,7 +77,7 @@ namespace EventContent { * * This class is not polymorphic. */ - class FileInfo { + class QUOTIENT_API FileInfo { public: FileInfo() = default; explicit FileInfo(const QFileInfo& fi); @@ -121,7 +122,7 @@ namespace EventContent { /** * A content info class for image content types: image, thumbnail, video */ - class ImageInfo : public FileInfo { + class QUOTIENT_API ImageInfo : public FileInfo { public: ImageInfo() = default; explicit ImageInfo(const QFileInfo& fi, QSize imageSize = {}); @@ -146,7 +147,7 @@ namespace EventContent { * the JSON representation of event content; namely, * "info/thumbnail_url" and "info/thumbnail_info" fields are used. */ - class Thumbnail : public ImageInfo { + class QUOTIENT_API Thumbnail : public ImageInfo { public: Thumbnail() = default; // Allow empty thumbnails Thumbnail(const QJsonObject& infoJson, const Omittable &file = none); @@ -160,7 +161,7 @@ namespace EventContent { void fillInfoJson(QJsonObject* infoJson) const; }; - class TypedBase : public Base { + class QUOTIENT_API TypedBase : public Base { public: virtual QMimeType type() const = 0; virtual const FileInfo* fileInfo() const { return nullptr; } @@ -183,7 +184,7 @@ namespace EventContent { * \tparam InfoT base info class */ template - class UrlBasedContent : public TypedBase, public InfoT { + class QUOTIENT_API UrlBasedContent : public TypedBase, public InfoT { public: using InfoT::InfoT; explicit UrlBasedContent(const QJsonObject& json) @@ -215,7 +216,7 @@ namespace EventContent { }; template - class UrlWithThumbnailContent : public UrlBasedContent { + class QUOTIENT_API UrlWithThumbnailContent : public UrlBasedContent { public: // NB: when using inherited constructors, thumbnail has to be // initialised separately diff --git a/lib/events/reactionevent.h b/lib/events/reactionevent.h index 5a2b98c4..ce11eaed 100644 --- a/lib/events/reactionevent.h +++ b/lib/events/reactionevent.h @@ -7,7 +7,7 @@ namespace Quotient { -struct EventRelation { +struct QUOTIENT_API EventRelation { using reltypeid_t = const char*; static constexpr reltypeid_t Reply() { return "m.in_reply_to"; } static constexpr reltypeid_t Annotation() { return "m.annotation"; } @@ -31,12 +31,12 @@ struct EventRelation { } }; template <> -struct JsonObjectConverter { +struct QUOTIENT_API JsonObjectConverter { static void dumpTo(QJsonObject& jo, const EventRelation& pod); static void fillFrom(const QJsonObject& jo, EventRelation& pod); }; -class ReactionEvent : public RoomEvent { +class QUOTIENT_API ReactionEvent : public RoomEvent { public: DEFINE_EVENT_TYPEID("m.reaction", ReactionEvent) diff --git a/lib/events/receiptevent.h b/lib/events/receiptevent.h index 9683deef..5e077e47 100644 --- a/lib/events/receiptevent.h +++ b/lib/events/receiptevent.h @@ -19,7 +19,7 @@ struct ReceiptsForEvent { }; using EventsWithReceipts = QVector; -class ReceiptEvent : public Event { +class QUOTIENT_API ReceiptEvent : public Event { public: DEFINE_EVENT_TYPEID("m.receipt", ReceiptEvent) explicit ReceiptEvent(const EventsWithReceipts& ewrs); diff --git a/lib/events/roomavatarevent.h b/lib/events/roomavatarevent.h index 8618ba31..c54b5801 100644 --- a/lib/events/roomavatarevent.h +++ b/lib/events/roomavatarevent.h @@ -7,7 +7,8 @@ #include "stateevent.h" namespace Quotient { -class RoomAvatarEvent : public StateEvent { +class QUOTIENT_API RoomAvatarEvent + : public StateEvent { // It's a bit of an overkill to use a full-fledged ImageContent // because in reality m.room.avatar usually only has a single URL, // without a thumbnail. But The Spec says there be thumbnails, and diff --git a/lib/events/roomcreateevent.h b/lib/events/roomcreateevent.h index b3ad287c..016855b9 100644 --- a/lib/events/roomcreateevent.h +++ b/lib/events/roomcreateevent.h @@ -7,7 +7,7 @@ #include "quotient_common.h" namespace Quotient { -class RoomCreateEvent : public StateEventBase { +class QUOTIENT_API RoomCreateEvent : public StateEventBase { public: DEFINE_EVENT_TYPEID("m.room.create", RoomCreateEvent) diff --git a/lib/events/roomevent.h b/lib/events/roomevent.h index 8be58481..3fbb247e 100644 --- a/lib/events/roomevent.h +++ b/lib/events/roomevent.h @@ -11,7 +11,7 @@ namespace Quotient { class RedactionEvent; /** This class corresponds to m.room.* events */ -class RoomEvent : public Event { +class QUOTIENT_API RoomEvent : public Event { public: static inline _impl::EventFactory factory { "RoomEvent" }; @@ -70,7 +70,7 @@ using RoomEventPtr = event_ptr_tt; using RoomEvents = EventsArray; using RoomEventsRange = Range; -class CallEventBase : public RoomEvent { +class QUOTIENT_API CallEventBase : public RoomEvent { public: CallEventBase(Type type, event_mtype_t matrixType, const QString& callId, int version, const QJsonObject& contentJson = {}); diff --git a/lib/events/roomkeyevent.h b/lib/events/roomkeyevent.h index d021fbec..c4df7936 100644 --- a/lib/events/roomkeyevent.h +++ b/lib/events/roomkeyevent.h @@ -6,7 +6,7 @@ #include "event.h" namespace Quotient { -class RoomKeyEvent : public Event +class QUOTIENT_API RoomKeyEvent : public Event { public: DEFINE_EVENT_TYPEID("m.room_key", RoomKeyEvent) diff --git a/lib/events/roommemberevent.h b/lib/events/roommemberevent.h index 0fb464d4..5e446dbe 100644 --- a/lib/events/roommemberevent.h +++ b/lib/events/roommemberevent.h @@ -10,7 +10,7 @@ #include "quotient_common.h" namespace Quotient { -class MemberEventContent : public EventContent::Base { +class QUOTIENT_API MemberEventContent : public EventContent::Base { public: using MembershipType [[deprecated("Use Quotient::Membership instead")]] = Membership; @@ -33,7 +33,7 @@ protected: using MembershipType [[deprecated("Use Membership instead")]] = Membership; -class RoomMemberEvent : public StateEvent { +class QUOTIENT_API RoomMemberEvent : public StateEvent { Q_GADGET public: DEFINE_EVENT_TYPEID("m.room.member", RoomMemberEvent) @@ -95,6 +95,5 @@ doLoadEvent(const QJsonObject& json, const QString& matrixType) return makeEvent(json); return makeEvent(unknownEventTypeId(), json); } - REGISTER_EVENT_TYPE(RoomMemberEvent) } // namespace Quotient diff --git a/lib/events/roommessageevent.h b/lib/events/roommessageevent.h index 56597ddc..0c901b7a 100644 --- a/lib/events/roommessageevent.h +++ b/lib/events/roommessageevent.h @@ -16,7 +16,7 @@ namespace MessageEventContent = EventContent; // Back-compatibility /** * The event class corresponding to m.room.message events */ -class RoomMessageEvent : public RoomEvent { +class QUOTIENT_API RoomMessageEvent : public RoomEvent { Q_GADGET public: DEFINE_EVENT_TYPEID("m.room.message", RoomMessageEvent) @@ -120,7 +120,7 @@ namespace EventContent { * Available fields: mimeType, body. The body can be either rich text * or plain text, depending on what mimeType specifies. */ - class TextContent : public TypedBase { + class QUOTIENT_API TextContent : public TypedBase { public: TextContent(QString text, const QString& contentType, Omittable relatesTo = none); @@ -149,7 +149,7 @@ namespace EventContent { * - thumbnail.mimeType * - thumbnail.imageSize */ - class LocationContent : public TypedBase { + class QUOTIENT_API LocationContent : public TypedBase { public: LocationContent(const QString& geoUri, const Thumbnail& thumbnail = {}); explicit LocationContent(const QJsonObject& json); @@ -168,7 +168,7 @@ namespace EventContent { * A base class for info types that include duration: audio and video */ template - class PlayableContent : public ContentT { + class QUOTIENT_API PlayableContent : public ContentT { public: using ContentT::ContentT; PlayableContent(const QJsonObject& json) diff --git a/lib/events/roompowerlevelsevent.h b/lib/events/roompowerlevelsevent.h index 0346fc0d..80e27048 100644 --- a/lib/events/roompowerlevelsevent.h +++ b/lib/events/roompowerlevelsevent.h @@ -7,7 +7,7 @@ #include "stateevent.h" namespace Quotient { -class PowerLevelsEventContent : public EventContent::Base { +class QUOTIENT_API PowerLevelsEventContent : public EventContent::Base { public: struct Notifications { int room; @@ -34,7 +34,8 @@ protected: void fillJson(QJsonObject* o) const override; }; -class RoomPowerLevelsEvent : public StateEvent { +class QUOTIENT_API RoomPowerLevelsEvent + : public StateEvent { Q_GADGET public: DEFINE_EVENT_TYPEID("m.room.power_levels", RoomPowerLevelsEvent) @@ -61,9 +62,6 @@ public: int powerLevelForEvent(const QString& eventId) const; int powerLevelForState(const QString& eventId) const; int powerLevelForUser(const QString& userId) const; - -private: }; - REGISTER_EVENT_TYPE(RoomPowerLevelsEvent) } // namespace Quotient diff --git a/lib/events/roomtombstoneevent.h b/lib/events/roomtombstoneevent.h index 30e53738..e336c448 100644 --- a/lib/events/roomtombstoneevent.h +++ b/lib/events/roomtombstoneevent.h @@ -6,7 +6,7 @@ #include "stateevent.h" namespace Quotient { -class RoomTombstoneEvent : public StateEventBase { +class QUOTIENT_API RoomTombstoneEvent : public StateEventBase { public: DEFINE_EVENT_TYPEID("m.room.tombstone", RoomTombstoneEvent) diff --git a/lib/events/simplestateevents.h b/lib/events/simplestateevents.h index 9ce78609..d6557012 100644 --- a/lib/events/simplestateevents.h +++ b/lib/events/simplestateevents.h @@ -30,7 +30,8 @@ namespace EventContent { } // namespace EventContent #define DEFINE_SIMPLE_STATE_EVENT(_Name, _TypeId, _ValueType, _ContentKey) \ - class _Name : public StateEvent> { \ + class QUOTIENT_API _Name \ + : public StateEvent> { \ public: \ using value_type = content_type::value_type; \ DEFINE_EVENT_TYPEID(_TypeId, _Name) \ diff --git a/lib/events/stateevent.h b/lib/events/stateevent.h index c37965aa..6095d628 100644 --- a/lib/events/stateevent.h +++ b/lib/events/stateevent.h @@ -17,7 +17,7 @@ inline QJsonObject basicStateEventJson(const QString& matrixTypeId, { ContentKey, content } }; } -class StateEventBase : public RoomEvent { +class QUOTIENT_API StateEventBase : public RoomEvent { public: static inline _impl::EventFactory factory { "StateEvent" }; diff --git a/lib/events/stickerevent.h b/lib/events/stickerevent.h index 93671086..0957dca3 100644 --- a/lib/events/stickerevent.h +++ b/lib/events/stickerevent.h @@ -11,7 +11,7 @@ namespace Quotient { /// Sticker messages are specialised image messages that are displayed without /// controls (e.g. no "download" link, or light-box view on click, as would be /// displayed for for m.image events). -class StickerEvent : public RoomEvent +class QUOTIENT_API StickerEvent : public RoomEvent { public: DEFINE_EVENT_TYPEID("m.sticker", StickerEvent) diff --git a/lib/events/typingevent.h b/lib/events/typingevent.h index 7456100a..522f7e42 100644 --- a/lib/events/typingevent.h +++ b/lib/events/typingevent.h @@ -6,7 +6,7 @@ #include "event.h" namespace Quotient { -class TypingEvent : public Event { +class QUOTIENT_API TypingEvent : public Event { public: DEFINE_EVENT_TYPEID("m.typing", TypingEvent) diff --git a/lib/eventstats.h b/lib/eventstats.h index 77c661a7..a10c81fb 100644 --- a/lib/eventstats.h +++ b/lib/eventstats.h @@ -16,7 +16,7 @@ namespace Quotient { //! \note It's just a simple grouping of counters and is not automatically //! updated from the room as subsequent syncs arrive. //! \sa Room::unreadStats, Room::partiallyReadStats, Room::isEventNotable -struct EventStats { +struct QUOTIENT_API EventStats { Q_GADGET Q_PROPERTY(qsizetype notableCount MEMBER notableCount CONSTANT) Q_PROPERTY(qsizetype highlightCount MEMBER highlightCount CONSTANT) @@ -109,6 +109,6 @@ public: bool isValidFor(const Room* room, const marker_t& marker) const; }; -QDebug operator<<(QDebug dbg, const EventStats& es); +QUOTIENT_API QDebug operator<<(QDebug dbg, const EventStats& es); } diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h index ddf243ed..f41fc63c 100644 --- a/lib/jobs/basejob.h +++ b/lib/jobs/basejob.h @@ -20,7 +20,7 @@ class ConnectionData; enum class HttpVerb { Get, Put, Post, Delete }; -class BaseJob : public QObject { +class QUOTIENT_API BaseJob : public QObject { Q_OBJECT Q_PROPERTY(QUrl requestUrl READ requestUrl CONSTANT) Q_PROPERTY(int maxRetries READ maxRetries WRITE setMaxRetries) @@ -470,7 +470,7 @@ private: QScopedPointer d; }; -inline bool isJobPending(BaseJob* job) +inline bool QUOTIENT_API isJobPending(BaseJob* job) { return job && job->error() == BaseJob::Pending; } diff --git a/lib/jobs/downloadfilejob.h b/lib/jobs/downloadfilejob.h index 0752af89..d9f3b686 100644 --- a/lib/jobs/downloadfilejob.h +++ b/lib/jobs/downloadfilejob.h @@ -6,7 +6,7 @@ #include "csapi/content-repo.h" namespace Quotient { -class DownloadFileJob : public GetContentJob { +class QUOTIENT_API DownloadFileJob : public GetContentJob { public: using GetContentJob::makeRequestUrl; static QUrl makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri); diff --git a/lib/jobs/mediathumbnailjob.h b/lib/jobs/mediathumbnailjob.h index 3183feb1..c9f6da35 100644 --- a/lib/jobs/mediathumbnailjob.h +++ b/lib/jobs/mediathumbnailjob.h @@ -8,7 +8,7 @@ #include namespace Quotient { -class MediaThumbnailJob : public GetContentThumbnailJob { +class QUOTIENT_API MediaThumbnailJob : public GetContentThumbnailJob { public: using GetContentThumbnailJob::makeRequestUrl; static QUrl makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri, diff --git a/lib/jobs/requestdata.h b/lib/jobs/requestdata.h index 4f05e5ff..41ad833a 100644 --- a/lib/jobs/requestdata.h +++ b/lib/jobs/requestdata.h @@ -3,6 +3,8 @@ #pragma once +#include "quotient_export.h" + #include #include @@ -19,7 +21,7 @@ namespace Quotient { * as well as JSON (and possibly other structures in the future) to * a QByteArray consumed by QNetworkAccessManager request methods. */ -class RequestData { +class QUOTIENT_API RequestData { public: RequestData(const QByteArray& a = {}); RequestData(const QJsonObject& jo); diff --git a/lib/mxcreply.h b/lib/mxcreply.h index efaf01c6..23049b7d 100644 --- a/lib/mxcreply.h +++ b/lib/mxcreply.h @@ -3,13 +3,15 @@ #pragma once +#include "quotient_export.h" + #include #include namespace Quotient { class Room; -class MxcReply : public QNetworkReply +class QUOTIENT_API MxcReply : public QNetworkReply { public: explicit MxcReply(); diff --git a/lib/networkaccessmanager.h b/lib/networkaccessmanager.h index 87bc12a1..d06f9736 100644 --- a/lib/networkaccessmanager.h +++ b/lib/networkaccessmanager.h @@ -3,6 +3,8 @@ #pragma once +#include "quotient_export.h" + #include #include @@ -10,7 +12,7 @@ namespace Quotient { class Room; class Connection; -class NetworkAccessManager : public QNetworkAccessManager { +class QUOTIENT_API NetworkAccessManager : public QNetworkAccessManager { Q_OBJECT public: NetworkAccessManager(QObject* parent = nullptr); diff --git a/lib/networksettings.h b/lib/networksettings.h index df11a9c8..c1446355 100644 --- a/lib/networksettings.h +++ b/lib/networksettings.h @@ -10,7 +10,7 @@ Q_DECLARE_METATYPE(QNetworkProxy::ProxyType) namespace Quotient { -class NetworkSettings : public SettingsGroup { +class QUOTIENT_API NetworkSettings : public SettingsGroup { Q_OBJECT QTNT_DECLARE_SETTING(QNetworkProxy::ProxyType, proxyType, setProxyType) QTNT_DECLARE_SETTING(QString, proxyHostName, setProxyHostName) diff --git a/lib/quotient_common.h b/lib/quotient_common.h index 0e3e2a40..a5926e8c 100644 --- a/lib/quotient_common.h +++ b/lib/quotient_common.h @@ -3,6 +3,8 @@ #pragma once +#include "quotient_export.h" + #include #include @@ -26,8 +28,21 @@ #define DECL_DEPRECATED_ENUMERATOR(Deprecated, Recommended) \ Deprecated Q_DECL_ENUMERATOR_DEPRECATED_X("Use " #Recommended) = Recommended +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) +// The first line is a usual way to indicate a namespace to moc; +// the second line redeclares the namespace static metaobject with +// QUOTIENT_API so that dynamically linked clients could serialise +// flag/enum values from the namespace. +#define QUO_NAMESPACE \ +Q_NAMESPACE \ +extern QUOTIENT_API const QMetaObject staticMetaObject; +#else +// Since Qt 5.14.0, it's all packed in a single macro +#define QUO_NAMESPACE Q_NAMESPACE_EXPORT(QUOTIENT_API) +#endif + namespace Quotient { -Q_NAMESPACE +QUO_NAMESPACE // std::array {} needs explicit template parameters on macOS because // Apple stdlib doesn't have deduction guides for std::array. C++20 has diff --git a/lib/room.h b/lib/room.h index 85c51a87..63a4aaea 100644 --- a/lib/room.h +++ b/lib/room.h @@ -45,7 +45,7 @@ class RedactEventJob; * This is specifically tuned to work with QML exposing all traits as * Q_PROPERTY values. */ -class FileTransferInfo { +class QUOTIENT_API FileTransferInfo { Q_GADGET Q_PROPERTY(bool isUpload MEMBER isUpload CONSTANT) Q_PROPERTY(bool active READ active CONSTANT) @@ -73,7 +73,7 @@ public: //! \brief Data structure for a room member's read receipt //! \sa Room::lastReadReceipt -class ReadReceipt { +class QUOTIENT_API ReadReceipt { Q_GADGET Q_PROPERTY(QString eventId MEMBER eventId CONSTANT) Q_PROPERTY(QDateTime timestamp MEMBER timestamp CONSTANT) @@ -110,7 +110,7 @@ private: Q_PROPERTY(Type type MEMBER type CONSTANT) }; -class Room : public QObject { +class QUOTIENT_API Room : public QObject { Q_OBJECT Q_PROPERTY(Connection* connection READ connection CONSTANT) Q_PROPERTY(User* localUser READ localUser CONSTANT) @@ -1037,7 +1037,7 @@ private: void setJoinState(JoinState state); }; -class MemberSorter { +class QUOTIENT_API MemberSorter { public: explicit MemberSorter(const Room* r) : room(r) {} diff --git a/lib/settings.h b/lib/settings.h index efd0d714..b66879c5 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -3,6 +3,8 @@ #pragma once +#include "quotient_export.h" + #include #include #include @@ -11,7 +13,7 @@ class QVariant; namespace Quotient { -class Settings : public QSettings { +class QUOTIENT_API Settings : public QSettings { Q_OBJECT public: /// Add a legacy organisation/application name to migrate settings from @@ -76,7 +78,7 @@ protected: QSettings legacySettings { legacyOrganizationName, legacyApplicationName }; }; -class SettingsGroup : public Settings { +class QUOTIENT_API SettingsGroup : public Settings { public: explicit SettingsGroup(QString path, QObject* parent = nullptr) : Settings(parent) @@ -124,7 +126,7 @@ private: setValue(QStringLiteral(qsettingname), std::move(newValue)); \ } -class AccountSettings : public SettingsGroup { +class QUOTIENT_API AccountSettings : public SettingsGroup { Q_OBJECT Q_PROPERTY(QString userId READ userId CONSTANT) QTNT_DECLARE_SETTING(QString, deviceId, setDeviceId) diff --git a/lib/ssosession.h b/lib/ssosession.h index 72dd60c4..a658c043 100644 --- a/lib/ssosession.h +++ b/lib/ssosession.h @@ -3,6 +3,8 @@ #pragma once +#include "quotient_export.h" + #include #include @@ -29,7 +31,7 @@ class Connection; * connection->prepareForSso(initialDeviceName)->ssoUrl()); * \endcode */ -class SsoSession : public QObject { +class QUOTIENT_API SsoSession : public QObject { Q_OBJECT Q_PROPERTY(QUrl ssoUrl READ ssoUrl CONSTANT) Q_PROPERTY(QUrl callbackUrl READ callbackUrl CONSTANT) diff --git a/lib/syncdata.h b/lib/syncdata.h index 36d2e0bf..e29540c2 100644 --- a/lib/syncdata.h +++ b/lib/syncdata.h @@ -22,7 +22,7 @@ constexpr auto HighlightCountKey = "highlight_count"_ls; * means that nothing has come from the server; heroes.value().isEmpty() * means a peculiar case of a room with the only member - the current user. */ -struct RoomSummary { +struct QUOTIENT_API RoomSummary { Omittable joinedMemberCount; Omittable invitedMemberCount; Omittable heroes; //< mxids of users to take part in the room diff --git a/lib/uri.h b/lib/uri.h index d8b892b6..78cd27c8 100644 --- a/lib/uri.h +++ b/lib/uri.h @@ -23,7 +23,7 @@ namespace Quotient { * its type, and obtain components, also in either unencoded (for displaying) * or encoded (for APIs) form. */ -class Uri : private QUrl { +class QUOTIENT_API Uri : private QUrl { Q_GADGET public: enum Type : char { diff --git a/lib/uriresolver.h b/lib/uriresolver.h index ff97324a..9140046c 100644 --- a/lib/uriresolver.h +++ b/lib/uriresolver.h @@ -25,7 +25,7 @@ class User; * gradual implementation. Derived classes are encouraged to override as many * of them as possible. */ -class UriResolverBase { +class QUOTIENT_API UriResolverBase { public: /*! \brief Resolve the resource and dispatch an action depending on its type * @@ -105,7 +105,7 @@ protected: * * \sa UriResolverBase, UriDispatcher */ -UriResolveResult +QUOTIENT_API UriResolveResult visitResource(Connection* account, const Uri& uri, std::function userHandler, std::function roomEventHandler, @@ -141,7 +141,7 @@ inline UriResolveResult checkResource(Connection* account, const Uri& uri) * synchronously - the returned value is the result of resolving the URI, * not acting on it. */ -class UriDispatcher : public QObject, public UriResolverBase { +class QUOTIENT_API UriDispatcher : public QObject, public UriResolverBase { Q_OBJECT public: explicit UriDispatcher(QObject* parent = nullptr) : QObject(parent) {} diff --git a/lib/user.h b/lib/user.h index 78b72bf2..435304ce 100644 --- a/lib/user.h +++ b/lib/user.h @@ -5,6 +5,7 @@ #pragma once #include "avatar.h" +#include "quotient_export.h" #include @@ -13,7 +14,7 @@ class Connection; class Room; class RoomMemberEvent; -class User : public QObject { +class QUOTIENT_API User : public QObject { Q_OBJECT Q_PROPERTY(QString id READ id CONSTANT) Q_PROPERTY(bool isGuest READ isGuest CONSTANT) diff --git a/lib/util.h b/lib/util.h index 97f0ecbc..399f93c2 100644 --- a/lib/util.h +++ b/lib/util.h @@ -4,6 +4,8 @@ #pragma once +#include "quotient_export.h" + #include #include @@ -244,26 +246,26 @@ inline std::pair findFirstOf(InputIt first, InputIt last, } /** Convert what looks like a URL or a Matrix ID to an HTML hyperlink */ -void linkifyUrls(QString& htmlEscapedText); +QUOTIENT_API void linkifyUrls(QString& htmlEscapedText); /** Sanitize the text before showing in HTML * * This does toHtmlEscaped() and removes Unicode BiDi marks. */ -QString sanitized(const QString& plainText); +QUOTIENT_API QString sanitized(const QString& plainText); /** Pretty-print plain text into HTML * * This includes HTML escaping of <,>,",& and calling linkifyUrls() */ -QString prettyPrint(const QString& plainText); +QUOTIENT_API QString prettyPrint(const QString& plainText); /** Return a path to cache directory after making sure that it exists * * The returned path has a trailing slash, clients don't need to append it. * \param dir path to cache directory relative to the standard cache path */ -QString cacheLocation(const QString& dirName); +QUOTIENT_API QString cacheLocation(const QString& dirName); /** Hue color component of based of the hash of the string. * @@ -272,13 +274,13 @@ QString cacheLocation(const QString& dirName); * Naming and range are the same as QColor's hueF method: * https://doc.qt.io/qt-5/qcolor.html#integer-vs-floating-point-precision */ -qreal stringToHueF(const QString& s); +QUOTIENT_API qreal stringToHueF(const QString& s); /** Extract the serverpart from MXID */ -QString serverPart(const QString& mxId); +QUOTIENT_API QString serverPart(const QString& mxId); -QString versionString(); -int majorVersion(); -int minorVersion(); -int patchVersion(); +QUOTIENT_API QString versionString(); +QUOTIENT_API int majorVersion(); +QUOTIENT_API int minorVersion(); +QUOTIENT_API int patchVersion(); } // namespace Quotient -- cgit v1.2.3 From 2245a44aca8d51e331cf1211ff6e2b38c57e5246 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Wed, 8 Jun 2022 14:26:30 +0200 Subject: Pack up StickerEvent in the header file Dropping yet another translation unit. --- CMakeLists.txt | 2 +- lib/events/stickerevent.cpp | 26 -------------------------- lib/events/stickerevent.h | 19 +++++++++++++++---- 3 files changed, 16 insertions(+), 31 deletions(-) delete mode 100644 lib/events/stickerevent.cpp (limited to 'lib/events/stickerevent.h') diff --git a/CMakeLists.txt b/CMakeLists.txt index 94055b7f..b2c4ff83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -165,7 +165,7 @@ list(APPEND lib_SRCS lib/events/encryptionevent.h lib/events/encryptionevent.cpp lib/events/encryptedevent.h lib/events/encryptedevent.cpp lib/events/roomkeyevent.h lib/events/roomkeyevent.cpp - lib/events/stickerevent.h lib/events/stickerevent.cpp + lib/events/stickerevent.h lib/events/keyverificationevent.h lib/events/filesourceinfo.h lib/events/filesourceinfo.cpp lib/jobs/requestdata.h lib/jobs/requestdata.cpp diff --git a/lib/events/stickerevent.cpp b/lib/events/stickerevent.cpp deleted file mode 100644 index 6d318f0e..00000000 --- a/lib/events/stickerevent.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// SDPX-FileCopyrightText: 2020 Carl Schwan -// SPDX-License-Identifier: LGPL-2.1-or-later - -#include "stickerevent.h" - -using namespace Quotient; - -StickerEvent::StickerEvent(const QJsonObject &obj) - : RoomEvent(typeId(), obj) - , m_imageContent(EventContent::ImageContent(obj["content"_ls].toObject())) -{} - -QString StickerEvent::body() const -{ - return contentPart("body"_ls); -} - -const EventContent::ImageContent &StickerEvent::image() const -{ - return m_imageContent; -} - -QUrl StickerEvent::url() const -{ - return m_imageContent.url(); -} diff --git a/lib/events/stickerevent.h b/lib/events/stickerevent.h index 0957dca3..e378422d 100644 --- a/lib/events/stickerevent.h +++ b/lib/events/stickerevent.h @@ -16,21 +16,32 @@ class QUOTIENT_API StickerEvent : public RoomEvent public: DEFINE_EVENT_TYPEID("m.sticker", StickerEvent) - explicit StickerEvent(const QJsonObject &obj); + explicit StickerEvent(const QJsonObject& obj) + : RoomEvent(TypeId, obj) + , m_imageContent( + EventContent::ImageContent(obj["content"_ls].toObject())) + {} /// \brief A textual representation or associated description of the /// sticker image. /// /// This could be the alt text of the original image, or a message to /// accompany and further describe the sticker. - QString body() const; + QUO_CONTENT_GETTER(QString, body) /// \brief Metadata about the image referred to in url including a /// thumbnail representation. - const EventContent::ImageContent &image() const; + const EventContent::ImageContent& image() const + { + return m_imageContent; + } /// \brief The URL to the sticker image. This must be a valid mxc:// URI. - QUrl url() const; + QUrl url() const + { + return m_imageContent.url(); + } + private: EventContent::ImageContent m_imageContent; }; -- cgit v1.2.3 From a18f505fe7ca66556d66538a7c9b9ff31d2c1b29 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Tue, 9 Aug 2022 18:42:24 +0200 Subject: EventMetaType, QUO_EVENT, QUO_BASE_EVENT The new metatype framework replaces EventFactory/DEFINE_EVENT_TYPEID/REGISTER_EVENT_TYPE; it is faster, more functional and extensible. Of note: - EventMetaType mostly reproduces the logic of EventFactory but supports custom base event types not just for loading (that part EventFactory also supported) but also for matching - previously you had to have Event::is*Event() for base type matching. Now Quotient::is() can match against both base and leaf types. - Instead of DEFINE_EVENT_TYPEID and REGISTER_EVENT_TYPE there's now a single macro, QUO_EVENT, intended for use in the way similar to Q_OBJECT. Actually, the entire framework borrows heavily from QMetaObject and Q_OBJECT. Making event types full-fledged QObjects is still not considered because half of QObject functions would not be applicable (e.g. signals/slots) while another half (in particular, using Matrix type ids to select event types) would still have to be done on top of QObject. And QML can just access events as const QJsonObjects which is arguably more lightweight as well. - QUO_BASE_EVENT is a new macro replacing EventFactory object definitions. This was necessary for the same reason why Q_OBJECT is a macro: aside from a static object definition, this macro introduces a virtual function override to resolve the metatype at runtime. This very mechanism is used to make event type matching/casting as quick as possible - QUO_BASE_EVENT and QUO_EVENT use the C++20 __VA_OPT__ feature that is only available with the new MSVC preprocessor (see https://docs.microsoft.com/en-us/cpp/preprocessor/preprocessor-experimental-overview); the respective switch was added to CMakeLists.txt. --- CMakeLists.txt | 2 +- lib/events/callanswerevent.h | 3 +- lib/events/callcandidatesevent.h | 4 +- lib/events/callhangupevent.h | 4 +- lib/events/callinviteevent.h | 4 +- lib/events/directchatevent.h | 3 +- lib/events/encryptedevent.h | 4 +- lib/events/encryptionevent.h | 3 +- lib/events/event.cpp | 41 +++- lib/events/event.h | 355 ++++++++++++++++++++++++----------- lib/events/keyverificationevent.h | 26 +-- lib/events/receiptevent.h | 3 +- lib/events/redactionevent.h | 3 +- lib/events/roomavatarevent.h | 3 +- lib/events/roomcanonicalaliasevent.h | 3 +- lib/events/roomcreateevent.h | 3 +- lib/events/roomevent.h | 16 +- lib/events/roomkeyevent.h | 3 +- lib/events/roommemberevent.h | 12 +- lib/events/roommessageevent.h | 4 +- lib/events/roompowerlevelsevent.h | 3 +- lib/events/roomtombstoneevent.h | 3 +- lib/events/simplestateevents.h | 5 +- lib/events/stateevent.h | 30 +-- lib/events/stickerevent.h | 3 +- 25 files changed, 326 insertions(+), 217 deletions(-) (limited to 'lib/events/stickerevent.h') diff --git a/CMakeLists.txt b/CMakeLists.txt index 06e754aa..9983f860 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ endif(CMAKE_BUILD_TYPE) message(STATUS "Using compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}" ) include(CheckCXXCompilerFlag) if (MSVC) - add_compile_options(/EHsc /W4 + add_compile_options(/Zc:preprocessor /EHsc /W4 /wd4100 /wd4127 /wd4242 /wd4244 /wd4245 /wd4267 /wd4365 /wd4456 /wd4459 /wd4464 /wd4505 /wd4514 /wd4571 /wd4619 /wd4623 /wd4625 /wd4626 /wd4706 /wd4710 /wd4774 /wd4820 /wd4946 /wd5026 /wd5027) diff --git a/lib/events/callanswerevent.h b/lib/events/callanswerevent.h index 4d539b85..70ca1c7e 100644 --- a/lib/events/callanswerevent.h +++ b/lib/events/callanswerevent.h @@ -9,7 +9,7 @@ namespace Quotient { class QUOTIENT_API CallAnswerEvent : public CallEventBase { public: - DEFINE_EVENT_TYPEID("m.call.answer", CallAnswerEvent) + QUO_EVENT(CallAnswerEvent, "m.call.answer") explicit CallAnswerEvent(const QJsonObject& obj); @@ -20,5 +20,4 @@ public: return contentPart("answer"_ls).value("sdp"_ls).toString(); } }; -REGISTER_EVENT_TYPE(CallAnswerEvent) } // namespace Quotient diff --git a/lib/events/callcandidatesevent.h b/lib/events/callcandidatesevent.h index e949f722..cb96f358 100644 --- a/lib/events/callcandidatesevent.h +++ b/lib/events/callcandidatesevent.h @@ -11,7 +11,7 @@ namespace Quotient { class CallCandidatesEvent : public CallEventBase { public: - DEFINE_EVENT_TYPEID("m.call.candidates", CallCandidatesEvent) + QUO_EVENT(CallCandidatesEvent, "m.call.candidates") explicit CallCandidatesEvent(const QJsonObject& obj) : CallEventBase(typeId(), obj) @@ -27,6 +27,4 @@ public: QUO_CONTENT_GETTER(QString, callId) QUO_CONTENT_GETTER(int, version) }; - -REGISTER_EVENT_TYPE(CallCandidatesEvent) } // namespace Quotient diff --git a/lib/events/callhangupevent.h b/lib/events/callhangupevent.h index b0017c59..e4d9bb78 100644 --- a/lib/events/callhangupevent.h +++ b/lib/events/callhangupevent.h @@ -9,7 +9,7 @@ namespace Quotient { class QUOTIENT_API CallHangupEvent : public CallEventBase { public: - DEFINE_EVENT_TYPEID("m.call.hangup", CallHangupEvent) + QUO_EVENT(CallHangupEvent, "m.call.hangup") explicit CallHangupEvent(const QJsonObject& obj) : CallEventBase(typeId(), obj) @@ -18,6 +18,4 @@ public: : CallEventBase(typeId(), matrixTypeId(), callId, 0) {} }; - -REGISTER_EVENT_TYPE(CallHangupEvent) } // namespace Quotient diff --git a/lib/events/callinviteevent.h b/lib/events/callinviteevent.h index 5b4ca0df..f96f416d 100644 --- a/lib/events/callinviteevent.h +++ b/lib/events/callinviteevent.h @@ -9,7 +9,7 @@ namespace Quotient { class QUOTIENT_API CallInviteEvent : public CallEventBase { public: - DEFINE_EVENT_TYPEID("m.call.invite", CallInviteEvent) + QUO_EVENT(CallInviteEvent, "m.call.invite") explicit CallInviteEvent(const QJsonObject& obj); @@ -22,6 +22,4 @@ public: return contentPart("offer"_ls).value("sdp"_ls).toString(); } }; - -REGISTER_EVENT_TYPE(CallInviteEvent) } // namespace Quotient diff --git a/lib/events/directchatevent.h b/lib/events/directchatevent.h index 2018d3d6..942edba4 100644 --- a/lib/events/directchatevent.h +++ b/lib/events/directchatevent.h @@ -8,11 +8,10 @@ namespace Quotient { class QUOTIENT_API DirectChatEvent : public Event { public: - DEFINE_EVENT_TYPEID("m.direct", DirectChatEvent) + QUO_EVENT(DirectChatEvent, "m.direct") explicit DirectChatEvent(const QJsonObject& obj) : Event(typeId(), obj) {} QMultiHash usersToDirectChats() const; }; -REGISTER_EVENT_TYPE(DirectChatEvent) } // namespace Quotient diff --git a/lib/events/encryptedevent.h b/lib/events/encryptedevent.h index ddd5e415..22e51cb8 100644 --- a/lib/events/encryptedevent.h +++ b/lib/events/encryptedevent.h @@ -27,7 +27,7 @@ namespace Quotient { */ class QUOTIENT_API EncryptedEvent : public RoomEvent { public: - DEFINE_EVENT_TYPEID("m.room.encrypted", EncryptedEvent) + QUO_EVENT(EncryptedEvent, "m.room.encrypted") /* In case with Olm, the encrypted content of the event is * a map from the recipient Curve25519 identity key to ciphertext @@ -59,6 +59,4 @@ public: void setRelation(const QJsonObject& relation); }; -REGISTER_EVENT_TYPE(EncryptedEvent) - } // namespace Quotient diff --git a/lib/events/encryptionevent.h b/lib/events/encryptionevent.h index 91452c3f..60e77451 100644 --- a/lib/events/encryptionevent.h +++ b/lib/events/encryptionevent.h @@ -28,7 +28,7 @@ public: class QUOTIENT_API EncryptionEvent : public StateEvent { public: - DEFINE_EVENT_TYPEID("m.room.encryption", EncryptionEvent) + QUO_EVENT(EncryptionEvent, "m.room.encryption") using EncryptionType [[deprecated("Use Quotient::EncryptionType instead")]] = @@ -48,5 +48,4 @@ public: bool useEncryption() const { return !algorithm().isEmpty(); } }; -REGISTER_EVENT_TYPE(EncryptionEvent) } // namespace Quotient diff --git a/lib/events/event.cpp b/lib/events/event.cpp index 1f1eebaa..595e20a5 100644 --- a/lib/events/event.cpp +++ b/lib/events/event.cpp @@ -4,6 +4,7 @@ #include "event.h" #include "logging.h" +#include "stateevent.h" #include @@ -11,12 +12,38 @@ using namespace Quotient; QString EventTypeRegistry::getMatrixType(event_type_t typeId) { return typeId; } -void _impl::EventFactoryBase::logAddingMethod(event_type_t TypeId, - size_t newSize) +void AbstractEventMetaType::addDerived(AbstractEventMetaType* newType) { - qDebug(EVENTS) << "Adding factory method for" << TypeId << "events;" - << newSize << "methods will be in the" << name - << "chain"; + if (const auto existing = + std::find_if(derivedTypes.cbegin(), derivedTypes.cend(), + [&newType](const AbstractEventMetaType* t) { + return t->matrixId == newType->matrixId; + }); + existing != derivedTypes.cend()) + { + if (*existing == newType) + return; + // Two different metatype objects claim the same Matrix type id; this + // is not normal, so give as much information as possible to diagnose + if ((*existing)->className == newType->className) { + qCritical(EVENTS) + << newType->className << "claims" << newType->matrixId + << "repeatedly; check that it's exported across translation " + "units or shared objects"; + Q_ASSERT(false); // That situation is plain wrong + return; // So maybe std::terminate() even? + } + qWarning(EVENTS).nospace() + << newType->matrixId << " is already mapped to " + << (*existing)->className << " before " << newType->className + << "; unless the two have different isValid() conditions, the " + "latter class will never be used"; + } + derivedTypes.emplace_back(newType); + qDebug(EVENTS).nospace() + << newType->matrixId << " -> " << newType->className << "; " + << derivedTypes.size() << " derived type(s) registered for " + << className; } Event::Event(Type type, const QJsonObject& json) : _type(type), _json(json) @@ -48,6 +75,10 @@ const QJsonObject Event::unsignedJson() const return fullJson()[UnsignedKeyL].toObject(); } +bool Event::isStateEvent() const { return is(); } + +bool Event::isCallEvent() const { return is(); } + void Event::dumpTo(QDebug dbg) const { dbg << QJsonDocument(contentJson()).toJson(QJsonDocument::Compact); diff --git a/lib/events/event.h b/lib/events/event.h index 711f8fd4..ea827244 100644 --- a/lib/events/event.h +++ b/lib/events/event.h @@ -85,91 +85,167 @@ inline event_ptr_tt makeEvent(ArgTs&&... args) return std::make_unique(std::forward(args)...); } -namespace _impl { - class QUOTIENT_API EventFactoryBase { - public: - EventFactoryBase(const EventFactoryBase&) = delete; - - protected: // This class is only to inherit from - explicit EventFactoryBase(const char* name) - : name(name) - {} - void logAddingMethod(event_type_t TypeId, size_t newSize); - - private: - const char* const name; - }; -} // namespace _impl - -//! \brief A family of event factories to create events from CS API responses -//! -//! Each of these factories, as instantiated by event base types (Event, -//! RoomEvent etc.) is capable of producing an event object derived from -//! \p BaseEventT, using the JSON payload and the event type passed to its -//! make() method. Don't use these directly to make events; use loadEvent() -//! overloads as the frontend for these. Never instantiate new factories -//! outside of base event classes. -//! \sa loadEvent, setupFactory, Event::factory, RoomEvent::factory, -//! StateEventBase::factory -template -class EventFactory : public _impl::EventFactoryBase { -private: - using method_t = event_ptr_tt (*)(const QJsonObject&, - const QString&); - std::vector methods {}; +// === EventMetaType === - template - static event_ptr_tt makeIfMatches(const QJsonObject& json, - const QString& matrixType) +class Event; + +template +bool is(const Event& e); + +//! \brief The base class for event metatypes +//! +//! You should not normally have to use this directly, unless you need to devise +//! a whole new kind of event metatypes. +class QUOTIENT_API AbstractEventMetaType { +public: + // The public fields here are const and are not to be changeable anyway. + // NOLINTBEGIN(misc-non-private-member-variables-in-classes) + const char* const className; + const event_type_t matrixId; + const AbstractEventMetaType* const baseType = nullptr; + // NOLINTEND(misc-non-private-member-variables-in-classes) + + explicit AbstractEventMetaType(const char* className) + : className(className) + {} + explicit AbstractEventMetaType(const char* className, event_type_t matrixId, + AbstractEventMetaType& nearestBase) + : className(className), matrixId(matrixId), baseType(&nearestBase) { - // If your matrix event type is not all ASCII, it's your problem - // (see https://github.com/matrix-org/matrix-doc/pull/2758) - return EventT::TypeId == matrixType ? makeEvent(json) : nullptr; + nearestBase.addDerived(this); } + void addDerived(AbstractEventMetaType *newType); + + virtual ~AbstractEventMetaType() = default; + +protected: + // Allow template specialisations to call into one another + template + friend class EventMetaType; + + // The returned value indicates whether a generic object has to be created + // on the top level when `event` is empty, instead of returning nullptr + virtual bool doLoadFrom(const QJsonObject& fullJson, const QString& type, + Event*& event) const = 0; + +private: + std::vector derivedTypes{}; + Q_DISABLE_COPY_MOVE(AbstractEventMetaType) +}; + +// Any event metatype is unique (note Q_DISABLE_COPY_MOVE above) so can be +// identified by its address +inline bool operator==(const AbstractEventMetaType& lhs, + const AbstractEventMetaType& rhs) +{ + return &lhs == &rhs; +} + +//! \brief A family of event meta-types to load and match events +//! +//! TL;DR for the loadFrom() story: +//! - for base event types, use QUO_BASE_EVENT and, if you have additional +//! validation (e.g., JSON has to contain a certain key - see StateEventBase +//! for a real example), define it in the static EventT::isValid() member +//! function accepting QJsonObject and returning bool. +//! - for leaf (specific) event types - simply use QUO_EVENT and it will do +//! everything necessary, including the TypeId definition. +//! \sa QUO_EVENT, QUO_BASE_EVENT +template +class QUOTIENT_API EventMetaType : public AbstractEventMetaType { + // Above: can't constrain EventT to be EventClass because it's incomplete + // at the point of EventMetaType instantiation. public: - explicit EventFactory(const char* fName) - : EventFactoryBase { fName } - {} + using AbstractEventMetaType::AbstractEventMetaType; - //! \brief Add a method to create events of a given type + //! \brief Try to load an event from JSON, with dynamic type resolution //! - //! Adds a standard factory method (makeIfMatches) for \p EventT so that - //! event objects of this type can be created dynamically by loadEvent. - //! The caller is responsible for ensuring this method is called only - //! once per type. - //! \sa loadEvent, Quotient::loadEvent - template - const auto& addMethod() + //! The generic logic defined in this class template and invoked applies to + //! all event types defined in the library and boils down to the following: + //! 1. + //! a. If EventT has TypeId defined (which normally is a case of + //! all leaf - specific - event types, via QUO_EVENT macro) and + //! \p type doesn't exactly match it, nullptr is immediately returned. + //! b. In absence of TypeId, an event type is assumed to be a base; + //! its derivedTypes are examined, and this algorithm is applied + //! recursively on each. + //! 2. Optional validation: if EventT (or, due to the way inheritance works, + //! any of its base event types) has a static isValid() predicate and + //! the event JSON does not satisfy it, nullptr is immediately returned + //! to the upper level or to the loadFrom() caller. This is how existence + //! of `state_key` is checked in any type derived from StateEventBase. + //! 3. If step 1b above returned non-nullptr, immediately return it. + //! 4. + //! a. If EventT::isValid() or EventT::TypeId (either, or both) exist and + //! are satisfied (see steps 1a and 2 above), an object of this type + //! is created from the passed JSON and returned. In case of a base + //! event type, this will be a generic (aka "unknown") event. + //! b. If neither exists, a generic event is only created and returned + //! when on the top level (i.e., outside of recursion into + //! derivedTypes); lower levels return nullptr instead and the type + //! lookup continues. The latter is a case of a derived base event + //! metatype (e.g. RoomEvent) called from its base event metatype + //! (i.e., Event). If no matching type derived from RoomEvent is found, + //! the nested lookup returns nullptr rather than a generic RoomEvent, + //! so that other types derived from Event could be examined. + event_ptr_tt loadFrom(const QJsonObject& fullJson, + const QString& type) const { - const auto m = &makeIfMatches; - const auto it = std::find(methods.cbegin(), methods.cend(), m); - if (it != methods.cend()) - return *it; - logAddingMethod(EventT::TypeId, methods.size() + 1); - return methods.emplace_back(m); + Event* event = nullptr; + const bool goodEnough = doLoadFrom(fullJson, type, event); + if (!event && goodEnough) + return event_ptr_tt{ makeEvent(fullJson) }; + return event_ptr_tt{ static_cast(event) }; } - auto loadEvent(const QJsonObject& json, const QString& matrixType) +private: + bool doLoadFrom(const QJsonObject& fullJson, const QString& type, + Event*& event) const override + { + if constexpr (requires { EventT::TypeId; }) { + if (EventT::TypeId != type) + return false; + } else { + for (const auto& p : derivedTypes) { + p->doLoadFrom(fullJson, type, event); + if (event) { + Q_ASSERT(is(*event)); + return false; + } + } + } + if constexpr (requires { EventT::isValid; }) { + if (!EventT::isValid(fullJson)) + return false; + } else if constexpr (!requires { EventT::TypeId; }) + return true; // Create a generic event object if on the top level + event = makeEvent(fullJson); + return false; + } + static auto makeEvent(const QJsonObject& fullJson) { - for (const auto& f : methods) - if (auto e = f(json, matrixType)) - return e; - return makeEvent(UnknownEventTypeId, json); + if constexpr (requires { EventT::TypeId; }) + return new EventT(fullJson); + else + return new EventT(UnknownEventTypeId, fullJson); } }; -//! \brief Point of customisation to dynamically load events -//! -//! The default specialisation of this calls BaseEventT::factory.loadEvent() -//! and if that fails (i.e. returns nullptr) creates an unknown event of -//! BaseEventT. Other specialisations may reuse other factories, add validations -//! common to BaseEventT events, and so on. -template -event_ptr_tt doLoadEvent(const QJsonObject& json, - const QString& matrixType) +template +constexpr const auto& mostSpecificMetaType() { - return BaseEventT::factory.loadEvent(json, matrixType); + if constexpr (requires { EventT::MetaType; }) + return EventT::MetaType; + else + return EventT::BaseMetaType; +} + +template +inline event_ptr_tt doLoadEvent(const QJsonObject& json, + const QString& matrixType) +{ + return mostSpecificMetaType().loadFrom(json, matrixType); } // === Event === @@ -177,7 +253,12 @@ event_ptr_tt doLoadEvent(const QJsonObject& json, class QUOTIENT_API Event { public: using Type = event_type_t; - static inline EventFactory factory { "Event" }; + static inline EventMetaType BaseMetaType { "Event" }; + virtual const AbstractEventMetaType& metaType() const + { + return BaseMetaType; + } + explicit Event(Type type, const QJsonObject& json); explicit Event(Type type, event_mtype_t matrixType, @@ -194,8 +275,26 @@ public: return { { TypeKey, matrixType }, { ContentKey, content } }; } - Type type() const { return _type; } + //! \brief Event Matrix type, as identified by its metatype object + //! + //! For generic/unknown events it will contain a descriptive/generic string + //! defined by the respective base event type (that can be empty). + //! \sa matrixType + Type type() const { return metaType().matrixId; } + + //! \brief Exact Matrix type stored in JSON + //! + //! Coincides with the result of type() (but is slower) for events defined + //! in C++ (not necessarily in the library); for generic/unknown events + //! the returned value will be different. QString matrixType() const; + + template + bool is() const + { + return Quotient::is(*this); + } + [[deprecated("Use fullJson() and stringify it with QJsonDocument::toJson() " "or by other means")]] QByteArray originalJson() const; @@ -237,13 +336,17 @@ public: friend QUOTIENT_API QDebug operator<<(QDebug dbg, const Event& e) { QDebugStateSaver _dss { dbg }; - dbg.noquote().nospace() << e.matrixType() << '(' << e.type() << "): "; + dbg.noquote().nospace() + << e.matrixType() << '(' << e.metaType().className << "): "; e.dumpTo(dbg); return dbg; } - virtual bool isStateEvent() const { return false; } - virtual bool isCallEvent() const { return false; } + // State events are quite special in Matrix; so isStateEvent() is here, + // as an exception. For other base events, Event::is<>() and + // Quotient::is<>() should be used; don't add is* methods here + bool isStateEvent() const; + [[deprecated("Use is() instead")]] bool isCallEvent() const; protected: QJsonObject& editJson() { return _json; } @@ -259,11 +362,64 @@ template using EventsArray = std::vector>; using Events = EventsArray; +// === Facilities for event class definitions === + +//! \brief Supply event metatype information in base event types +//! +//! Use this macro in a public section of your base event class to provide +//! type identity and enable dynamic loading of generic events of that type. +//! Do _not_ add this macro if your class is an intermediate wrapper and is not +//! supposed to be instantiated on its own. Provides BaseMetaType static field +//! initialised by parameters passed to the macro, and a metaType() override +//! pointing to that BaseMetaType. +//! \sa EventMetaType, EventMetaType::SuppressLoadDerived +#define QUO_BASE_EVENT(CppType_, ...) \ + static inline EventMetaType BaseMetaType{ \ + #CppType_ __VA_OPT__(,) __VA_ARGS__ }; \ + const AbstractEventMetaType& metaType() const override \ + { \ + return BaseMetaType; \ + } \ + // End of macro + +//! Supply event metatype information in (specific) event types +//! +//! Use this macro in a public section of your event class to provide type +//! identity and enable dynamic loading of generic events of that type. +//! Do _not_ use this macro if your class is an intermediate wrapper and is not +//! supposed to be instantiated on its own. Provides MetaType static field +//! initialised as described below; a metaType() override pointing to it; and +//! the TypeId static field that is equal to MetaType.matrixId. +//! +//! The first two macro parameters are used as the first two EventMetaType +//! constructor parameters; the third EventMetaType parameter is always +//! BaseMetaType; and additional base types can be passed in extra macro +//! parameters if you need to include the same event type in more than one +//! event factory hierarchy (e.g., EncryptedEvent). +//! \sa EventMetaType +#define QUO_EVENT(CppType_, MatrixType_, ...) \ + static inline const auto& TypeId = MatrixType_##_ls; \ + static inline const EventMetaType MetaType{ \ + #CppType_, TypeId, BaseMetaType __VA_OPT__(,) __VA_ARGS__ \ + }; \ + const AbstractEventMetaType& metaType() const override \ + { \ + return MetaType; \ + } \ + [[deprecated("Use " #CppType_ "::TypeId directly instead")]] \ + static constexpr const char* matrixTypeId() { return MatrixType_; } \ + [[deprecated("Use " #CppType_ "::TypeId directly instead")]] \ + static event_type_t typeId() { return TypeId; } \ + // End of macro + +//! \deprecated This is the old name for what is now known as QUO_EVENT +#define DEFINE_EVENT_TYPEID(Type_, Id_) QUO_EVENT(Type_, Id_) + #define QUO_CONTENT_GETTER_X(PartType_, PartName_, JsonKey_) \ - PartType_ PartName_() const \ - { \ - static const auto PartName_##JsonKey = JsonKey_; \ - return contentPart(PartName_##JsonKey); \ + PartType_ PartName_() const \ + { \ + static const auto PartName_##JsonKey = JsonKey_; \ + return contentPart(PartName_##JsonKey); \ } //! \brief Define an inline method obtaining a content part @@ -277,25 +433,9 @@ using Events = EventsArray; #define QUO_CONTENT_GETTER(PartType_, PartName_) \ QUO_CONTENT_GETTER_X(PartType_, PartName_, toSnakeCase(#PartName_##_ls)) -// === Facilities for event class definitions === - -// This macro should be used in a public section of an event class to -// provide matrixTypeId() and typeId(). -#define DEFINE_EVENT_TYPEID(Id_, Type_) \ - static constexpr event_type_t TypeId = Id_##_ls; \ - [[deprecated("Use " #Type_ "::TypeId directly instead")]] \ - static constexpr event_mtype_t matrixTypeId() { return Id_; } \ - [[deprecated("Use " #Type_ "::TypeId directly instead")]] \ - static event_type_t typeId() { return TypeId; } \ - // End of macro - -// This macro should be put after an event class definition (in .h or .cpp) -// to enable its deserialisation from a /sync and other -// polymorphic event arrays -#define REGISTER_EVENT_TYPE(Type_) \ - [[maybe_unused]] inline const auto& factoryMethodFor##Type_ = \ - Type_::factory.addMethod(); \ - // End of macro +//! \deprecated This macro was used after an event class definition +//! to enable its dynamic loading; it is completely superseded by QUO_EVENT +#define REGISTER_EVENT_TYPE(Type_) /// \brief Define a new event class with a single key-value pair in the content /// @@ -309,7 +449,7 @@ using Events = EventsArray; JsonKey_) \ class QUOTIENT_API Name_ : public Base_ { \ public: \ - DEFINE_EVENT_TYPEID(TypeId_, Name_) \ + QUO_EVENT(Name_, TypeId_) \ using value_type = ValueType_; \ explicit Name_(const QJsonObject& obj) : Base_(TypeId, obj) {} \ explicit Name_(const value_type& v) \ @@ -318,7 +458,6 @@ using Events = EventsArray; QUO_CONTENT_GETTER_X(ValueType_, GetterName_, JsonKey) \ static inline const auto JsonKey = toSnakeCase(#GetterName_##_ls); \ }; \ - REGISTER_EVENT_TYPE(Name_) \ // End of macro // === is<>(), eventCast<>() and switchOnType<>() === @@ -326,12 +465,16 @@ using Events = EventsArray; template inline bool is(const Event& e) { - return e.type() == typeId(); -} - -inline bool isUnknown(const Event& e) -{ - return e.type() == UnknownEventTypeId; + if constexpr (requires { EventT::MetaType; }) { + return &e.metaType() == &EventT::MetaType; + } else { + const auto* p = &e.metaType(); + do { + if (p == &EventT::BaseMetaType) + return true; + } while ((p = p->baseType) != nullptr); + return false; + } } //! \brief Cast the event pointer down in a type-safe way diff --git a/lib/events/keyverificationevent.h b/lib/events/keyverificationevent.h index 5b587522..5b5a518f 100644 --- a/lib/events/keyverificationevent.h +++ b/lib/events/keyverificationevent.h @@ -13,7 +13,7 @@ static constexpr auto SasV1Method = "m.sas.v1"_ls; /// Typically sent as a to-device event. class QUOTIENT_API KeyVerificationRequestEvent : public Event { public: - DEFINE_EVENT_TYPEID("m.key.verification.request", KeyVerificationRequestEvent) + QUO_EVENT(KeyVerificationRequestEvent, "m.key.verification.request") explicit KeyVerificationRequestEvent(const QJsonObject& obj) : Event(TypeId, obj) @@ -45,11 +45,10 @@ public: /// by the receiver. QUO_CONTENT_GETTER(QDateTime, timestamp) }; -REGISTER_EVENT_TYPE(KeyVerificationRequestEvent) class QUOTIENT_API KeyVerificationReadyEvent : public Event { public: - DEFINE_EVENT_TYPEID("m.key.verification.ready", KeyVerificationReadyEvent) + QUO_EVENT(KeyVerificationReadyEvent, "m.key.verification.ready") explicit KeyVerificationReadyEvent(const QJsonObject& obj) : Event(TypeId, obj) @@ -72,13 +71,11 @@ public: /// The verification methods supported by the sender. QUO_CONTENT_GETTER(QStringList, methods) }; -REGISTER_EVENT_TYPE(KeyVerificationReadyEvent) - /// Begins a key verification process. class QUOTIENT_API KeyVerificationStartEvent : public Event { public: - DEFINE_EVENT_TYPEID("m.key.verification.start", KeyVerificationStartEvent) + QUO_EVENT(KeyVerificationStartEvent, "m.key.verification.start") explicit KeyVerificationStartEvent(const QJsonObject& obj) : Event(TypeId, obj) @@ -146,13 +143,12 @@ public: return contentPart("short_authentification_string"_ls); } }; -REGISTER_EVENT_TYPE(KeyVerificationStartEvent) /// Accepts a previously sent m.key.verification.start message. /// Typically sent as a to-device event. class QUOTIENT_API KeyVerificationAcceptEvent : public Event { public: - DEFINE_EVENT_TYPEID("m.key.verification.accept", KeyVerificationAcceptEvent) + QUO_EVENT(KeyVerificationAcceptEvent, "m.key.verification.accept") explicit KeyVerificationAcceptEvent(const QJsonObject& obj) : Event(TypeId, obj) @@ -199,11 +195,10 @@ public: /// canonical JSON representation of the m.key.verification.start message. QUO_CONTENT_GETTER(QString, commitment) }; -REGISTER_EVENT_TYPE(KeyVerificationAcceptEvent) class QUOTIENT_API KeyVerificationCancelEvent : public Event { public: - DEFINE_EVENT_TYPEID("m.key.verification.cancel", KeyVerificationCancelEvent) + QUO_EVENT(KeyVerificationCancelEvent, "m.key.verification.cancel") explicit KeyVerificationCancelEvent(const QJsonObject& obj) : Event(TypeId, obj) @@ -228,13 +223,12 @@ public: /// The error code for why the process/request was cancelled by the user. QUO_CONTENT_GETTER(QString, code) }; -REGISTER_EVENT_TYPE(KeyVerificationCancelEvent) /// Sends the ephemeral public key for a device to the partner device. /// Typically sent as a to-device event. class QUOTIENT_API KeyVerificationKeyEvent : public Event { public: - DEFINE_EVENT_TYPEID("m.key.verification.key", KeyVerificationKeyEvent) + QUO_EVENT(KeyVerificationKeyEvent, "m.key.verification.key") explicit KeyVerificationKeyEvent(const QJsonObject& obj) : Event(TypeId, obj) @@ -251,12 +245,11 @@ public: /// The device's ephemeral public key, encoded as unpadded base64. QUO_CONTENT_GETTER(QString, key) }; -REGISTER_EVENT_TYPE(KeyVerificationKeyEvent) /// Sends the MAC of a device's key to the partner device. class QUOTIENT_API KeyVerificationMacEvent : public Event { public: - DEFINE_EVENT_TYPEID("m.key.verification.mac", KeyVerificationMacEvent) + QUO_EVENT(KeyVerificationMacEvent, "m.key.verification.mac") explicit KeyVerificationMacEvent(const QJsonObject& obj) : Event(TypeId, obj) @@ -280,11 +273,10 @@ public: return contentPart>("mac"_ls); } }; -REGISTER_EVENT_TYPE(KeyVerificationMacEvent) class QUOTIENT_API KeyVerificationDoneEvent : public Event { public: - DEFINE_EVENT_TYPEID("m.key.verification.done", KeyVerificationDoneEvent) + QUO_EVENT(KeyVerificationDoneEvent, "m.key.verification.done") explicit KeyVerificationDoneEvent(const QJsonObject& obj) : Event(TypeId, obj) @@ -297,6 +289,4 @@ public: /// The same transactionId as before QUO_CONTENT_GETTER(QString, transactionId) }; -REGISTER_EVENT_TYPE(KeyVerificationDoneEvent) - } // namespace Quotient diff --git a/lib/events/receiptevent.h b/lib/events/receiptevent.h index 5e077e47..a02f4592 100644 --- a/lib/events/receiptevent.h +++ b/lib/events/receiptevent.h @@ -21,11 +21,10 @@ using EventsWithReceipts = QVector; class QUOTIENT_API ReceiptEvent : public Event { public: - DEFINE_EVENT_TYPEID("m.receipt", ReceiptEvent) + QUO_EVENT(ReceiptEvent, "m.receipt") explicit ReceiptEvent(const EventsWithReceipts& ewrs); explicit ReceiptEvent(const QJsonObject& obj) : Event(typeId(), obj) {} EventsWithReceipts eventsWithReceipts() const; }; -REGISTER_EVENT_TYPE(ReceiptEvent) } // namespace Quotient diff --git a/lib/events/redactionevent.h b/lib/events/redactionevent.h index 63617e54..c193054a 100644 --- a/lib/events/redactionevent.h +++ b/lib/events/redactionevent.h @@ -8,7 +8,7 @@ namespace Quotient { class QUOTIENT_API RedactionEvent : public RoomEvent { public: - DEFINE_EVENT_TYPEID("m.room.redaction", RedactionEvent) + QUO_EVENT(RedactionEvent, "m.room.redaction") explicit RedactionEvent(const QJsonObject& obj) : RoomEvent(typeId(), obj) {} @@ -19,5 +19,4 @@ public: } QUO_CONTENT_GETTER(QString, reason) }; -REGISTER_EVENT_TYPE(RedactionEvent) } // namespace Quotient diff --git a/lib/events/roomavatarevent.h b/lib/events/roomavatarevent.h index af291696..2ebe29bf 100644 --- a/lib/events/roomavatarevent.h +++ b/lib/events/roomavatarevent.h @@ -14,7 +14,7 @@ class QUOTIENT_API RoomAvatarEvent // without a thumbnail. But The Spec says there be thumbnails, and // we follow The Spec. public: - DEFINE_EVENT_TYPEID("m.room.avatar", RoomAvatarEvent) + QUO_EVENT(RoomAvatarEvent, "m.room.avatar") explicit RoomAvatarEvent(const QJsonObject& obj) : StateEvent(typeId(), obj) {} explicit RoomAvatarEvent(const EventContent::ImageContent& avatar) @@ -31,5 +31,4 @@ public: QUrl url() const { return content().url(); } }; -REGISTER_EVENT_TYPE(RoomAvatarEvent) } // namespace Quotient diff --git a/lib/events/roomcanonicalaliasevent.h b/lib/events/roomcanonicalaliasevent.h index 60ca68ac..e1c7888e 100644 --- a/lib/events/roomcanonicalaliasevent.h +++ b/lib/events/roomcanonicalaliasevent.h @@ -34,7 +34,7 @@ inline auto toJson(const EventContent::AliasesEventContent& c) class QUOTIENT_API RoomCanonicalAliasEvent : public StateEvent { public: - DEFINE_EVENT_TYPEID("m.room.canonical_alias", RoomCanonicalAliasEvent) + QUO_EVENT(RoomCanonicalAliasEvent, "m.room.canonical_alias") explicit RoomCanonicalAliasEvent(const QJsonObject& obj) : StateEvent(typeId(), obj) @@ -55,5 +55,4 @@ public: QString alias() const { return content().canonicalAlias; } QStringList altAliases() const { return content().altAliases; } }; -REGISTER_EVENT_TYPE(RoomCanonicalAliasEvent) } // namespace Quotient diff --git a/lib/events/roomcreateevent.h b/lib/events/roomcreateevent.h index 989030ac..f22752b4 100644 --- a/lib/events/roomcreateevent.h +++ b/lib/events/roomcreateevent.h @@ -9,7 +9,7 @@ namespace Quotient { class QUOTIENT_API RoomCreateEvent : public StateEventBase { public: - DEFINE_EVENT_TYPEID("m.room.create", RoomCreateEvent) + QUO_EVENT(RoomCreateEvent, "m.room.create") explicit RoomCreateEvent(const QJsonObject& obj) : StateEventBase(typeId(), obj) @@ -26,5 +26,4 @@ public: bool isUpgrade() const; RoomType roomType() const; }; -REGISTER_EVENT_TYPE(RoomCreateEvent) } // namespace Quotient diff --git a/lib/events/roomevent.h b/lib/events/roomevent.h index 9461340b..532e72e2 100644 --- a/lib/events/roomevent.h +++ b/lib/events/roomevent.h @@ -10,10 +10,11 @@ namespace Quotient { class RedactionEvent; -/** This class corresponds to m.room.* events */ +// That check could look into Event and find most stuff already deleted... +// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) class QUOTIENT_API RoomEvent : public Event { public: - static inline EventFactory factory { "RoomEvent" }; + QUO_BASE_EVENT(RoomEvent, {}, Event::BaseMetaType) // RedactionEvent is an incomplete type here so we cannot inline // constructors and destructors and we cannot use 'using'. @@ -80,21 +81,14 @@ using RoomEventPtr = event_ptr_tt; using RoomEvents = EventsArray; using RoomEventsRange = Range; -template <> -inline EventPtr doLoadEvent(const QJsonObject& json, const QString& matrixType) -{ - if (matrixType == "m.room.encrypted") - return RoomEvent::factory.loadEvent(json, matrixType); - return Event::factory.loadEvent(json, matrixType); -} - class QUOTIENT_API CallEventBase : public RoomEvent { public: + QUO_BASE_EVENT(CallEventBase, "m.call.*"_ls, RoomEvent::BaseMetaType) + CallEventBase(Type type, event_mtype_t matrixType, const QString& callId, int version, const QJsonObject& contentJson = {}); CallEventBase(Type type, const QJsonObject& json); ~CallEventBase() override = default; - bool isCallEvent() const override { return true; } QUO_CONTENT_GETTER(QString, callId) QUO_CONTENT_GETTER(int, version) diff --git a/lib/events/roomkeyevent.h b/lib/events/roomkeyevent.h index 0dfdf383..6883a2a5 100644 --- a/lib/events/roomkeyevent.h +++ b/lib/events/roomkeyevent.h @@ -9,7 +9,7 @@ namespace Quotient { class QUOTIENT_API RoomKeyEvent : public Event { public: - DEFINE_EVENT_TYPEID("m.room_key", RoomKeyEvent) + QUO_EVENT(RoomKeyEvent, "m.room_key") explicit RoomKeyEvent(const QJsonObject& obj); explicit RoomKeyEvent(const QString& algorithm, const QString& roomId, @@ -23,5 +23,4 @@ public: return contentPart("session_key"_ls).toLatin1(); } }; -REGISTER_EVENT_TYPE(RoomKeyEvent) } // namespace Quotient diff --git a/lib/events/roommemberevent.h b/lib/events/roommemberevent.h index dd33ea6b..c690586e 100644 --- a/lib/events/roommemberevent.h +++ b/lib/events/roommemberevent.h @@ -31,7 +31,7 @@ using MembershipType [[deprecated("Use Membership instead")]] = Membership; class QUOTIENT_API RoomMemberEvent : public StateEvent { Q_GADGET public: - DEFINE_EVENT_TYPEID("m.room.member", RoomMemberEvent) + QUO_EVENT(RoomMemberEvent, "m.room.member") using MembershipType [[deprecated("Use Quotient::Membership instead")]] = Membership; @@ -79,14 +79,4 @@ public: bool isRename() const; bool isAvatarUpdate() const; }; - -template <> -inline event_ptr_tt -doLoadEvent(const QJsonObject& json, const QString& matrixType) -{ - if (matrixType == QLatin1String(RoomMemberEvent::matrixTypeId())) - return makeEvent(json); - return makeEvent(unknownEventTypeId(), json); -} -REGISTER_EVENT_TYPE(RoomMemberEvent) } // namespace Quotient diff --git a/lib/events/roommessageevent.h b/lib/events/roommessageevent.h index 6968ad70..889fc4dc 100644 --- a/lib/events/roommessageevent.h +++ b/lib/events/roommessageevent.h @@ -20,7 +20,7 @@ namespace MessageEventContent = EventContent; // Back-compatibility class QUOTIENT_API RoomMessageEvent : public RoomEvent { Q_GADGET public: - DEFINE_EVENT_TYPEID("m.room.message", RoomMessageEvent) + QUO_EVENT(RoomMessageEvent, "m.room.message") enum class MsgType { Text, @@ -94,7 +94,7 @@ private: Q_ENUM(MsgType) }; -REGISTER_EVENT_TYPE(RoomMessageEvent) + using MessageEventType = RoomMessageEvent::MsgType; namespace EventContent { diff --git a/lib/events/roompowerlevelsevent.h b/lib/events/roompowerlevelsevent.h index a1638a27..7ac12db0 100644 --- a/lib/events/roompowerlevelsevent.h +++ b/lib/events/roompowerlevelsevent.h @@ -33,7 +33,7 @@ struct QUOTIENT_API PowerLevelsEventContent { class QUOTIENT_API RoomPowerLevelsEvent : public StateEvent { public: - DEFINE_EVENT_TYPEID("m.room.power_levels", RoomPowerLevelsEvent) + QUO_EVENT(RoomPowerLevelsEvent, "m.room.power_levels") explicit RoomPowerLevelsEvent(PowerLevelsEventContent&& content) : StateEvent(typeId(), matrixTypeId(), QString(), std::move(content)) @@ -61,5 +61,4 @@ public: int powerLevelForState(const QString& eventId) const; int powerLevelForUser(const QString& userId) const; }; -REGISTER_EVENT_TYPE(RoomPowerLevelsEvent) } // namespace Quotient diff --git a/lib/events/roomtombstoneevent.h b/lib/events/roomtombstoneevent.h index 15d26923..97586587 100644 --- a/lib/events/roomtombstoneevent.h +++ b/lib/events/roomtombstoneevent.h @@ -8,7 +8,7 @@ namespace Quotient { class QUOTIENT_API RoomTombstoneEvent : public StateEventBase { public: - DEFINE_EVENT_TYPEID("m.room.tombstone", RoomTombstoneEvent) + QUO_EVENT(RoomTombstoneEvent, "m.room.tombstone") explicit RoomTombstoneEvent(const QJsonObject& obj) : StateEventBase(typeId(), obj) @@ -17,5 +17,4 @@ public: QString serverMessage() const; QString successorRoomId() const; }; -REGISTER_EVENT_TYPE(RoomTombstoneEvent) } // namespace Quotient diff --git a/lib/events/simplestateevents.h b/lib/events/simplestateevents.h index a8eaab56..c79d03b0 100644 --- a/lib/events/simplestateevents.h +++ b/lib/events/simplestateevents.h @@ -14,7 +14,7 @@ namespace Quotient { EventContent::SingleKeyValue<_ValueType, &_Name##Key>> { \ public: \ using value_type = _ValueType; \ - DEFINE_EVENT_TYPEID(_TypeId, _Name) \ + QUO_EVENT(_Name, _TypeId) \ template \ explicit _Name(T&& value) \ : StateEvent(TypeId, matrixTypeId(), QString(), \ @@ -25,7 +25,6 @@ namespace Quotient { {} \ auto _ContentKey() const { return content().value; } \ }; \ - REGISTER_EVENT_TYPE(_Name) \ // End of macro DEFINE_SIMPLE_STATE_EVENT(RoomNameEvent, "m.room.name", QString, name) @@ -38,7 +37,7 @@ class QUOTIENT_API RoomAliasesEvent : public StateEvent< EventContent::SingleKeyValue> { public: - DEFINE_EVENT_TYPEID("m.room.aliases", RoomAliasesEvent) + QUO_EVENT(RoomAliasesEvent, "m.room.aliases") explicit RoomAliasesEvent(const QJsonObject& obj) : StateEvent(typeId(), obj) {} diff --git a/lib/events/stateevent.h b/lib/events/stateevent.h index 9f1d7118..74876803 100644 --- a/lib/events/stateevent.h +++ b/lib/events/stateevent.h @@ -9,7 +9,12 @@ namespace Quotient { class QUOTIENT_API StateEventBase : public RoomEvent { public: - static inline EventFactory factory { "StateEvent" }; + QUO_BASE_EVENT(StateEventBase, "json.contains('state_key')"_ls, + RoomEvent::BaseMetaType) + static bool isValid(const QJsonObject& fullJson) + { + return fullJson.contains(StateKeyKeyL); + } StateEventBase(Type type, const QJsonObject& json); StateEventBase(Type type, event_mtype_t matrixType, @@ -27,7 +32,6 @@ public: { ContentKey, contentJson } }; } - bool isStateEvent() const override { return true; } QString replacedState() const; void dumpTo(QDebug dbg) const override; @@ -44,28 +48,6 @@ inline QJsonObject basicStateEventJson(const QString& matrixTypeId, return StateEventBase::basicJson(matrixTypeId, stateKey, content); } -//! \brief Override RoomEvent factory with that from StateEventBase if JSON has -//! stateKey -//! -//! This means in particular that an event with a type known to RoomEvent but -//! having stateKey set (even to an empty value) will be treated as a state -//! event and most likely end up as unknown (consider, e.g., m.room.message -//! that has stateKey set). -template <> -inline RoomEventPtr doLoadEvent(const QJsonObject& json, - const QString& matrixType) -{ - if (json.contains(StateKeyKeyL)) - return StateEventBase::factory.loadEvent(json, matrixType); - return RoomEvent::factory.loadEvent(json, matrixType); -} - -template <> -inline bool is(const Event& e) -{ - return e.isStateEvent(); -} - /** * A combination of event type and state key uniquely identifies a piece * of state in Matrix. diff --git a/lib/events/stickerevent.h b/lib/events/stickerevent.h index e378422d..67905481 100644 --- a/lib/events/stickerevent.h +++ b/lib/events/stickerevent.h @@ -14,7 +14,7 @@ namespace Quotient { class QUOTIENT_API StickerEvent : public RoomEvent { public: - DEFINE_EVENT_TYPEID("m.sticker", StickerEvent) + QUO_EVENT(StickerEvent, "m.sticker") explicit StickerEvent(const QJsonObject& obj) : RoomEvent(TypeId, obj) @@ -45,5 +45,4 @@ public: private: EventContent::ImageContent m_imageContent; }; -REGISTER_EVENT_TYPE(StickerEvent) } // namespace Quotient -- cgit v1.2.3