diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/connection.cpp | 6 | ||||
-rw-r--r-- | lib/connection.h | 4 | ||||
-rw-r--r-- | lib/events/event.cpp | 23 | ||||
-rw-r--r-- | lib/events/event.h | 86 | ||||
-rw-r--r-- | lib/jobs/generated/message_pagination.cpp | 76 | ||||
-rw-r--r-- | lib/jobs/generated/message_pagination.h | 40 | ||||
-rw-r--r-- | lib/jobs/roommessagesjob.cpp | 65 | ||||
-rw-r--r-- | lib/jobs/roommessagesjob.h | 47 | ||||
-rw-r--r-- | lib/jobs/syncjob.cpp | 43 | ||||
-rw-r--r-- | lib/jobs/syncjob.h | 27 | ||||
-rw-r--r-- | lib/room.cpp | 200 | ||||
-rw-r--r-- | lib/room.h | 11 | ||||
-rw-r--r-- | lib/user.cpp | 23 | ||||
-rw-r--r-- | lib/user.h | 3 | ||||
-rw-r--r-- | lib/util.h | 31 |
15 files changed, 330 insertions, 355 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp index adeb7929..b433ccbc 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -30,7 +30,6 @@ #include "jobs/generated/account-data.h" #include "jobs/sendeventjob.h" #include "jobs/joinroomjob.h" -#include "jobs/roommessagesjob.h" #include "jobs/syncjob.h" #include "jobs/mediathumbnailjob.h" #include "jobs/downloadfilejob.h" @@ -372,11 +371,6 @@ void Connection::leaveRoom(Room* room) callApi<LeaveRoomJob>(room->id()); } -RoomMessagesJob* Connection::getMessages(Room* room, const QString& from) const -{ - return callApi<RoomMessagesJob>(room->id(), from); -} - inline auto splitMediaId(const QString& mediaId) { auto idParts = mediaId.split('/'); diff --git a/lib/connection.h b/lib/connection.h index 839371ef..22f71eac 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -331,9 +331,7 @@ namespace QMatrixClient RoomEvent* event) const; /** @deprecated Use callApi<LeaveRoomJob>() or Room::leaveRoom() instead */ virtual void leaveRoom( Room* room ); - /** @deprecated User callApi<RoomMessagesJob>() or Room::getPreviousContent() instead */ - virtual RoomMessagesJob* getMessages(Room* room, - const QString& from) const; + signals: /** * @deprecated diff --git a/lib/events/event.cpp b/lib/events/event.cpp index 193250de..57049671 100644 --- a/lib/events/event.cpp +++ b/lib/events/event.cpp @@ -160,14 +160,13 @@ void RoomEvent::addId(const QString& id) template <> RoomEventPtr _impl::doMakeEvent(const QJsonObject& obj) { - return RoomEventPtr { makeIfMatches<RoomEvent, - RoomMessageEvent, RoomNameEvent, RoomAliasesEvent, - RoomCanonicalAliasEvent, RoomMemberEvent, RoomTopicEvent, - RoomAvatarEvent, EncryptionEvent, RedactionEvent> - (obj, obj["type"].toString()) }; -} + // Check more specific event types first + if (auto e = doMakeEvent<StateEventBase>(obj)) + return e; -StateEventBase::~StateEventBase() = default; + return makeIfMatches<RoomEvent, + RoomMessageEvent, RedactionEvent>(obj, obj["type"].toString()); +} bool StateEventBase::repeatsState() const { @@ -176,3 +175,13 @@ bool StateEventBase::repeatsState() const .toObject().value("prev_content"); return contentJson == prevContentJson; } + +template<> +StateEventPtr _impl::doMakeEvent<StateEventBase>(const QJsonObject& obj) +{ + return makeIfMatches<StateEventBase, + RoomNameEvent, RoomAliasesEvent, + RoomCanonicalAliasEvent, RoomMemberEvent, RoomTopicEvent, + RoomAvatarEvent, EncryptionEvent>(obj, obj["type"].toString()); + +} diff --git a/lib/events/event.h b/lib/events/event.h index 396406f1..8449c2ec 100644 --- a/lib/events/event.h +++ b/lib/events/event.h @@ -53,7 +53,10 @@ namespace QMatrixClient } template <typename EventT> - event_ptr_tt<EventT> doMakeEvent(const QJsonObject& obj); + inline event_ptr_tt<EventT> doMakeEvent(const QJsonObject& obj) + { + return create<EventT>(obj); + } } class Event @@ -114,7 +117,7 @@ namespace QMatrixClient * parameter type) and create an event object of that type. */ template <typename EventT> - event_ptr_tt<EventT> makeEvent(const QJsonObject& obj) + inline event_ptr_tt<EventT> makeEvent(const QJsonObject& obj) { auto e = _impl::doMakeEvent<EventT>(obj); if (!e) @@ -128,50 +131,17 @@ namespace QMatrixClient EventPtr doMakeEvent<Event>(const QJsonObject& obj); } - template <> struct FromJson<EventPtr> + template <typename EventT> struct FromJson<event_ptr_tt<EventT>> { - EventPtr operator()(const QJsonValue& jv) const + auto operator()(const QJsonValue& jv) const { - return makeEvent<Event>(jv.toObject()); + return makeEvent<EventT>(jv.toObject()); } }; - /** - * \brief A vector of pointers to events with deserialisation capabilities - * - * This is a simple wrapper over a generic vector type that adds - * a convenience method to deserialise events from QJsonArray. - * \tparam EventT base type of all events in the vector - */ template <typename EventT> - class EventsBatch : public std::vector<event_ptr_tt<EventT>> - { - public: - /** - * \brief Deserialise events from an array - * - * Given the following JSON construct, creates events from - * the array stored at key "node": - * \code - * "container": { - * "node": [ { "event_id": "!evt1:srv.org", ... }, ... ] - * } - * \endcode - * \param container - the wrapping JSON object - * \param node - the key in container that holds the array of events - */ - void fromJson(const QJsonObject& container, const QString& node) - { - const auto objs = container.value(node).toArray(); - using size_type = typename std::vector<event_ptr_tt<EventT>>::size_type; - // The below line accommodates the difference in size types of - // STL and Qt containers. - this->reserve(static_cast<size_type>(objs.size())); - for (const auto& objValue: objs) - this->emplace_back(makeEvent<EventT>(objValue.toObject())); - } - }; - using Events = EventsBatch<Event>; + using EventsArray = std::vector<event_ptr_tt<EventT>>; + using Events = EventsArray<Event>; class RedactionEvent; @@ -231,8 +201,9 @@ namespace QMatrixClient event_ptr_tt<RedactionEvent> _redactedBecause; QString _txnId; }; - using RoomEvents = EventsBatch<RoomEvent>; using RoomEventPtr = event_ptr_tt<RoomEvent>; + using RoomEvents = EventsArray<RoomEvent>; + using RoomEventsRange = Range<RoomEvents>; namespace _impl { @@ -240,29 +211,6 @@ namespace QMatrixClient RoomEventPtr doMakeEvent<RoomEvent>(const QJsonObject& obj); } - /** - * Conceptually similar to QStringView (but much more primitive), it's a - * simple abstraction over a pair of RoomEvents::const_iterator values - * referring to the beginning and the end of a range in a RoomEvents - * container. - */ - struct RoomEventsRange - { - RoomEvents::iterator from; - RoomEvents::iterator to; - - RoomEvents::size_type size() const - { - Q_ASSERT(std::distance(from, to) >= 0); - return RoomEvents::size_type(std::distance(from, to)); - } - bool empty() const { return from == to; } - RoomEvents::const_iterator begin() const { return from; } - RoomEvents::const_iterator end() const { return to; } - RoomEvents::iterator begin() { return from; } - RoomEvents::iterator end() { return to; } - }; - class StateEventBase: public RoomEvent { public: @@ -273,10 +221,18 @@ namespace QMatrixClient explicit StateEventBase(Type type) : RoomEvent(type) { } - ~StateEventBase() override = 0; + ~StateEventBase() override = default; virtual bool repeatsState() const; }; + using StateEventPtr = event_ptr_tt<StateEventBase>; + using StateEvents = EventsArray<StateEventBase>; + + namespace _impl + { + template <> + StateEventPtr doMakeEvent<StateEventBase>(const QJsonObject& obj); + } template <typename ContentT> struct Prev diff --git a/lib/jobs/generated/message_pagination.cpp b/lib/jobs/generated/message_pagination.cpp new file mode 100644 index 00000000..f89ccd03 --- /dev/null +++ b/lib/jobs/generated/message_pagination.cpp @@ -0,0 +1,76 @@ +/****************************************************************************** + * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN + */ + +#include "message_pagination.h" + +#include "converters.h" + +#include <QtCore/QStringBuilder> + +using namespace QMatrixClient; + +static const auto basePath = QStringLiteral("/_matrix/client/r0"); + +class GetRoomEventsJob::Private +{ + public: + QString begin; + QString end; + RoomEvents chunk; +}; + +BaseJob::Query queryToGetRoomEvents(const QString& from, const QString& to, const QString& dir, int limit, const QString& filter) +{ + BaseJob::Query _q; + _q.addQueryItem("from", from); + if (!to.isEmpty()) + _q.addQueryItem("to", to); + _q.addQueryItem("dir", dir); + _q.addQueryItem("limit", QString("%1").arg(limit)); + if (!filter.isEmpty()) + _q.addQueryItem("filter", filter); + return _q; +} + +QUrl GetRoomEventsJob::makeRequestUrl(QUrl baseUrl, const QString& roomId, const QString& from, const QString& dir, const QString& to, int limit, const QString& filter) +{ + return BaseJob::makeRequestUrl(std::move(baseUrl), + basePath % "/rooms/" % roomId % "/messages", + queryToGetRoomEvents(from, to, dir, limit, filter)); +} + +GetRoomEventsJob::GetRoomEventsJob(const QString& roomId, const QString& from, const QString& dir, const QString& to, int limit, const QString& filter) + : BaseJob(HttpVerb::Get, "GetRoomEventsJob", + basePath % "/rooms/" % roomId % "/messages", + queryToGetRoomEvents(from, to, dir, limit, filter)) + , d(new Private) +{ +} + +GetRoomEventsJob::~GetRoomEventsJob() = default; + +const QString& GetRoomEventsJob::begin() const +{ + return d->begin; +} + +const QString& GetRoomEventsJob::end() const +{ + return d->end; +} + +RoomEvents&& GetRoomEventsJob::chunk() +{ + return std::move(d->chunk); +} + +BaseJob::Status GetRoomEventsJob::parseJson(const QJsonDocument& data) +{ + auto json = data.object(); + d->begin = fromJson<QString>(json.value("start")); + d->end = fromJson<QString>(json.value("end")); + d->chunk = fromJson<RoomEvents>(json.value("chunk")); + return Success; +} + diff --git a/lib/jobs/generated/message_pagination.h b/lib/jobs/generated/message_pagination.h new file mode 100644 index 00000000..b8588ad1 --- /dev/null +++ b/lib/jobs/generated/message_pagination.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN + */ + +#pragma once + +#include "../basejob.h" + +#include "events/event.h" + + +namespace QMatrixClient +{ + // Operations + + class GetRoomEventsJob : public BaseJob + { + public: + /** Construct a URL out of baseUrl and usual parameters passed to + * GetRoomEventsJob. This function can be used when + * a URL for GetRoomEventsJob is necessary but the job + * itself isn't. + */ + static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId, const QString& from, const QString& dir, const QString& to = {}, int limit = {}, const QString& filter = {}); + + explicit GetRoomEventsJob(const QString& roomId, const QString& from, const QString& dir, const QString& to = {}, int limit = {}, const QString& filter = {}); + ~GetRoomEventsJob() override; + + const QString& begin() const; + const QString& end() const; + RoomEvents&& chunk(); + + protected: + Status parseJson(const QJsonDocument& data) override; + + private: + class Private; + QScopedPointer<Private> d; + }; +} // namespace QMatrixClient diff --git a/lib/jobs/roommessagesjob.cpp b/lib/jobs/roommessagesjob.cpp deleted file mode 100644 index e5568f17..00000000 --- a/lib/jobs/roommessagesjob.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2016 Felix Rohrbach <kde@fxrh.de> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "roommessagesjob.h" - -using namespace QMatrixClient; - -class RoomMessagesJob::Private -{ - public: - RoomEvents events; - QString end; -}; - -RoomMessagesJob::RoomMessagesJob(const QString& roomId, const QString& from, - int limit, FetchDirection dir) - : BaseJob(HttpVerb::Get, "RoomMessagesJob", - QStringLiteral("/_matrix/client/r0/rooms/%1/messages").arg(roomId), - Query( - { { "from", from } - , { "dir", dir == FetchDirection::Backward ? "b" : "f" } - , { "limit", QString::number(limit) } - })) - , d(new Private) -{ - qCDebug(JOBS) << "Room messages query:" << query().toString(QUrl::PrettyDecoded); -} - -RoomMessagesJob::~RoomMessagesJob() -{ - delete d; -} - -RoomEvents&& RoomMessagesJob::releaseEvents() -{ - return move(d->events); -} - -QString RoomMessagesJob::end() const -{ - return d->end; -} - -BaseJob::Status RoomMessagesJob::parseJson(const QJsonDocument& data) -{ - const auto obj = data.object(); - d->events.fromJson(obj, "chunk"); - d->end = obj.value("end").toString(); - return Success; -} diff --git a/lib/jobs/roommessagesjob.h b/lib/jobs/roommessagesjob.h deleted file mode 100644 index 7b3fd9c9..00000000 --- a/lib/jobs/roommessagesjob.h +++ /dev/null @@ -1,47 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2016 Felix Rohrbach <kde@fxrh.de> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#pragma once - -#include "basejob.h" - -#include "../events/event.h" - -namespace QMatrixClient -{ - enum class FetchDirection { Backward, Forward }; - - class RoomMessagesJob: public BaseJob - { - public: - RoomMessagesJob(const QString& roomId, const QString& from, - int limit = 10, - FetchDirection dir = FetchDirection::Backward); - virtual ~RoomMessagesJob(); - - RoomEvents&& releaseEvents(); - QString end() const; - - protected: - Status parseJson(const QJsonDocument& data) override; - - private: - class Private; - Private* d; - }; -} // namespace QMatrixClient diff --git a/lib/jobs/syncjob.cpp b/lib/jobs/syncjob.cpp index 435dfd0e..a739ea0d 100644 --- a/lib/jobs/syncjob.cpp +++ b/lib/jobs/syncjob.cpp @@ -54,11 +54,17 @@ SyncDataList&& SyncData::takeRoomData() return std::move(roomData); } -SyncBatch<Event>&& SyncData::takeAccountData() +Events&& SyncData::takeAccountData() { return std::move(accountData); } +template <typename EventsArrayT, typename StrT> +inline EventsArrayT load(const QJsonObject& batches, StrT keyName) +{ + return fromJson<EventsArrayT>(batches[keyName].toObject().value("events")); +} + BaseJob::Status SyncJob::parseJson(const QJsonDocument& data) { return d.parseJson(data); @@ -71,7 +77,7 @@ BaseJob::Status SyncData::parseJson(const QJsonDocument &data) auto json = data.object(); nextBatch_ = json.value("next_batch").toString(); // TODO: presence - accountData.fromJson(json); + accountData = load<Events>(json, "account_data"); QJsonObject rooms = json.value("rooms").toObject(); JoinStates::Int ii = 1; // ii is used to make a JoinState value @@ -96,33 +102,26 @@ SyncRoomData::SyncRoomData(const QString& roomId_, JoinState joinState_, const QJsonObject& room_) : roomId(roomId_) , joinState(joinState_) - , state(joinState == JoinState::Invite ? "invite_state" : "state") - , timeline("timeline") - , ephemeral("ephemeral") - , accountData("account_data") + , state(load<StateEvents>(room_, + joinState == JoinState::Invite ? "invite_state" : "state")) { switch (joinState) { - case JoinState::Invite: - state.fromJson(room_); - break; case JoinState::Join: - state.fromJson(room_); - timeline.fromJson(room_); - ephemeral.fromJson(room_); - accountData.fromJson(room_); - break; + ephemeral = load<Events>(room_, "ephemeral"); + accountData = load<Events>(room_, "account_data"); + // [[fallthrough]] case JoinState::Leave: - state.fromJson(room_); - timeline.fromJson(room_); + { + timeline = load<RoomEvents>(room_, "timeline"); + auto timelineJson = room_.value("timeline").toObject(); + timelineLimited = timelineJson.value("limited").toBool(); + timelinePrevBatch = timelineJson.value("prev_batch").toString(); + break; - default: - qCWarning(SYNCJOB) << "SyncRoomData: Unknown JoinState value, ignoring:" << int(joinState); + } + default: /* nothing on top of state */; } - auto timelineJson = room_.value("timeline").toObject(); - timelineLimited = timelineJson.value("limited").toBool(); - timelinePrevBatch = timelineJson.value("prev_batch").toString(); - auto unreadJson = room_.value("unread_notifications").toObject(); unreadCount = unreadJson.value(UnreadCountKey).toInt(-2); highlightCount = unreadJson.value("highlight_count").toInt(); diff --git a/lib/jobs/syncjob.h b/lib/jobs/syncjob.h index 919060be..b12f9fff 100644 --- a/lib/jobs/syncjob.h +++ b/lib/jobs/syncjob.h @@ -26,30 +26,15 @@ namespace QMatrixClient { - template <typename EventT> - class SyncBatch : public EventsBatch<EventT> - { - public: - explicit SyncBatch(QString k) : jsonKey(std::move(k)) { } - void fromJson(const QJsonObject& roomContents) - { - EventsBatch<EventT>::fromJson( - roomContents[jsonKey].toObject(), "events"); - } - - private: - QString jsonKey; - }; - class SyncRoomData { public: QString roomId; JoinState joinState; - SyncBatch<RoomEvent> state; - SyncBatch<RoomEvent> timeline; - SyncBatch<Event> ephemeral; - SyncBatch<Event> accountData; + StateEvents state; + RoomEvents timeline; + Events ephemeral; + Events accountData; bool timelineLimited; QString timelinePrevBatch; @@ -71,13 +56,13 @@ namespace QMatrixClient { public: BaseJob::Status parseJson(const QJsonDocument &data); - SyncBatch<Event>&& takeAccountData(); + Events&& takeAccountData(); SyncDataList&& takeRoomData(); QString nextBatch() const; private: QString nextBatch_; - SyncBatch<Event> accountData { "account_data" }; + Events accountData; SyncDataList roomData; }; diff --git a/lib/room.cpp b/lib/room.cpp index 5771c51d..6c708a42 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -25,6 +25,7 @@ #include "jobs/generated/receipts.h" #include "jobs/generated/redaction.h" #include "jobs/generated/account-data.h" +#include "jobs/generated/message_pagination.h" #include "jobs/setroomstatejob.h" #include "events/simplestateevents.h" #include "events/roomavatarevent.h" @@ -33,7 +34,6 @@ #include "events/receiptevent.h" #include "events/redactionevent.h" #include "jobs/sendeventjob.h" -#include "jobs/roommessagesjob.h" #include "jobs/mediathumbnailjob.h" #include "jobs/downloadfilejob.h" #include "jobs/postreadmarkersjob.h" @@ -112,7 +112,7 @@ class Room::Private TagsMap tags; QHash<QString, AccountDataMap> accountData; QString prevBatch; - QPointer<RoomMessagesJob> roomMessagesJob; + QPointer<GetRoomEventsJob> eventsHistoryJob; struct FileTransferPrivateInfo { @@ -1036,21 +1036,31 @@ void Room::updateData(SyncRoomData&& data) for (auto&& event: data.accountData) processAccountDataEvent(move(event)); + bool emitNamesChanged = false; if (!data.state.empty()) { et.restart(); - processStateEvents(data.state); - qCDebug(PROFILER) << "*** Room::processStateEvents(state):" + for (const auto& e: data.state) + emitNamesChanged |= processStateEvent(*e); + + qCDebug(PROFILER) << "*** Room::processStateEvents():" << data.state.size() << "event(s)," << et; } if (!data.timeline.empty()) { et.restart(); // State changes can arrive in a timeline event; so check those. - processStateEvents(data.timeline); + for (const auto& e: data.timeline) + emitNamesChanged |= processStateEvent(*e); qCDebug(PROFILER) << "*** Room::processStateEvents(timeline):" << data.timeline.size() << "event(s)," << et; + } + if (emitNamesChanged) + emit namesChanged(this); + d->updateDisplayname(); + if (!data.timeline.empty()) + { et.restart(); d->addNewMessageEvents(move(data.timeline)); qCDebug(PROFILER) << "*** Room::addNewMessageEvents():" << et; @@ -1122,13 +1132,13 @@ void Room::getPreviousContent(int limit) void Room::Private::getPreviousContent(int limit) { - if( !isJobRunning(roomMessagesJob) ) + if( !isJobRunning(eventsHistoryJob) ) { - roomMessagesJob = - connection->callApi<RoomMessagesJob>(id, prevBatch, limit); - connect( roomMessagesJob, &RoomMessagesJob::success, [=] { - prevBatch = roomMessagesJob->end(); - addHistoricalMessageEvents(roomMessagesJob->releaseEvents()); + eventsHistoryJob = + connection->callApi<GetRoomEventsJob>(id, prevBatch, "b", "", limit); + connect( eventsHistoryJob, &BaseJob::success, q, [=] { + prevBatch = eventsHistoryJob->end(); + addHistoricalMessageEvents(eventsHistoryJob->chunk()); }); } } @@ -1450,107 +1460,95 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events) Q_ASSERT(timeline.size() == timelineSize + insertedSize); } -void Room::processStateEvents(const RoomEvents& events) +bool Room::processStateEvent(const RoomEvent& e) { - bool emitNamesChanged = false; - for (const auto& e: events) + switch (e.type()) { - switch (e->type()) - { - case EventType::RoomName: { - auto* nameEvent = weakPtr<const RoomNameEvent>(e); - d->name = nameEvent->name(); - qCDebug(MAIN) << "Room name updated:" << d->name; - emitNamesChanged = true; - break; - } - case EventType::RoomAliases: { - auto* aliasesEvent = weakPtr<const RoomAliasesEvent>(e); - d->aliases = aliasesEvent->aliases(); - qCDebug(MAIN) << "Room aliases updated:" << d->aliases; - emitNamesChanged = true; - break; - } - case EventType::RoomCanonicalAlias: { - auto* aliasEvent = weakPtr<const RoomCanonicalAliasEvent>(e); - d->canonicalAlias = aliasEvent->alias(); - setObjectName(d->canonicalAlias); - qCDebug(MAIN) << "Room canonical alias updated:" << d->canonicalAlias; - emitNamesChanged = true; - break; - } - case EventType::RoomTopic: { - auto* topicEvent = weakPtr<const RoomTopicEvent>(e); - d->topic = topicEvent->topic(); - qCDebug(MAIN) << "Room topic updated:" << d->topic; - emit topicChanged(); - break; + case EventType::RoomName: { + d->name = static_cast<const RoomNameEvent&>(e).name(); + qCDebug(MAIN) << "Room name updated:" << d->name; + return true; + } + case EventType::RoomAliases: { + d->aliases = static_cast<const RoomAliasesEvent&>(e).aliases(); + qCDebug(MAIN) << "Room aliases updated:" << d->aliases; + return true; + } + case EventType::RoomCanonicalAlias: { + d->canonicalAlias = + static_cast<const RoomCanonicalAliasEvent&>(e).alias(); + setObjectName(d->canonicalAlias); + qCDebug(MAIN) << "Room canonical alias updated:" << d->canonicalAlias; + return true; + } + case EventType::RoomTopic: { + d->topic = static_cast<const RoomTopicEvent&>(e).topic(); + qCDebug(MAIN) << "Room topic updated:" << d->topic; + emit topicChanged(); + return false; + } + case EventType::RoomAvatar: { + const auto& avatarEventContent = + static_cast<const RoomAvatarEvent&>(e).content(); + if (d->avatar.updateUrl(avatarEventContent.url)) + { + qCDebug(MAIN) << "Room avatar URL updated:" + << avatarEventContent.url.toString(); + emit avatarChanged(); } - case EventType::RoomAvatar: { - const auto& avatarEventContent = - weakPtr<const RoomAvatarEvent>(e)->content(); - if (d->avatar.updateUrl(avatarEventContent.url)) + return false; + } + case EventType::RoomMember: { + const auto& memberEvent = static_cast<const RoomMemberEvent&>(e); + auto* u = user(memberEvent.userId()); + u->processEvent(memberEvent, this); + if (u == localUser() && memberJoinState(u) == JoinState::Invite + && memberEvent.isDirect()) + connection()->addToDirectChats(this, + user(memberEvent.senderId())); + + if( memberEvent.membership() == MembershipType::Join ) + { + if (memberJoinState(u) != JoinState::Join) { - qCDebug(MAIN) << "Room avatar URL updated:" - << avatarEventContent.url.toString(); - emit avatarChanged(); + d->insertMemberIntoMap(u); + connect(u, &User::nameAboutToChange, this, + [=] (QString newName, QString, const Room* context) { + if (context == this) + emit memberAboutToRename(u, newName); + }); + connect(u, &User::nameChanged, this, + [=] (QString, QString oldName, const Room* context) { + if (context == this) + d->renameMember(u, oldName); + }); + emit userAdded(u); } - break; } - case EventType::RoomMember: { - auto* memberEvent = weakPtr<const RoomMemberEvent>(e); - auto u = user(memberEvent->userId()); - u->processEvent(memberEvent, this); - if (u == localUser() && memberJoinState(u) == JoinState::Invite - && memberEvent->isDirect()) - connection()->addToDirectChats(this, - user(memberEvent->senderId())); - - if( memberEvent->membership() == MembershipType::Join ) - { - if (memberJoinState(u) != JoinState::Join) - { - d->insertMemberIntoMap(u); - connect(u, &User::nameAboutToChange, this, - [=] (QString newName, QString, const Room* context) { - if (context == this) - emit memberAboutToRename(u, newName); - }); - connect(u, &User::nameChanged, this, - [=] (QString, QString oldName, const Room* context) { - if (context == this) - d->renameMember(u, oldName); - }); - emit userAdded(u); - } - } - else if( memberEvent->membership() == MembershipType::Leave ) + else if( memberEvent.membership() == MembershipType::Leave ) + { + if (memberJoinState(u) == JoinState::Join) { - if (memberJoinState(u) == JoinState::Join) - { - if (!d->membersLeft.contains(u)) - d->membersLeft.append(u); - d->removeMemberFromMap(u->name(this), u); - emit userRemoved(u); - } + if (!d->membersLeft.contains(u)) + d->membersLeft.append(u); + d->removeMemberFromMap(u->name(this), u); + emit userRemoved(u); } - break; } - case EventType::RoomEncryption: - { - d->encryptionAlgorithm = - weakPtr<const EncryptionEvent>(e)->algorithm(); - qCDebug(MAIN) << "Encryption switched on in" << displayName(); - emit encryption(); - break; - } - default: /* Ignore events of other types */; + return false; } + case EventType::RoomEncryption: + { + d->encryptionAlgorithm = + static_cast<const EncryptionEvent&>(e).algorithm(); + qCDebug(MAIN) << "Encryption switched on in" << displayName(); + emit encryption(); + return false; + } + default: + /* Ignore events of other types */ + return false; } - if (emitNamesChanged) { - emit namesChanged(this); - } - d->updateDisplayname(); } void Room::processEphemeralEvent(EventPtr&& event) @@ -408,13 +408,14 @@ namespace QMatrixClient void fileTransferCancelled(QString id); protected: - virtual void processStateEvents(const RoomEvents& events); + /// Returns true if any of room names/aliases has changed + virtual bool processStateEvent(const RoomEvent& e); virtual void processEphemeralEvent(EventPtr&& event); virtual void processAccountDataEvent(EventPtr&& event); - virtual void onAddNewTimelineEvents(timeline_iter_t from) { } - virtual void onAddHistoricalTimelineEvents(rev_iter_t from) { } - virtual void onRedaction(const RoomEvent& prevEvent, - const RoomEvent& after) { } + virtual void onAddNewTimelineEvents(timeline_iter_t /*from*/) { } + virtual void onAddHistoricalTimelineEvents(rev_iter_t /*from*/) { } + virtual void onRedaction(const RoomEvent& /*prevEvent*/, + const RoomEvent& /*after*/) { } private: class Private; diff --git a/lib/user.cpp b/lib/user.cpp index 91b340d5..89e324f9 100644 --- a/lib/user.cpp +++ b/lib/user.cpp @@ -358,19 +358,20 @@ QUrl User::avatarUrl(const Room* room) const return avatarObject(room).url(); } -void User::processEvent(const RoomMemberEvent* event, const Room* room) +void User::processEvent(const RoomMemberEvent& event, const Room* room) { - if (event->membership() != MembershipType::Invite && - event->membership() != MembershipType::Join) + Q_ASSERT(room); + if (event.membership() != MembershipType::Invite && + event.membership() != MembershipType::Join) return; auto aboutToEnter = room->memberJoinState(this) == JoinState::Leave && - (event->membership() == MembershipType::Join || - event->membership() == MembershipType::Invite); + (event.membership() == MembershipType::Join || + event.membership() == MembershipType::Invite); if (aboutToEnter) ++d->totalRooms; - auto newName = event->displayName(); + auto newName = event.displayName(); // `bridged` value uses the same notification signal as the name; // it is assumed that first setting of the bridge occurs together with // the first setting of the name, and further bridge updates are @@ -390,17 +391,17 @@ void User::processEvent(const RoomMemberEvent* event, const Room* room) } newName.truncate(match.capturedStart(0)); } - if (event->prevContent()) + if (event.prevContent()) { // FIXME: the hint doesn't work for bridged users auto oldNameHint = - d->nameForRoom(room, event->prevContent()->displayName); + d->nameForRoom(room, event.prevContent()->displayName); updateName(newName, oldNameHint, room); - updateAvatarUrl(event->avatarUrl(), - d->avatarUrlForRoom(room, event->prevContent()->avatarUrl), + updateAvatarUrl(event.avatarUrl(), + d->avatarUrlForRoom(room, event.prevContent()->avatarUrl), room); } else { updateName(newName, room); - updateAvatarUrl(event->avatarUrl(), d->avatarUrlForRoom(room), room); + updateAvatarUrl(event.avatarUrl(), d->avatarUrlForRoom(room), room); } } @@ -103,8 +103,7 @@ namespace QMatrixClient QString avatarMediaId(const Room* room = nullptr) const; QUrl avatarUrl(const Room* room = nullptr) const; - void processEvent(const RoomMemberEvent* event, - const Room* r = nullptr); + void processEvent(const RoomMemberEvent& event, const Room* r); public slots: void rename(const QString& newName); @@ -58,6 +58,37 @@ namespace QMatrixClient static void qAsConst(const T &&) Q_DECL_EQ_DELETE; #endif + /** An abstraction over a pair of iterators + * This is a very basic range type over a container with iterators that + * are at least ForwardIterators. Inspired by Ranges TS. + */ + template <typename ArrayT> + class Range + { + // Looking forward for Ranges TS to produce something (in C++23?..) + using iterator = typename ArrayT::iterator; + using const_iterator = typename ArrayT::const_iterator; + using size_type = typename ArrayT::size_type; + public: + Range(ArrayT& arr) : from(std::begin(arr)), to(std::end(arr)) { } + Range(iterator from, iterator to) : from(from), to(to) { } + + size_type size() const + { + Q_ASSERT(std::distance(from, to) >= 0); + return size_type(std::distance(from, to)); + } + bool empty() const { return from == to; } + const_iterator begin() const { return from; } + const_iterator end() const { return to; } + iterator begin() { return from; } + iterator end() { return to; } + + private: + iterator from; + iterator to; + }; + /** A guard pointer that disconnects an interested object upon destruction * It's almost QPointer<> except that you have to initialise it with one * more additional parameter - a pointer to a QObject that will be |