diff options
-rw-r--r-- | events/event.h | 25 | ||||
-rw-r--r-- | room.cpp | 124 | ||||
-rw-r--r-- | room.h | 20 |
3 files changed, 83 insertions, 86 deletions
diff --git a/events/event.h b/events/event.h index bb80cde8..2e5e5da1 100644 --- a/events/event.h +++ b/events/event.h @@ -35,7 +35,7 @@ namespace QMatrixClient RoomMessage, RoomName, RoomAliases, RoomCanonicalAlias, RoomMember, RoomTopic, Typing, Receipt, Unknown }; - + class Event { public: @@ -62,28 +62,7 @@ namespace QMatrixClient }; using Events = QVector<Event*>; - Events eventsFromJson(const QJsonArray& contents); - - /** - * Finds a place in the timeline where a new event/message could be inserted. - * @return an iterator to an item with the earliest timestamp after - * the one of 'item'; or timeline.end(), if all events are earlier - */ - template <class ItemT, class ContT> - typename ContT::iterator - findInsertionPos(ContT & timeline, const ItemT *item) - { - return std::lower_bound (timeline.begin(), timeline.end(), item, - [](const typename ContT::value_type a, const ItemT * b) { - // FIXME: We should not order the message list by origin timestamp. - // Rather, an order of receiving should be used (which actually - // poses a question on whether this method is needed at all - - // or we'd just prepend and append, depending on whether we - // received something from /sync or from /messages. - return a->timestamp() < b->timestamp(); - } - ); - } + Events eventsFromJson(const QJsonArray& json); /** * @brief Lookup a value by a key in a varargs list @@ -46,7 +46,7 @@ class Room::Private public: /** Map of user names to users. User names potentially duplicate, hence a multi-hashmap. */ typedef QMultiHash<QString, User*> members_map_t; - + Private(Connection* c, const QString& id_) : q(nullptr), connection(c), id(id_), joinState(JoinState::Join) , roomMessagesJob(nullptr) @@ -76,7 +76,7 @@ class Room::Private QHash<User*, QString> lastReadEvent; QString prevBatch; RoomMessagesJob* roomMessagesJob; - + // Convenience methods to work with the membersMap and usersLeft. // addMember() and removeMember() emit respective Room:: signals // after a succesful operation. @@ -335,18 +335,13 @@ void Room::updateData(const SyncRoomData& data) d->prevBatch = data.timelinePrevBatch; setJoinState(data.joinState); - for( Event* stateEvent: data.state ) - { - processStateEvent(stateEvent); - } + processStateEvents(data.state); - for( Event* timelineEvent: data.timeline ) + if (!data.timeline.empty()) { - - processMessageEvent(timelineEvent); - emit newMessage(timelineEvent); - // State changes can arrive in a timeline event - try to check those. - processStateEvent(timelineEvent); + // State changes can arrive in a timeline event; so check those. + processStateEvents(data.timeline); + addNewMessageEvents(data.timeline); } for( Event* ephemeralEvent: data.ephemeral ) @@ -379,11 +374,7 @@ void Room::Private::getPreviousContent() connect( roomMessagesJob, &RoomMessagesJob::result, [=]() { if( !roomMessagesJob->error() ) { - for( Event* event: roomMessagesJob->events() ) - { - q->processMessageEvent(event); - emit q->newMessage(event); - } + q->addHistoricalMessageEvents(roomMessagesJob->events()); prevBatch = roomMessagesJob->end(); } roomMessagesJob = nullptr; @@ -396,61 +387,80 @@ Connection* Room::connection() const return d->connection; } -void Room::processMessageEvent(Event* event) +void Room::addNewMessageEvents(const Events& events) +{ + emit aboutToAddNewMessages(events); + doAddNewMessageEvents(events); + emit addedMessages(); +} + +void Room::doAddNewMessageEvents(const Events& events) { - d->messageEvents.insert(findInsertionPos(d->messageEvents, event), event); + d->messageEvents.reserve(d->messageEvents.size() + events.size()); + std::copy(events.begin(), events.end(), std::back_inserter(d->messageEvents)); } -void Room::processStateEvent(Event* event) +void Room::addHistoricalMessageEvents(const Events& events) { - if( event->type() == EventType::RoomName ) + emit aboutToAddHistoricalMessages(events); + doAddHistoricalMessageEvents(events); + emit addedMessages(); +} + +void Room::doAddHistoricalMessageEvents(const Events& events) +{ + // Historical messages arrive in newest-to-oldest order + d->messageEvents.reserve(d->messageEvents.size() + events.size()); + std::copy(events.begin(), events.end(), std::front_inserter(d->messageEvents)); +} + +void Room::processStateEvents(const Events& events) +{ + for (auto event: events) { - if (RoomNameEvent* nameEvent = static_cast<RoomNameEvent*>(event)) + if( event->type() == EventType::RoomName ) { + RoomNameEvent* nameEvent = static_cast<RoomNameEvent*>(event); d->name = nameEvent->name(); qDebug() << "room name:" << d->name; d->updateDisplayname(); emit namesChanged(this); - } else + } + if( event->type() == EventType::RoomAliases ) + { + RoomAliasesEvent* aliasesEvent = static_cast<RoomAliasesEvent*>(event); + d->aliases = aliasesEvent->aliases(); + qDebug() << "room aliases:" << d->aliases; + // No displayname update - aliases are not used to render a displayname + emit namesChanged(this); + } + if( event->type() == EventType::RoomCanonicalAlias ) { - qDebug() << - "!!! event type is RoomName but the event is not RoomNameEvent"; + RoomCanonicalAliasEvent* aliasEvent = static_cast<RoomCanonicalAliasEvent*>(event); + d->canonicalAlias = aliasEvent->alias(); + qDebug() << "room canonical alias:" << d->canonicalAlias; + d->updateDisplayname(); + emit namesChanged(this); } - } - if( event->type() == EventType::RoomAliases ) - { - RoomAliasesEvent* aliasesEvent = static_cast<RoomAliasesEvent*>(event); - d->aliases = aliasesEvent->aliases(); - qDebug() << "room aliases:" << d->aliases; - // No displayname update - aliases are not used to render a displayname - emit namesChanged(this); - } - if( event->type() == EventType::RoomCanonicalAlias ) - { - RoomCanonicalAliasEvent* aliasEvent = static_cast<RoomCanonicalAliasEvent*>(event); - d->canonicalAlias = aliasEvent->alias(); - qDebug() << "room canonical alias:" << d->canonicalAlias; - d->updateDisplayname(); - emit namesChanged(this); - } - if( event->type() == EventType::RoomTopic ) - { - RoomTopicEvent* topicEvent = static_cast<RoomTopicEvent*>(event); - d->topic = topicEvent->topic(); - emit topicChanged(); - } - if( event->type() == EventType::RoomMember ) - { - RoomMemberEvent* memberEvent = static_cast<RoomMemberEvent*>(event); - User* u = d->connection->user(memberEvent->userId()); - u->processEvent(event); - if( memberEvent->membership() == MembershipType::Join ) + if( event->type() == EventType::RoomTopic ) { - d->addMember(u); + RoomTopicEvent* topicEvent = static_cast<RoomTopicEvent*>(event); + d->topic = topicEvent->topic(); + emit topicChanged(); } - else if( memberEvent->membership() == MembershipType::Leave ) + if( event->type() == EventType::RoomMember ) { - d->removeMember(u); + RoomMemberEvent* memberEvent = static_cast<RoomMemberEvent*>(event); + User* u = d->connection->user(memberEvent->userId()); + u->processEvent(event); + if( memberEvent->membership() == MembershipType::Join ) + { + d->addMember(u); + } + else if( memberEvent->membership() == MembershipType::Leave ) + { + d->removeMember(u); + } } } } @@ -82,13 +82,17 @@ namespace QMatrixClient void userRenamed(User* user, QString oldName); signals: - void newMessage(Event* event); + void aboutToAddHistoricalMessages(const Events& events); + void aboutToAddNewMessages(const Events& events); + void addedMessages(); + /** - * Triggered when the room name, canonical alias or other aliases - * change. Not triggered when displayname changes. + * @brief The room name, the canonical alias or other aliases changed + * + * Not triggered when displayname changes. */ void namesChanged(Room* room); - /** Triggered only for changes in the room displayname. */ + /** @brief The room displayname changed */ void displaynameChanged(Room* room); void topicChanged(); void userAdded(User* user); @@ -101,13 +105,17 @@ namespace QMatrixClient protected: Connection* connection() const; - virtual void processMessageEvent(Event* event); - virtual void processStateEvent(Event* event); + virtual void doAddNewMessageEvents(const Events& events); + virtual void doAddHistoricalMessageEvents(const Events& events); + virtual void processStateEvents(const Events& events); virtual void processEphemeralEvent(Event* event); private: class Private; Private* d; + + void addNewMessageEvents(const Events& events); + void addHistoricalMessageEvents(const Events& events); }; } |