feature: Add SwitchRole proxy role type

This commit is contained in:
Grecko 2017-09-17 21:16:26 +02:00
parent 94a08b49ec
commit 9a475e52ac
4 changed files with 256 additions and 1 deletions

View File

@ -4,6 +4,8 @@
#include <QQmlExpression>
#include <QCoreApplication>
#include <QDebug>
#include <QQmlInfo>
#include "filter.h"
namespace qqsfpm {
@ -90,9 +92,119 @@ QVariant JoinRole::data(const QModelIndex &sourceIndex, const QQmlSortFilterProx
return result;
}
SwitchRoleAttached::SwitchRoleAttached(QObject* parent) : QObject (parent)
{
if (!qobject_cast<Filter*>(parent))
qmlInfo(parent) << "SwitchRole must be attached to a Filter";
}
QVariant SwitchRoleAttached::value() const
{
return m_value;
}
void SwitchRoleAttached::setValue(QVariant value)
{
if (m_value == value)
return;
m_value = value;
Q_EMIT valueChanged();
}
QString SwitchRole::defaultRoleName() const
{
return m_defaultRoleName;
}
void SwitchRole::setDefaultRoleName(QString defaultRoleName)
{
if (m_defaultRoleName == defaultRoleName)
return;
m_defaultRoleName = defaultRoleName;
Q_EMIT defaultRoleNameChanged();
invalidate();
}
QQmlListProperty<Filter> SwitchRole::filters()
{
return QQmlListProperty<Filter>(this, &m_filters,
&SwitchRole::append_filter,
&SwitchRole::count_filter,
&SwitchRole::at_filter,
&SwitchRole::clear_filters);
}
void SwitchRole::proxyModelCompleted(const QQmlSortFilterProxyModel& proxyModel)
{
for (Filter* filter : m_filters)
filter->proxyModelCompleted(proxyModel);
}
SwitchRoleAttached* SwitchRole::qmlAttachedProperties(QObject* object)
{
return new SwitchRoleAttached(object);
}
QVariant SwitchRole::data(const QModelIndex &sourceIndex, const QQmlSortFilterProxyModel &proxyModel)
{
for (auto filter: m_filters) {
if (!filter->enabled())
continue;
if (filter->filterAcceptsRow(sourceIndex, proxyModel)) {
auto attached = static_cast<SwitchRoleAttached*>(qmlAttachedPropertiesObject<SwitchRole>(filter, false));
if (!attached) {
qWarning() << "No SwitchRole.value provided for this filter" << filter;
continue;
}
QVariant value = attached->value();
if (!value.isValid()) {
qWarning() << "No SwitchRole.value provided for this filter" << filter;
continue;
}
return value;
}
}
return proxyModel.sourceData(sourceIndex, m_defaultRoleName);
}
void SwitchRole::append_filter(QQmlListProperty<Filter>* list, Filter* filter)
{
if (!filter)
return;
SwitchRole* that = static_cast<SwitchRole*>(list->object);
that->m_filters.append(filter);
connect(filter, &Filter::invalidated, that, &SwitchRole::invalidate);
auto attached = static_cast<SwitchRoleAttached*>(qmlAttachedPropertiesObject<SwitchRole>(filter, true));
connect(attached, &SwitchRoleAttached::valueChanged, that, &SwitchRole::invalidate);
that->invalidate();
}
int SwitchRole::count_filter(QQmlListProperty<Filter>* list)
{
QList<Filter*>* filters = static_cast<QList<Filter*>*>(list->data);
return filters->count();
}
Filter* SwitchRole::at_filter(QQmlListProperty<Filter>* list, int index)
{
QList<Filter*>* filters = static_cast<QList<Filter*>*>(list->data);
return filters->at(index);
}
void SwitchRole::clear_filters(QQmlListProperty<Filter> *list)
{
SwitchRole* that = static_cast<SwitchRole*>(list->object);
that->m_filters.clear();
that->invalidate();
}
void registerProxyRoleTypes() {
qmlRegisterUncreatableType<ProxyRole>("SortFilterProxyModel", 0, 2, "ProxyRole", "ProxyRole is an abstract class");
qmlRegisterType<JoinRole>("SortFilterProxyModel", 0, 2, "JoinRole");
qmlRegisterType<SwitchRole>("SortFilterProxyModel", 0, 2, "SwitchRole");
}
Q_COREAPP_STARTUP_FUNCTION(registerProxyRoleTypes)

View File

@ -3,6 +3,7 @@
#include <QObject>
#include <QMutex>
#include <qqml.h>
#include "qqmlsortfilterproxymodel.h"
namespace qqsfpm {
@ -62,6 +63,57 @@ private:
QString m_separator = " ";
};
class SwitchRoleAttached : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
public:
SwitchRoleAttached(QObject* parent);
QVariant value() const;
void setValue(QVariant value);
Q_SIGNALS:
void valueChanged();
private:
QVariant m_value;
};
class SwitchRole : public ProxyRole
{
Q_OBJECT
Q_PROPERTY(QString defaultRoleName READ defaultRoleName WRITE setDefaultRoleName NOTIFY defaultRoleNameChanged)
Q_PROPERTY(QQmlListProperty<qqsfpm::Filter> filters READ filters)
public:
using ProxyRole::ProxyRole;
QString defaultRoleName() const;
void setDefaultRoleName(QString defaultRoleName);
QQmlListProperty<Filter> filters();
void proxyModelCompleted(const QQmlSortFilterProxyModel& proxyModel) override;
static SwitchRoleAttached* qmlAttachedProperties(QObject* object);
Q_SIGNALS:
void defaultRoleNameChanged();
private:
QVariant data(const QModelIndex& sourceIndex, const QQmlSortFilterProxyModel& proxyModel) override;
static void append_filter(QQmlListProperty<Filter>* list, Filter* filter);
static int count_filter(QQmlListProperty<Filter>* list);
static Filter* at_filter(QQmlListProperty<Filter>* list, int index);
static void clear_filters(QQmlListProperty<Filter>* list);
QString m_defaultRoleName;
QList<Filter*> m_filters;
};
}
QML_DECLARE_TYPEINFO(qqsfpm::SwitchRole, QML_HAS_ATTACHED_PROPERTIES)
#endif // PROXYROLE_H

