feat: add ExpressionRole proxy role type
This commit is contained in:
parent
4dc2eb1d7a
commit
38903de8f8
|
@ -218,10 +218,96 @@ void SwitchRole::clear_filters(QQmlListProperty<Filter> *list)
|
||||||
that->invalidate();
|
that->invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QQmlScriptString& ExpressionRole::expression() const
|
||||||
|
{
|
||||||
|
return m_scriptString;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpressionRole::setExpression(const QQmlScriptString& scriptString)
|
||||||
|
{
|
||||||
|
if (m_scriptString == scriptString)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_scriptString = scriptString;
|
||||||
|
updateExpression();
|
||||||
|
|
||||||
|
Q_EMIT expressionChanged();
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpressionRole::proxyModelCompleted(const QQmlSortFilterProxyModel& proxyModel)
|
||||||
|
{
|
||||||
|
updateContext(proxyModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ExpressionRole::data(const QModelIndex& sourceIndex, const QQmlSortFilterProxyModel& proxyModel)
|
||||||
|
{
|
||||||
|
if (!m_scriptString.isEmpty()) {
|
||||||
|
QVariantMap modelMap;
|
||||||
|
QHash<int, QByteArray> roles = proxyModel.roleNames();
|
||||||
|
|
||||||
|
QQmlContext context(qmlContext(this));
|
||||||
|
auto addToContext = [&] (const QString &name, const QVariant& value) {
|
||||||
|
context.setContextProperty(name, value);
|
||||||
|
modelMap.insert(name, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto it = roles.cbegin(); it != roles.cend(); ++it)
|
||||||
|
addToContext(it.value(), proxyModel.sourceData(sourceIndex, it.key()));
|
||||||
|
addToContext("index", sourceIndex.row());
|
||||||
|
|
||||||
|
context.setContextProperty("model", modelMap);
|
||||||
|
|
||||||
|
QQmlExpression expression(m_scriptString, &context);
|
||||||
|
QVariant result = expression.evaluate();
|
||||||
|
|
||||||
|
if (expression.hasError()) {
|
||||||
|
qWarning() << expression.error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpressionRole::updateContext(const QQmlSortFilterProxyModel& proxyModel)
|
||||||
|
{
|
||||||
|
delete m_context;
|
||||||
|
m_context = new QQmlContext(qmlContext(this), this);
|
||||||
|
// what about roles changes ?
|
||||||
|
QVariantMap modelMap;
|
||||||
|
|
||||||
|
auto addToContext = [&] (const QString &name, const QVariant& value) {
|
||||||
|
m_context->setContextProperty(name, value);
|
||||||
|
modelMap.insert(name, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const QByteArray& roleName : proxyModel.roleNames().values())
|
||||||
|
addToContext(roleName, QVariant());
|
||||||
|
|
||||||
|
addToContext("index", -1);
|
||||||
|
|
||||||
|
m_context->setContextProperty("model", modelMap);
|
||||||
|
updateExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpressionRole::updateExpression()
|
||||||
|
{
|
||||||
|
if (!m_context)
|
||||||
|
return;
|
||||||
|
|
||||||
|
delete m_expression;
|
||||||
|
m_expression = new QQmlExpression(m_scriptString, m_context, 0, this);
|
||||||
|
connect(m_expression, &QQmlExpression::valueChanged, this, &ExpressionRole::invalidate);
|
||||||
|
m_expression->setNotifyOnValueChanged(true);
|
||||||
|
m_expression->evaluate();
|
||||||
|
}
|
||||||
|
|
||||||
void registerProxyRoleTypes() {
|
void registerProxyRoleTypes() {
|
||||||
qmlRegisterUncreatableType<ProxyRole>("SortFilterProxyModel", 0, 2, "ProxyRole", "ProxyRole is an abstract class");
|
qmlRegisterUncreatableType<ProxyRole>("SortFilterProxyModel", 0, 2, "ProxyRole", "ProxyRole is an abstract class");
|
||||||
qmlRegisterType<JoinRole>("SortFilterProxyModel", 0, 2, "JoinRole");
|
qmlRegisterType<JoinRole>("SortFilterProxyModel", 0, 2, "JoinRole");
|
||||||
qmlRegisterType<SwitchRole>("SortFilterProxyModel", 0, 2, "SwitchRole");
|
qmlRegisterType<SwitchRole>("SortFilterProxyModel", 0, 2, "SwitchRole");
|
||||||
|
qmlRegisterType<ExpressionRole>("SortFilterProxyModel", 0, 2, "ExpressionRole");
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_COREAPP_STARTUP_FUNCTION(registerProxyRoleTypes)
|
Q_COREAPP_STARTUP_FUNCTION(registerProxyRoleTypes)
|
||||||
|
|
28
proxyrole.h
28
proxyrole.h
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
|
#include <QQmlScriptString>
|
||||||
|
#include <QQmlExpression>
|
||||||
#include <qqml.h>
|
#include <qqml.h>
|
||||||
#include "qqmlsortfilterproxymodel.h"
|
#include "qqmlsortfilterproxymodel.h"
|
||||||
|
|
||||||
|
@ -118,6 +120,32 @@ private:
|
||||||
QList<Filter*> m_filters;
|
QList<Filter*> m_filters;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ExpressionRole : public ProxyRole
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QQmlScriptString expression READ expression WRITE setExpression NOTIFY expressionChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
using ProxyRole::ProxyRole;
|
||||||
|
|
||||||
|
const QQmlScriptString& expression() const;
|
||||||
|
void setExpression(const QQmlScriptString& scriptString);
|
||||||
|
|
||||||
|
void proxyModelCompleted(const QQmlSortFilterProxyModel& proxyModel) override;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void expressionChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVariant data(const QModelIndex& sourceIndex, const QQmlSortFilterProxyModel& proxyModel) override;
|
||||||
|
void updateContext(const QQmlSortFilterProxyModel& proxyModel);
|
||||||
|
void updateExpression();
|
||||||
|
|
||||||
|
QQmlScriptString m_scriptString;
|
||||||
|
QQmlExpression* m_expression = nullptr;
|
||||||
|
QQmlContext* m_context = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QML_DECLARE_TYPEINFO(qqsfpm::SwitchRole, QML_HAS_ATTACHED_PROPERTIES)
|
QML_DECLARE_TYPEINFO(qqsfpm::SwitchRole, QML_HAS_ATTACHED_PROPERTIES)
|
||||||
|
|
|
@ -205,8 +205,14 @@ void QQmlSortFilterProxyModel::classBegin()
|
||||||
void QQmlSortFilterProxyModel::componentComplete()
|
void QQmlSortFilterProxyModel::componentComplete()
|
||||||
{
|
{
|
||||||
m_completed = true;
|
m_completed = true;
|
||||||
|
|
||||||
for (const auto& filter : m_filters)
|
for (const auto& filter : m_filters)
|
||||||
filter->proxyModelCompleted(*this);
|
filter->proxyModelCompleted(*this);
|
||||||
|
for (const auto& sorter : m_sorters)
|
||||||
|
sorter->proxyModelCompleted(*this);
|
||||||
|
for (const auto& proxyRole : m_proxyRoles)
|
||||||
|
proxyRole->proxyModelCompleted(*this);
|
||||||
|
|
||||||
invalidate();
|
invalidate();
|
||||||
sort(0);
|
sort(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,4 +25,5 @@ OTHER_FILES += \
|
||||||
tst_stringsorter.qml \
|
tst_stringsorter.qml \
|
||||||
tst_proxyroles.qml \
|
tst_proxyroles.qml \
|
||||||
tst_joinrole.qml \
|
tst_joinrole.qml \
|
||||||
tst_switchrole.qml
|
tst_switchrole.qml \
|
||||||
|
tst_expressionrole.qml
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQml 2.2
|
||||||
|
import QtTest 1.1
|
||||||
|
import SortFilterProxyModel 0.2
|
||||||
|
import QtQml 2.2
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property int c: 0
|
||||||
|
ListModel {
|
||||||
|
id: listModel
|
||||||
|
ListElement { a: 1; b: 2 }
|
||||||
|
}
|
||||||
|
|
||||||
|
SortFilterProxyModel {
|
||||||
|
id: testModel
|
||||||
|
sourceModel: listModel
|
||||||
|
|
||||||
|
proxyRoles: ExpressionRole {
|
||||||
|
name: "expressionRole"
|
||||||
|
expression: a + model.b + c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Instantiator {
|
||||||
|
id: instantiator
|
||||||
|
model: testModel
|
||||||
|
QtObject {
|
||||||
|
property string expressionRole: model.expressionRole
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCase {
|
||||||
|
name: "ExpressionRole"
|
||||||
|
|
||||||
|
function test_expressionRole() {
|
||||||
|
fuzzyCompare(instantiator.object.expressionRole, 3, 1e-7);
|
||||||
|
listModel.setProperty(0, "b", 9);
|
||||||
|
fuzzyCompare(instantiator.object.expressionRole, 10, 1e-7);
|
||||||
|
c = 1327;
|
||||||
|
fuzzyCompare(instantiator.object.expressionRole, 1337, 1e-7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue