aboutsummaryrefslogtreecommitdiff
path: root/lib/room.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/room.cpp')
-rw-r--r--lib/room.cpp1734
1 files changed, 798 insertions, 936 deletions
diff --git a/lib/room.cpp b/lib/room.cpp
index 5da9373e..c7c94fe5 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -13,55 +13,55 @@
*
* 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "room.h"
-#include "csapi/kicking.h"
-#include "csapi/inviting.h"
+#include "avatar.h"
+#include "connection.h"
+#include "converters.h"
+#include "csapi/account-data.h"
#include "csapi/banning.h"
+#include "csapi/inviting.h"
+#include "csapi/kicking.h"
#include "csapi/leaving.h"
#include "csapi/receipts.h"
#include "csapi/redaction.h"
-#include "csapi/account-data.h"
-#include "csapi/room_state.h"
#include "csapi/room_send.h"
+#include "csapi/room_state.h"
+#include "csapi/room_upgrades.h"
#include "csapi/rooms.h"
#include "csapi/tags.h"
-#include "csapi/room_upgrades.h"
-#include "events/simplestateevents.h"
-#include "events/roomcreateevent.h"
-#include "events/roomtombstoneevent.h"
-#include "events/roomavatarevent.h"
-#include "events/roommemberevent.h"
-#include "events/typingevent.h"
-#include "events/receiptevent.h"
-#include "events/callinviteevent.h"
-#include "events/callcandidatesevent.h"
#include "events/callanswerevent.h"
+#include "events/callcandidatesevent.h"
#include "events/callhangupevent.h"
+#include "events/callinviteevent.h"
+#include "events/receiptevent.h"
#include "events/redactionevent.h"
-#include "jobs/mediathumbnailjob.h"
+#include "events/roomavatarevent.h"
+#include "events/roomcreateevent.h"
+#include "events/roommemberevent.h"
+#include "events/roomtombstoneevent.h"
+#include "events/simplestateevents.h"
+#include "events/typingevent.h"
#include "jobs/downloadfilejob.h"
+#include "jobs/mediathumbnailjob.h"
#include "jobs/postreadmarkersjob.h"
-#include "avatar.h"
-#include "connection.h"
-#include "user.h"
-#include "converters.h"
#include "syncdata.h"
+#include "user.h"
+#include <QtCore/QDir>
#include <QtCore/QHash>
-#include <QtCore/QStringBuilder> // for efficient string concats (operator%)
+#include <QtCore/QMimeDatabase>
#include <QtCore/QPointer>
-#include <QtCore/QDir>
-#include <QtCore/QTemporaryFile>
#include <QtCore/QRegularExpression>
-#include <QtCore/QMimeDatabase>
+#include <QtCore/QStringBuilder> // for efficient string concats (operator%)
+#include <QtCore/QTemporaryFile>
#include <array>
-#include <functional>
#include <cmath>
+#include <functional>
using namespace QMatrixClient;
using namespace std::placeholders;
@@ -75,239 +75,235 @@ enum EventsPlacement : int { Older = -1, Newer = 1 };
class Room::Private
{
public:
- /** Map of user names to users. User names potentially duplicate, hence a multi-hashmap. */
- using members_map_t = QMultiHash<QString, User*>;
-
- Private(Connection* c, QString id_, JoinState initialJoinState)
- : q(nullptr), connection(c), id(move(id_))
- , joinState(initialJoinState)
- { }
-
- Room* q;
-
- Connection* connection;
- QString id;
- JoinState joinState;
- RoomSummary summary = { none, 0, none };
- /// The state of the room at timeline position before-0
- /// \sa timelineBase
- std::unordered_map<StateEventKey, StateEventPtr> baseState;
- /// The state of the room at timeline position after-maxTimelineIndex()
- /// \sa Room::syncEdge
- QHash<StateEventKey, const StateEventBase*> currentState;
- Timeline timeline;
- PendingEvents unsyncedEvents;
- QHash<QString, TimelineItem::index_t> eventsIndex;
- QString displayname;
- Avatar avatar;
- int highlightCount = 0;
- int notificationCount = 0;
- members_map_t membersMap;
- QList<User*> usersTyping;
- QMultiHash<QString, User*> eventIdReadUsers;
- QList<User*> membersLeft;
- int unreadMessages = 0;
- bool displayed = false;
- QString firstDisplayedEventId;
- QString lastDisplayedEventId;
- QHash<const User*, QString> lastReadEventIds;
- QString serverReadMarker;
- TagsMap tags;
- std::unordered_map<QString, EventPtr> accountData;
- QString prevBatch;
- QPointer<GetRoomEventsJob> eventsHistoryJob;
- QPointer<GetMembersByRoomJob> allMembersJob;
-
- struct FileTransferPrivateInfo
+ /** Map of user names to users. User names potentially duplicate, hence a
+ * multi-hashmap. */
+ using members_map_t = QMultiHash<QString, User*>;
+
+ Private(Connection* c, QString id_, JoinState initialJoinState)
+ : q(nullptr), connection(c), id(move(id_)), joinState(initialJoinState)
+ {
+ }
+
+ Room* q;
+
+ Connection* connection;
+ QString id;
+ JoinState joinState;
+ RoomSummary summary = { none, 0, none };
+ /// The state of the room at timeline position before-0
+ /// \sa timelineBase
+ std::unordered_map<StateEventKey, StateEventPtr> baseState;
+ /// The state of the room at timeline position after-maxTimelineIndex()
+ /// \sa Room::syncEdge
+ QHash<StateEventKey, const StateEventBase*> currentState;
+ Timeline timeline;
+ PendingEvents unsyncedEvents;
+ QHash<QString, TimelineItem::index_t> eventsIndex;
+ QString displayname;
+ Avatar avatar;
+ int highlightCount = 0;
+ int notificationCount = 0;
+ members_map_t membersMap;
+ QList<User*> usersTyping;
+ QMultiHash<QString, User*> eventIdReadUsers;
+ QList<User*> membersLeft;
+ int unreadMessages = 0;
+ bool displayed = false;
+ QString firstDisplayedEventId;
+ QString lastDisplayedEventId;
+ QHash<const User*, QString> lastReadEventIds;
+ QString serverReadMarker;
+ TagsMap tags;
+ std::unordered_map<QString, EventPtr> accountData;
+ QString prevBatch;
+ QPointer<GetRoomEventsJob> eventsHistoryJob;
+ QPointer<GetMembersByRoomJob> allMembersJob;
+
+ struct FileTransferPrivateInfo {
+ FileTransferPrivateInfo() = default;
+ FileTransferPrivateInfo(BaseJob* j, const QString& fileName,
+ bool isUploading = false)
+ : status(FileTransferInfo::Started),
+ job(j),
+ localFileInfo(fileName),
+ isUpload(isUploading)
{
- FileTransferPrivateInfo() = default;
- FileTransferPrivateInfo(BaseJob* j, const QString& fileName,
- bool isUploading = false)
- : status(FileTransferInfo::Started), job(j)
- , localFileInfo(fileName), isUpload(isUploading)
- { }
-
- FileTransferInfo::Status status = FileTransferInfo::None;
- QPointer<BaseJob> job = nullptr;
- QFileInfo localFileInfo { };
- bool isUpload = false;
- qint64 progress = 0;
- qint64 total = -1;
-
- void update(qint64 p, qint64 t)
- {
- if (t == 0)
- {
- t = -1;
- if (p == 0)
- p = -1;
- }
- if (p != -1)
- qCDebug(PROFILER) << "Transfer progress:" << p << "/" << t
- << "=" << llround(double(p) / t * 100) << "%";
- progress = p; total = t;
- }
- };
- void failedTransfer(const QString& tid, const QString& errorMessage = {})
+ }
+
+ FileTransferInfo::Status status = FileTransferInfo::None;
+ QPointer<BaseJob> job = nullptr;
+ QFileInfo localFileInfo {};
+ bool isUpload = false;
+ qint64 progress = 0;
+ qint64 total = -1;
+
+ void update(qint64 p, qint64 t)
{
- qCWarning(MAIN) << "File transfer failed for id" << tid;
- if (!errorMessage.isEmpty())
- qCWarning(MAIN) << "Message:" << errorMessage;
- fileTransfers[tid].status = FileTransferInfo::Failed;
- emit q->fileTransferFailed(tid, errorMessage);
+ if (t == 0) {
+ t = -1;
+ if (p == 0)
+ p = -1;
+ }
+ if (p != -1)
+ qCDebug(PROFILER) << "Transfer progress:" << p << "/" << t
+ << "=" << llround(double(p) / t * 100) << "%";
+ progress = p;
+ total = t;
}
- /// A map from event/txn ids to information about the long operation;
- /// used for both download and upload operations
- QHash<QString, FileTransferPrivateInfo> fileTransfers;
+ };
+ void failedTransfer(const QString& tid, const QString& errorMessage = {})
+ {
+ qCWarning(MAIN) << "File transfer failed for id" << tid;
+ if (!errorMessage.isEmpty())
+ qCWarning(MAIN) << "Message:" << errorMessage;
+ fileTransfers[tid].status = FileTransferInfo::Failed;
+ emit q->fileTransferFailed(tid, errorMessage);
+ }
+ /// A map from event/txn ids to information about the long operation;
+ /// used for both download and upload operations
+ QHash<QString, FileTransferPrivateInfo> fileTransfers;
- const RoomMessageEvent* getEventWithFile(const QString& eventId) const;
- QString fileNameToDownload(const RoomMessageEvent* event) const;
+ const RoomMessageEvent* getEventWithFile(const QString& eventId) const;
+ QString fileNameToDownload(const RoomMessageEvent* event) const;
- Changes setSummary(RoomSummary&& newSummary);
+ Changes setSummary(RoomSummary&& newSummary);
- //void inviteUser(User* u); // We might get it at some point in time.
- void insertMemberIntoMap(User* u);
- void renameMember(User* u, QString oldName);
- void removeMemberFromMap(const QString& username, User* u);
+ // void inviteUser(User* u); // We might get it at some point in time.
+ void insertMemberIntoMap(User* u);
+ void renameMember(User* u, QString oldName);
+ void removeMemberFromMap(const QString& username, User* u);
- // This updates the room displayname field (which is the way a room
- // should be shown in the room list); called whenever the list of
- // members, the room name (m.room.name) or canonical alias change.
- void updateDisplayname();
- // This is used by updateDisplayname() but only calculates the new name
- // without any updates.
- QString calculateDisplayname() const;
+ // This updates the room displayname field (which is the way a room
+ // should be shown in the room list); called whenever the list of
+ // members, the room name (m.room.name) or canonical alias change.
+ void updateDisplayname();
+ // This is used by updateDisplayname() but only calculates the new name
+ // without any updates.
+ QString calculateDisplayname() const;
- /// A point in the timeline corresponding to baseState
- rev_iter_t timelineBase() const { return q->findInTimeline(-1); }
+ /// A point in the timeline corresponding to baseState
+ rev_iter_t timelineBase() const { return q->findInTimeline(-1); }
- void getPreviousContent(int limit = 10);
+ void getPreviousContent(int limit = 10);
- template <typename EventT>
- const EventT* getCurrentState(QString stateKey = {}) const
- {
- static const EventT empty;
- const auto* evt =
- currentState.value({EventT::matrixTypeId(), stateKey}, &empty);
- Q_ASSERT(evt->type() == EventT::typeId() &&
- evt->matrixType() == EventT::matrixTypeId());
- return static_cast<const EventT*>(evt);
- }
+ template <typename EventT>
+ const EventT* getCurrentState(QString stateKey = {}) const
+ {
+ static const EventT empty;
+ const auto* evt = currentState.value(
+ { EventT::matrixTypeId(), stateKey }, &empty);
+ Q_ASSERT(evt->type() == EventT::typeId()
+ && evt->matrixType() == EventT::matrixTypeId());
+ return static_cast<const EventT*>(evt);
+ }
- bool isEventNotable(const TimelineItem& ti) const
- {
- return !ti->isRedacted() &&
- ti->senderId() != connection->userId() &&
- is<RoomMessageEvent>(*ti);
- }
+ bool isEventNotable(const TimelineItem& ti) const
+ {
+ return !ti->isRedacted() && ti->senderId() != connection->userId()
+ && is<RoomMessageEvent>(*ti);
+ }
- template <typename EventArrayT>
- Changes updateStateFrom(EventArrayT&& events)
- {
- Changes changes = NoChange;
- if (!events.empty())
- {
- QElapsedTimer et; et.start();
- for (auto&& eptr: events)
- {
- const auto& evt = *eptr;
- Q_ASSERT(evt.isStateEvent());
- // Update baseState afterwards to make sure that the old state
- // is valid and usable inside processStateEvent
- changes |= q->processStateEvent(evt);
- baseState[{evt.matrixType(),evt.stateKey()}] = move(eptr);
- }
- if (events.size() > 9 || et.nsecsElapsed() >= profilerMinNsecs())
- qCDebug(PROFILER) << "*** Room::Private::updateStateFrom():"
- << events.size() << "event(s)," << et;
+ template <typename EventArrayT>
+ Changes updateStateFrom(EventArrayT&& events)
+ {
+ Changes changes = NoChange;
+ if (!events.empty()) {
+ QElapsedTimer et;
+ et.start();
+ for (auto&& eptr : events) {
+ const auto& evt = *eptr;
+ Q_ASSERT(evt.isStateEvent());
+ // Update baseState afterwards to make sure that the old state
+ // is valid and usable inside processStateEvent
+ changes |= q->processStateEvent(evt);
+ baseState[{ evt.matrixType(), evt.stateKey() }] = move(eptr);
}
- return changes;
- }
- Changes addNewMessageEvents(RoomEvents&& events);
- void addHistoricalMessageEvents(RoomEvents&& events);
-
- /** Move events into the timeline
- *
- * Insert events into the timeline, either new or historical.
- * Pointers in the original container become empty, the ownership
- * is passed to the timeline container.
- * @param events - the range of events to be inserted
- * @param placement - position and direction of insertion: Older for
- * historical messages, Newer for new ones
- */
- Timeline::difference_type moveEventsToTimeline(RoomEventsRange events,
- EventsPlacement placement);
-
- /**
- * Remove events from the passed container that are already in the timeline
- */
- void dropDuplicateEvents(RoomEvents& events) const;
-
- Changes setLastReadEvent(User* u, QString eventId);
- void updateUnreadCount(rev_iter_t from, rev_iter_t to);
- Changes promoteReadMarker(User* u, rev_iter_t newMarker,
- bool force = false);
-
- Changes markMessagesAsRead(rev_iter_t upToMarker);
-
- void getAllMembers();
-
- QString sendEvent(RoomEventPtr&& event);
-
- template <typename EventT, typename... ArgTs>
- QString sendEvent(ArgTs&&... eventArgs)
- {
- return sendEvent(makeEvent<EventT>(std::forward<ArgTs>(eventArgs)...));
+ if (events.size() > 9 || et.nsecsElapsed() >= profilerMinNsecs())
+ qCDebug(PROFILER) << "*** Room::Private::updateStateFrom():"
+ << events.size() << "event(s)," << et;
}
+ return changes;
+ }
+ Changes addNewMessageEvents(RoomEvents&& events);
+ void addHistoricalMessageEvents(RoomEvents&& events);
+
+ /** Move events into the timeline
+ *
+ * Insert events into the timeline, either new or historical.
+ * Pointers in the original container become empty, the ownership
+ * is passed to the timeline container.
+ * @param events - the range of events to be inserted
+ * @param placement - position and direction of insertion: Older for
+ * historical messages, Newer for new ones
+ */
+ Timeline::difference_type moveEventsToTimeline(RoomEventsRange events,
+ EventsPlacement placement);
+
+ /**
+ * Remove events from the passed container that are already in the timeline
+ */
+ void dropDuplicateEvents(RoomEvents& events) const;
+
+ Changes setLastReadEvent(User* u, QString eventId);
+ void updateUnreadCount(rev_iter_t from, rev_iter_t to);
+ Changes promoteReadMarker(User* u, rev_iter_t newMarker,
+ bool force = false);
+
+ Changes markMessagesAsRead(rev_iter_t upToMarker);
+
+ void getAllMembers();
+
+ QString sendEvent(RoomEventPtr&& event);
+
+ template <typename EventT, typename... ArgTs>
+ QString sendEvent(ArgTs&&... eventArgs)
+ {
+ return sendEvent(makeEvent<EventT>(std::forward<ArgTs>(eventArgs)...));
+ }
- RoomEvent* addAsPending(RoomEventPtr&& event);
+ RoomEvent* addAsPending(RoomEventPtr&& event);
- QString doSendEvent(const RoomEvent* pEvent);
- void onEventSendingFailure(const QString& txnId, BaseJob* call = nullptr);
+ QString doSendEvent(const RoomEvent* pEvent);
+ void onEventSendingFailure(const QString& txnId, BaseJob* call = nullptr);
- template <typename EvT>
- SetRoomStateWithKeyJob* requestSetState(const QString& stateKey,
- const EvT& event)
- {
- if (q->successorId().isEmpty())
- {
- // TODO: Queue up state events sending (see #133).
- return connection->callApi<SetRoomStateWithKeyJob>(
- id, EvT::matrixTypeId(), stateKey, event.contentJson());
- }
- qCWarning(MAIN) << q << "has been upgraded, state won't be set";
- return nullptr;
+ template <typename EvT>
+ SetRoomStateWithKeyJob* requestSetState(const QString& stateKey,
+ const EvT& event)
+ {
+ if (q->successorId().isEmpty()) {
+ // TODO: Queue up state events sending (see #133).
+ return connection->callApi<SetRoomStateWithKeyJob>(
+ id, EvT::matrixTypeId(), stateKey, event.contentJson());
}
+ qCWarning(MAIN) << q << "has been upgraded, state won't be set";
+ return nullptr;
+ }
- template <typename EvT>
- auto requestSetState(const EvT& event)
- {
- return connection->callApi<SetRoomStateJob>(
- id, EvT::matrixTypeId(), event.contentJson());
- }
+ template <typename EvT> auto requestSetState(const EvT& event)
+ {
+ return connection->callApi<SetRoomStateJob>(id, EvT::matrixTypeId(),
+ event.contentJson());
+ }
- /**
- * @brief Apply redaction to the timeline
- *
- * Tries to find an event in the timeline and redact it; deletes the
- * redaction event whether the redacted event was found or not.
- */
- bool processRedaction(const RedactionEvent& redaction);
+ /**
+ * @brief Apply redaction to the timeline
+ *
+ * Tries to find an event in the timeline and redact it; deletes the
+ * redaction event whether the redacted event was found or not.
+ */
+ bool processRedaction(const RedactionEvent& redaction);
- void setTags(TagsMap newTags);
+ void setTags(TagsMap newTags);
- QJsonObject toJson() const;
+ QJsonObject toJson() const;
private:
- using users_shortlist_t = std::array<User*, 3>;
- template<typename ContT>
- users_shortlist_t buildShortlist(const ContT& users) const;
- users_shortlist_t buildShortlist(const QStringList& userIds) const;
+ using users_shortlist_t = std::array<User*, 3>;
+ template <typename ContT>
+ users_shortlist_t buildShortlist(const ContT& users) const;
+ users_shortlist_t buildShortlist(const QStringList& userIds) const;
- bool isLocalUser(const User* u) const
- {
- return u == q->localUser();
- }
+ bool isLocalUser(const User* u) const { return u == q->localUser(); }
};
Room::Room(Connection* connection, QString id, JoinState initialJoinState)
@@ -318,24 +314,18 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState)
// https://marcmutz.wordpress.com/translated-articles/pimp-my-pimpl-%E2%80%94-reloaded/
d->q = this;
d->displayname = d->calculateDisplayname(); // Set initial "Empty room" name
- connectUntil(connection, &Connection::loadedRoomState, this,
- [this] (Room* r) {
- if (this == r)
- emit baseStateLoaded();
- return this == r; // loadedRoomState fires only once per room
- });
+ connectUntil(
+ connection, &Connection::loadedRoomState, this, [this](Room* r) {
+ if (this == r)
+ emit baseStateLoaded();
+ return this == r; // loadedRoomState fires only once per room
+ });
qCDebug(MAIN) << "New" << toCString(initialJoinState) << "Room:" << id;
}
-Room::~Room()
-{
- delete d;
-}
+Room::~Room() { delete d; }
-const QString& Room::id() const
-{
- return d->id;
-}
+const QString& Room::id() const { return d->id; }
QString Room::version() const
{
@@ -345,8 +335,8 @@ QString Room::version() const
bool Room::isUnstable() const
{
- return !connection()->loadingCapabilities() &&
- !connection()->stableRoomVersions().contains(version());
+ return !connection()->loadingCapabilities()
+ && !connection()->stableRoomVersions().contains(version());
}
QString Room::predecessorId() const
@@ -359,10 +349,7 @@ QString Room::successorId() const
return d->getCurrentState<RoomTombstoneEvent>()->successorRoomId();
}
-const Room::Timeline& Room::messageEvents() const
-{
- return d->timeline;
-}
+const Room::Timeline& Room::messageEvents() const { return d->timeline; }
const Room::PendingEvents& Room::pendingEvents() const
{
@@ -384,35 +371,20 @@ QString Room::canonicalAlias() const
return d->getCurrentState<RoomCanonicalAliasEvent>()->alias();
}
-QString Room::displayName() const
-{
- return d->displayname;
-}
+QString Room::displayName() const { return d->displayname; }
QString Room::topic() const
{
return d->getCurrentState<RoomTopicEvent>()->topic();
}
-QString Room::avatarMediaId() const
-{
- return d->avatar.mediaId();
-}
+QString Room::avatarMediaId() const { return d->avatar.mediaId(); }
-QUrl Room::avatarUrl() const
-{
- return d->avatar.url();
-}
+QUrl Room::avatarUrl() const { return d->avatar.url(); }
-const Avatar& Room::avatarObject() const
-{
- return d->avatar;
-}
+const Avatar& Room::avatarObject() const { return d->avatar; }
-QImage Room::avatar(int dimension)
-{
- return avatar(dimension, dimension);
-}
+QImage Room::avatar(int dimension) { return avatar(dimension, dimension); }
QImage Room::avatar(int width, int height)
{
@@ -422,9 +394,10 @@ QImage Room::avatar(int width, int height)
// Use the first (excluding self) user's avatar for direct chats
const auto dcUsers = directChatUsers();
- for (auto* u: dcUsers)
+ for (auto* u : dcUsers)
if (u != localUser())
- return u->avatar(width, height, this, [=] { emit avatarChanged(); });
+ return u->avatar(width, height, this,
+ [=] { emit avatarChanged(); });
return {};
}
@@ -436,24 +409,20 @@ User* Room::user(const QString& userId) const
JoinState Room::memberJoinState(User* user) const
{
- return
- d->membersMap.contains(user->name(this), user) ? JoinState::Join :
- JoinState::Leave;
+ return d->membersMap.contains(user->name(this), user) ? JoinState::Join
+ : JoinState::Leave;
}
-JoinState Room::joinState() const
-{
- return d->joinState;
-}
+JoinState Room::joinState() const { return d->joinState; }
void Room::setJoinState(JoinState state)
{
JoinState oldState = d->joinState;
- if( state == oldState )
+ if (state == oldState)
return;
d->joinState = state;
- qCDebug(MAIN) << "Room" << id() << "changed state: "
- << int(oldState) << "->" << int(state);
+ qCDebug(MAIN) << "Room" << id() << "changed state: " << int(oldState)
+ << "->" << int(state);
emit changed(Change::JoinStateChange);
emit joinStateChanged(oldState, state);
}
@@ -468,8 +437,7 @@ Room::Changes Room::Private::setLastReadEvent(User* u, QString eventId)
swap(storedId, eventId);
emit q->lastReadEventChanged(u);
emit q->readMarkerForUserMoved(u, eventId, storedId);
- if (isLocalUser(u))
- {
+ if (isLocalUser(u)) {
if (storedId != serverReadMarker)
connection->callApi<PostReadMarkersJob>(id, storedId);
emit q->readMarkerMoved(eventId, storedId);
@@ -488,32 +456,33 @@ void Room::Private::updateUnreadCount(rev_iter_t from, rev_iter_t to)
// unreadMessages and might need to promote the read marker further
// over local-origin messages.
const auto readMarker = q->readMarker();
- if (readMarker >= from && readMarker < to)
- {
+ if (readMarker >= from && readMarker < to) {
promoteReadMarker(q->localUser(), readMarker, true);
return;
}
Q_ASSERT(to <= readMarker);
- QElapsedTimer et; et.start();
- const auto newUnreadMessages = count_if(from, to,
- std::bind(&Room::Private::isEventNotable, this, _1));
+ QElapsedTimer et;
+ et.start();
+ const auto newUnreadMessages = count_if(
+ from, to, std::bind(&Room::Private::isEventNotable, this, _1));
if (et.nsecsElapsed() > profilerMinNsecs() / 10)
qCDebug(PROFILER) << "Counting gained unread messages took" << et;
- if(newUnreadMessages > 0)
- {
- // See https://github.com/QMatrixClient/libqmatrixclient/wiki/unread_count
+ if (newUnreadMessages > 0) {
+ // See
+ // https://github.com/QMatrixClient/libqmatrixclient/wiki/unread_count
if (unreadMessages < 0)
unreadMessages = 0;
unreadMessages += newUnreadMessages;
qCDebug(MAIN) << "Room" << q->objectName() << "has gained"
- << newUnreadMessages << "unread message(s),"
- << (q->readMarker() == timeline.crend() ?
- "in total at least" : "in total")
- << unreadMessages << "unread message(s)";
+ << newUnreadMessages << "unread message(s),"
+ << (q->readMarker() == timeline.crend()
+ ? "in total at least"
+ : "in total")
+ << unreadMessages << "unread message(s)";
emit q->unreadMessagesChanged(q);
}
}
@@ -525,34 +494,36 @@ Room::Changes Room::Private::promoteReadMarker(User* u, rev_iter_t newMarker,
Q_ASSERT(newMarker >= timeline.crbegin() && newMarker <= timeline.crend());
const auto prevMarker = q->readMarker(u);
- if (!force && prevMarker <= newMarker) // Remember, we deal with reverse iterators
+ if (!force
+ && prevMarker <= newMarker) // Remember, we deal with reverse iterators
return Change::NoChange;
Q_ASSERT(newMarker < timeline.crend());
// Try to auto-promote the read marker over the user's own messages
// (switch to direct iterators for that).
- auto eagerMarker = find_if(newMarker.base(), timeline.cend(),
- [=](const TimelineItem& ti) { return ti->senderId() != u->id(); });
+ auto eagerMarker = find_if(
+ newMarker.base(), timeline.cend(),
+ [=](const TimelineItem& ti) { return ti->senderId() != u->id(); });
auto changes = setLastReadEvent(u, (*(eagerMarker - 1))->id());
- if (isLocalUser(u))
- {
+ if (isLocalUser(u)) {
const auto oldUnreadCount = unreadMessages;
- QElapsedTimer et; et.start();
- unreadMessages = count_if(eagerMarker, timeline.cend(),
- std::bind(&Room::Private::isEventNotable, this, _1));
+ QElapsedTimer et;
+ et.start();
+ unreadMessages =
+ count_if(eagerMarker, timeline.cend(),
+ std::bind(&Room::Private::isEventNotable, this, _1));
if (et.nsecsElapsed() > profilerMinNsecs() / 10)
qCDebug(PROFILER) << "Recounting unread messages took" << et;
- // See https://github.com/QMatrixClient/libqmatrixclient/wiki/unread_count
+ // See
+ // https://github.com/QMatrixClient/libqmatrixclient/wiki/unread_count
if (unreadMessages == 0)
unreadMessages = -1;
- if (force || unreadMessages != oldUnreadCount)
- {
- if (unreadMessages == -1)
- {
+ if (force || unreadMessages != oldUnreadCount) {
+ if (unreadMessages == -1) {
qCDebug(MAIN) << "Room" << displayname
<< "has no more unread messages";
} else
@@ -575,10 +546,8 @@ Room::Changes Room::Private::markMessagesAsRead(rev_iter_t upToMarker)
// We shouldn't send read receipts for the local user's own messages - so
// search earlier messages for the latest message not from the local user
// until the previous last-read message, whichever comes first.
- for (; upToMarker < prevMarker; ++upToMarker)
- {
- if ((*upToMarker)->senderId() != q->localUser()->id())
- {
+ for (; upToMarker < prevMarker; ++upToMarker) {
+ if ((*upToMarker)->senderId() != q->localUser()->id()) {
connection->callApi<PostReceiptJob>(id, "m.read",
(*upToMarker)->id());
break;
@@ -601,47 +570,36 @@ void Room::markAllMessagesAsRead()
bool Room::canSwitchVersions() const
{
// TODO, #276: m.room.power_levels
- const auto* plEvt =
- d->currentState.value({"m.room.power_levels", ""});
+ const auto* plEvt = d->currentState.value({ "m.room.power_levels", "" });
if (!plEvt)
return true;
const auto plJson = plEvt->contentJson();
const auto currentUserLevel =
- plJson.value("users"_ls).toObject()
- .value(localUser()->id()).toInt(
- plJson.value("users_default"_ls).toInt());
+ plJson.value("users"_ls)
+ .toObject()
+ .value(localUser()->id())
+ .toInt(plJson.value("users_default"_ls).toInt());
const auto tombstonePowerLevel =
- plJson.value("events").toObject()
- .value("m.room.tombstone"_ls).toInt(
- plJson.value("state_default"_ls).toInt());
+ plJson.value("events")
+ .toObject()
+ .value("m.room.tombstone"_ls)
+ .toInt(plJson.value("state_default"_ls).toInt());
return currentUserLevel >= tombstonePowerLevel;
}
-bool Room::hasUnreadMessages() const
-{
- return unreadCount() >= 0;
-}
+bool Room::hasUnreadMessages() const { return unreadCount() >= 0; }
-int Room::unreadCount() const
-{
- return d->unreadMessages;
-}
+int Room::unreadCount() const { return d->unreadMessages; }
-Room::rev_iter_t Room::historyEdge() const
-{
- return d->timeline.crend();
-}
+Room::rev_iter_t Room::historyEdge() const { return d->timeline.crend(); }
Room::Timeline::const_iterator Room::syncEdge() const
{
return d->timeline.cend();
}
-Room::rev_iter_t Room::timelineEdge() const
-{
- return historyEdge();
-}
+Room::rev_iter_t Room::timelineEdge() const { return historyEdge(); }
TimelineItem::index_t Room::minTimelineIndex() const
{
@@ -655,21 +613,19 @@ TimelineItem::index_t Room::maxTimelineIndex() const
bool Room::isValidIndex(TimelineItem::index_t timelineIndex) const
{
- return !d->timeline.empty() &&
- timelineIndex >= minTimelineIndex() &&
- timelineIndex <= maxTimelineIndex();
+ return !d->timeline.empty() && timelineIndex >= minTimelineIndex()
+ && timelineIndex <= maxTimelineIndex();
}
Room::rev_iter_t Room::findInTimeline(TimelineItem::index_t index) const
{
- return timelineEdge() -
- (isValidIndex(index) ? index - minTimelineIndex() + 1 : 0);
+ return timelineEdge()
+ - (isValidIndex(index) ? index - minTimelineIndex() + 1 : 0);
}
Room::rev_iter_t Room::findInTimeline(const QString& evtId) const
{
- if (!d->timeline.empty() && d->eventsIndex.contains(evtId))
- {
+ if (!d->timeline.empty() && d->eventsIndex.contains(evtId)) {
auto it = findInTimeline(d->eventsIndex.value(evtId));
Q_ASSERT((*it)->id() == evtId);
return it;
@@ -680,14 +636,18 @@ Room::rev_iter_t Room::findInTimeline(const QString& evtId) const
Room::PendingEvents::iterator Room::findPendingEvent(const QString& txnId)
{
return std::find_if(d->unsyncedEvents.begin(), d->unsyncedEvents.end(),
- [txnId] (const auto& item) { return item->transactionId() == txnId; });
+ [txnId](const auto& item) {
+ return item->transactionId() == txnId;
+ });
}
Room::PendingEvents::const_iterator
Room::findPendingEvent(const QString& txnId) const
{
return std::find_if(d->unsyncedEvents.cbegin(), d->unsyncedEvents.cend(),
- [txnId] (const auto& item) { return item->transactionId() == txnId; });
+ [txnId](const auto& item) {
+ return item->transactionId() == txnId;
+ });
}
void Room::Private::getAllMembers()
@@ -697,28 +657,25 @@ void Room::Private::getAllMembers()
return;
allMembersJob = connection->callApi<GetMembersByRoomJob>(
- id, connection->nextBatchToken(), "join");
+ id, connection->nextBatchToken(), "join");
auto nextIndex = timeline.empty() ? 0 : timeline.back().index() + 1;
- connect( allMembersJob, &BaseJob::success, q, [=] {
+ connect(allMembersJob, &BaseJob::success, q, [=] {
Q_ASSERT(timeline.empty() || nextIndex <= q->maxTimelineIndex() + 1);
auto roomChanges = updateStateFrom(allMembersJob->chunk());
// Replay member events that arrived after the point for which
// the full members list was requested.
- if (!timeline.empty() )
+ if (!timeline.empty())
for (auto it = q->findInTimeline(nextIndex).base();
it != timeline.cend(); ++it)
if (is<RoomMemberEvent>(**it))
roomChanges |= q->processStateEvent(**it);
- if (roomChanges&MembersChange)
+ if (roomChanges & MembersChange)
emit q->memberListChanged();
emit q->allMembersLoaded();
});
}
-bool Room::displayed() const
-{
- return d->displayed;
-}
+bool Room::displayed() const { return d->displayed; }
void Room::setDisplayed(bool displayed)
{
@@ -727,18 +684,14 @@ void Room::setDisplayed(bool displayed)
d->displayed = displayed;
emit displayedChanged(displayed);
- if( displayed )
- {
+ if (displayed) {
resetHighlightCount();
resetNotificationCount();
d->getAllMembers();
}
}
-QString Room::firstDisplayedEventId() const
-{
- return d->firstDisplayedEventId;
-}
+QString Room::firstDisplayedEventId() const { return d->firstDisplayedEventId; }
Room::rev_iter_t Room::firstDisplayedMarker() const
{
@@ -760,10 +713,7 @@ void Room::setFirstDisplayedEvent(TimelineItem::index_t index)
setFirstDisplayedEventId(findInTimeline(index)->event()->id());
}
-QString Room::lastDisplayedEventId() const
-{
- return d->lastDisplayedEventId;
-}
+QString Room::lastDisplayedEventId() const { return d->lastDisplayedEventId; }
Room::rev_iter_t Room::lastDisplayedMarker() const
{
@@ -791,41 +741,33 @@ Room::rev_iter_t Room::readMarker(const User* user) const
return findInTimeline(d->lastReadEventIds.value(user));
}
-Room::rev_iter_t Room::readMarker() const
-{
- return readMarker(localUser());
-}
+Room::rev_iter_t Room::readMarker() const { return readMarker(localUser()); }
QString Room::readMarkerEventId() const
{
return d->lastReadEventIds.value(localUser());
}
-QList<User*> Room::usersAtEventId(const QString& eventId) {
+QList<User*> Room::usersAtEventId(const QString& eventId)
+{
return d->eventIdReadUsers.values(eventId);
}
-int Room::notificationCount() const
-{
- return d->notificationCount;
-}
+int Room::notificationCount() const { return d->notificationCount; }
void Room::resetNotificationCount()
{
- if( d->notificationCount == 0 )
+ if (d->notificationCount == 0)
return;
d->notificationCount = 0;
emit notificationCountChanged(this);
}
-int Room::highlightCount() const
-{
- return d->highlightCount;
-}
+int Room::highlightCount() const { return d->highlightCount; }
void Room::resetHighlightCount()
{
- if( d->highlightCount == 0 )
+ if (d->highlightCount == 0)
return;
d->highlightCount = 0;
emit highlightCountChanged(this);
@@ -834,9 +776,8 @@ void Room::resetHighlightCount()
void Room::switchVersion(QString newVersion)
{
auto* job = connection()->callApi<UpgradeRoomJob>(id(), newVersion);
- connect(job, &BaseJob::failure, this, [this,job] {
- emit upgradeFailed(job->errorString());
- });
+ connect(job, &BaseJob::failure, this,
+ [this, job] { emit upgradeFailed(job->errorString()); });
}
bool Room::hasAccountData(const QString& type) const
@@ -851,20 +792,11 @@ const EventPtr& Room::accountData(const QString& type) const
return it != d->accountData.end() ? it->second : NoEventPtr;
}
-QStringList Room::tagNames() const
-{
- return d->tags.keys();
-}
+QStringList Room::tagNames() const { return d->tags.keys(); }
-TagsMap Room::tags() const
-{
- return d->tags;
-}
+TagsMap Room::tags() const { return d->tags; }
-TagRecord Room::tag(const QString& name) const
-{
- return d->tags.value(name);
-}
+TagRecord Room::tag(const QString& name) const { return d->tags.value(name); }
std::pair<bool, QString> validatedTag(QString name)
{
@@ -882,8 +814,8 @@ std::pair<bool, QString> validatedTag(QString name)
void Room::addTag(const QString& name, const TagRecord& record)
{
const auto& checkRes = validatedTag(name);
- if (d->tags.contains(name) ||
- (checkRes.first && d->tags.contains(checkRes.second)))
+ if (d->tags.contains(name)
+ || (checkRes.first && d->tags.contains(checkRes.second)))
return;
emit tagsAboutToChange();
@@ -895,13 +827,12 @@ void Room::addTag(const QString& name, const TagRecord& record)
void Room::addTag(const QString& name, float order)
{
- addTag(name, TagRecord{order});
+ addTag(name, TagRecord { order });
}
void Room::removeTag(const QString& name)
{
- if (d->tags.contains(name))
- {
+ if (d->tags.contains(name)) {
emit tagsAboutToChange();
d->tags.remove(name);
emit tagsChanged();
@@ -918,18 +849,16 @@ void Room::setTags(TagsMap newTags)
d->setTags(move(newTags));
connection()->callApi<SetAccountDataPerRoomJob>(
localUser()->id(), id(), TagEvent::matrixTypeId(),
- TagEvent(d->tags).contentJson());
+ TagEvent(d->tags).contentJson());
}
void Room::Private::setTags(TagsMap newTags)
{
emit q->tagsAboutToChange();
const auto keys = newTags.keys();
- for (const auto& k: keys)
- {
+ for (const auto& k : keys) {
const auto& checkRes = validatedTag(k);
- if (checkRes.first)
- {
+ if (checkRes.first) {
if (newTags.contains(checkRes.second))
newTags.remove(k);
else
@@ -942,20 +871,11 @@ void Room::Private::setTags(TagsMap newTags)
emit q->tagsChanged();
}
-bool Room::isFavourite() const
-{
- return d->tags.contains(FavouriteTag);
-}
+bool Room::isFavourite() const { return d->tags.contains(FavouriteTag); }
-bool Room::isLowPriority() const
-{
- return d->tags.contains(LowPriorityTag);
-}
+bool Room::isLowPriority() const { return d->tags.contains(LowPriorityTag); }
-bool Room::isDirectChat() const
-{
- return connection()->isDirectChat(id());
-}
+bool Room::isDirectChat() const { return connection()->isDirectChat(id()); }
QList<User*> Room::directChatUsers() const
{
@@ -966,8 +886,7 @@ const RoomMessageEvent*
Room::Private::getEventWithFile(const QString& eventId) const
{
auto evtIt = q->findInTimeline(eventId);
- if (evtIt != timeline.rend() && is<RoomMessageEvent>(**evtIt))
- {
+ if (evtIt != timeline.rend() && is<RoomMessageEvent>(**evtIt)) {
auto* event = evtIt->viewAs<RoomMessageEvent>();
if (event->hasFileContent())
return event;
@@ -981,12 +900,9 @@ QString Room::Private::fileNameToDownload(const RoomMessageEvent* event) const
Q_ASSERT(event->hasFileContent());
const auto* fileInfo = event->content()->fileInfo();
QString fileName;
- if (!fileInfo->originalName.isEmpty())
- {
+ if (!fileInfo->originalName.isEmpty()) {
fileName = QFileInfo(fileInfo->originalName).fileName();
- }
- else if (!event->plainBody().isEmpty())
- {
+ } else if (!event->plainBody().isEmpty()) {
// Having no better options, assume that the body has
// the original file URL or at least the file name.
QUrl u { event->plainBody() };
@@ -997,13 +913,13 @@ QString Room::Private::fileNameToDownload(const RoomMessageEvent* event) const
if (fileName.isEmpty() || !QTemporaryFile(fileName).open())
return "file." % fileInfo->mimeType.preferredSuffix();
- if (QSysInfo::productType() == "windows")
- {
+ if (QSysInfo::productType() == "windows") {
const auto& suffixes = fileInfo->mimeType.suffixes();
- if (!suffixes.isEmpty() &&
- std::none_of(suffixes.begin(), suffixes.end(),
- [&fileName] (const QString& s) {
- return fileName.endsWith(s); }))
+ if (!suffixes.isEmpty()
+ && std::none_of(suffixes.begin(), suffixes.end(),
+ [&fileName](const QString& s) {
+ return fileName.endsWith(s);
+ }))
return fileName % '.' % fileInfo->mimeType.preferredSuffix();
}
return fileName;
@@ -1012,12 +928,12 @@ QString Room::Private::fileNameToDownload(const RoomMessageEvent* event) const
QUrl Room::urlToThumbnail(const QString& eventId) const
{
if (auto* event = d->getEventWithFile(eventId))
- if (event->hasThumbnail())
- {
+ if (event->hasThumbnail()) {
auto* thumbnail = event->content()->thumbnailInfo();
Q_ASSERT(thumbnail != nullptr);
return MediaThumbnailJob::makeRequestUrl(connection()->homeserver(),
- thumbnail->url, thumbnail->imageSize);
+ thumbnail->url,
+ thumbnail->imageSize);
}
qDebug() << "Event" << eventId << "has no thumbnail";
return {};
@@ -1025,8 +941,7 @@ QUrl Room::urlToThumbnail(const QString& eventId) const
QUrl Room::urlToDownload(const QString& eventId) const
{
- if (auto* event = d->getEventWithFile(eventId))
- {
+ if (auto* event = d->getEventWithFile(eventId)) {
auto* fileInfo = event->content()->fileInfo();
Q_ASSERT(fileInfo != nullptr);
return DownloadFileJob::makeRequestUrl(connection()->homeserver(),
@@ -1053,8 +968,7 @@ FileTransferInfo Room::fileTransferInfo(const QString& id) const
qint64 progress = infoIt->progress;
qint64 total = infoIt->total;
- if (total > INT_MAX)
- {
+ if (total > INT_MAX) {
// JavaScript doesn't deal with 64-bit integers; scale down if necessary
progress = llround(double(progress) / total * INT_MAX);
total = INT_MAX;
@@ -1066,13 +980,16 @@ FileTransferInfo Room::fileTransferInfo(const QString& id) const
fti.progress = int(progress);
fti.total = int(total);
fti.localDir = QUrl::fromLocalFile(infoIt->localFileInfo.absolutePath());
- fti.localPath = QUrl::fromLocalFile(infoIt->localFileInfo.absoluteFilePath());
+ fti.localPath =
+ QUrl::fromLocalFile(infoIt->localFileInfo.absoluteFilePath());
return fti;
#else
- return { infoIt->status, infoIt->isUpload, int(progress), int(total),
- QUrl::fromLocalFile(infoIt->localFileInfo.absolutePath()),
- QUrl::fromLocalFile(infoIt->localFileInfo.absoluteFilePath())
- };
+ return { infoIt->status,
+ infoIt->isUpload,
+ int(progress),
+ int(total),
+ QUrl::fromLocalFile(infoIt->localFileInfo.absolutePath()),
+ QUrl::fromLocalFile(infoIt->localFileInfo.absoluteFilePath()) };
#endif
}
@@ -1096,39 +1013,24 @@ QString Room::prettyPrint(const QString& plainText) const
return QMatrixClient::prettyPrint(plainText);
}
-QList< User* > Room::usersTyping() const
-{
- return d->usersTyping;
-}
+QList<User*> Room::usersTyping() const { return d->usersTyping; }
-QList< User* > Room::membersLeft() const
-{
- return d->membersLeft;
-}
+QList<User*> Room::membersLeft() const { return d->membersLeft; }
-QList< User* > Room::users() const
-{
- return d->membersMap.values();
-}
+QList<User*> Room::users() const { return d->membersMap.values(); }
QStringList Room::memberNames() const
{
QStringList res;
for (auto u : qAsConst(d->membersMap))
- res.append( roomMembername(u) );
+ res.append(roomMembername(u));
return res;
}
-int Room::memberCount() const
-{
- return d->membersMap.size();
-}
+int Room::memberCount() const { return d->membersMap.size(); }
-int Room::timelineSize() const
-{
- return int(d->timeline.size());
-}
+int Room::timelineSize() const { return int(d->timeline.size()); }
bool Room::usesEncryption() const
{
@@ -1149,31 +1051,25 @@ int Room::invitedCount() const
return d->summary.invitedMemberCount.value();
}
-int Room::totalMemberCount() const
-{
- return joinedCount() + invitedCount();
-}
+int Room::totalMemberCount() const { return joinedCount() + invitedCount(); }
-GetRoomEventsJob* Room::eventsHistoryJob() const
-{
- return d->eventsHistoryJob;
-}
+GetRoomEventsJob* Room::eventsHistoryJob() const { return d->eventsHistoryJob; }
Room::Changes Room::Private::setSummary(RoomSummary&& newSummary)
{
if (!summary.merge(newSummary))
return Change::NoChange;
- qCDebug(MAIN).nospace().noquote()
- << "Updated room summary for " << q->objectName() << ": " << summary;
+ qCDebug(MAIN).nospace().noquote() << "Updated room summary for "
+ << q->objectName() << ": " << summary;
emit q->memberListChanged();
return Change::SummaryChange;
}
-void Room::Private::insertMemberIntoMap(User *u)
+void Room::Private::insertMemberIntoMap(User* u)
{
const auto userName = u->name(q);
- // If there is exactly one namesake of the added user, signal member renaming
- // for that other one because the two should be disambiguated now.
+ // If there is exactly one namesake of the added user, signal member
+ // renaming for that other one because the two should be disambiguated now.
auto namesakes = membersMap.values(userName);
if (namesakes.size() == 1)
emit q->memberAboutToRename(namesakes.front(),
@@ -1185,14 +1081,11 @@ void Room::Private::insertMemberIntoMap(User *u)
void Room::Private::renameMember(User* u, QString oldName)
{
- if (u->name(q) == oldName)
- {
+ if (u->name(q) == oldName) {
qCWarning(MAIN) << "Room::Private::renameMember(): the user "
<< u->fullName(q)
<< "is already known in the room under a new name.";
- }
- else if (membersMap.contains(oldName, u))
- {
+ } else if (membersMap.contains(oldName, u)) {
removeMemberFromMap(oldName, u);
insertMemberIntoMap(u);
}
@@ -1203,15 +1096,15 @@ void Room::Private::removeMemberFromMap(const QString& username, User* u)
{
User* namesake = nullptr;
auto namesakes = membersMap.values(username);
- if (namesakes.size() == 2)
- {
- namesake = namesakes.front() == u ? namesakes.back() : namesakes.front();
+ if (namesakes.size() == 2) {
+ namesake =
+ namesakes.front() == u ? namesakes.back() : namesakes.front();
Q_ASSERT_X(namesake != u, __FUNCTION__, "Room members list is broken");
emit q->memberAboutToRename(namesake, username);
}
membersMap.remove(username, u);
- // If there was one namesake besides the removed user, signal member renaming
- // for it because it doesn't need to be disambiguated anymore.
+ // If there was one namesake besides the removed user, signal member
+ // renaming for it because it doesn't need to be disambiguated anymore.
// TODO: Think about left users.
if (namesake)
emit q->memberRenamed(namesake);
@@ -1222,27 +1115,31 @@ inline auto makeErrorStr(const Event& e, QByteArray msg)
return msg.append("; event dump follows:\n").append(e.originalJson());
}
-Room::Timeline::difference_type Room::Private::moveEventsToTimeline(
- RoomEventsRange events, EventsPlacement placement)
+Room::Timeline::difference_type
+Room::Private::moveEventsToTimeline(RoomEventsRange events,
+ EventsPlacement placement)
{
Q_ASSERT(!events.empty());
// Historical messages arrive in newest-to-oldest order, so the process for
// them is almost symmetric to the one for new messages. New messages get
// appended from index 0; old messages go backwards from index -1.
- auto index = timeline.empty() ? -((placement+1)/2) /* 1 -> -1; -1 -> 0 */ :
- placement == Older ? timeline.front().index() :
- timeline.back().index();
+ auto index = timeline.empty()
+ ? -((placement + 1) / 2) /* 1 -> -1; -1 -> 0 */
+ : placement == Older ? timeline.front().index()
+ : timeline.back().index();
auto baseIndex = index;
- for (auto&& e: events)
- {
+ for (auto&& e : events) {
const auto eId = e->id();
Q_ASSERT_X(e, __FUNCTION__, "Attempt to add nullptr to timeline");
- Q_ASSERT_X(!eId.isEmpty(), __FUNCTION__,
- makeErrorStr(*e,
- "Event with empty id cannot be in the timeline"));
- Q_ASSERT_X(!eventsIndex.contains(eId), __FUNCTION__,
- makeErrorStr(*e, "Event is already in the timeline; "
- "incoming events were not properly deduplicated"));
+ Q_ASSERT_X(
+ !eId.isEmpty(), __FUNCTION__,
+ makeErrorStr(*e,
+ "Event with empty id cannot be in the timeline"));
+ Q_ASSERT_X(
+ !eventsIndex.contains(eId), __FUNCTION__,
+ makeErrorStr(*e,
+ "Event is already in the timeline; "
+ "incoming events were not properly deduplicated"));
if (placement == Older)
timeline.emplace_front(move(e), --index);
else
@@ -1279,8 +1176,7 @@ QString Room::roomMembername(const User* u) const
// (extension to the spec)
QVector<QString> bridges;
for (; namesakesIt != d->membersMap.cend() && namesakesIt.key() == username;
- ++namesakesIt)
- {
+ ++namesakesIt) {
const auto bridgeName = (*namesakesIt)->bridged();
if (bridges.contains(bridgeName)) // Two accounts on the same bridge
return u->fullName(this); // Disambiguate fully
@@ -1298,60 +1194,56 @@ QString Room::roomMembername(const QString& userId) const
void Room::updateData(SyncRoomData&& data, bool fromCache)
{
- if( d->prevBatch.isEmpty() )
+ if (d->prevBatch.isEmpty())
d->prevBatch = data.timelinePrevBatch;
setJoinState(data.joinState);
Changes roomChanges = Change::NoChange;
- QElapsedTimer et; et.start();
- for (auto&& event: data.accountData)
+ QElapsedTimer et;
+ et.start();
+ for (auto&& event : data.accountData)
roomChanges |= processAccountDataEvent(move(event));
roomChanges |= d->updateStateFrom(data.state);
- if (!data.timeline.empty())
- {
+ if (!data.timeline.empty()) {
et.restart();
roomChanges |= d->addNewMessageEvents(move(data.timeline));
if (data.timeline.size() > 9 || et.nsecsElapsed() >= profilerMinNsecs())
qCDebug(PROFILER) << "*** Room::addNewMessageEvents():"
<< data.timeline.size() << "event(s)," << et;
}
- if (roomChanges&TopicChange)
+ if (roomChanges & TopicChange)
emit topicChanged();
- if (roomChanges&NameChange)
+ if (roomChanges & NameChange)
emit namesChanged(this);
- if (roomChanges&MembersChange)
+ if (roomChanges & MembersChange)
emit memberListChanged();
roomChanges |= d->setSummary(move(data.summary));
d->updateDisplayname();
- for( auto&& ephemeralEvent: data.ephemeral )
+ for (auto&& ephemeralEvent : data.ephemeral)
roomChanges |= processEphemeralEvent(move(ephemeralEvent));
// See https://github.com/QMatrixClient/libqmatrixclient/wiki/unread_count
- if (data.unreadCount != -2 && data.unreadCount != d->unreadMessages)
- {
+ if (data.unreadCount != -2 && data.unreadCount != d->unreadMessages) {
qCDebug(MAIN) << "Setting unread_count to" << data.unreadCount;
d->unreadMessages = data.unreadCount;
emit unreadMessagesChanged(this);
}
- if( data.highlightCount != d->highlightCount )
- {
+ if (data.highlightCount != d->highlightCount) {
d->highlightCount = data.highlightCount;
emit highlightCountChanged(this);
}
- if( data.notificationCount != d->notificationCount )
- {
+ if (data.notificationCount != d->notificationCount) {
d->notificationCount = data.notificationCount;
emit notificationCountChanged(this);
}
- if (roomChanges != Change::NoChange)
- {
+ if (roomChanges != Change::NoChange) {
emit changed(roomChanges);
if (!fromCache)
connection()->saveRoomState(this);
@@ -1382,37 +1274,34 @@ QString Room::Private::doSendEvent(const RoomEvent* pEvent)
{
const auto txnId = pEvent->transactionId();
// TODO, #133: Enqueue the job rather than immediately trigger it.
- if (auto call = connection->callApi<SendMessageJob>(BackgroundRequest,
- id, pEvent->matrixType(), txnId, pEvent->contentJson()))
- {
- Room::connect(call, &BaseJob::started, q,
- [this,txnId] {
- auto it = q->findPendingEvent(txnId);
- if (it == unsyncedEvents.end())
- {
- qWarning(EVENTS) << "Pending event for transaction" << txnId
- << "not found - got synced so soon?";
- return;
- }
- it->setDeparted();
- emit q->pendingEventChanged(it - unsyncedEvents.begin());
- });
+ if (auto call = connection->callApi<SendMessageJob>(
+ BackgroundRequest, id, pEvent->matrixType(), txnId,
+ pEvent->contentJson())) {
+ Room::connect(call, &BaseJob::started, q, [this, txnId] {
+ auto it = q->findPendingEvent(txnId);
+ if (it == unsyncedEvents.end()) {
+ qWarning(EVENTS) << "Pending event for transaction" << txnId
+ << "not found - got synced so soon?";
+ return;
+ }
+ it->setDeparted();
+ emit q->pendingEventChanged(it - unsyncedEvents.begin());
+ });
Room::connect(call, &BaseJob::failure, q,
- std::bind(&Room::Private::onEventSendingFailure, this, txnId, call));
- Room::connect(call, &BaseJob::success, q,
- [this,call,txnId] {
- emit q->messageSent(txnId, call->eventId());
- auto it = q->findPendingEvent(txnId);
- if (it == unsyncedEvents.end())
- {
- qDebug(EVENTS) << "Pending event for transaction" << txnId
- << "already merged";
- return;
- }
+ std::bind(&Room::Private::onEventSendingFailure, this,
+ txnId, call));
+ Room::connect(call, &BaseJob::success, q, [this, call, txnId] {
+ emit q->messageSent(txnId, call->eventId());
+ auto it = q->findPendingEvent(txnId);
+ if (it == unsyncedEvents.end()) {
+ qDebug(EVENTS) << "Pending event for transaction" << txnId
+ << "already merged";
+ return;
+ }
- it->setReachedServer(call->eventId());
- emit q->pendingEventChanged(it - unsyncedEvents.begin());
- });
+ it->setReachedServer(call->eventId());
+ emit q->pendingEventChanged(it - unsyncedEvents.begin());
+ });
} else
onEventSendingFailure(txnId);
return txnId;
@@ -1421,15 +1310,14 @@ QString Room::Private::doSendEvent(const RoomEvent* pEvent)
void Room::Private::onEventSendingFailure(const QString& txnId, BaseJob* call)
{
auto it = q->findPendingEvent(txnId);
- if (it == unsyncedEvents.end())
- {
+ if (it == unsyncedEvents.end()) {
qCritical(EVENTS) << "Pending event for transaction" << txnId
<< "could not be sent";
return;
}
- it->setSendingFailed(call
- ? call->statusCaption() % ": " % call->errorString()
- : tr("The call could not be started"));
+ it->setSendingFailed(call ? call->statusCaption() % ": "
+ % call->errorString()
+ : tr("The call could not be started"));
emit q->pendingEventChanged(it - unsyncedEvents.begin());
}
@@ -1439,30 +1327,29 @@ QString Room::retryMessage(const QString& txnId)
Q_ASSERT(it != d->unsyncedEvents.end());
qDebug(EVENTS) << "Retrying transaction" << txnId;
const auto& transferIt = d->fileTransfers.find(txnId);
- if (transferIt != d->fileTransfers.end())
- {
+ if (transferIt != d->fileTransfers.end()) {
Q_ASSERT(transferIt->isUpload);
- if (transferIt->status == FileTransferInfo::Completed)
- {
+ if (transferIt->status == FileTransferInfo::Completed) {
qCDebug(MAIN) << "File for transaction" << txnId
<< "has already been uploaded, bypassing re-upload";
} else {
- if (isJobRunning(transferIt->job))
- {
+ if (isJobRunning(transferIt->job)) {
qCDebug(MAIN) << "Abandoning the upload job for transaction"
<< txnId << "and starting again";
transferIt->job->abandon();
- emit fileTransferFailed(txnId, tr("File upload will be retried"));
+ emit fileTransferFailed(txnId,
+ tr("File upload will be retried"));
}
uploadFile(txnId,
- QUrl::fromLocalFile(transferIt->localFileInfo.absoluteFilePath()));
+ QUrl::fromLocalFile(
+ transferIt->localFileInfo.absoluteFilePath()));
// FIXME: Content type is no more passed here but it should
}
}
- if (it->deliveryStatus() == EventStatus::ReachedServer)
- {
- qCWarning(MAIN) << "The previous attempt has reached the server; two"
- " events are likely to be in the timeline after retry";
+ if (it->deliveryStatus() == EventStatus::ReachedServer) {
+ qCWarning(MAIN)
+ << "The previous attempt has reached the server; two"
+ " events are likely to be in the timeline after retry";
}
it->resetStatus();
return d->doSendEvent(it->event());
@@ -1470,23 +1357,22 @@ QString Room::retryMessage(const QString& txnId)
void Room::discardMessage(const QString& txnId)
{
- auto it = std::find_if(d->unsyncedEvents.begin(), d->unsyncedEvents.end(),
- [txnId] (const auto& evt) { return evt->transactionId() == txnId; });
+ auto it = std::find_if(
+ d->unsyncedEvents.begin(), d->unsyncedEvents.end(),
+ [txnId](const auto& evt) { return evt->transactionId() == txnId; });
Q_ASSERT(it != d->unsyncedEvents.end());
qDebug(EVENTS) << "Discarding transaction" << txnId;
const auto& transferIt = d->fileTransfers.find(txnId);
- if (transferIt != d->fileTransfers.end())
- {
+ if (transferIt != d->fileTransfers.end()) {
Q_ASSERT(transferIt->isUpload);
- if (isJobRunning(transferIt->job))
- {
+ if (isJobRunning(transferIt->job)) {
transferIt->status = FileTransferInfo::Cancelled;
transferIt->job->abandon();
emit fileTransferFailed(txnId, tr("File upload cancelled"));
- } else if (transferIt->status == FileTransferInfo::Completed)
- {
- qCWarning(MAIN) << "File for transaction" << txnId
- << "has been uploaded but the message was discarded";
+ } else if (transferIt->status == FileTransferInfo::Completed) {
+ qCWarning(MAIN)
+ << "File for transaction" << txnId
+ << "has been uploaded but the message was discarded";
}
}
emit pendingEventAboutToDiscard(int(it - d->unsyncedEvents.begin()));
@@ -1507,8 +1393,9 @@ QString Room::postPlainText(const QString& plainText)
QString Room::postHtmlMessage(const QString& plainText, const QString& html,
MessageEventType type)
{
- return d->sendEvent<RoomMessageEvent>(plainText, type,
- new EventContent::TextContent(html, QStringLiteral("text/html")));
+ return d->sendEvent<RoomMessageEvent>(
+ plainText, type,
+ new EventContent::TextContent(html, QStringLiteral("text/html")));
}
QString Room::postHtmlText(const QString& plainText, const QString& html)
@@ -1523,58 +1410,58 @@ QString Room::postFile(const QString& plainText, const QUrl& localPath,
Q_ASSERT(localFile.isFile());
// Remote URL will only be known after upload; fill in the local path
// to enable the preview while the event is pending.
- const auto txnId = d->addAsPending(makeEvent<RoomMessageEvent>(
- plainText, localFile, asGenericFile)
- )->transactionId();
+ const auto txnId =
+ d->addAsPending(makeEvent<RoomMessageEvent>(plainText, localFile,
+ asGenericFile))
+ ->transactionId();
uploadFile(txnId, localPath);
auto* context = new QObject(this);
connect(this, &Room::fileTransferCompleted, context,
- [context,this,txnId] (const QString& id, QUrl, const QUrl& mxcUri) {
- if (id == txnId)
- {
- auto it = findPendingEvent(txnId);
- if (it != d->unsyncedEvents.end())
- {
- it->setFileUploaded(mxcUri);
- emit pendingEventChanged(
+ [context, this, txnId](const QString& id, QUrl,
+ const QUrl& mxcUri) {
+ if (id == txnId) {
+ auto it = findPendingEvent(txnId);
+ if (it != d->unsyncedEvents.end()) {
+ it->setFileUploaded(mxcUri);
+ emit pendingEventChanged(
int(it - d->unsyncedEvents.begin()));
- d->doSendEvent(it->get());
- } else {
- // Normally in this situation we should instruct
- // the media server to delete the file; alas, there's no
- // API specced for that.
- qCWarning(MAIN) << "File uploaded to" << mxcUri
- << "but the event referring to it was cancelled";
+ d->doSendEvent(it->get());
+ } else {
+ // Normally in this situation we should instruct
+ // the media server to delete the file; alas, there's no
+ // API specced for that.
+ qCWarning(MAIN) << "File uploaded to" << mxcUri
+ << "but the event referring to it was "
+ "cancelled";
+ }
+ context->deleteLater();
}
- context->deleteLater();
- }
- });
+ });
connect(this, &Room::fileTransferCancelled, this,
- [context,this,txnId] (const QString& id) {
- if (id == txnId)
- {
- auto it = findPendingEvent(txnId);
- if (it != d->unsyncedEvents.end())
- {
- const auto idx = int(it - d->unsyncedEvents.begin());
- emit pendingEventAboutToDiscard(idx);
- // See #286 on why iterator may not be valid here.
- d->unsyncedEvents.erase(d->unsyncedEvents.begin() + idx);
- emit pendingEventDiscarded();
+ [context, this, txnId](const QString& id) {
+ if (id == txnId) {
+ auto it = findPendingEvent(txnId);
+ if (it != d->unsyncedEvents.end()) {
+ const auto idx = int(it - d->unsyncedEvents.begin());
+ emit pendingEventAboutToDiscard(idx);
+ // See #286 on why iterator may not be valid here.
+ d->unsyncedEvents.erase(d->unsyncedEvents.begin()
+ + idx);
+ emit pendingEventDiscarded();
+ }
+ context->deleteLater();
}
- context->deleteLater();
- }
- });
+ });
return txnId;
}
QString Room::postEvent(RoomEvent* event)
{
- if (usesEncryption())
- {
+ if (usesEncryption()) {
qCCritical(MAIN) << "Room" << displayName()
- << "enforces encryption; sending encrypted messages is not supported yet";
+ << "enforces encryption; sending encrypted messages "
+ "is not supported yet";
}
return d->sendEvent(RoomEventPtr(event));
}
@@ -1582,7 +1469,8 @@ QString Room::postEvent(RoomEvent* event)
QString Room::postJson(const QString& matrixType,
const QJsonObject& eventContent)
{
- return d->sendEvent(loadEvent<RoomEvent>(basicEventJson(matrixType, eventContent)));
+ return d->sendEvent(
+ loadEvent<RoomEvent>(basicEventJson(matrixType, eventContent)));
}
void Room::setName(const QString& newName)
@@ -1625,10 +1513,7 @@ bool isEchoEvent(const RoomEventPtr& le, const PendingEventItem& re)
return le->contentJson() == re->contentJson();
}
-bool Room::supportsCalls() const
-{
- return joinedCount() == 2;
-}
+bool Room::supportsCalls() const { return joinedCount() == 2; }
void Room::checkVersion()
{
@@ -1638,8 +1523,7 @@ void Room::checkVersion()
// This method is only called after the base state has been loaded
// or the server capabilities have been loaded.
emit stabilityUpdated(defaultVersion, stableVersions);
- if (!stableVersions.contains(version()))
- {
+ if (!stableVersions.contains(version())) {
qCDebug(MAIN) << this << "version is" << version()
<< "which the server doesn't count as stable";
if (canSwitchVersions())
@@ -1680,25 +1564,22 @@ void Room::hangupCall(const QString& callId)
postEvent(new CallHangupEvent(callId));
}
-void Room::getPreviousContent(int limit)
-{
- d->getPreviousContent(limit);
-}
+void Room::getPreviousContent(int limit) { d->getPreviousContent(limit); }
void Room::Private::getPreviousContent(int limit)
{
if (isJobRunning(eventsHistoryJob))
return;
- eventsHistoryJob =
- connection->callApi<GetRoomEventsJob>(id, prevBatch, "b", "", limit);
+ eventsHistoryJob = connection->callApi<GetRoomEventsJob>(id, prevBatch, "b",
+ "", limit);
emit q->eventsHistoryJobChanged();
- connect( eventsHistoryJob, &BaseJob::success, q, [=] {
+ connect(eventsHistoryJob, &BaseJob::success, q, [=] {
prevBatch = eventsHistoryJob->end();
addHistoricalMessageEvents(eventsHistoryJob->chunk());
});
- connect( eventsHistoryJob, &QObject::destroyed,
- q, &Room::eventsHistoryJobChanged);
+ connect(eventsHistoryJob, &QObject::destroyed, q,
+ &Room::eventsHistoryJobChanged);
}
void Room::inviteToRoom(const QString& memberId)
@@ -1712,7 +1593,8 @@ LeaveRoomJob* Room::leaveRoom()
return connection()->leaveRoom(this);
}
-SetRoomStateWithKeyJob*Room::setMemberState(const QString& memberId, const RoomMemberEvent& event) const
+SetRoomStateWithKeyJob* Room::setMemberState(const QString& memberId,
+ const RoomMemberEvent& event) const
{
return d->requestSetState(memberId, event);
}
@@ -1735,7 +1617,7 @@ void Room::unban(const QString& userId)
void Room::redactEvent(const QString& eventId, const QString& reason)
{
connection()->callApi<RedactEventJob>(
- id(), eventId, connection()->generateTxnId(), reason);
+ id(), eventId, connection()->generateTxnId(), reason);
}
void Room::uploadFile(const QString& id, const QUrl& localFilename,
@@ -1745,18 +1627,17 @@ void Room::uploadFile(const QString& id, const QUrl& localFilename,
"localFilename should point at a local file");
auto fileName = localFilename.toLocalFile();
auto job = connection()->uploadFile(fileName, overrideContentType);
- if (isJobRunning(job))
- {
+ if (isJobRunning(job)) {
d->fileTransfers.insert(id, { job, fileName, true });
connect(job, &BaseJob::uploadProgress, this,
- [this,id] (qint64 sent, qint64 total) {
+ [this, id](qint64 sent, qint64 total) {
d->fileTransfers[id].update(sent, total);
emit fileTransferProgress(id, sent, total);
});
- connect(job, &BaseJob::success, this, [this,id,localFilename,job] {
- d->fileTransfers[id].status = FileTransferInfo::Completed;
- emit fileTransferCompleted(id, localFilename, job->contentUri());
- });
+ connect(job, &BaseJob::success, this, [this, id, localFilename, job] {
+ d->fileTransfers[id].status = FileTransferInfo::Completed;
+ emit fileTransferCompleted(id, localFilename, job->contentUri());
+ });
connect(job, &BaseJob::failure, this,
std::bind(&Private::failedTransfer, d, id, job->errorString()));
emit newFileTransfer(id, localFilename);
@@ -1767,9 +1648,8 @@ void Room::uploadFile(const QString& id, const QUrl& localFilename,
void Room::downloadFile(const QString& eventId, const QUrl& localFilename)
{
auto ongoingTransfer = d->fileTransfers.find(eventId);
- if (ongoingTransfer != d->fileTransfers.end() &&
- ongoingTransfer->status == FileTransferInfo::Started)
- {
+ if (ongoingTransfer != d->fileTransfers.end()
+ && ongoingTransfer->status == FileTransferInfo::Started) {
qCWarning(MAIN) << "Transfer for" << eventId
<< "is ongoing; download won't start";
return;
@@ -1778,42 +1658,41 @@ void Room::downloadFile(const QString& eventId, const QUrl& localFilename)
Q_ASSERT_X(localFilename.isEmpty() || localFilename.isLocalFile(),
__FUNCTION__, "localFilename should point at a local file");
const auto* event = d->getEventWithFile(eventId);
- if (!event)
- {
+ if (!event) {
qCCritical(MAIN)
- << eventId << "is not in the local timeline or has no file content";
+ << eventId
+ << "is not in the local timeline or has no file content";
Q_ASSERT(false);
return;
}
const auto fileUrl = event->content()->fileInfo()->url;
auto filePath = localFilename.toLocalFile();
- if (filePath.isEmpty())
- {
+ if (filePath.isEmpty()) {
// Build our own file path, starting with temp directory and eventId.
filePath = eventId;
- filePath = QDir::tempPath() % '/' %
- filePath.replace(QRegularExpression("[/\\<>|\"*?:]"), "_") %
- '#' % d->fileNameToDownload(event);
+ filePath = QDir::tempPath() % '/'
+ % filePath.replace(QRegularExpression("[/\\<>|\"*?:]"), "_")
+ % '#' % d->fileNameToDownload(event);
}
auto job = connection()->downloadFile(fileUrl, filePath);
- if (isJobRunning(job))
- {
+ if (isJobRunning(job)) {
// If there was a previous transfer (completed or failed), remove it.
d->fileTransfers.remove(eventId);
d->fileTransfers.insert(eventId, { job, job->targetFileName() });
connect(job, &BaseJob::downloadProgress, this,
- [this,eventId] (qint64 received, qint64 total) {
- d->fileTransfers[eventId].update(received, total);
- emit fileTransferProgress(eventId, received, total);
- });
- connect(job, &BaseJob::success, this, [this,eventId,fileUrl,job] {
- d->fileTransfers[eventId].status = FileTransferInfo::Completed;
- emit fileTransferCompleted(eventId, fileUrl,
- QUrl::fromLocalFile(job->targetFileName()));
- });
+ [this, eventId](qint64 received, qint64 total) {
+ d->fileTransfers[eventId].update(received, total);
+ emit fileTransferProgress(eventId, received, total);
+ });
+ connect(job, &BaseJob::success, this, [this, eventId, fileUrl, job] {
+ d->fileTransfers[eventId].status = FileTransferInfo::Completed;
+ emit fileTransferCompleted(
+ eventId, fileUrl,
+ QUrl::fromLocalFile(job->targetFileName()));
+ });
connect(job, &BaseJob::failure, this,
- std::bind(&Private::failedTransfer, d,
- eventId, job->errorString()));
+ std::bind(&Private::failedTransfer, d, eventId,
+ job->errorString()));
} else
d->failedTransfer(eventId);
}
@@ -1821,10 +1700,9 @@ void Room::downloadFile(const QString& eventId, const QUrl& localFilename)
void Room::cancelFileTransfer(const QString& id)
{
auto it = d->fileTransfers.find(id);
- if (it == d->fileTransfers.end())
- {
- qCWarning(MAIN) << "No information on file transfer" << id
- << "in room" << d->id;
+ if (it == d->fileTransfers.end()) {
+ qCWarning(MAIN) << "No information on file transfer" << id << "in room"
+ << d->id;
return;
}
if (isJobRunning(it->job))
@@ -1840,15 +1718,16 @@ void Room::Private::dropDuplicateEvents(RoomEvents& events) const
// Multiple-remove (by different criteria), single-erase
// 1. Check for duplicates against the timeline.
- auto dupsBegin = remove_if(events.begin(), events.end(),
- [&] (const RoomEventPtr& e)
- { return eventsIndex.contains(e->id()); });
+ auto dupsBegin =
+ remove_if(events.begin(), events.end(), [&](const RoomEventPtr& e) {
+ return eventsIndex.contains(e->id());
+ });
// 2. Check for duplicates within the batch if there are still events.
for (auto eIt = events.begin(); distance(eIt, dupsBegin) > 1; ++eIt)
- dupsBegin = remove_if(eIt + 1, dupsBegin,
- [&] (const RoomEventPtr& e)
- { return e->id() == (*eIt)->id(); });
+ dupsBegin = remove_if(eIt + 1, dupsBegin, [&](const RoomEventPtr& e) {
+ return e->id() == (*eIt)->id();
+ });
if (dupsBegin == events.end())
return;
@@ -1867,48 +1746,54 @@ RoomEventPtr makeRedacted(const RoomEvent& target,
const RedactionEvent& redaction)
{
auto originalJson = target.originalJsonObject();
- static const QStringList keepKeys {
- EventIdKey, TypeKey, QStringLiteral("room_id"),
- QStringLiteral("sender"), QStringLiteral("state_key"),
- QStringLiteral("prev_content"), ContentKey,
- QStringLiteral("hashes"), QStringLiteral("signatures"),
- QStringLiteral("depth"), QStringLiteral("prev_events"),
- QStringLiteral("prev_state"), QStringLiteral("auth_events"),
- QStringLiteral("origin"), QStringLiteral("origin_server_ts"),
- QStringLiteral("membership")
+ static const QStringList keepKeys { EventIdKey,
+ TypeKey,
+ QStringLiteral("room_id"),
+ QStringLiteral("sender"),
+ QStringLiteral("state_key"),
+ QStringLiteral("prev_content"),
+ ContentKey,
+ QStringLiteral("hashes"),
+ QStringLiteral("signatures"),
+ QStringLiteral("depth"),
+ QStringLiteral("prev_events"),
+ QStringLiteral("prev_state"),
+ QStringLiteral("auth_events"),
+ QStringLiteral("origin"),
+ QStringLiteral("origin_server_ts"),
+ QStringLiteral("membership") };
+
+ std::vector<std::pair<Event::Type, QStringList>> keepContentKeysMap {
+ { RoomMemberEvent::typeId(), { QStringLiteral("membership") } },
+ { RoomCreateEvent::typeId(), { QStringLiteral("creator") } }
+ // , { RoomJoinRules::typeId(), { QStringLiteral("join_rule") } }
+ // , { RoomPowerLevels::typeId(),
+ // { QStringLiteral("ban"), QStringLiteral("events"),
+ // QStringLiteral("events_default"),
+ // QStringLiteral("kick"), QStringLiteral("redact"),
+ // QStringLiteral("state_default"),
+ // QStringLiteral("users"), QStringLiteral("users_default")
+ // } }
+ ,
+ { RoomAliasesEvent::typeId(), { QStringLiteral("aliases") } }
+ // , { RoomHistoryVisibility::typeId(),
+ // { QStringLiteral("history_visibility") } }
};
-
- std::vector<std::pair<Event::Type, QStringList>> keepContentKeysMap
- { { RoomMemberEvent::typeId(), { QStringLiteral("membership") } }
- , { RoomCreateEvent::typeId(), { QStringLiteral("creator") } }
-// , { RoomJoinRules::typeId(), { QStringLiteral("join_rule") } }
-// , { RoomPowerLevels::typeId(),
-// { QStringLiteral("ban"), QStringLiteral("events"),
-// QStringLiteral("events_default"), QStringLiteral("kick"),
-// QStringLiteral("redact"), QStringLiteral("state_default"),
-// QStringLiteral("users"), QStringLiteral("users_default") } }
- , { RoomAliasesEvent::typeId(), { QStringLiteral("aliases") } }
-// , { RoomHistoryVisibility::typeId(),
-// { QStringLiteral("history_visibility") } }
- };
- for (auto it = originalJson.begin(); it != originalJson.end();)
- {
+ for (auto it = originalJson.begin(); it != originalJson.end();) {
if (!keepKeys.contains(it.key()))
it = originalJson.erase(it); // TODO: shred the value
else
++it;
}
- auto keepContentKeys =
- find_if(keepContentKeysMap.begin(), keepContentKeysMap.end(),
- [&target](const auto& t) { return target.type() == t.first; } );
- if (keepContentKeys == keepContentKeysMap.end())
- {
+ auto keepContentKeys = find_if(
+ keepContentKeysMap.begin(), keepContentKeysMap.end(),
+ [&target](const auto& t) { return target.type() == t.first; });
+ if (keepContentKeys == keepContentKeysMap.end()) {
originalJson.remove(ContentKeyL);
originalJson.remove(PrevContentKeyL);
} else {
auto content = originalJson.take(ContentKeyL).toObject();
- for (auto it = content.begin(); it != content.end(); )
- {
+ for (auto it = content.begin(); it != content.end();) {
if (!keepContentKeys->second.contains(it.key()))
it = content.erase(it);
else
@@ -1934,10 +1819,9 @@ bool Room::Private::processRedaction(const RedactionEvent& redaction)
Q_ASSERT(q->isValidIndex(*pIdx));
auto& ti = timeline[Timeline::size_type(*pIdx - q->minTimelineIndex())];
- if (ti->isRedacted() && ti->redactedBecause()->id() == redaction.id())
- {
- qCDebug(MAIN) << "Redaction" << redaction.id()
- << "of event" << ti->id() << "already done, skipping";
+ if (ti->isRedacted() && ti->redactedBecause()->id() == redaction.id()) {
+ qCDebug(MAIN) << "Redaction" << redaction.id() << "of event" << ti->id()
+ << "already done, skipping";
return true;
}
@@ -1945,15 +1829,16 @@ bool Room::Private::processRedaction(const RedactionEvent& redaction)
// instead of the redacted one. oldEvent will be deleted on return.
auto oldEvent = ti.replaceEvent(makeRedacted(*ti, redaction));
qCDebug(MAIN) << "Redacted" << oldEvent->id() << "with" << redaction.id();
- if (oldEvent->isStateEvent())
- {
- const StateEventKey evtKey { oldEvent->matrixType(), oldEvent->stateKey() };
+ if (oldEvent->isStateEvent()) {
+ const StateEventKey evtKey { oldEvent->matrixType(),
+ oldEvent->stateKey() };
Q_ASSERT(currentState.contains(evtKey));
- if (currentState[evtKey] == oldEvent.get())
- {
- Q_ASSERT(ti.index() >= 0); // Historical states can't be in currentState
- qCDebug(MAIN).nospace() << "Reverting state "
- << oldEvent->matrixType() << "/" << oldEvent->stateKey();
+ if (currentState[evtKey] == oldEvent.get()) {
+ Q_ASSERT(ti.index()
+ >= 0); // Historical states can't be in currentState
+ qCDebug(MAIN).nospace()
+ << "Reverting state " << oldEvent->matrixType() << "/"
+ << oldEvent->stateKey();
// Retarget the current state to the newly made event.
if (q->processStateEvent(*ti))
emit q->namesChanged(q);
@@ -1971,10 +1856,7 @@ Connection* Room::connection() const
return d->connection;
}
-User* Room::localUser() const
-{
- return connection()->user();
-}
+User* Room::localUser() const { return connection()->user(); }
inline bool isRedaction(const RoomEventPtr& ep)
{
@@ -1992,22 +1874,22 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
// batch landed in the timeline already redacted.
// NB: We have to store redaction events to the timeline too - see #220.
auto redactionIt = std::find_if(events.begin(), events.end(), isRedaction);
- for(const auto& eptr: RoomEventsRange(redactionIt, events.end()))
- if (auto* r = eventCast<RedactionEvent>(eptr))
- {
+ for (const auto& eptr : RoomEventsRange(redactionIt, events.end()))
+ if (auto* r = eventCast<RedactionEvent>(eptr)) {
// Try to find the target in the timeline, then in the batch.
if (processRedaction(*r))
continue;
- auto targetIt = std::find_if(events.begin(), redactionIt,
- [id=r->redactedEvent()] (const RoomEventPtr& ep) {
- return ep->id() == id;
- });
+ auto targetIt = std::find_if(
+ events.begin(), redactionIt,
+ [id = r->redactedEvent()](const RoomEventPtr& ep) {
+ return ep->id() == id;
+ });
if (targetIt != redactionIt)
*targetIt = makeRedacted(**targetIt, *r);
else
- qCDebug(MAIN) << "Redaction" << r->id()
- << "ignored: target event" << r->redactedEvent()
- << "is not found";
+ qCDebug(MAIN)
+ << "Redaction" << r->id() << "ignored: target event"
+ << r->redactedEvent() << "is not found";
// If the target event comes later, it comes already redacted.
}
@@ -2017,26 +1899,26 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
// postulate that the current state is only current between syncs but not
// within a sync.
Changes roomChanges = Change::NoChange;
- for (const auto& eptr: events)
+ for (const auto& eptr : events)
roomChanges |= q->processStateEvent(*eptr);
auto timelineSize = timeline.size();
auto totalInserted = 0;
- for (auto it = events.begin(); it != events.end();)
- {
- auto nextPendingPair = findFirstOf(it, events.end(),
- unsyncedEvents.begin(), unsyncedEvents.end(), isEchoEvent);
+ for (auto it = events.begin(); it != events.end();) {
+ auto nextPendingPair =
+ findFirstOf(it, events.end(), unsyncedEvents.begin(),
+ unsyncedEvents.end(), isEchoEvent);
auto nextPending = nextPendingPair.first;
- if (it != nextPending)
- {
+ if (it != nextPending) {
RoomEventsRange eventsSpan { it, nextPending };
emit q->aboutToAddNewMessages(eventsSpan);
auto insertedSize = moveEventsToTimeline(eventsSpan, Newer);
totalInserted += insertedSize;
auto firstInserted = timeline.cend() - insertedSize;
q->onAddNewTimelineEvents(firstInserted);
- emit q->addedMessages(firstInserted->index(), timeline.back().index());
+ emit q->addedMessages(firstInserted->index(),
+ timeline.back().index());
}
if (nextPending == events.end())
break;
@@ -2058,8 +1940,8 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
// unsyncedEvents (see #286). Fortunately, unsyncedEvents only grows at
// its back so we can rely on the index staying valid at least.
unsyncedEvents.erase(unsyncedEvents.begin() + pendingEvtIdx);
- if (auto insertedSize = moveEventsToTimeline({nextPending, it}, Newer))
- {
+ if (auto insertedSize =
+ moveEventsToTimeline({ nextPending, it }, Newer)) {
totalInserted += insertedSize;
q->onAddNewTimelineEvents(timeline.cend() - insertedSize);
}
@@ -2073,11 +1955,10 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
if (auto* evt = it->viewAs<CallEventBase>())
emit q->callEvent(q, evt);
- if (totalInserted > 0)
- {
- qCDebug(MAIN)
- << "Room" << q->objectName() << "received" << totalInserted
- << "new events; the last event is now" << timeline.back();
+ if (totalInserted > 0) {
+ qCDebug(MAIN) << "Room" << q->objectName() << "received"
+ << totalInserted << "new events; the last event is now"
+ << timeline.back();
// The first event in the just-added batch (referred to by `from`)
// defines whose read marker can possibly be promoted any further over
@@ -2086,11 +1967,11 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
// markMessagesAsRead() invocation) to promote their read markers over
// the new message events.
auto firstWriter = q->user((*from)->senderId());
- if (q->readMarker(firstWriter) != timeline.crend())
- {
+ if (q->readMarker(firstWriter) != timeline.crend()) {
roomChanges |= promoteReadMarker(firstWriter, rev_iter_t(from) - 1);
- qCDebug(MAIN) << "Auto-promoted read marker for" << firstWriter->id()
- << "to" << *q->readMarker(firstWriter);
+ qCDebug(MAIN) << "Auto-promoted read marker for"
+ << firstWriter->id() << "to"
+ << *q->readMarker(firstWriter);
}
updateUnreadCount(timeline.crbegin(), rev_iter_t(from));
@@ -2103,7 +1984,8 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
void Room::Private::addHistoricalMessageEvents(RoomEvents&& events)
{
- QElapsedTimer et; et.start();
+ QElapsedTimer et;
+ et.start();
const auto timelineSize = timeline.size();
dropDuplicateEvents(events);
@@ -2114,12 +1996,10 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events)
// messages. Also, the cache doesn't store events with empty content;
// so when such events show up in the timeline they should be properly
// incorporated.
- for (const auto& eptr: events)
- {
+ for (const auto& eptr : events) {
const auto& e = *eptr;
- if (e.isStateEvent() &&
- !currentState.contains({e.matrixType(), e.stateKey()}))
- {
+ if (e.isStateEvent()
+ && !currentState.contains({ e.matrixType(), e.stateKey() })) {
q->processStateEvent(e);
}
}
@@ -2147,167 +2027,157 @@ Room::Changes Room::processStateEvent(const RoomEvent& e)
if (!e.isStateEvent())
return Change::NoChange;
- const auto* oldStateEvent = std::exchange(
- d->currentState[{e.matrixType(),e.stateKey()}],
- static_cast<const StateEventBase*>(&e));
- Q_ASSERT(!oldStateEvent ||
- (oldStateEvent->matrixType() == e.matrixType() &&
- oldStateEvent->stateKey() == e.stateKey()));
+ const auto* oldStateEvent =
+ std::exchange(d->currentState[{ e.matrixType(), e.stateKey() }],
+ static_cast<const StateEventBase*>(&e));
+ Q_ASSERT(!oldStateEvent
+ || (oldStateEvent->matrixType() == e.matrixType()
+ && oldStateEvent->stateKey() == e.stateKey()));
if (!is<RoomMemberEvent>(e))
qCDebug(EVENTS) << "Room state event:" << e;
- return visit(e
- , [] (const RoomNameEvent&) {
- return NameChange;
- }
- , [this,oldStateEvent] (const RoomAliasesEvent& ae) {
- const auto previousAliases = oldStateEvent
- ? static_cast<const RoomAliasesEvent*>(oldStateEvent)->aliases()
- : QStringList();
- connection()->updateRoomAliases(id(), previousAliases, ae.aliases());
- return OtherChange;
- }
- , [this] (const RoomCanonicalAliasEvent& evt) {
- setObjectName(evt.alias().isEmpty() ? d->id : evt.alias());
- return CanonicalAliasChange;
- }
- , [] (const RoomTopicEvent&) {
- return TopicChange;
- }
- , [this] (const RoomAvatarEvent& evt) {
- if (d->avatar.updateUrl(evt.url()))
- emit avatarChanged();
- return AvatarChange;
- }
- , [this] (const RoomMemberEvent& evt) {
- auto* u = user(evt.userId());
- u->processEvent(evt, this);
- if (u == localUser() && memberJoinState(u) == JoinState::Invite
+ return visit(
+ e, [](const RoomNameEvent&) { return NameChange; },
+ [this, oldStateEvent](const RoomAliasesEvent& ae) {
+ const auto previousAliases = oldStateEvent
+ ? static_cast<const RoomAliasesEvent*>(oldStateEvent)
+ ->aliases()
+ : QStringList();
+ connection()->updateRoomAliases(id(), previousAliases,
+ ae.aliases());
+ return OtherChange;
+ },
+ [this](const RoomCanonicalAliasEvent& evt) {
+ setObjectName(evt.alias().isEmpty() ? d->id : evt.alias());
+ return CanonicalAliasChange;
+ },
+ [](const RoomTopicEvent&) { return TopicChange; },
+ [this](const RoomAvatarEvent& evt) {
+ if (d->avatar.updateUrl(evt.url()))
+ emit avatarChanged();
+ return AvatarChange;
+ },
+ [this](const RoomMemberEvent& evt) {
+ auto* u = user(evt.userId());
+ u->processEvent(evt, this);
+ if (u == localUser() && memberJoinState(u) == JoinState::Invite
&& evt.isDirect())
- connection()->addToDirectChats(this, user(evt.senderId()));
-
- if( evt.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( evt.membership() != MembershipType::Join )
- {
- if (memberJoinState(u) == JoinState::Join)
- {
- if (evt.membership() == MembershipType::Invite)
- qCWarning(MAIN) << "Invalid membership change:" << evt;
- if (!d->membersLeft.contains(u))
- d->membersLeft.append(u);
- d->removeMemberFromMap(u->name(this), u);
- emit userRemoved(u);
+ connection()->addToDirectChats(this, user(evt.senderId()));
+
+ if (evt.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 (evt.membership() != MembershipType::Join) {
+ if (memberJoinState(u) == JoinState::Join) {
+ if (evt.membership() == MembershipType::Invite)
+ qCWarning(MAIN)
+ << "Invalid membership change:" << evt;
+ if (!d->membersLeft.contains(u))
+ d->membersLeft.append(u);
+ d->removeMemberFromMap(u->name(this), u);
+ emit userRemoved(u);
+ }
}
- }
- return MembersChange;
- }
- , [this] (const EncryptionEvent&) {
- emit encryption(); // It can only be done once, so emit it here.
- return OtherChange;
- }
- , [this] (const RoomTombstoneEvent& evt) {
- const auto successorId = evt.successorRoomId();
- if (auto* successor = connection()->room(successorId))
- emit upgraded(evt.serverMessage(), successor);
- else
- connectUntil(connection(), &Connection::loadedRoomState, this,
- [this,successorId,serverMsg=evt.serverMessage()]
- (Room* newRoom) {
- if (newRoom->id() != successorId)
- return false;
- emit upgraded(serverMsg, newRoom);
- return true;
- });
-
- return OtherChange;
- }
- );
+ return MembersChange;
+ },
+ [this](const EncryptionEvent&) {
+ emit encryption(); // It can only be done once, so emit it here.
+ return OtherChange;
+ },
+ [this](const RoomTombstoneEvent& evt) {
+ const auto successorId = evt.successorRoomId();
+ if (auto* successor = connection()->room(successorId))
+ emit upgraded(evt.serverMessage(), successor);
+ else
+ connectUntil(
+ connection(), &Connection::loadedRoomState, this,
+ [this, successorId,
+ serverMsg = evt.serverMessage()](Room* newRoom) {
+ if (newRoom->id() != successorId)
+ return false;
+ emit upgraded(serverMsg, newRoom);
+ return true;
+ });
+
+ return OtherChange;
+ });
}
Room::Changes Room::processEphemeralEvent(EventPtr&& event)
{
Changes changes = NoChange;
- QElapsedTimer et; et.start();
- if (auto* evt = eventCast<TypingEvent>(event))
- {
+ QElapsedTimer et;
+ et.start();
+ if (auto* evt = eventCast<TypingEvent>(event)) {
d->usersTyping.clear();
- for( const QString& userId: qAsConst(evt->users()) )
- {
+ for (const QString& userId : qAsConst(evt->users())) {
auto u = user(userId);
if (memberJoinState(u) == JoinState::Join)
d->usersTyping.append(u);
}
if (evt->users().size() > 3 || et.nsecsElapsed() >= profilerMinNsecs())
qCDebug(PROFILER) << "*** Room::processEphemeralEvent(typing):"
- << evt->users().size() << "users," << et;
+ << evt->users().size() << "users," << et;
emit typingChanged();
}
- if (auto* evt = eventCast<ReceiptEvent>(event))
- {
+ if (auto* evt = eventCast<ReceiptEvent>(event)) {
int totalReceipts = 0;
- for( const auto &p: qAsConst(evt->eventsWithReceipts()) )
- {
+ for (const auto& p : qAsConst(evt->eventsWithReceipts())) {
totalReceipts += p.receipts.size();
{
if (p.receipts.size() == 1)
- qCDebug(EPHEMERAL) << "Marking" << p.evtId
- << "as read for" << p.receipts[0].userId;
+ qCDebug(EPHEMERAL) << "Marking" << p.evtId << "as read for"
+ << p.receipts[0].userId;
else
- qCDebug(EPHEMERAL) << "Marking" << p.evtId
- << "as read for" << p.receipts.size() << "users";
+ qCDebug(EPHEMERAL) << "Marking" << p.evtId << "as read for"
+ << p.receipts.size() << "users";
}
const auto newMarker = findInTimeline(p.evtId);
- if (newMarker != timelineEdge())
- {
- for( const Receipt& r: p.receipts )
- {
+ if (newMarker != timelineEdge()) {
+ for (const Receipt& r : p.receipts) {
if (r.userId == connection()->userId())
continue; // FIXME, #185
auto u = user(r.userId);
if (memberJoinState(u) == JoinState::Join)
changes |= d->promoteReadMarker(u, newMarker);
}
- } else
- {
+ } else {
qCDebug(EPHEMERAL) << "Event" << p.evtId
- << "not found; saving read receipts anyway";
+ << "not found; saving read receipts anyway";
// If the event is not found (most likely, because it's too old
// and hasn't been fetched from the server yet), but there is
// a previous marker for a user, keep the previous marker.
// Otherwise, blindly store the event id for this user.
- for( const Receipt& r: p.receipts )
- {
+ for (const Receipt& r : p.receipts) {
if (r.userId == connection()->userId())
continue; // FIXME, #185
auto u = user(r.userId);
- if (memberJoinState(u) == JoinState::Join &&
- readMarker(u) == timelineEdge())
+ if (memberJoinState(u) == JoinState::Join
+ && readMarker(u) == timelineEdge())
changes |= d->setLastReadEvent(u, p.evtId);
}
}
}
- if (evt->eventsWithReceipts().size() > 3 || totalReceipts > 10 ||
- et.nsecsElapsed() >= profilerMinNsecs())
- qCDebug(PROFILER) << "*** Room::processEphemeralEvent(receipts):"
- << evt->eventsWithReceipts().size()
- << "event(s) with" << totalReceipts << "receipt(s)," << et;
+ if (evt->eventsWithReceipts().size() > 3 || totalReceipts > 10
+ || et.nsecsElapsed() >= profilerMinNsecs())
+ qCDebug(PROFILER)
+ << "*** Room::processEphemeralEvent(receipts):"
+ << evt->eventsWithReceipts().size() << "event(s) with"
+ << totalReceipts << "receipt(s)," << et;
}
return changes;
}
@@ -2315,28 +2185,25 @@ Room::Changes Room::processEphemeralEvent(EventPtr&& event)
Room::Changes Room::processAccountDataEvent(EventPtr&& event)
{
Changes changes = NoChange;
- if (auto* evt = eventCast<TagEvent>(event))
- {
+ if (auto* evt = eventCast<TagEvent>(event)) {
d->setTags(evt->tags());
changes |= Change::TagsChange;
}
- if (auto* evt = eventCast<ReadMarkerEvent>(event))
- {
+ if (auto* evt = eventCast<ReadMarkerEvent>(event)) {
auto readEventId = evt->event_id();
qCDebug(MAIN) << "Server-side read marker at" << readEventId;
d->serverReadMarker = readEventId;
const auto newMarker = findInTimeline(readEventId);
changes |= newMarker != timelineEdge()
- ? d->markMessagesAsRead(newMarker)
- : d->setLastReadEvent(localUser(), readEventId);
+ ? d->markMessagesAsRead(newMarker)
+ : d->setLastReadEvent(localUser(), readEventId);
}
// For all account data events
auto& currentData = d->accountData[event->matrixType()];
// A polymorphic event-specific comparison might be a bit more
// efficient; maaybe do it another day
- if (!currentData || currentData->contentJson() != event->contentJson())
- {
+ if (!currentData || currentData->contentJson() != event->contentJson()) {
emit accountDataAboutToChange(event->matrixType());
currentData = move(event);
qCDebug(MAIN) << "Updated account data of type"
@@ -2356,15 +2223,14 @@ Room::Private::buildShortlist(const ContT& users) const
// display names of two topmost users excluding the current one to render
// the name of the room. The below code selects 3 topmost users,
// slightly extending the spec.
- users_shortlist_t shortlist { }; // Prefill with nullptrs
+ users_shortlist_t shortlist {}; // Prefill with nullptrs
std::partial_sort_copy(
- users.begin(), users.end(),
- shortlist.begin(), shortlist.end(),
- [this] (const User* u1, const User* u2) {
- // localUser(), if it's in the list, is sorted below all others
- return isLocalUser(u2) || (!isLocalUser(u1) && u1->id() < u2->id());
- }
- );
+ users.begin(), users.end(), shortlist.begin(), shortlist.end(),
+ [this](const User* u1, const User* u2) {
+ // localUser(), if it's in the list, is sorted below all others
+ return isLocalUser(u2)
+ || (!isLocalUser(u1) && u1->id() < u2->id());
+ });
return shortlist;
}
@@ -2373,7 +2239,7 @@ Room::Private::buildShortlist(const QStringList& userIds) const
{
QList<User*> users;
users.reserve(userIds.size());
- for (const auto& h: userIds)
+ for (const auto& h : userIds)
users.push_back(q->user(h));
return buildShortlist(users);
}
@@ -2395,23 +2261,22 @@ QString Room::Private::calculateDisplayname() const
return dispName;
// Using m.room.aliases in naming is explicitly discouraged by the spec
- //if (!q->aliases().empty() && !q->aliases().at(0).isEmpty())
+ // if (!q->aliases().empty() && !q->aliases().at(0).isEmpty())
// return q->aliases().at(0);
// Supplementary code for 3 and 4: build the shortlist of users whose names
// will be used to construct the room name. Takes into account MSC688's
// "heroes" if available.
- const bool emptyRoom = membersMap.isEmpty() ||
- (membersMap.size() == 1 && isLocalUser(*membersMap.begin()));
- const auto shortlist =
- !summary.heroes.omitted() ? buildShortlist(summary.heroes.value()) :
- !emptyRoom ? buildShortlist(membersMap) :
- buildShortlist(membersLeft);
+ const bool emptyRoom = membersMap.isEmpty()
+ || (membersMap.size() == 1 && isLocalUser(*membersMap.begin()));
+ const auto shortlist = !summary.heroes.omitted()
+ ? buildShortlist(summary.heroes.value())
+ : !emptyRoom ? buildShortlist(membersMap)
+ : buildShortlist(membersLeft);
QStringList names;
- for (auto u: shortlist)
- {
+ for (auto u : shortlist) {
if (u == nullptr || isLocalUser(u))
break;
names.push_back(q->roomMembername(u));
@@ -2421,10 +2286,10 @@ QString Room::Private::calculateDisplayname() const
? membersLeft.size() - int(joinState == JoinState::Leave)
: q->joinedCount() - int(joinState == JoinState::Join);
if (usersCountExceptLocal > int(shortlist.size()))
- names <<
- tr("%Ln other(s)",
- "Used to make a room name from user names: A, B and _N others_",
- usersCountExceptLocal);
+ names << tr(
+ "%Ln other(s)",
+ "Used to make a room name from user names: A, B and _N others_",
+ usersCountExceptLocal);
auto namesList = QLocale().createSeparatedList(names);
// 3. Room members
@@ -2442,8 +2307,7 @@ QString Room::Private::calculateDisplayname() const
void Room::Private::updateDisplayname()
{
auto swappedName = calculateDisplayname();
- if (swappedName != displayname)
- {
+ if (swappedName != displayname) {
emit q->displaynameAboutToChange(q);
swap(displayname, swappedName);
qDebug(MAIN) << q->objectName() << "has changed display name from"
@@ -2454,17 +2318,17 @@ void Room::Private::updateDisplayname()
QJsonObject Room::Private::toJson() const
{
- QElapsedTimer et; et.start();
+ QElapsedTimer et;
+ et.start();
QJsonObject result;
addParam<IfNotEmpty>(result, QStringLiteral("summary"), summary);
{
QJsonArray stateEvents;
- for (const auto* evt: currentState)
- {
+ for (const auto* evt : currentState) {
Q_ASSERT(evt->isStateEvent());
- if ((evt->isRedacted() && !is<RoomMemberEvent>(*evt)) ||
- evt->contentJson().isEmpty())
+ if ((evt->isRedacted() && !is<RoomMemberEvent>(*evt))
+ || evt->contentJson().isEmpty())
continue;
auto json = evt->fullJson();
@@ -2474,56 +2338,54 @@ QJsonObject Room::Private::toJson() const
stateEvents.append(json);
}
- const auto stateObjName = joinState == JoinState::Invite ?
- QStringLiteral("invite_state") : QStringLiteral("state");
- result.insert(stateObjName,
- QJsonObject {{ QStringLiteral("events"), stateEvents }});
+ const auto stateObjName = joinState == JoinState::Invite
+ ? QStringLiteral("invite_state")
+ : QStringLiteral("state");
+ result.insert(
+ stateObjName,
+ QJsonObject { { QStringLiteral("events"), stateEvents } });
}
- if (!accountData.empty())
- {
+ if (!accountData.empty()) {
QJsonArray accountDataEvents;
- for (const auto& e: accountData)
- {
+ for (const auto& e : accountData) {
if (!e.second->contentJson().isEmpty())
accountDataEvents.append(e.second->fullJson());
}
result.insert(QStringLiteral("account_data"),
- QJsonObject {{ QStringLiteral("events"), accountDataEvents }});
+ QJsonObject { { QStringLiteral("events"),
+ accountDataEvents } });
}
- QJsonObject unreadNotifObj
- { { SyncRoomData::UnreadCountKey, unreadMessages } };
+ QJsonObject unreadNotifObj { { SyncRoomData::UnreadCountKey,
+ unreadMessages } };
if (highlightCount > 0)
- unreadNotifObj.insert(QStringLiteral("highlight_count"), highlightCount);
+ unreadNotifObj.insert(QStringLiteral("highlight_count"),
+ highlightCount);
if (notificationCount > 0)
- unreadNotifObj.insert(QStringLiteral("notification_count"), notificationCount);
+ unreadNotifObj.insert(QStringLiteral("notification_count"),
+ notificationCount);
result.insert(QStringLiteral("unread_notifications"), unreadNotifObj);
if (et.elapsed() > 30)
- qCDebug(PROFILER) << "Room::toJson() for" << displayname << "took" << et;
+ qCDebug(PROFILER) << "Room::toJson() for" << displayname << "took"
+ << et;
return result;
}
-QJsonObject Room::toJson() const
-{
- return d->toJson();
-}
+QJsonObject Room::toJson() const { return d->toJson(); }
-MemberSorter Room::memberSorter() const
-{
- return MemberSorter(this);
-}
+MemberSorter Room::memberSorter() const { return MemberSorter(this); }
-bool MemberSorter::operator()(User *u1, User *u2) const
+bool MemberSorter::operator()(User* u1, User* u2) const
{
return operator()(u1, room->roomMembername(u2));
}
-bool MemberSorter::operator ()(User* u1, const QString& u2name) const
+bool MemberSorter::operator()(User* u1, const QString& u2name) const
{
auto n1 = room->roomMembername(u1);
if (n1.startsWith('@'))