From 9a5afd39189453b55f68b780bcb3339bb1fc05ca Mon Sep 17 00:00:00 2001 From: Ming Rui Zhang <mingrui.zhang@savoirfairelinux.com> Date: Mon, 10 May 2021 15:46:37 -0400 Subject: [PATCH] accountcombobox: use QSortFilterProxyModel to filter out current account Gitlab: #405 Change-Id: I364d7945739ef45319e0bb7834075ac52ec5c009 --- src/accountadapter.cpp | 8 ++- src/accountadapter.h | 4 ++ src/accountlistmodel.cpp | 47 +++----------- src/accountlistmodel.h | 61 ++++++++++++++++--- src/mainview/MainView.qml | 6 -- src/mainview/components/AccountComboBox.qml | 34 +++++------ .../components/AccountComboBoxPopup.qml | 15 ++--- .../components/AccountItemDelegate.qml | 9 +-- src/qmlregister.cpp | 2 +- 9 files changed, 101 insertions(+), 85 deletions(-) diff --git a/src/accountadapter.cpp b/src/accountadapter.cpp index e29cc2550..8be5d784f 100644 --- a/src/accountadapter.cpp +++ b/src/accountadapter.cpp @@ -25,6 +25,7 @@ #include "appsettingsmanager.h" #include "qtutils.h" +#include "qmlregister.h" #include <QtConcurrent/QtConcurrent> @@ -33,7 +34,12 @@ AccountAdapter::AccountAdapter(AppSettingsManager* settingsManager, QObject* parent) : QmlAdapterBase(instance, parent) , settingsManager_(settingsManager) -{} + , accSrcModel_(new AccountListModel(instance)) + , accModel_(new CurrentAccountFilterModel(instance, accSrcModel_.get())) +{ + QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, accModel_.get(), "CurrentAccountFilterModel"); + QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, accSrcModel_.get(), "AccountListModel"); +} void AccountAdapter::safeInit() diff --git a/src/accountadapter.h b/src/accountadapter.h index 985781ab3..d749133b2 100644 --- a/src/accountadapter.h +++ b/src/accountadapter.h @@ -24,6 +24,7 @@ #include <QSettings> #include <QString> +#include "accountlistmodel.h" #include "lrcinstance.h" #include "utils.h" @@ -134,5 +135,8 @@ private: QMetaObject::Connection registeredNameSavedConnection_; AppSettingsManager* settingsManager_; + + QScopedPointer<AccountListModel> accSrcModel_; + QScopedPointer<CurrentAccountFilterModel> accModel_; }; Q_DECLARE_METATYPE(AccountAdapter*) diff --git a/src/accountlistmodel.cpp b/src/accountlistmodel.cpp index 9c3bcb9df..4c253e71b 100644 --- a/src/accountlistmodel.cpp +++ b/src/accountlistmodel.cpp @@ -28,9 +28,11 @@ #include "api/contact.h" #include "api/conversation.h" -AccountListModel::AccountListModel(QObject* parent) +AccountListModel::AccountListModel(LRCInstance* instance, QObject* parent) : AbstractListModelBase(parent) -{} +{ + lrcInstance_ = instance; +} AccountListModel::~AccountListModel() {} @@ -92,47 +94,14 @@ AccountListModel::data(const QModelIndex& index, int role) const QHash<int, QByteArray> AccountListModel::roleNames() const { + using namespace AccountList; QHash<int, QByteArray> roles; - roles[Alias] = "Alias"; - roles[Username] = "Username"; - roles[Type] = "Type"; - roles[Status] = "Status"; - roles[ID] = "ID"; - roles[PictureUid] = "PictureUid"; +#define X(role) roles[role] = #role; + ACC_ROLES +#undef X return roles; } -QModelIndex -AccountListModel::index(int row, int column, const QModelIndex& parent) const -{ - Q_UNUSED(parent); - if (column != 0) { - return QModelIndex(); - } - - if (row >= 0 && row < rowCount()) { - return createIndex(row, column); - } - return QModelIndex(); -} - -QModelIndex -AccountListModel::parent(const QModelIndex& child) const -{ - Q_UNUSED(child); - return QModelIndex(); -} - -Qt::ItemFlags -AccountListModel::flags(const QModelIndex& index) const -{ - auto flags = QAbstractItemModel::flags(index) | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable; - if (!index.isValid()) { - return QAbstractItemModel::flags(index); - } - return flags; -} - void AccountListModel::reset() { diff --git a/src/accountlistmodel.h b/src/accountlistmodel.h index d8538fc38..eadd135e4 100644 --- a/src/accountlistmodel.h +++ b/src/accountlistmodel.h @@ -21,15 +21,62 @@ #include "abstractlistmodelbase.h" -class AccountListModel : public AbstractListModelBase +#include <QSortFilterProxyModel> + +#define ACC_ROLES \ + X(Alias) \ + X(Username) \ + X(Type) \ + X(Status) \ + X(ID) \ + X(PictureUid) + +namespace AccountList { +Q_NAMESPACE +enum Role { + DummyRole = Qt::UserRole + 1, +#define X(role) role, + ACC_ROLES +#undef X +}; +Q_ENUM_NS(Role) +} // namespace AccountList + +/* + * The CurrentAccountFilterModel class + * is for the sole purpose of filtering out current account. + */ +class CurrentAccountFilterModel final : public QSortFilterProxyModel { Q_OBJECT public: - enum Role { Alias = Qt::UserRole + 1, Username, Type, Status, ID, PictureUid }; - Q_ENUM(Role) + explicit CurrentAccountFilterModel(LRCInstance* lrcInstance, + QAbstractListModel* parent = nullptr) + : QSortFilterProxyModel(parent) + , lrcInstance_(lrcInstance) + { + setSourceModel(parent); + } + + virtual bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override + { + // Accept all contacts in conversation list filtered with account type, except those in a call. + auto index = sourceModel()->index(sourceRow, 0, sourceParent); + auto accountID = sourceModel()->data(index, AccountList::ID); + return accountID != lrcInstance_->getCurrAccId(); + } - explicit AccountListModel(QObject* parent = nullptr); +protected: + LRCInstance* lrcInstance_ {nullptr}; +}; + +class AccountListModel : public AbstractListModelBase +{ + Q_OBJECT + +public: + explicit AccountListModel(LRCInstance* instance, QObject* parent = nullptr); ~AccountListModel(); /* @@ -43,9 +90,6 @@ public: * Override role name as access point in qml. */ QHash<int, QByteArray> roleNames() const override; - QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const; - QModelIndex parent(const QModelIndex& child) const; - Qt::ItemFlags flags(const QModelIndex& index) const; /* * This function is to reset the model when there's new account added. @@ -57,6 +101,9 @@ public: */ Q_INVOKABLE void updateAvatarUid(const QString& accountId); +protected: + using Role = AccountList::Role; + private: /* * Give a uuid for each account avatar and it will serve PictureUid role diff --git a/src/mainview/MainView.qml b/src/mainview/MainView.qml index 1c565dbb5..d4280cce3 100644 --- a/src/mainview/MainView.qml +++ b/src/mainview/MainView.qml @@ -350,12 +350,6 @@ Rectangle { } } - AccountListModel { - id: accountListModel - - lrcInstance: LRCInstance - } - SettingsMenu { id: settingsMenu diff --git a/src/mainview/components/AccountComboBox.qml b/src/mainview/components/AccountComboBox.qml index cbcd7f1df..7d5873820 100644 --- a/src/mainview/components/AccountComboBox.qml +++ b/src/mainview/components/AccountComboBox.qml @@ -49,8 +49,8 @@ Label { } function resetAccountListModel(accountId) { - accountListModel.updateAvatarUid(accountId) - accountListModel.reset() + AccountListModel.updateAvatarUid(accountId) + AccountListModel.reset() } function togglePopup() { @@ -105,18 +105,18 @@ Label { } Connections { - target: accountListModel + target: AccountListModel function onModelReset() { avatar.updateImage(AccountAdapter.currentAccountId, - accountListModel.data(accountListModel.index(0, 0), - AccountListModel.PictureUid)) - avatar.presenceStatus = accountListModel.data(accountListModel.index(0, 0), - AccountListModel.Status) - userAliasText.text = accountListModel.data(accountListModel.index(0,0), - AccountListModel.Alias) - usernameText.text = accountListModel.data(accountListModel.index(0,0), - AccountListModel.Username) + AccountListModel.data(AccountListModel.index(0, 0), + AccountList.PictureUid)) + avatar.presenceStatus = AccountListModel.data(AccountListModel.index(0, 0), + AccountList.Status) + userAliasText.text = AccountListModel.data(AccountListModel.index(0,0), + AccountList.Alias) + usernameText.text = AccountListModel.data(AccountListModel.index(0,0), + AccountList.Username) } } @@ -135,8 +135,8 @@ Label { imageId: AccountAdapter.currentAccountId - presenceStatus: accountListModel.data(accountListModel.index(0, 0), - AccountListModel.Status) + presenceStatus: AccountListModel.data(AccountListModel.index(0, 0), + AccountList.Status) } ColumnLayout { @@ -150,8 +150,8 @@ Label { Layout.fillWidth: true Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter - text: accountListModel.data(accountListModel.index(0,0), - AccountListModel.Alias) + text: AccountListModel.data(AccountListModel.index(0,0), + AccountList.Alias) font.pointSize: JamiTheme.textFontSize color: JamiTheme.textColor elide: Text.ElideRight @@ -165,8 +165,8 @@ Label { visible: text.length - text: accountListModel.data(accountListModel.index(0,0), - AccountListModel.Username) + text: AccountListModel.data(AccountListModel.index(0,0), + AccountList.Username) font.pointSize: JamiTheme.textFontSize color: JamiTheme.faddedLastInteractionFontColor elide: Text.ElideRight diff --git a/src/mainview/components/AccountComboBoxPopup.qml b/src/mainview/components/AccountComboBoxPopup.qml index 3b0128d44..8a9cf094b 100644 --- a/src/mainview/components/AccountComboBoxPopup.qml +++ b/src/mainview/components/AccountComboBoxPopup.qml @@ -34,9 +34,10 @@ Popup { implicitWidth: parent.width // limit the number of accounts shown at once implicitHeight: { - return Math.min(JamiTheme.accountListItemHeight * - Math.min(5, accountListModel.rowCount() + 1), - mainViewSidePanelRect.height) + return visible ? Math.min( + JamiTheme.accountListItemHeight * Math.min( + 5, CurrentAccountFilterModel.rowCount() + 1), + mainViewSidePanelRect.height) : 0 } padding: 0 modal: true @@ -54,15 +55,15 @@ Popup { clip: true - // TODO: this should use proxy model or custom filter out the - // current account - model: accountListModel + model: CurrentAccountFilterModel delegate: AccountItemDelegate { height: JamiTheme.accountListItemHeight width: root.width onClicked: { root.close() - AccountAdapter.changeAccount(index) + var sourceRow = CurrentAccountFilterModel.mapToSource( + CurrentAccountFilterModel.index(index, 0)).row + AccountAdapter.changeAccount(sourceRow) } } diff --git a/src/mainview/components/AccountItemDelegate.qml b/src/mainview/components/AccountItemDelegate.qml index fc4a21237..13dcca576 100644 --- a/src/mainview/components/AccountItemDelegate.qml +++ b/src/mainview/components/AccountItemDelegate.qml @@ -56,14 +56,9 @@ ItemDelegate { presenceStatus: Status - Component.onCompleted: { - return updateImage( - accountListModel.data( - accountListModel.index(index, 0), AccountListModel.ID), - accountListModel.data( - accountListModel.index(index, 0), AccountListModel.PictureUid)) - } + Component.onCompleted: updateImage(ID, PictureUid) } + ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true diff --git a/src/qmlregister.cpp b/src/qmlregister.cpp index 862ae16ba..d8e8e0f2c 100644 --- a/src/qmlregister.cpp +++ b/src/qmlregister.cpp @@ -93,7 +93,6 @@ registerTypes() QML_REGISTERNAMESPACE(NS_ENUMS, dummy::staticMetaObject, ""); // QAbstractListModels - QML_REGISTERTYPE(NS_MODELS, AccountListModel); QML_REGISTERTYPE(NS_MODELS, DeviceItemListModel); QML_REGISTERTYPE(NS_MODELS, BannedListModel); QML_REGISTERTYPE(NS_MODELS, ModeratorListModel); @@ -108,6 +107,7 @@ registerTypes() QML_REGISTERTYPE(NS_MODELS, SmartListModel); // Roles & type enums for models + QML_REGISTERNAMESPACE(NS_MODELS, AccountList::staticMetaObject, "AccountList"); QML_REGISTERNAMESPACE(NS_MODELS, ConversationList::staticMetaObject, "ConversationList"); QML_REGISTERNAMESPACE(NS_MODELS, ContactList::staticMetaObject, "ContactList"); -- GitLab