summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorKonstantinos Sideris <sideris.konstantin@gmail.com>2018-07-21 13:35:36 +0300
committerKonstantinos Sideris <sideris.konstantin@gmail.com>2018-07-21 13:35:36 +0300
commit54c7eb374a9d850ff8050077be57fafdff4531e9 (patch)
treeda222ead856e7ea457618c215a2f53a5a136940d /src
parentClear timeline widgets when they exceed a certain limit (#158) (diff)
downloadnheko-54c7eb374a9d850ff8050077be57fafdff4531e9.tar.xz
Lower the complexity of the group filtering algorithm (#380)
The old algorithm during filtering will check every room
if it's part of the group. O(N*G)

The room ids for a group are now stored in a map for faster lookup
so the search can be completed in a single pass. O(N)
Diffstat (limited to 'src')
-rw-r--r--src/ChatPage.cpp4
-rw-r--r--src/CommunitiesList.cpp10
-rw-r--r--src/CommunitiesList.h4
-rw-r--r--src/CommunitiesListItem.h6
-rw-r--r--src/RoomList.cpp53
-rw-r--r--src/RoomList.h19
6 files changed, 52 insertions, 44 deletions
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 6f5e31e5..27c4fbe9 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -514,9 +514,9 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
                         current_community_ = groupId;
 
                         if (groupId == "world")
-                                room_list_->setFilterRooms(false);
+                                room_list_->removeFilter();
                         else
-                                room_list_->setRoomFilter(communitiesList_->roomList(groupId));
+                                room_list_->applyFilter(communitiesList_->roomList(groupId));
                 });
 
         connect(&notificationsManager,
diff --git a/src/CommunitiesList.cpp b/src/CommunitiesList.cpp
index c271be89..af30050d 100644
--- a/src/CommunitiesList.cpp
+++ b/src/CommunitiesList.cpp
@@ -1,5 +1,5 @@
-#include "CommunitiesList.h"
 #include "Cache.h"
+#include "CommunitiesList.h"
 #include "Logging.h"
 #include "MatrixClient.h"
 
@@ -83,7 +83,7 @@ CommunitiesList::addCommunity(const std::string &group_id)
         connect(this,
                 &CommunitiesList::groupRoomsRetrieved,
                 this,
-                [this](const QString &id, const std::vector<QString> &rooms) {
+                [this](const QString &id, const std::map<QString, bool> &rooms) {
                         if (communities_.find(id) == communities_.end())
                                 return;
 
@@ -109,9 +109,9 @@ CommunitiesList::addCommunity(const std::string &group_id)
                           return;
                   }
 
-                  std::vector<QString> room_ids;
+                  std::map<QString, bool> room_ids;
                   for (const auto &room : res.at("chunk"))
-                          room_ids.push_back(QString::fromStdString(room.at("room_id")));
+                          room_ids.emplace(QString::fromStdString(room.at("room_id")), true);
 
                   emit groupRoomsRetrieved(id, room_ids);
           });
@@ -185,7 +185,7 @@ CommunitiesList::fetchCommunityAvatar(const QString &id, const QString &avatarUr
           });
 }
 
-std::vector<QString>
+std::map<QString, bool>
 CommunitiesList::roomList(const QString &id) const
 {
         if (communityExists(id))
diff --git a/src/CommunitiesList.h b/src/CommunitiesList.h
index 32a64bf2..d4db54cc 100644
--- a/src/CommunitiesList.h
+++ b/src/CommunitiesList.h
@@ -18,13 +18,13 @@ public:
 
         void addCommunity(const std::string &id);
         void removeCommunity(const QString &id) { communities_.erase(id); };
-        std::vector<QString> roomList(const QString &id) const;
+        std::map<QString, bool> roomList(const QString &id) const;
 
 signals:
         void communityChanged(const QString &id);
         void avatarRetrieved(const QString &id, const QPixmap &img);
         void groupProfileRetrieved(const QString &group_id, const mtx::responses::GroupProfile &);
-        void groupRoomsRetrieved(const QString &group_id, const std::vector<QString> &res);
+        void groupRoomsRetrieved(const QString &group_id, const std::map<QString, bool> &res);
 
 public slots:
         void updateCommunityAvatar(const QString &id, const QPixmap &img);
diff --git a/src/CommunitiesListItem.h b/src/CommunitiesListItem.h
index a9b6e333..bfd54661 100644
--- a/src/CommunitiesListItem.h
+++ b/src/CommunitiesListItem.h
@@ -32,8 +32,8 @@ public:
         bool isPressed() const { return isPressed_; }
         void setAvatar(const QImage &img);
 
-        void setRooms(std::vector<QString> room_ids) { room_ids_ = std::move(room_ids); }
-        std::vector<QString> rooms() const { return room_ids_; }
+        void setRooms(std::map<QString, bool> room_ids) { room_ids_ = std::move(room_ids); }
+        std::map<QString, bool> rooms() const { return room_ids_; }
 
         QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; }
         QColor hoverBackgroundColor() const { return hoverBackgroundColor_; }
@@ -69,7 +69,7 @@ private:
 
         QString resolveName() const;
 
-        std::vector<QString> room_ids_;
+        std::map<QString, bool> room_ids_;
 
         QString name_;
         QString groupId_;
diff --git a/src/RoomList.cpp b/src/RoomList.cpp
index a9328984..771081b9 100644
--- a/src/RoomList.cpp
+++ b/src/RoomList.cpp
@@ -56,6 +56,8 @@ RoomList::RoomList(QSharedPointer<UserSettings> userSettings, QWidget *parent)
         scrollArea_->setWidget(scrollAreaContents_);
         topLayout_->addWidget(scrollArea_);
 
