[network/ruqola] src/widgets: Use usersinroomtreeview

Laurent Montel <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit ec306049fb9fbd7e3fdbfda555b74c3419e68ac0 by Laurent Montel.
Committed on 29/07/2026 at 06:09.
Pushed by mlaurent into branch 'master'.

Use usersinroomtreeview

M  +8    -0    src/widgets/common/usersforroommodeldelegate.cpp
M  +20   -0    src/widgets/room/autotests/usersinroomtreeviewtest.cpp
M  +1    -0    src/widgets/room/autotests/usersinroomtreeviewtest.h
M  +2    -2    src/widgets/room/autotests/usersinroomwidgettest.cpp
M  +23   -0    src/widgets/room/usersinroomtreeview.cpp
M  +1    -0    src/widgets/room/usersinroomtreeview.h
M  +29   -25   src/widgets/room/usersinroomwidget.cpp
M  +2    -4    src/widgets/room/usersinroomwidget.h

https://invent.kde.org/network/ruqola/-/commit/ec306049fb9fbd7e3fdbfda555b74c3419e68ac0

diff --git a/src/widgets/common/usersforroommodeldelegate.cpp b/src/widgets/common/usersforroommodeldelegate.cpp
index dbde655f85..e8003d4dfd 100644
--- a/src/widgets/common/usersforroommodeldelegate.cpp
+++ b/src/widgets/common/usersforroommodeldelegate.cpp
@@ -26,6 +26,14 @@ UsersForRoomModelDelegate::~UsersForRoomModelDelegate() = default;
 
 void UsersForRoomModelDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
 {
+    // Section rows are top-level rows in tree mode and should use default
+    // painting to show their DisplayRole title (Online, Offline, ...).
+    // We cannot rely on hasChildren() because empty sections would be missed.
+    if (!index.parent().isValid()) {
+        QItemDelegate::paint(painter, option, index);
+        return;
+    }
+
     // [M] icon ? status name (username)
     drawBackground(painter, option, index);
 
diff --git a/src/widgets/room/autotests/usersinroomtreeviewtest.cpp b/src/widgets/room/autotests/usersinroomtreeviewtest.cpp
index 7dfc77257a..8adeebf135 100644
--- a/src/widgets/room/autotests/usersinroomtreeviewtest.cpp
+++ b/src/widgets/room/autotests/usersinroomtreeviewtest.cpp
@@ -5,6 +5,9 @@
 */
 
 #include "usersinroomtreeviewtest.h"
+#include "model/usersforroomfilterproxymodel.h"
+#include "model/usersforroomlistheadingsproxymodel.h"
+#include "model/usersforroommodel.h"
 #include "room/usersinroomtreeview.h"
 #include <QTest>
 QTEST_MAIN(UsersInRoomTreeViewTest)
@@ -20,9 +23,26 @@ void UsersInRoomTreeViewTest::shouldHaveDefaultValues()
     QVERIFY(!w.dragEnabled());
     QVERIFY(!w.rootIsDecorated());
     QVERIFY(w.itemsExpandable());
+    QVERIFY(!w.expandsOnDoubleClick());
     QCOMPARE(w.indentation(), 0);
     QCOMPARE(w.horizontalScrollBarPolicy(), Qt::ScrollBarAlwaysOff);
     QVERIFY(w.isHeaderHidden());
 }
 
+void UsersInRoomTreeViewTest::shouldKeepSectionProxyChain()
+{
+    UsersInRoomTreeView w;
+    auto *const filterProxy = w.usersForRoomFilterProxy();
+    QVERIFY(filterProxy);
+
+    auto *const headingsProxy = qobject_cast<UsersForRoomListHeadingsProxyModel *>(filterProxy->sourceModel());
+    QVERIFY(headingsProxy);
+
+    UsersForRoomModel usersModel;
+    headingsProxy->setSourceModel(&usersModel);
+
+    QCOMPARE(headingsProxy->sourceModel(), &usersModel);
+    QVERIFY(filterProxy->sourceModel() != &usersModel);
+}
+
 #include "moc_usersinroomtreeviewtest.cpp"
