aboutsummaryrefslogtreecommitdiff
path: root/room.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'room.cpp')
-rw-r--r--room.cpp132
1 files changed, 73 insertions, 59 deletions
diff --git a/room.cpp b/room.cpp
index f13fae19..9f57f3fd 100644
--- a/room.cpp
+++ b/room.cpp
@@ -23,7 +23,7 @@
#include <QtCore/QHash>
#include <QtCore/QJsonArray>
#include <QtCore/QStringBuilder> // for efficient string concats (operator%)
-#include <QtCore/QDebug>
+#include <QtCore/QElapsedTimer>
#include "connection.h"
#include "state.h"
@@ -39,6 +39,7 @@
#include "jobs/postmessagejob.h"
#include "jobs/roommessagesjob.h"
#include "jobs/postreceiptjob.h"
+#include "jobs/leaveroomjob.h"
using namespace QMatrixClient;
@@ -49,10 +50,10 @@ class Room::Private
typedef QMultiHash<QString, User*> members_map_t;
typedef std::pair<rev_iter_t, rev_iter_t> rev_iter_pair_t;
- Private(Connection* c, const QString& id_)
- : q(nullptr), connection(c), id(id_), joinState(JoinState::Join)
- , unreadMessages(false), highlightCount(0), notificationCount(0)
- , roomMessagesJob(nullptr)
+ Private(Connection* c, QString id_)
+ : q(nullptr), connection(c), id(std::move(id_))
+ , joinState(JoinState::Join), unreadMessages(false)
+ , highlightCount(0), notificationCount(0), roomMessagesJob(nullptr)
{ }
Room* q;
@@ -89,7 +90,7 @@ class Room::Private
void addMember(User* u);
bool hasMember(User* u) const;
// You can't identify a single user by displayname, only by id
- User* member(QString id) const;
+ User* member(const QString& id) const;
void renameMember(User* u, QString oldName);
void removeMember(User* u);
@@ -115,9 +116,9 @@ class Room::Private
/**
* Removes events from the passed container that are already in the timeline
*/
- void dropDuplicateEvents(Events& events) const;
+ void dropDuplicateEvents(Events* events) const;
- void setLastReadEvent(User* u, QString eventId);
+ void setLastReadEvent(User* u, const QString& eventId);
rev_iter_pair_t promoteReadMarker(User* u, rev_iter_t newMarker);
private:
@@ -125,7 +126,7 @@ class Room::Private
QString roomNameFromMemberNames(const QList<User*>& userlist) const;
void insertMemberIntoMap(User* u);
- void removeMemberFromMap(QString username, User* u);
+ void removeMemberFromMap(const QString& username, User* u);
void insertEvent(Event* e, Timeline::iterator where,
TimelineItem::index_t index);
@@ -138,8 +139,6 @@ Room::Room(Connection* connection, QString id)
// https://marcmutz.wordpress.com/translated-articles/pimp-my-pimpl-%E2%80%94-reloaded/
d->q = this;
qCDebug(MAIN) << "New Room:" << id;
-
- //connection->getMembers(this); // I don't think we need this anymore in r0.0.1
}
Room::~Room()
@@ -196,7 +195,7 @@ void Room::setJoinState(JoinState state)
emit joinStateChanged(oldState, state);
}
-void Room::Private::setLastReadEvent(User* u, QString eventId)
+void Room::Private::setLastReadEvent(User* u, const QString& eventId)
{
lastReadEventIds.insert(u, eventId);
emit q->lastReadEventChanged(u);
@@ -235,7 +234,7 @@ Room::Private::promoteReadMarker(User* u, Room::rev_iter_t newMarker)
emit q->unreadMessagesChanged(q);
} else
qCDebug(MAIN) << "Room" << displayname << "still has"
- << stillUnreadMessagesCount << "unread message(s)";
+ << stillUnreadMessagesCount << "unread message(s)";
}
// Return newMarker, rather than eagerMarker, to save markMessagesAsRead()
@@ -245,7 +244,7 @@ Room::Private::promoteReadMarker(User* u, Room::rev_iter_t newMarker)
void Room::markMessagesAsRead(Room::rev_iter_t upToMarker)
{
- User* localUser = connection()->user();
+ auto localUser = connection()->user();
Private::rev_iter_pair_t markers = d->promoteReadMarker(localUser, upToMarker);
if (markers.first != markers.second)
qCDebug(MAIN) << "Marked messages as read until" << *readMarker();
@@ -307,7 +306,7 @@ Room::rev_iter_t Room::findInTimeline(TimelineItem::index_t index) const
(isValidIndex(index) ? index - minTimelineIndex() + 1 : 0);
}
-Room::rev_iter_t Room::findInTimeline(QString evtId) const
+Room::rev_iter_t Room::findInTimeline(const QString& evtId) const
{
if (!d->timeline.empty() && d->eventsIndex.contains(evtId))
return findInTimeline(d->eventsIndex.value(evtId));
@@ -350,7 +349,7 @@ int Room::highlightCount() const
void Room::resetHighlightCount()
{
-if( d->highlightCount == 0 )
+ if( d->highlightCount == 0 )
return;
d->highlightCount = 0;
emit highlightCountChanged(this);
@@ -373,27 +372,23 @@ QList< User* > Room::users() const
void Room::Private::insertMemberIntoMap(User *u)
{
- QList<User*> namesakes = membersMap.values(u->name());
+ auto namesakes = membersMap.values(u->name());
membersMap.insert(u->name(), u);
// 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 (namesakes.size() == 1)
emit q->memberRenamed(namesakes[0]);
-
- updateDisplayname();
}
-void Room::Private::removeMemberFromMap(QString username, User* u)
+void Room::Private::removeMemberFromMap(const QString& username, User* u)
{
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.
// TODO: Think about left users.
- QList<User*> formerNamesakes = membersMap.values(username);
+ auto formerNamesakes = membersMap.values(username);
if (formerNamesakes.size() == 1)
emit q->memberRenamed(formerNamesakes[0]);
-
- updateDisplayname();
}
inline QByteArray makeErrorStr(const Event* e, const char* msg)
@@ -414,7 +409,7 @@ void Room::Private::insertEvent(Event* e, Timeline::iterator where,
{
qCWarning(MAIN) << "Event" << e->id() << "is already in the timeline.";
qCWarning(MAIN) << "Either dropDuplicateEvents() wasn't called or duplicate "
- "events within the same batch arrived from the server.";
+ "events within the same batch arrived from the server.";
return;
}
timeline.emplace(where, e, index);
@@ -437,9 +432,9 @@ bool Room::Private::hasMember(User* u) const
return membersMap.values(u->name()).contains(u);
}
-User* Room::Private::member(QString id) const
+User* Room::Private::member(const QString& id) const
{
- User* u = connection->user(id);
+ auto u = connection->user(id);
return hasMember(u) ? u : nullptr;
}
@@ -448,8 +443,8 @@ void Room::Private::renameMember(User* u, QString oldName)
if (hasMember(u))
{
qCWarning(MAIN) << "Room::Private::renameMember(): the user "
- << u->name()
- << "is already known in the room under a new name.";
+ << u->name()
+ << "is already known in the room under a new name.";
return;
}
@@ -458,8 +453,6 @@ void Room::Private::renameMember(User* u, QString oldName)
removeMemberFromMap(oldName, u);
insertMemberIntoMap(u);
emit q->memberRenamed(u);
-
- updateDisplayname();
}
}
@@ -476,7 +469,7 @@ void Room::Private::removeMember(User* u)
void Room::userRenamed(User* user, QString oldName)
{
- d->renameMember(user, oldName);
+ d->renameMember(user, std::move(oldName));
}
QString Room::roomMembername(User *u) const
@@ -510,27 +503,38 @@ QString Room::roomMembername(User *u) const
return username % " (" % u->id() % ")";
}
-QString Room::roomMembername(QString userId) const
+QString Room::roomMembername(const QString& userId) const
{
return roomMembername(connection()->user(userId));
}
-void Room::updateData(SyncRoomData& data)
+void Room::updateData(SyncRoomData&& data)
{
if( d->prevBatch.isEmpty() )
d->prevBatch = data.timelinePrevBatch;
setJoinState(data.joinState);
+ QElapsedTimer et; et.start();
+
processStateEvents(data.state);
+ qCDebug(PROFILER) << "*** Room::processStateEvents(state):"
+ << et.elapsed() << "ms," << data.state.size() << "events";
+ et.restart();
// State changes can arrive in a timeline event; so check those.
processStateEvents(data.timeline);
+ qCDebug(PROFILER) << "*** Room::processStateEvents(timeline):"
+ << et.elapsed() << "ms," << data.timeline.size() << "events";
+ et.restart();
addNewMessageEvents(data.timeline.release());
+ qCDebug(PROFILER) << "*** Room::addNewMessageEvents():" << et.elapsed() << "ms";
+ et.restart();
for( Event* ephemeralEvent: data.ephemeral )
{
processEphemeralEvent(ephemeralEvent);
}
+ qCDebug(PROFILER) << "*** Room::processEphemeralEvents():" << et.elapsed() << "ms";
if( data.highlightCount != d->highlightCount )
{
@@ -577,15 +581,20 @@ void Room::Private::getPreviousContent(int limit)
}
}
-void Room::Private::dropDuplicateEvents(Events& events) const
+void Room::leaveRoom() const
+{
+ connection()->callApi<LeaveRoomJob>(id());
+}
+
+void Room::Private::dropDuplicateEvents(Events* events) const
{
// Collect all duplicate events at the end of the container
auto dupsBegin =
- std::stable_partition(events.begin(), events.end(),
+ std::stable_partition(events->begin(), events->end(),
[&] (Event* e) { return !eventsIndex.contains(e->id()); });
// Dispose of those dups
- std::for_each(dupsBegin, events.end(), [] (Event* e) { delete e; });
- events.erase(dupsBegin, events.end());
+ std::for_each(dupsBegin, events->end(), [] (Event* e) { delete e; });
+ events->erase(dupsBegin, events->end());
}
Connection* Room::connection() const
@@ -595,7 +604,7 @@ Connection* Room::connection() const
void Room::addNewMessageEvents(Events events)
{
- d->dropDuplicateEvents(events);
+ d->dropDuplicateEvents(&events);
if (events.empty())
return;
emit aboutToAddNewMessages(events);
@@ -614,8 +623,8 @@ void Room::doAddNewMessageEvents(const Events& events)
newUnreadMessages += d->isEventNotable(e);
}
qCDebug(MAIN) << "Room" << displayName() << "received" << events.size()
- << "(with" << newUnreadMessages << "notable)"
- << "new events; the last event is now" << d->timeline.back();
+ << "(with" << newUnreadMessages << "notable)"
+ << "new events; the last event is now" << d->timeline.back();
// The first event in the batch defines whose read marker can possibly be
// promoted any further over the same author's events newly arrived.
@@ -627,7 +636,7 @@ void Room::doAddNewMessageEvents(const Events& events)
{
d->promoteReadMarker(firstWriter, findInTimeline(events.front()->id()));
qCDebug(MAIN) << "Auto-promoted read marker for" << firstWriter->id()
- << "to" << *readMarker(firstWriter);
+ << "to" << *readMarker(firstWriter);
}
if( !d->unreadMessages && newUnreadMessages > 0)
@@ -640,7 +649,7 @@ void Room::doAddNewMessageEvents(const Events& events)
void Room::addHistoricalMessageEvents(Events events)
{
- d->dropDuplicateEvents(events);
+ d->dropDuplicateEvents(&events);
if (events.empty())
return;
emit aboutToAddHistoricalMessages(events);
@@ -655,46 +664,44 @@ void Room::doAddHistoricalMessageEvents(const Events& events)
for (auto e: events)
d->prependEvent(e);
qCDebug(MAIN) << "Room" << displayName() << "received" << events.size()
- << "past events; the oldest event is now" << d->timeline.front();
+ << "past events; the oldest event is now" << d->timeline.front();
}
void Room::processStateEvents(const Events& events)
{
+ bool emitNamesChanged = false;
for (auto event: events)
{
if( event->type() == EventType::RoomName )
{
- RoomNameEvent* nameEvent = static_cast<RoomNameEvent*>(event);
+ auto nameEvent = static_cast<RoomNameEvent*>(event);
d->name = nameEvent->name();
qCDebug(MAIN) << "room name:" << d->name;
- d->updateDisplayname();
- emit namesChanged(this);
+ emitNamesChanged = true;
}
if( event->type() == EventType::RoomAliases )
{
- RoomAliasesEvent* aliasesEvent = static_cast<RoomAliasesEvent*>(event);
+ auto aliasesEvent = static_cast<RoomAliasesEvent*>(event);
d->aliases = aliasesEvent->aliases();
qCDebug(MAIN) << "room aliases:" << d->aliases;
- // No displayname update - aliases are not used to render a displayname
- emit namesChanged(this);
+ emitNamesChanged = true;
}
if( event->type() == EventType::RoomCanonicalAlias )
{
- RoomCanonicalAliasEvent* aliasEvent = static_cast<RoomCanonicalAliasEvent*>(event);
+ auto aliasEvent = static_cast<RoomCanonicalAliasEvent*>(event);
d->canonicalAlias = aliasEvent->alias();
qCDebug(MAIN) << "room canonical alias:" << d->canonicalAlias;
- d->updateDisplayname();
- emit namesChanged(this);
+ emitNamesChanged = true;
}
if( event->type() == EventType::RoomTopic )
{
- RoomTopicEvent* topicEvent = static_cast<RoomTopicEvent*>(event);
+ auto topicEvent = static_cast<RoomTopicEvent*>(event);
d->topic = topicEvent->topic();
emit topicChanged();
}
if( event->type() == EventType::RoomMember )
{
- RoomMemberEvent* memberEvent = static_cast<RoomMemberEvent*>(event);
+ auto memberEvent = static_cast<RoomMemberEvent*>(event);
// Can't use d->member() below because the user may be not a member (yet)
User* u = d->connection->user(memberEvent->userId());
u->processEvent(event);
@@ -708,13 +715,17 @@ void Room::processStateEvents(const Events& events)
}
}
}
+ if (emitNamesChanged) {
+ emit namesChanged(this);
+ }
+ d->updateDisplayname();
}
void Room::processEphemeralEvent(Event* event)
{
if( event->type() == EventType::Typing )
{
- TypingEvent* typingEvent = static_cast<TypingEvent*>(event);
+ auto typingEvent = static_cast<TypingEvent*>(event);
d->usersTyping.clear();
for( const QString& userId: typingEvent->users() )
{
@@ -732,9 +743,12 @@ void Room::processEphemeralEvent(Event* event)
const auto& receipts = eventReceiptPair.second;
{
if (receipts.size() == 1)
- qCDebug(MAIN) << "Marking event" << eventId << "as read for" << receipts[0].userId;
+ qCDebug(EPHEMERAL) << "Marking" << eventId
+ << "as read for" << receipts[0].userId;
else
- qCDebug(MAIN) << "Marking event" << eventId << "as read for" << receipts.size() << "users";
+ qCDebug(EPHEMERAL) << "Marking" << eventId
+ << "as read for"
+ << receipts.size() << "users";
}
if (d->eventsIndex.contains(eventId))
{
@@ -744,8 +758,8 @@ void Room::processEphemeralEvent(Event* event)
d->promoteReadMarker(m, newMarker);
} else
{
- qCDebug(MAIN) << "Event" << eventId
- << "not found; saving read markers anyway";
+ qCDebug(EPHEMERAL) << "Event" << eventId
+ << "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.