aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/connection.cpp6
-rw-r--r--lib/connection.h4
-rw-r--r--lib/events/event.cpp23
-rw-r--r--lib/events/event.h86
-rw-r--r--lib/jobs/generated/message_pagination.cpp76
-rw-r--r--lib/jobs/generated/message_pagination.h40
-rw-r--r--lib/jobs/roommessagesjob.cpp65
-rw-r--r--lib/jobs/roommessagesjob.h47
-rw-r--r--lib/jobs/syncjob.cpp43
-rw-r--r--lib/jobs/syncjob.h27
-rw-r--r--lib/room.cpp200
-rw-r--r--lib/room.h11
-rw-r--r--lib/user.cpp23
-rw-r--r--lib/user.h3
-rw-r--r--lib/util.h31
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)
diff --git a/lib/room.h b/lib/room.h
index 288db5fb..7b4b3578 100644
--- a/lib/room.h
+++ b/lib/room.h
@@ -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);
}
}
diff --git a/lib/user.h b/lib/user.h
index 8ac96539..76aa672f 100644
--- a/lib/user.h
+++ b/lib/user.h
@@ -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);
diff --git a/lib/util.h b/lib/util.h
index 55f3af6a..f65b05a3 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -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