diff --git a/qqmlsortfilterproxymodel.cpp b/qqmlsortfilterproxymodel.cpp index f17b8d5..cdb6a0e 100644 --- a/qqmlsortfilterproxymodel.cpp +++ b/qqmlsortfilterproxymodel.cpp @@ -365,7 +365,13 @@ bool QQmlSortFilterProxyModel::lessThan(const QModelIndex& source_left, const QM if (QSortFilterProxyModel::lessThan(source_right, source_left)) return !m_ascendingSortOrder; } - for(auto sorter : m_sorters) { + auto sortedSorters = m_sorters; + std::stable_sort(sortedSorters.begin(), + sortedSorters.end(), + [] (Sorter* a, Sorter* b) { + return a->priority() > b->priority(); + }); + for(auto sorter : sortedSorters) { if (sorter->enabled()) { int comparison = sorter->compareRows(source_left, source_right, *this); if (comparison != 0) diff --git a/sorters/sorter.cpp b/sorters/sorter.cpp index 6876573..d2d92e1 100644 --- a/sorters/sorter.cpp +++ b/sorters/sorter.cpp @@ -79,6 +79,30 @@ void Sorter::setSortOrder(Qt::SortOrder sortOrder) invalidate(); } +/*! + \qmlproperty int Sorter::priority + + This property holds the sort priority of this sorter. + Sorters with a higher priority are applied first. + In case of equal priority, Sorters are ordered by their insertion order. + + By default, the priority is 0. +*/ +int Sorter::priority() const +{ + return m_priority; +} + +void Sorter::setPriority(int priority) +{ + if (m_priority == priority) + return; + + m_priority = priority; + Q_EMIT priorityChanged(); + invalidate(); +} + int Sorter::compareRows(const QModelIndex &source_left, const QModelIndex &source_right, const QQmlSortFilterProxyModel& proxyModel) const { int comparison = compare(source_left, source_right, proxyModel); diff --git a/sorters/sorter.h b/sorters/sorter.h index 27549f0..f7ecd88 100644 --- a/sorters/sorter.h +++ b/sorters/sorter.h @@ -13,6 +13,7 @@ class Sorter : public QObject Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(bool ascendingOrder READ ascendingOrder WRITE setAscendingOrder NOTIFY sortOrderChanged) Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged) + Q_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged) public: Sorter(QObject* parent = nullptr); @@ -27,6 +28,9 @@ public: Qt::SortOrder sortOrder() const; void setSortOrder(Qt::SortOrder sortOrder); + int priority() const; + void setPriority(int priority); + int compareRows(const QModelIndex& source_left, const QModelIndex& source_right, const QQmlSortFilterProxyModel& proxyModel) const; virtual void proxyModelCompleted(const QQmlSortFilterProxyModel& proxyModel); @@ -34,6 +38,7 @@ public: Q_SIGNALS: void enabledChanged(); void sortOrderChanged(); + void priorityChanged(); void invalidated(); @@ -45,6 +50,7 @@ protected: private: bool m_enabled = true; Qt::SortOrder m_sortOrder = Qt::AscendingOrder; + int m_priority = 0; }; } diff --git a/tests/tst_sortercontainerattached.qml b/tests/tst_sortercontainerattached.qml index bb0acf0..a0d46d1 100644 --- a/tests/tst_sortercontainerattached.qml +++ b/tests/tst_sortercontainerattached.qml @@ -23,14 +23,12 @@ Item { id: testModel sourceModel: dataModel } - ListModel { id: sorterRoleModel ListElement { roleName: "a" } ListElement { roleName: "b" } ListElement { roleName: "c" } } - Instantiator { id: sorterInstantiator model: sorterRoleModel @@ -40,21 +38,41 @@ Item { } } + SortFilterProxyModel { + id: testModelPriority + sourceModel: dataModel + } + ListModel { + id: sorterRoleModelPriority + ListElement { roleName: "a" } + ListElement { roleName: "b" } + ListElement { roleName: "c" } + } + Instantiator { + id: sorterInstantiatorPriority + model: sorterRoleModelPriority + delegate: RoleSorter { + SorterContainer.container: testModelPriority + roleName: model.roleName + priority: -model.index + } + } + TestCase { name: "SorterContainerAttached" - function modelValues() { + function modelValues(model) { var modelValues = []; - for (var i = 0; i < testModel.count; i++) - modelValues.push(testModel.get(i)); + for (var i = 0; i < model.count; i++) + modelValues.push(model.get(i)); return modelValues; } function test_sorterContainers() { compare(sorterInstantiator.count, 3); - compare(modelValues(), [ + compare(modelValues(testModel), [ { a: 1, b: 7, c: 3 }, { a: 1, b: 8, c: 5 }, { a: 1, b: 8, c: 6 }, @@ -68,7 +86,7 @@ Item { sorterRoleModel.remove(0); // a, b, c --> b, c wait(0); compare(sorterInstantiator.count, 2); - compare(JSON.stringify(modelValues()), JSON.stringify([ + compare(JSON.stringify(modelValues(testModel)), JSON.stringify([ { a: 2, b: 1, c: 7 }, { a: 3, b: 2, c: 8 }, { a: 3, b: 2, c: 9 }, @@ -80,5 +98,34 @@ Item { { a: 2, b: 9, c: 1 }, ])); } + + function test_sorterContainersPriority() { + compare(sorterInstantiatorPriority.count, 3); + compare(JSON.stringify(modelValues(testModelPriority)), JSON.stringify([ + { a: 1, b: 7, c: 3 }, + { a: 1, b: 8, c: 5 }, + { a: 1, b: 8, c: 6 }, + { a: 2, b: 1, c: 7 }, + { a: 2, b: 6, c: 2 }, + { a: 2, b: 9, c: 1 }, + { a: 3, b: 2, c: 8 }, + { a: 3, b: 2, c: 9 }, + { a: 3, b: 5, c: 0 } + ])); + sorterRoleModelPriority.move(0, 1, 1); // a, b, c --> b, a, c + wait(0); + compare(sorterInstantiatorPriority.count, 3); + compare(JSON.stringify(modelValues(testModelPriority)), JSON.stringify([ + { a: 2, b: 1, c: 7 }, + { a: 3, b: 2, c: 8 }, + { a: 3, b: 2, c: 9 }, + { a: 3, b: 5, c: 0 }, + { a: 2, b: 6, c: 2 }, + { a: 1, b: 7, c: 3 }, + { a: 1, b: 8, c: 5 }, + { a: 1, b: 8, c: 6 }, + { a: 2, b: 9, c: 1 } + ])); + } } } diff --git a/tests/tst_sorters.qml b/tests/tst_sorters.qml index 692994a..23a21d9 100644 --- a/tests/tst_sorters.qml +++ b/tests/tst_sorters.qml @@ -7,10 +7,10 @@ import SortFilterProxyModel.Test 0.2 Item { ListModel { id: listModel - ListElement { test: "first"; test2: "c" } - ListElement { test: "second"; test2: "a" } - ListElement { test: "third"; test2: "b" } - ListElement { test: "fourth"; test2: "b" } + ListElement { test: "first"; test2: "c"; test3: 1 } + ListElement { test: "second"; test2: "a"; test3: 0 } + ListElement { test: "third"; test2: "b"; test3: 2} + ListElement { test: "fourth"; test2: "b"; test3: 3 } } ListModel { @@ -74,6 +74,12 @@ Item { RoleSorter { roleName: "test" } ] + property list sortersWithPriority: [ + RoleSorter { roleName: "test3" }, + RoleSorter { roleName: "test" }, + RoleSorter { roleName: "test2"; priority: 1 } + ] + SortFilterProxyModel { id: testModel sourceModel: listModel @@ -123,6 +129,15 @@ Item { verifyModelValues(testModel, expectedValues); } + function test_sortersWithPriority() { + testModel.sorters = sortersWithPriority; + var expectedValues = ["second", "third", "fourth", "first"]; + verifyModelValues(testModel, expectedValues); + testModel.sorters[0].priority = 2; + expectedValues = ["second", "first", "third", "fourth"]; + verifyModelValues(testModel, expectedValues); + } + function test_noRolesFirstModel() { noRolesFirstListModel.append([{test: "b"}, {test: "a"}]); var expectedValues = ["a", "b"];