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();
|
||||
}
|
||||
|
||||
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() {
|
||||
qmlRegisterUncreatableType<ProxyRole>("SortFilterProxyModel", 0, 2, "ProxyRole", "ProxyRole is an abstract class");
|
||||
qmlRegisterType<JoinRole>("SortFilterProxyModel", 0, 2, "JoinRole");
|
||||
qmlRegisterType<SwitchRole>("SortFilterProxyModel", 0, 2, "SwitchRole");
|
||||
qmlRegisterType<ExpressionRole>("SortFilterProxyModel", 0, 2, "ExpressionRole");
|
||||
}
|
||||
|
||||
Q_COREAPP_STARTUP_FUNCTION(registerProxyRoleTypes)
|
||||
|
|
28
proxyrole.h
28
proxyrole.h
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QQmlScriptString>
|
||||
#include <QQmlExpression>
|
||||
#include <qqml.h>
|
||||
#include "qqmlsortfilterproxymodel.h"
|
||||
|
||||
|
@ -118,6 +120,32 @@ private:
|
|||
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)
|
||||
|
|
|
@ -205,8 +205,14 @@ void QQmlSortFilterProxyModel::classBegin()
|
|||
void QQmlSortFilterProxyModel::componentComplete()
|
||||
{
|
||||
m_completed = true;
|
||||
|
||||
for (const auto& filter : m_filters)
|
||||
filter->proxyModelCompleted(*this);
|
||||
for (const auto& sorter : m_sorters)
|
||||
sorter->proxyModelCompleted(*this);
|
||||
for (const auto& proxyRole : m_proxyRoles)
|
||||
proxyRole->proxyModelCompleted(*this);
|
||||
|
||||
invalidate();
|
||||
sort(0);
|
||||
}
|
||||
|
|
|
@ -25,4 +25,5 @@ OTHER_FILES += \
|
|||
tst_stringsorter.qml \
|
||||
tst_proxyroles.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