From f08fd2eaed37de8985a08a12f7945be8d8a1451c Mon Sep 17 00:00:00 2001 From: Grecko Date: Sat, 29 Sep 2018 14:33:13 +0200 Subject: [PATCH] feat: Add FilterRole role type --- SortFilterProxyModel.pri | 6 ++-- proxyroles/filterrole.cpp | 60 +++++++++++++++++++++++++++++++ proxyroles/filterrole.h | 29 +++++++++++++++ proxyroles/proxyrolesqmltypes.cpp | 2 ++ tests/SortFilterProxyModel.pro | 3 +- tests/tst_filterrole.qml | 47 ++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 proxyroles/filterrole.cpp create mode 100644 proxyroles/filterrole.h create mode 100644 tests/tst_filterrole.qml diff --git a/SortFilterProxyModel.pri b/SortFilterProxyModel.pri index 89daa3d..22f7a83 100644 --- a/SortFilterProxyModel.pri +++ b/SortFilterProxyModel.pri @@ -26,7 +26,8 @@ HEADERS += $$PWD/qqmlsortfilterproxymodel.h \ $$PWD/proxyroles/expressionrole.h \ $$PWD/proxyroles/singlerole.h \ $$PWD/proxyroles/regexprole.h \ - $$PWD/sorters/filtersorter.h + $$PWD/sorters/filtersorter.h \ + $$PWD/proxyroles/filterrole.h SOURCES += $$PWD/qqmlsortfilterproxymodel.cpp \ $$PWD/filters/filter.cpp \ @@ -55,4 +56,5 @@ SOURCES += $$PWD/qqmlsortfilterproxymodel.cpp \ $$PWD/proxyroles/proxyrolesqmltypes.cpp \ $$PWD/proxyroles/singlerole.cpp \ $$PWD/proxyroles/regexprole.cpp \ - $$PWD/sorters/filtersorter.cpp + $$PWD/sorters/filtersorter.cpp \ + $$PWD/proxyroles/filterrole.cpp diff --git a/proxyroles/filterrole.cpp b/proxyroles/filterrole.cpp new file mode 100644 index 0000000..baf16d6 --- /dev/null +++ b/proxyroles/filterrole.cpp @@ -0,0 +1,60 @@ +#include "filterrole.h" +#include "filters/filter.h" + +namespace qqsfpm { + +/*! + \qmltype FilterRole + \inherits SingleRole + \inqmlmodule SortFilterProxyModel + \brief A role resolving to \c true for rows matching all its filters + + A FilterRole is a \l ProxyRole that returns \c true for rows matching all its filters. + + In the following example, the \c isAdult role will be equal to \c true if the \c age role is superior or equal to 18. + SortFilterProxyModel { + sourceModel: personModel + proxyRoles: FilterRole { + name: "isAdult" + RangeFilter { roleName: "age"; minimumValue: 18; minimumInclusive: true } + } + } + \endcode +*/ + +/*! + \qmlproperty string FilterRole::filters + + This property holds the list of filters for this filter role. + The data of this role will be equal to the \c true if all its filters match the model row, \c false otherwise. + + \sa Filter +*/ + +void FilterRole::onFilterAppended(Filter* filter) +{ + connect(filter, &Filter::invalidated, this, &FilterRole::invalidate); + invalidate(); +} + +void FilterRole::onFilterRemoved(Filter* filter) +{ + disconnect(filter, &Filter::invalidated, this, &FilterRole::invalidate); + invalidate(); +} + +void FilterRole::onFiltersCleared() +{ + invalidate(); +} + +QVariant FilterRole::data(const QModelIndex& sourceIndex, const QQmlSortFilterProxyModel& proxyModel) +{ + return std::all_of(m_filters.begin(), m_filters.end(), + [&] (Filter* filter) { + return filter->filterAcceptsRow(sourceIndex, proxyModel); + } + ); +} + +} diff --git a/proxyroles/filterrole.h b/proxyroles/filterrole.h new file mode 100644 index 0000000..dd1285a --- /dev/null +++ b/proxyroles/filterrole.h @@ -0,0 +1,29 @@ +#ifndef FILTERROLE_H +#define FILTERROLE_H + +#include "singlerole.h" +#include "filters/filtercontainer.h" + +namespace qqsfpm { + +class FilterRole : public SingleRole, public FilterContainer +{ + Q_OBJECT + Q_INTERFACES(qqsfpm::FilterContainer) + Q_PROPERTY(QQmlListProperty filters READ filtersListProperty) + Q_CLASSINFO("DefaultProperty", "filters") + +public: + using SingleRole::SingleRole; + +private: + void onFilterAppended(Filter* filter) override; + void onFilterRemoved(Filter* filter) override; + void onFiltersCleared() override; + + QVariant data(const QModelIndex& sourceIndex, const QQmlSortFilterProxyModel& proxyModel) override; +}; + +} + +#endif // FILTERROLE_H diff --git a/proxyroles/proxyrolesqmltypes.cpp b/proxyroles/proxyrolesqmltypes.cpp index e71a13d..efea256 100644 --- a/proxyroles/proxyrolesqmltypes.cpp +++ b/proxyroles/proxyrolesqmltypes.cpp @@ -3,6 +3,7 @@ #include "switchrole.h" #include "expressionrole.h" #include "regexprole.h" +#include "filterrole.h" #include #include @@ -14,6 +15,7 @@ void registerProxyRoleTypes() { qmlRegisterType("SortFilterProxyModel", 0, 2, "SwitchRole"); qmlRegisterType("SortFilterProxyModel", 0, 2, "ExpressionRole"); qmlRegisterType("SortFilterProxyModel", 0, 2, "RegExpRole"); + qmlRegisterType("SortFilterProxyModel", 0, 2, "FilterRole"); } Q_COREAPP_STARTUP_FUNCTION(registerProxyRoleTypes) diff --git a/tests/SortFilterProxyModel.pro b/tests/SortFilterProxyModel.pro index fc9ba52..743af57 100644 --- a/tests/SortFilterProxyModel.pro +++ b/tests/SortFilterProxyModel.pro @@ -31,4 +31,5 @@ OTHER_FILES += \ DISTFILES += \ tst_filtercontainers.qml \ tst_regexprole.qml \ - tst_filtersorter.qml + tst_filtersorter.qml \ + tst_filterrole.qml diff --git a/tests/tst_filterrole.qml b/tests/tst_filterrole.qml new file mode 100644 index 0000000..38ba394 --- /dev/null +++ b/tests/tst_filterrole.qml @@ -0,0 +1,47 @@ +import QtQuick 2.0 +import QtQml 2.2 +import QtTest 1.1 +import SortFilterProxyModel 0.2 +import QtQml 2.2 + +Item { + ListModel { + id: listModel + ListElement { name: "1"; age: 18 } + ListElement { name: "2"; age: 22 } + ListElement { name: "3"; age: 45 } + ListElement { name: "4"; age: 10 } + } + + SortFilterProxyModel { + id: testModel + sourceModel: listModel + + proxyRoles: FilterRole { + name: "isOldEnough" + RangeFilter { + id: ageFilter + roleName: "age" + minimumInclusive: true + minimumValue: 18 + } + } + } + TestCase { + name: "FilterRole" + + function test_filterRole() { + compare(testModel.get(0, "isOldEnough"), true); + compare(testModel.get(1, "isOldEnough"), true); + compare(testModel.get(2, "isOldEnough"), true); + compare(testModel.get(3, "isOldEnough"), false); + + ageFilter.minimumValue = 21; + + compare(testModel.get(0, "isOldEnough"), false); + compare(testModel.get(1, "isOldEnough"), true); + compare(testModel.get(2, "isOldEnough"), true); + compare(testModel.get(3, "isOldEnough"), false); + } + } +}