+        qRegisterMetaType<std::map<QString, bool>>();
+
         connect(this, &RoomList::updateRoomAvatarCb, this, &RoomList::updateRoomAvatar);
 }
 
@@ -340,10 +342,21 @@ RoomList::closeJoinRoomDialog(bool isJoining, QString roomAlias)
 }
 
 void
-RoomList::setFilterRooms(bool isFilteringEnabled)
+RoomList::removeFilter()
+{
+        for (int i = 0; i < contentsLayout_->count(); i++) {
+                auto widget =
+                  qobject_cast<RoomInfoListItem *>(contentsLayout_->itemAt(i)->widget());
+                if (widget)
+                        widget->show();
+        }
+}
+
+void
+RoomList::applyFilter(const std::map<QString, bool> &filter)
 {
         for (int i = 0; i < contentsLayout_->count(); i++) {
-                // If roomFilter_ contains the room for the current RoomInfoListItem,
+                // If filter contains the room for the current RoomInfoListItem,
                 // show the list item, otherwise hide it
                 auto listitem =
                   qobject_cast<RoomInfoListItem *>(contentsLayout_->itemAt(i)->widget());
@@ -351,28 +364,29 @@ RoomList::setFilterRooms(bool isFilteringEnabled)
                 if (!listitem)
                         continue;
 
-                if (!isFilteringEnabled || filterItemExists(listitem->roomId()))
+                if (filter.find(listitem->roomId()) != filter.end())
                         listitem->show();
                 else
                         listitem->hide();
         }
 
-        if (isFilteringEnabled && !filterItemExists(selectedRoom_)) {
-                RoomInfoListItem *firstVisibleRoom = nullptr;
+        // If the already selected room is part of the group, make sure it's visible.
+        if (!selectedRoom_.isEmpty() && (filter.find(selectedRoom_) != filter.end()))
+                return;
+
+        selectFirstVisibleRoom();
+}
 
-                for (int i = 0; i < contentsLayout_->count(); i++) {
-                        QWidget *item = contentsLayout_->itemAt(i)->widget();
+void
+RoomList::selectFirstVisibleRoom()
+{
+        for (int i = 0; i < contentsLayout_->count(); i++) {
+                auto item = qobject_cast<RoomInfoListItem *>(contentsLayout_->itemAt(i)->widget());
 
-                        if (item != nullptr && item->isVisible()) {
-                                firstVisibleRoom = qobject_cast<RoomInfoListItem *>(item);
-                                break;
-                        }
+                if (item && item->isVisible()) {
+                        highlightSelectedRoom(item->roomId());
+                        break;
                 }
-
-                if (firstVisibleRoom != nullptr)
-                        highlightSelectedRoom(firstVisibleRoom->roomId());
-        } else {
-                scrollArea_->ensureWidgetVisible(rooms_[selectedRoom_].data());
         }
 }
 
@@ -405,13 +419,6 @@ RoomList::updateRoom(const QString &room_id, const RoomInfo &info)
 }
 
 void
-RoomList::setRoomFilter(std::vector<QString> room_ids)
-{
-        roomFilter_ = room_ids;
-        setFilterRooms(true);
-}
-
-void
 RoomList::addInvitedRoom(const QString &room_id, const RoomInfo &info)
 {
         auto room_item = new RoomInfoListItem(room_id, info, scrollArea_);
diff --git a/src/RoomList.h b/src/RoomList.h
index 59b0e865..d676015c 100644
--- a/src/RoomList.h
+++ b/src/RoomList.h
@@ -17,6 +17,7 @@
 
 #pragma once
 
+#include <QMetaType>
 #include <QPushButton>
 #include <QScrollArea>
 #include <QSharedPointer>
@@ -33,6 +34,9 @@ class UserSettings;
 struct DescInfo;
 struct RoomInfo;
 
+using RoomIds = std::map<QString, bool>;
+Q_DECLARE_METATYPE(RoomIds)
+
 class RoomList : public QWidget
 {
         Q_OBJECT
@@ -49,8 +53,10 @@ public:
         void addRoom(const QString &room_id, const RoomInfo &info);
         void addInvitedRoom(const QString &room_id, const RoomInfo &info);
         void removeRoom(const QString &room_id, bool reset);
-        void setFilterRooms(bool filterRooms);
-        void setRoomFilter(std::vector<QString> room_ids);
+        //! Hide rooms that are not present in the given filter.
+        void applyFilter(const std::map<QString, bool> &rooms);
+        //! Show all the available rooms.
+        void removeFilter();
         void updateRoom(const QString &room_id, const RoomInfo &info);
         void cleanupInvites(const std::map<QString, bool> &invites);
 
@@ -82,10 +88,8 @@ private:
         std::pair<QString, QSharedPointer<RoomInfoListItem>> firstRoom() const;
         void calculateUnreadMessageCount();
         bool roomExists(const QString &room_id) { return rooms_.find(room_id) != rooms_.end(); }
-        bool filterItemExists(const QString &id)
-        {
-                return std::find(roomFilter_.begin(), roomFilter_.end(), id) != roomFilter_.end();
-        }
+        //! Select the first visible room in the room list.
+        void selectFirstVisibleRoom();
 
         QVBoxLayout *topLayout_;
         QVBoxLayout *contentsLayout_;
@@ -99,9 +103,6 @@ private:
         std::map<QString, QSharedPointer<RoomInfoListItem>> rooms_;
         QString selectedRoom_;
 
-        //! Which rooms to include in the room list.
-        std::vector<QString> roomFilter_;
-
         QSharedPointer<UserSettings> userSettings_;
 
         bool isSortPending_ = false;