diff --git a/src/widgets/room/autotests/usersinroomtreeviewtest.h b/src/widgets/room/autotests/usersinroomtreeviewtest.h
index 332cce2549..8e9476ae91 100644
--- a/src/widgets/room/autotests/usersinroomtreeviewtest.h
+++ b/src/widgets/room/autotests/usersinroomtreeviewtest.h
@@ -17,4 +17,5 @@ public:
 
 private Q_SLOTS:
     void shouldHaveDefaultValues();
+    void shouldKeepSectionProxyChain();
 };
diff --git a/src/widgets/room/autotests/usersinroomwidgettest.cpp b/src/widgets/room/autotests/usersinroomwidgettest.cpp
index a77b029728..985bc668fd 100644
--- a/src/widgets/room/autotests/usersinroomwidgettest.cpp
+++ b/src/widgets/room/autotests/usersinroomwidgettest.cpp
@@ -7,7 +7,7 @@
 #include "usersinroomwidgettest.h"
 
 #include "room/usersinroomcombobox.h"
-#include "room/usersinroomlistview.h"
+#include "room/usersinroomtreeview.h"
 #include "room/usersinroomwidget.h"
 #include <QLabel>
 #include <QLineEdit>
@@ -29,7 +29,7 @@ void UsersInRoomWidgetTest::shouldHaveDefaultValues()
     QVERIFY(mainLayout);
     QCOMPARE(mainLayout->contentsMargins(), QMargins{});
 
-    auto mListView = w.findChild<UsersInRoomListView *>(u"mListView"_s);
+    auto mListView = w.findChild<UsersInRoomTreeView *>(u"mListView"_s);
     QVERIFY(mListView);
 
     auto mSearchLineEdit = w.findChild<QLineEdit *>(u"mSearchLineEdit"_s);
diff --git a/src/widgets/room/usersinroomtreeview.cpp b/src/widgets/room/usersinroomtreeview.cpp
index a09489e7ed..b9cb9c4f48 100644
--- a/src/widgets/room/usersinroomtreeview.cpp
+++ b/src/widgets/room/usersinroomtreeview.cpp
@@ -24,6 +24,7 @@ UsersInRoomTreeView::UsersInRoomTreeView(QWidget *parent)
     setIndentation(0);
     setRootIsDecorated(false);
     setItemsExpandable(true);
+    setExpandsOnDoubleClick(false);
     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
     connect(model(), &QAbstractItemModel::rowsInserted, this, &QTreeView::expandAll);
@@ -31,7 +32,15 @@ UsersInRoomTreeView::UsersInRoomTreeView(QWidget *parent)
     connect(model(), &QAbstractItemModel::rowsMoved, this, &QTreeView::expandAll);
     connect(model(), &QAbstractItemModel::layoutChanged, this, &QTreeView::expandAll);
 
+    connect(model(), &QAbstractItemModel::rowsInserted, this, &UsersInRoomTreeView::updateSectionVisibility);
+    connect(model(), &QAbstractItemModel::rowsRemoved, this, &UsersInRoomTreeView::updateSectionVisibility);
+    connect(model(), &QAbstractItemModel::rowsMoved, this, &UsersInRoomTreeView::updateSectionVisibility);
+    connect(model(), &QAbstractItemModel::layoutChanged, this, &UsersInRoomTreeView::updateSectionVisibility);
+    connect(model(), &QAbstractItemModel::modelReset, this, &UsersInRoomTreeView::updateSectionVisibility);
+    connect(model(), &QAbstractItemModel::dataChanged, this, &UsersInRoomTreeView::updateSectionVisibility);
+
     expandAll();
+    updateSectionVisibility();
 }
 
 UsersInRoomTreeView::~UsersInRoomTreeView() = default;
@@ -70,6 +79,20 @@ UsersForRoomFilterProxyModel *UsersInRoomTreeView::usersForRoomFilterProxy() con
     return mUsersForRoomFilterProxy;
 }
 
