From 532f60614282b012047eed6dffddd32e7c174866 Mon Sep 17 00:00:00 2001 From: Johan Ouwerkerk Date: Sun, 31 May 2020 16:43:16 +0200 Subject: [PATCH] Make sure to sort entries by account (name) in the overview list. --- src/contents/ui/AccountsOverview.qml | 4 ++- src/main.cpp | 1 + src/model/accounts.cpp | 60 ++++++++++++++++++++++++++++++++++++ src/model/accounts.h | 11 +++++++ 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/contents/ui/AccountsOverview.qml b/src/contents/ui/AccountsOverview.qml index 1c91e06..7106cb9 100644 --- a/src/contents/ui/AccountsOverview.qml +++ b/src/contents/ui/AccountsOverview.qml @@ -88,7 +88,9 @@ Kirigami.ScrollablePage { ListView { id: mainList - model: accounts + model: Models.SortedAccountListModel { + sourceModel: accounts + } /* * Use a Loader to get a switch-like statement to select an * appropriate delegate based on properties of the account model. diff --git a/src/main.cpp b/src/main.cpp index e5d3e24..7f332bd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,6 +34,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[]) qmlRegisterUncreatableType("Keysmith.Models", 1, 0, "AccountListModel", "Use the Keysmith singleton to obtain an AccountListModel"); qmlRegisterUncreatableType("Keysmith.Models", 1, 0, "PasswordRequestModel", "Use the Keysmith singleton to obtain an PasswordRequestModel"); qmlRegisterUncreatableType("Keysmith.Models", 1, 0, "Account", "Use an AccountListModel from the Keysmith singleton to obtain an Account"); + qmlRegisterType("Keysmith.Models", 1, 0, "SortedAccountListModel"); qmlRegisterType("Keysmith.Validators", 1, 0, "AccountNameValidator"); qmlRegisterType("Keysmith.Validators", 1, 0, "Base32SecretValidator"); qmlRegisterType("Keysmith.Validators", 1, 0, "HOTPCounterValidator"); diff --git a/src/model/accounts.cpp b/src/model/accounts.cpp index 6c2cb37..f48c03e 100644 --- a/src/model/accounts.cpp +++ b/src/model/accounts.cpp @@ -260,4 +260,64 @@ namespace model qCDebug(logger) << "Ignoring new accounts model: not a valid object"; } } + + SortedAccountsListModel::SortedAccountsListModel(QObject *parent) : QSortFilterProxyModel(parent) + { + } + + void SortedAccountsListModel::setSourceModel(QAbstractItemModel *sourceModel) + { + SimpleAccountListModel *model = qobject_cast(sourceModel); + if (!model) { + qCDebug(logger) << "Not setting source model: it is not an accounts list model!"; + return; + } + + QSortFilterProxyModel::setSourceModel(sourceModel); + qCDebug(logger) << "Updating properties & resorting the model"; + setSortRole(SimpleAccountListModel::NonStandardRoles::AccountRole); + setDynamicSortFilter(true); + setSortLocaleAware(true); + sort(0); + } + + bool SortedAccountsListModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const + { + QAbstractItemModel *source = sourceModel(); + Q_ASSERT_X(source, Q_FUNC_INFO, "should have a source model at this point"); + + SimpleAccountListModel *model = qobject_cast(source); + // useless junk: implement sorting as no-op: claim equality between left & right + if (!model) { + qCDebug(logger) << "Short-circuiting lessThan operator: source model is not an accounts list model!"; + return false; + } + + QVariant leftValue = model->data(source_left, SimpleAccountListModel::NonStandardRoles::AccountRole); + QVariant rightValue = model->data(source_right, SimpleAccountListModel::NonStandardRoles::AccountRole); + + AccountView * leftAccount = leftValue.isNull() ? nullptr : leftValue.value(); + AccountView * rightAccount = rightValue.isNull() ? nullptr : rightValue.value(); + + // useless junk: implement sorting as no-op: claim left == right + if (!leftAccount && !rightAccount) { + qCDebug(logger) << "Short-circuiting lessThan operator: both source model indices do not point to accounts"; + return false; + } + + // Sort actual accounts before useless junk: claim left >= right + if (!leftAccount) { + qCDebug(logger) << "Short-circuiting lessThan operator: left source model index does not point to an account"; + return false; + } + + // Sort actual accounts before useless junk: claim left < right + if (!rightAccount) { + qCDebug(logger) << "Short-circuiting lessThan operator: right source model index does not point to an account"; + return true; + } + + // actual sorting by account name + return leftAccount->name().localeAwareCompare(rightAccount->name()) < 0; + } } diff --git a/src/model/accounts.h b/src/model/accounts.h index 0299b64..2327aa2 100644 --- a/src/model/accounts.h +++ b/src/model/accounts.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -87,6 +88,16 @@ namespace model QHash m_accounts; }; + class SortedAccountsListModel: public QSortFilterProxyModel + { + Q_OBJECT + public: + explicit SortedAccountsListModel(QObject *parent = nullptr); + void setSourceModel(QAbstractItemModel *sourceModel) override; + protected: + bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override; + }; + class AccountNameValidator: public QValidator { Q_OBJECT