View File

@ -24,4 +24,5 @@ OTHER_FILES += \
tst_rolesorter.qml \
tst_stringsorter.qml \
tst_proxyroles.qml \
tst_joinrole.qml
tst_joinrole.qml \
tst_switchrole.qml

90
tests/tst_switchrole.qml Normal file
View File

@ -0,0 +1,90 @@
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"; favorite: true }
ListElement { name: "2"; favorite: false }
ListElement { name: "3"; favorite: false }
ListElement { name: "4"; favorite: true }
}
SortFilterProxyModel {
id: testModel
sourceModel: listModel
proxyRoles: SwitchRole {
name: "switchRole"
filters: [
ValueFilter {
id: valueFilter
roleName: "favorite"
value: true
SwitchRole.value: "*"
},
ValueFilter {
id: secondValueFilter
roleName: "favorite"
value: true
SwitchRole.value: "%"
},
ValueFilter {
id: thirdValueFilter
roleName: "name"
value: 3
SwitchRole.value: "three"
}
]
defaultRoleName: "name"
}
}
Instantiator {
id: instantiator
model: testModel
QtObject {
property var switchRole: model.switchRole
}
}
TestCase {
name: "SwitchRole"
function test_data() {
compare(testModel.get(0, "switchRole"), "*");
compare(testModel.get(1, "switchRole"), "2");
compare(testModel.get(2, "switchRole"), "three");
compare(testModel.get(3, "switchRole"), "*");
}
function test_valueChange() {
compare(instantiator.object.switchRole, "*");
valueFilter.SwitchRole.value = "test";
compare(instantiator.object.switchRole, "test");
valueFilter.SwitchRole.value = "*";
}
function test_filterChange() {
compare(instantiator.object.switchRole, "*");
valueFilter.enabled = false;
compare(instantiator.object.switchRole, "%");
valueFilter.enabled = true;
}
function test_defaultSourceChange() {
compare(instantiator.object.switchRole, "*");
listModel.setProperty(0, "favorite", false);
compare(instantiator.object.switchRole, "1");
compare(instantiator.objectAt(1).switchRole, "2");
listModel.setProperty(1, "name", "test");
compare(instantiator.objectAt(1).switchRole, "test");
listModel.setProperty(1, "name", "2");
listModel.setProperty(0, "favorite", true);
}
}
}