+void UsersInRoomTreeView::updateSectionVisibility()
+{
+    if (!model()) {
+        return;
+    }
+
+    const int sectionCount = model()->rowCount();
+    for (int row = 0; row < sectionCount; ++row) {
+        const QModelIndex sectionIndex = model()->index(row, 0);
+        const bool hasChildren = model()->rowCount(sectionIndex) > 0;
+        setRowHidden(row, QModelIndex(), !hasChildren);
+    }
+}
+
 bool UsersInRoomTreeView::event(QEvent *ev)
 {
     if (ev->type() == QEvent::ApplicationPaletteChange) {
diff --git a/src/widgets/room/usersinroomtreeview.h b/src/widgets/room/usersinroomtreeview.h
index 669cb78185..a93cf4ebf6 100644
--- a/src/widgets/room/usersinroomtreeview.h
+++ b/src/widgets/room/usersinroomtreeview.h
@@ -24,6 +24,7 @@ protected:
 
 private:
     LIBRUQOLAWIDGETS_NO_EXPORT void generalPaletteChanged();
+    LIBRUQOLAWIDGETS_NO_EXPORT void updateSectionVisibility();
     QColor mTextColor;
     UsersForRoomListHeadingsProxyModel *const mUsersForRoomListHeadingsProxyModel;
     UsersForRoomFilterProxyModel *const mUsersForRoomFilterProxy;
diff --git a/src/widgets/room/usersinroomwidget.cpp b/src/widgets/room/usersinroomwidget.cpp
index fead233ab5..3d95c7df7f 100644
--- a/src/widgets/room/usersinroomwidget.cpp
+++ b/src/widgets/room/usersinroomwidget.cpp
@@ -9,9 +9,10 @@
 #include "common/usersforroommodeldelegate.h"
 #include "dialogs/directchannelinfodialog.h"
 #include "model/usersforroomfilterproxymodel.h"
+#include "model/usersforroomlistheadingsproxymodel.h"
 #include "model/usersforroommodel.h"
 #include "rocketchataccount.h"
-#include "room/usersinroomlistview.h"
+#include "room/usersinroomtreeview.h"
 #include "usersinroomcombobox.h"
 #include "usersinroommenu.h"
 #include <KLineEditEventHandler>
@@ -24,10 +25,9 @@
 using namespace Qt::Literals::StringLiterals;
 UsersInRoomWidget::UsersInRoomWidget(RocketChatAccount *account, QWidget *parent)
     : QWidget(parent)
-    , mListView(new UsersInRoomListView(this))
+    , mListView(new UsersInRoomTreeView(this))
     , mSearchLineEdit(new QLineEdit(this))
     , mMessageListInfo(new QLabel(this))
-    , mUsersForRoomFilterProxy(new UsersForRoomFilterProxyModel(this))
     , mUsersInRoomComboBox(new UsersInRoomComboBox(account ? account->hasAtLeastVersion(7, 3, 0) : false, this))
     , mRocketChatAccount(account)
 {
@@ -62,42 +62,39 @@ UsersInRoomWidget::UsersInRoomWidget(RocketChatAccount *account, QWidget *parent
     mListView->setObjectName(u"mListView"_s);
     mainLayout->addWidget(mListView);
     mListView->setContextMenuPolicy(Qt::CustomContextMenu);
-    connect(mListView, &QListView::customContextMenuRequested, this, &UsersInRoomWidget::slotCustomContextMenuRequested);
-    connect(mListView, &QListView::doubleClicked, this, &UsersInRoomWidget::slotDoubleClick);
-    mListView->setModel(mUsersForRoomFilterProxy);
+    connect(mListView, &UsersInRoomTreeView::customContextMenuRequested, this, &UsersInRoomWidget::slotCustomContextMenuRequested);
+    connect(mListView, &UsersInRoomTreeView::doubleClicked, this, &UsersInRoomWidget::slotDoubleClick);
     if (account) {
         auto delegate = new UsersForRoomModelDelegate(mListView);
         delegate->setRocketChatAccount(account);
         mListView->setItemDelegate(delegate);
     }
     mListView->setMouseTracking(true);
-    connect(mUsersForRoomFilterProxy, &UsersForRoomFilterProxyModel::hasFullListChanged, this, &UsersInRoomWidget::updateLabel);
-    connect(mUsersForRoomFilterProxy, &UsersForRoomFilterProxyModel::loadingInProgressChanged, this, &UsersInRoomWidget::updateLabel);
+    connect(mListView->usersForRoomFilterProxy(), &UsersForRoomFilterProxyModel::hasFullListChanged, this, &UsersInRoomWidget::updateLabel);
+    connect(mListView->usersForRoomFilterProxy(), &UsersForRoomFilterProxyModel::loadingInProgressChanged, this, &UsersInRoomWidget::updateLabel);
 }
 
 UsersInRoomWidget::~UsersInRoomWidget()
 {
-    mUsersForRoomFilterProxy->clearFilter();
+    mListView->usersForRoomFilterProxy()->clearFilter();
 }
 
 void UsersInRoomWidget::slotDoubleClick(const QModelIndex &index)
 {
-#ifdef USE_TREEVIEW
     if (!index.parent().isValid()) {
         return;
     }
-#endif
     slotShowUserInfo(index);
 }
 
 void UsersInRoomWidget::slotChangeStatusType([[maybe_unused]] int index)
 {
-    mUsersForRoomFilterProxy->setStatusType(mUsersInRoomComboBox->currentData().value<UsersForRoomFilterProxyModel::FilterUserType>());
+    mListView->usersForRoomFilterProxy()->setStatusType(mUsersInRoomComboBox->currentData().value<UsersForRoomFilterProxyModel::FilterUserType>());
 }
 
 void UsersInRoomWidget::slotTextChanged(const QString &str)
 {
-    mUsersForRoomFilterProxy->setFilterString(str);
+    mListView->usersForRoomFilterProxy()->setFilterString(str);
     mRocketChatAccount->loadMoreUsersInRoom(mRoom->roomId(), mRoom->channelType(), str);
 }
 
@@ -106,19 +103,24 @@ void UsersInRoomWidget::setRoom(Room *room)
     mRoom = room;
     if (mRoom) {
         auto model = mRocketChatAccount->usersModelForRoom(mRoom->roomId());
-        auto sourceModel = mUsersForRoomFilterProxy->sourceModel();
-        if (sourceModel) {
-            auto usersForRoomModel = qobject_cast<UsersForRoomModel *>(mUsersForRoomFilterProxy->sourceModel());
-            disconnect(usersForRoomModel, &UsersForRoomModel::hasFullListChanged, mUsersForRoomFilterProxy, &UsersForRoomFilterProxyModel::hasFullListChanged);
+        auto *const roomFilterProxy = mListView->usersForRoomFilterProxy();
+        auto *const headingsProxy = qobject_cast<UsersForRoomListHeadingsProxyModel *>(roomFilterProxy->sourceModel());
+        Q_ASSERT(headingsProxy);
+        if (!headingsProxy) {
+            return;
+        }
+        auto *const usersForRoomModel = qobject_cast<UsersForRoomModel *>(headingsProxy->sourceModel());
+        if (usersForRoomModel) {
+            disconnect(usersForRoomModel, &UsersForRoomModel::hasFullListChanged, roomFilterProxy, &UsersForRoomFilterProxyModel::hasFullListChanged);
             disconnect(usersForRoomModel,
                        &UsersForRoomModel::loadingInProgressChanged,
-                       mUsersForRoomFilterProxy,
+                       roomFilterProxy,
                        &UsersForRoomFilterProxyModel::loadingInProgressChanged);
         }
 
-        connect(model, &UsersForRoomModel::hasFullListChanged, mUsersForRoomFilterProxy, &UsersForRoomFilterProxyModel::hasFullListChanged);
-        connect(model, &UsersForRoomModel::loadingInProgressChanged, mUsersForRoomFilterProxy, &UsersForRoomFilterProxyModel::loadingInProgressChanged);
-        mUsersForRoomFilterProxy->setSourceModel(model);
+        connect(model, &UsersForRoomModel::hasFullListChanged, roomFilterProxy, &UsersForRoomFilterProxyModel::hasFullListChanged);
+        connect(model, &UsersForRoomModel::loadingInProgressChanged, roomFilterProxy, &UsersForRoomFilterProxyModel::loadingInProgressChanged);
+        headingsProxy->setSourceModel(model);
         updateLabel();
     }
 }
@@ -157,18 +159,20 @@ void UsersInRoomWidget::slotShowUserInfo(const QModelIndex &index)
 
 void UsersInRoomWidget::updateLabel()
 {
-    if (mUsersForRoomFilterProxy->loadMoreUsersInProgress()) {
+    auto *const roomFilterProxy = mListView->usersForRoomFilterProxy();
+    if (roomFilterProxy->loadMoreUsersInProgress()) {
         mMessageListInfo->setText(i18n("Loading…"));
     } else {
-        mMessageListInfo->setText(mUsersForRoomFilterProxy->numberOfUsers() == 0 ? i18n("No Message found") : displayShowMessageInRoom());
+        mMessageListInfo->setText(roomFilterProxy->numberOfUsers() == 0 ? i18n("No Message found") : displayShowMessageInRoom());
     }
 }
 
 QString UsersInRoomWidget::displayShowMessageInRoom() const
 {
+    auto *const roomFilterProxy = mListView->usersForRoomFilterProxy();
     QString displayMessageStr =
-        i18np("%1 User in room (Total: %2)", "%1 Users in room (Total: %2)", mUsersForRoomFilterProxy->numberOfUsers(), mUsersForRoomFilterProxy->total());
-    if (!mUsersForRoomFilterProxy->hasFullList()) {
+        i18np("%1 User in room (Total: %2)", "%1 Users in room (Total: %2)", roomFilterProxy->numberOfUsers(), roomFilterProxy->total());
+    if (!roomFilterProxy->hasFullList()) {
         displayMessageStr += u" <a href=\"loadmoreelement\">%1</a>"_s.arg(i18n("(Click here for Loading more…)"));
     }
     return displayMessageStr;
diff --git a/src/widgets/room/usersinroomwidget.h b/src/widgets/room/usersinroomwidget.h
index d04c4e0475..412ecbd2ba 100644
--- a/src/widgets/room/usersinroomwidget.h
+++ b/src/widgets/room/usersinroomwidget.h
@@ -14,10 +14,9 @@ class QLineEdit;
 class Room;
 class UsersInRoomMenu;
 class QLabel;
-class UsersForRoomFilterProxyModel;
 class UsersInRoomComboBox;
 class RocketChatAccount;
-class UsersInRoomListView;
+class UsersInRoomTreeView;
 class LIBRUQOLAWIDGETS_TESTS_EXPORT UsersInRoomWidget : public QWidget
 {
     Q_OBJECT
@@ -35,12 +34,11 @@ private:
     LIBRUQOLAWIDGETS_NO_EXPORT void slotChangeStatusType(int index);
     LIBRUQOLAWIDGETS_NO_EXPORT void slotShowUserInfo(const QModelIndex &index);
     LIBRUQOLAWIDGETS_NO_EXPORT void slotDoubleClick(const QModelIndex &index);
-    UsersInRoomListView *const mListView;
+    UsersInRoomTreeView *const mListView;
     QLineEdit *const mSearchLineEdit;
     QPointer<Room> mRoom;
     UsersInRoomMenu *mMenu = nullptr;
     QLabel *const mMessageListInfo;
-    UsersForRoomFilterProxyModel *const mUsersForRoomFilterProxy;
     UsersInRoomComboBox *const mUsersInRoomComboBox;
     RocketChatAccount *const mRocketChatAccount;
 };
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.