From 5f4cfb9209781129c12ea4c91829787499bb38b1 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 17 Jul 2009 18:43:46 +1000 Subject: Add some basic QML benchmarks --- src/declarative/qml/qmlbasicscript.cpp | 12 ++ tests/benchmarks/declarative/binding/binding.pro | 8 ++ .../benchmarks/declarative/binding/idproperty.txt | 7 ++ .../declarative/binding/localproperty.txt | 3 + .../declarative/binding/objectproperty.txt | 5 + tests/benchmarks/declarative/binding/testtypes.cpp | 3 + tests/benchmarks/declarative/binding/testtypes.h | 41 +++++++ .../benchmarks/declarative/binding/tst_binding.cpp | 126 +++++++++++++++++++++ .../declarative/qmlcomponent/myqmlobject.txt | 1 + .../qmlcomponent/myqmlobject_binding.txt | 4 + .../benchmarks/declarative/qmlcomponent/object.txt | 1 + .../declarative/qmlcomponent/qmlcomponent.pro | 8 ++ .../qmlcomponent/synthesized_properties.2.txt | 13 +++ .../qmlcomponent/synthesized_properties.txt | 3 + .../declarative/qmlcomponent/testtypes.cpp | 3 + .../declarative/qmlcomponent/testtypes.h | 41 +++++++ .../declarative/qmlcomponent/tst_qmlcomponent.cpp | 79 +++++++++++++ 17 files changed, 358 insertions(+) create mode 100644 tests/benchmarks/declarative/binding/binding.pro create mode 100644 tests/benchmarks/declarative/binding/idproperty.txt create mode 100644 tests/benchmarks/declarative/binding/localproperty.txt create mode 100644 tests/benchmarks/declarative/binding/objectproperty.txt create mode 100644 tests/benchmarks/declarative/binding/testtypes.cpp create mode 100644 tests/benchmarks/declarative/binding/testtypes.h create mode 100644 tests/benchmarks/declarative/binding/tst_binding.cpp create mode 100644 tests/benchmarks/declarative/qmlcomponent/myqmlobject.txt create mode 100644 tests/benchmarks/declarative/qmlcomponent/myqmlobject_binding.txt create mode 100644 tests/benchmarks/declarative/qmlcomponent/object.txt create mode 100644 tests/benchmarks/declarative/qmlcomponent/qmlcomponent.pro create mode 100644 tests/benchmarks/declarative/qmlcomponent/synthesized_properties.2.txt create mode 100644 tests/benchmarks/declarative/qmlcomponent/synthesized_properties.txt create mode 100644 tests/benchmarks/declarative/qmlcomponent/testtypes.cpp create mode 100644 tests/benchmarks/declarative/qmlcomponent/testtypes.h create mode 100644 tests/benchmarks/declarative/qmlcomponent/tst_qmlcomponent.cpp diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp index 40ffffe..3fe24ea 100644 --- a/src/declarative/qml/qmlbasicscript.cpp +++ b/src/declarative/qml/qmlbasicscript.cpp @@ -443,6 +443,18 @@ void QmlBasicScript::dump() qWarning().nospace() << "FETCH\t\t" << instr.fetch.idx << "\t\t" << QByteArray(data + instr.fetch.idx); break; + case ScriptInstruction::LoadIdObject: + qWarning().nospace() << "LOAD_ID_OBJECT"; + break; + case ScriptInstruction::FetchConstant: + qWarning().nospace() << "FETCH_CONSTANT"; + break; + case ScriptInstruction::FetchD0Constant: + qWarning().nospace() << "FETCH_D0_CONSTANT"; + break; + case ScriptInstruction::FetchD1Constant: + qWarning().nospace() << "FETCH_D1_CONSTANT"; + break; case ScriptInstruction::Equals: qWarning().nospace() << "EQUALS"; break; diff --git a/tests/benchmarks/declarative/binding/binding.pro b/tests/benchmarks/declarative/binding/binding.pro new file mode 100644 index 0000000..26ee4fa --- /dev/null +++ b/tests/benchmarks/declarative/binding/binding.pro @@ -0,0 +1,8 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_binding +QT += declarative + +SOURCES += tst_binding.cpp testtypes.cpp +HEADERS += testtypes.h + diff --git a/tests/benchmarks/declarative/binding/idproperty.txt b/tests/benchmarks/declarative/binding/idproperty.txt new file mode 100644 index 0000000..0a98e0d --- /dev/null +++ b/tests/benchmarks/declarative/binding/idproperty.txt @@ -0,0 +1,7 @@ +MyQmlObject { + id: MyObject + + MyQmlObject { + result: ### + } +} diff --git a/tests/benchmarks/declarative/binding/localproperty.txt b/tests/benchmarks/declarative/binding/localproperty.txt new file mode 100644 index 0000000..4694d99 --- /dev/null +++ b/tests/benchmarks/declarative/binding/localproperty.txt @@ -0,0 +1,3 @@ +MyQmlObject { + result: ### +} diff --git a/tests/benchmarks/declarative/binding/objectproperty.txt b/tests/benchmarks/declarative/binding/objectproperty.txt new file mode 100644 index 0000000..597c965 --- /dev/null +++ b/tests/benchmarks/declarative/binding/objectproperty.txt @@ -0,0 +1,5 @@ +MyQmlObject { + id: MyObject + + result: ### +} diff --git a/tests/benchmarks/declarative/binding/testtypes.cpp b/tests/benchmarks/declarative/binding/testtypes.cpp new file mode 100644 index 0000000..60e69e2 --- /dev/null +++ b/tests/benchmarks/declarative/binding/testtypes.cpp @@ -0,0 +1,3 @@ +#include "testtypes.h" + +QML_DEFINE_TYPE(MyQmlObject, MyQmlObject); diff --git a/tests/benchmarks/declarative/binding/testtypes.h b/tests/benchmarks/declarative/binding/testtypes.h new file mode 100644 index 0000000..20bf5f7 --- /dev/null +++ b/tests/benchmarks/declarative/binding/testtypes.h @@ -0,0 +1,41 @@ +#ifndef TESTTYPES_H +#define TESTTYPES_H + +#include +#include + +class MyQmlObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(int result READ result WRITE setResult); + Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged); + Q_PROPERTY(MyQmlObject *object READ object WRITE setObject NOTIFY objectChanged); + Q_PROPERTY(QmlList *data READ data); + Q_CLASSINFO("DefaultProperty", "data"); +public: + MyQmlObject() : m_result(0), m_value(0), m_object(0) {} + + int result() const { return m_result; } + void setResult(int r) { m_result = r; } + + int value() const { return m_value; } + void setValue(int v) { m_value = v; emit valueChanged(); } + + QmlList *data() { return &m_data; } + + MyQmlObject *object() const { return m_object; } + void setObject(MyQmlObject *o) { m_object = o; emit objectChanged(); } + +signals: + void valueChanged(); + void objectChanged(); + +private: + QmlConcreteList m_data; + int m_result; + int m_value; + MyQmlObject *m_object; +}; +QML_DECLARE_TYPE(MyQmlObject); + +#endif // TESTTYPES_H diff --git a/tests/benchmarks/declarative/binding/tst_binding.cpp b/tests/benchmarks/declarative/binding/tst_binding.cpp new file mode 100644 index 0000000..e593382 --- /dev/null +++ b/tests/benchmarks/declarative/binding/tst_binding.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "testtypes.h" + +//TESTED_FILES= + +class tst_binding : public QObject +{ + Q_OBJECT + +public: + tst_binding(); + virtual ~tst_binding(); + +public slots: + void init(); + void cleanup(); + +private slots: + void objectproperty_data(); + void objectproperty(); + void basicproperty_data(); + void basicproperty(); + +private: + QmlEngine engine; +}; + +tst_binding::tst_binding() +{ +} + +tst_binding::~tst_binding() +{ +} + +void tst_binding::init() +{ +} + +void tst_binding::cleanup() +{ +} + +#define COMPONENT(filename, binding) \ + QmlComponent c(&engine); \ + { \ + QFile f(filename); \ + QVERIFY(f.open(QIODevice::ReadOnly)); \ + QByteArray data = f.readAll(); \ + data.replace("###", binding.toUtf8()); \ + c.setData(data, QUrl()); \ + QVERIFY(c.isReady()); \ + } + +void tst_binding::objectproperty_data() +{ + QTest::addColumn("file"); + QTest::addColumn("binding"); + + QTest::newRow("object.value") << "objectproperty.txt" << "object.value"; + QTest::newRow("object.value + 10") << "objectproperty.txt" << "object.value + 10"; +} + +void tst_binding::objectproperty() +{ + QFETCH(QString, file); + QFETCH(QString, binding); + + COMPONENT(file, binding); + + MyQmlObject object1; + MyQmlObject object2; + + MyQmlObject *object = qobject_cast(c.create()); + QVERIFY(object != 0); + object->setObject(&object2); + + QBENCHMARK { + object->setObject(&object1); + object->setObject(&object2); + } +} + +void tst_binding::basicproperty_data() +{ + QTest::addColumn("file"); + QTest::addColumn("binding"); + + QTest::newRow("value") << "localproperty.txt" << "value"; + QTest::newRow("value + 10") << "localproperty.txt" << "value + 10"; + QTest::newRow("value + value + 10") << "localproperty.txt" << "value + value + 10"; + + QTest::newRow("MyObject.value") << "idproperty.txt" << "MyObject.value"; + QTest::newRow("MyObject.value + 10") << "idproperty.txt" << "MyObject.value + 10"; + QTest::newRow("MyObject.value + MyObject.value + 10") << "idproperty.txt" << "MyObject.value + MyObject.value + 10"; +} + +void tst_binding::basicproperty() +{ + QFETCH(QString, file); + QFETCH(QString, binding); + + COMPONENT(file, binding); + + MyQmlObject *object = qobject_cast(c.create()); + QVERIFY(object != 0); + object->setValue(10); + + QBENCHMARK { + object->setValue(1); + } +} + +QTEST_MAIN(tst_binding) +#include "tst_binding.moc" diff --git a/tests/benchmarks/declarative/qmlcomponent/myqmlobject.txt b/tests/benchmarks/declarative/qmlcomponent/myqmlobject.txt new file mode 100644 index 0000000..05ed87a --- /dev/null +++ b/tests/benchmarks/declarative/qmlcomponent/myqmlobject.txt @@ -0,0 +1 @@ +MyQmlObject {} diff --git a/tests/benchmarks/declarative/qmlcomponent/myqmlobject_binding.txt b/tests/benchmarks/declarative/qmlcomponent/myqmlobject_binding.txt new file mode 100644 index 0000000..4dfa7c3 --- /dev/null +++ b/tests/benchmarks/declarative/qmlcomponent/myqmlobject_binding.txt @@ -0,0 +1,4 @@ +MyQmlObject { + result: value +} + diff --git a/tests/benchmarks/declarative/qmlcomponent/object.txt b/tests/benchmarks/declarative/qmlcomponent/object.txt new file mode 100644 index 0000000..7dc75192 --- /dev/null +++ b/tests/benchmarks/declarative/qmlcomponent/object.txt @@ -0,0 +1 @@ +Object {} diff --git a/tests/benchmarks/declarative/qmlcomponent/qmlcomponent.pro b/tests/benchmarks/declarative/qmlcomponent/qmlcomponent.pro new file mode 100644 index 0000000..5f0cbe6 --- /dev/null +++ b/tests/benchmarks/declarative/qmlcomponent/qmlcomponent.pro @@ -0,0 +1,8 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_qmlcomponent +QT += declarative + +SOURCES += tst_qmlcomponent.cpp testtypes.cpp +HEADERS += testtypes.h + diff --git a/tests/benchmarks/declarative/qmlcomponent/synthesized_properties.2.txt b/tests/benchmarks/declarative/qmlcomponent/synthesized_properties.2.txt new file mode 100644 index 0000000..d59104d --- /dev/null +++ b/tests/benchmarks/declarative/qmlcomponent/synthesized_properties.2.txt @@ -0,0 +1,13 @@ +Object { + property int a + property bool b + property double c + property real d + property string e + property url f + property color g + property date h + property var i + property variant j +} + diff --git a/tests/benchmarks/declarative/qmlcomponent/synthesized_properties.txt b/tests/benchmarks/declarative/qmlcomponent/synthesized_properties.txt new file mode 100644 index 0000000..d9eb708 --- /dev/null +++ b/tests/benchmarks/declarative/qmlcomponent/synthesized_properties.txt @@ -0,0 +1,3 @@ +Object { + property int a +} diff --git a/tests/benchmarks/declarative/qmlcomponent/testtypes.cpp b/tests/benchmarks/declarative/qmlcomponent/testtypes.cpp new file mode 100644 index 0000000..60e69e2 --- /dev/null +++ b/tests/benchmarks/declarative/qmlcomponent/testtypes.cpp @@ -0,0 +1,3 @@ +#include "testtypes.h" + +QML_DEFINE_TYPE(MyQmlObject, MyQmlObject); diff --git a/tests/benchmarks/declarative/qmlcomponent/testtypes.h b/tests/benchmarks/declarative/qmlcomponent/testtypes.h new file mode 100644 index 0000000..20bf5f7 --- /dev/null +++ b/tests/benchmarks/declarative/qmlcomponent/testtypes.h @@ -0,0 +1,41 @@ +#ifndef TESTTYPES_H +#define TESTTYPES_H + +#include +#include + +class MyQmlObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(int result READ result WRITE setResult); + Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged); + Q_PROPERTY(MyQmlObject *object READ object WRITE setObject NOTIFY objectChanged); + Q_PROPERTY(QmlList *data READ data); + Q_CLASSINFO("DefaultProperty", "data"); +public: + MyQmlObject() : m_result(0), m_value(0), m_object(0) {} + + int result() const { return m_result; } + void setResult(int r) { m_result = r; } + + int value() const { return m_value; } + void setValue(int v) { m_value = v; emit valueChanged(); } + + QmlList *data() { return &m_data; } + + MyQmlObject *object() const { return m_object; } + void setObject(MyQmlObject *o) { m_object = o; emit objectChanged(); } + +signals: + void valueChanged(); + void objectChanged(); + +private: + QmlConcreteList m_data; + int m_result; + int m_value; + MyQmlObject *m_object; +}; +QML_DECLARE_TYPE(MyQmlObject); + +#endif // TESTTYPES_H diff --git a/tests/benchmarks/declarative/qmlcomponent/tst_qmlcomponent.cpp b/tests/benchmarks/declarative/qmlcomponent/tst_qmlcomponent.cpp new file mode 100644 index 0000000..1920bf2 --- /dev/null +++ b/tests/benchmarks/declarative/qmlcomponent/tst_qmlcomponent.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "testtypes.h" + +//TESTED_FILES= + + +class tst_qmlcomponent : public QObject +{ + Q_OBJECT + +public: + tst_qmlcomponent(); + virtual ~tst_qmlcomponent(); + +public slots: + void init(); + void cleanup(); + +private slots: + void creation_data(); + void creation(); + +private: + QmlEngine engine; +}; + +tst_qmlcomponent::tst_qmlcomponent() +{ +} + +tst_qmlcomponent::~tst_qmlcomponent() +{ +} + +void tst_qmlcomponent::init() +{ +} + +void tst_qmlcomponent::cleanup() +{ +} + +void tst_qmlcomponent::creation_data() +{ + QTest::addColumn("file"); + + QTest::newRow("Object") << "object.txt"; + QTest::newRow("MyQmlObject") << "myqmlobject.txt"; + QTest::newRow("MyQmlObject: basic binding") << "myqmlobject_binding.txt"; + QTest::newRow("Synthesized properties") << "synthesized_properties.txt"; + QTest::newRow("Synthesized properties.2") << "synthesized_properties.2.txt"; +} + +void tst_qmlcomponent::creation() +{ + QFETCH(QString, file); + + QmlComponent c(&engine, file); + QVERIFY(c.isReady()); + + QBENCHMARK { + QObject *obj = c.create(); + delete obj; + } +} + +QTEST_MAIN(tst_qmlcomponent) +#include "tst_qmlcomponent.moc" -- cgit v0.12 From f4c51725bf131baa34e30c435b285af16948744c Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 20 Jul 2009 12:57:20 +1000 Subject: Simplify binding optimization --- src/declarative/qml/qmlbasicscript.cpp | 424 +++++++++------------------------ src/declarative/qml/qmlbasicscript_p.h | 38 --- src/declarative/qml/qmlengine.cpp | 68 ------ src/declarative/qml/qmlengine_p.h | 9 +- 4 files changed, 116 insertions(+), 423 deletions(-) diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp index 3fe24ea..fb52b91 100644 --- a/src/declarative/qml/qmlbasicscript.cpp +++ b/src/declarative/qml/qmlbasicscript.cpp @@ -56,13 +56,10 @@ using namespace QmlJS; struct ScriptInstruction { enum { - Load, // fetch - Fetch, // fetch - LoadIdObject, // fetch FetchConstant, // constant - FetchD0Constant, // constant - FetchD1Constant, // constant + FetchContextConstant, // constant + FetchRootConstant, // constant Equals, // NA @@ -88,8 +85,6 @@ struct ScriptInstruction { }; }; -DEFINE_BOOL_CONFIG_OPTION(scriptWarnings, QML_SCRIPT_WARNINGS); - class QmlBasicScriptPrivate { public: @@ -120,60 +115,6 @@ public: } }; -QDebug operator<<(QDebug lhs, const QmlBasicScriptNodeCache &rhs) -{ - switch(rhs.type) { - case QmlBasicScriptNodeCache::Invalid: - lhs << "Invalid"; - break; - case QmlBasicScriptNodeCache::Core: - lhs << "Core" << rhs.object << rhs.core; - break; - case QmlBasicScriptNodeCache::Attached: - lhs << "Attached" << rhs.object << rhs.attached; - break; - case QmlBasicScriptNodeCache::SignalProperty: - lhs << "SignalProperty" << rhs.object << rhs.core; - break; - case QmlBasicScriptNodeCache::Variant: - lhs << "Variant" << rhs.context; - break; - } - - return lhs; -} - -void QmlBasicScriptNodeCache::clear() -{ - object = 0; - metaObject = 0; - type = Invalid; -} - -static QVariant toObjectOrVariant(const QVariant &v) -{ - switch(v.userType()) { - case QVariant::String: - case QVariant::UInt: - case QVariant::Int: - case QMetaType::Float: - case QVariant::Double: - case QVariant::Color: - case QVariant::Bool: - default: - { - if (v.type() == QVariant::UserType) { - QObject *o = QmlMetaType::toQObject(v); - if (o) - return qVariantFromValue(o); - else - return v; - } - return v; - } - } -} - static QVariant fetch_value(QObject *o, int idx, int type) { if (!o) @@ -259,26 +200,6 @@ static QVariant fetch_value(QObject *o, int idx, int type) }; } -QVariant QmlBasicScriptNodeCache::value(const char *) const -{ - //QFxPerfTimer pt; - switch(type) { - case Invalid: - break; - case Core: - return fetch_value(object, core, coreType); - break; - case Attached: - return qVariantFromValue(static_cast(attached)); - break; - case SignalProperty: - break; - case Variant: - return context->propertyValues[contextIndex]; - }; - return QVariant(); -} - struct QmlBasicScriptCompiler { QmlBasicScriptCompiler() @@ -298,7 +219,11 @@ struct QmlBasicScriptCompiler bool tryConstant(QmlJS::AST::Node *); bool parseConstant(QmlJS::AST::Node *); bool tryName(QmlJS::AST::Node *); - bool parseName(QmlJS::AST::Node *, QmlParser::Object ** = 0); + bool parseName(QmlJS::AST::Node *); + + bool buildName(QStringList &, QmlJS::AST::Node *); + const QMetaObject *fetch(int type, const QMetaObject *, int idx); + bool tryBinaryExpression(QmlJS::AST::Node *); bool compileBinaryExpression(QmlJS::AST::Node *); @@ -374,11 +299,7 @@ QByteArray QmlBasicScript::expression() const */ QmlBasicScript::~QmlBasicScript() { - if (flags & QmlBasicScriptPrivate::OwnData) - free(d); - if (rc) rc->release(); - d = 0; - rc = 0; + clear(); } /*! @@ -401,24 +322,14 @@ void QmlBasicScript::clear() */ void *QmlBasicScript::newScriptState() { - if (!d) { - return 0; - } else { - void *rv = ::malloc(d->stateSize * sizeof(QmlBasicScriptNodeCache)); - ::memset(rv, 0, d->stateSize * sizeof(QmlBasicScriptNodeCache)); - return rv; - } + return 0; } /*! Delete the \a data previously allocated by newScriptState(). */ -void QmlBasicScript::deleteScriptState(void *data) +void QmlBasicScript::deleteScriptState(void *) { - if (!data) return; - Q_ASSERT(d); - clearCache(data); - free(data); } /*! @@ -430,30 +341,21 @@ void QmlBasicScript::dump() return; qWarning() << d->instructionCount << "instructions:"; - const char *data = d->data(); for (int ii = 0; ii < d->instructionCount; ++ii) { const ScriptInstruction &instr = d->instructions()[ii]; switch(instr.type) { - case ScriptInstruction::Load: - qWarning().nospace() << "LOAD\t\t" << instr.fetch.idx << "\t\t" - << QByteArray(data + instr.fetch.idx); - break; - case ScriptInstruction::Fetch: - qWarning().nospace() << "FETCH\t\t" << instr.fetch.idx << "\t\t" - << QByteArray(data + instr.fetch.idx); - break; case ScriptInstruction::LoadIdObject: qWarning().nospace() << "LOAD_ID_OBJECT"; break; case ScriptInstruction::FetchConstant: qWarning().nospace() << "FETCH_CONSTANT"; break; - case ScriptInstruction::FetchD0Constant: - qWarning().nospace() << "FETCH_D0_CONSTANT"; + case ScriptInstruction::FetchContextConstant: + qWarning().nospace() << "FETCH_CONTEXT_CONSTANT"; break; - case ScriptInstruction::FetchD1Constant: - qWarning().nospace() << "FETCH_D1_CONSTANT"; + case ScriptInstruction::FetchRootConstant: + qWarning().nospace() << "FETCH_ROOT_CONSTANT"; break; case ScriptInstruction::Equals: qWarning().nospace() << "EQUALS"; @@ -564,101 +466,120 @@ bool QmlBasicScriptCompiler::tryName(QmlJS::AST::Node *node) node->kind == AST::Node::Kind_FieldMemberExpression; } -bool QmlBasicScriptCompiler::parseName(AST::Node *node, - QmlParser::Object **type) +bool QmlBasicScriptCompiler::buildName(QStringList &name, + QmlJS::AST::Node *node) { - bool load = false; - QmlParser::Object *loadedType = 0; - QString name; if (node->kind == AST::Node::Kind_IdentifierExpression) { - name = static_cast(node)->name->asString(); - load = true; + name << static_cast(node)->name->asString(); } else if (node->kind == AST::Node::Kind_FieldMemberExpression) { - AST::FieldMemberExpression *expr = static_cast(node); + AST::FieldMemberExpression *expr = + static_cast(node); - if (!parseName(expr->base, &loadedType)) + if (!buildName(name, expr->base)) return false; - name = expr->name->asString(); + name << expr->name->asString(); } else { return false; } + return true; +} + +const QMetaObject * +QmlBasicScriptCompiler::fetch(int type, const QMetaObject *mo, int idx) +{ ScriptInstruction instr; - if (load) { + (int &)instr.type = type; + instr.constant.idx = idx; + QMetaProperty prop = mo->property(idx); + if (prop.isConstant()) + instr.constant.notify = 0; + else + instr.constant.notify = prop.notifySignalIndex(); + instr.constant.type = prop.userType(); + bytecode << instr; + return QmlMetaType::metaObjectForType(prop.userType()); +} - if (ids.contains(name)) { - instr.type = ScriptInstruction::LoadIdObject; - instr.fetch.idx = ids.value(name)->idIndex; +bool QmlBasicScriptCompiler::parseName(AST::Node *node) +{ - if (type) - *type = ids.value(name); + QStringList nameParts; + if (!buildName(nameParts, node)) + return false; - } else { - int d0Idx = context->metaObject()->indexOfProperty(name.toUtf8().constData()); - int d1Idx = -1; - if (d0Idx == -1) - d1Idx = component->metaObject()->indexOfProperty(name.toUtf8().constData()); - if (d0Idx != -1) { - - instr.type = ScriptInstruction::FetchD0Constant; - instr.constant.idx = d0Idx; - QMetaProperty prop = context->metaObject()->property(d0Idx); - if (prop.isConstant()) - instr.constant.notify = 0; - else - instr.constant.notify = prop.notifySignalIndex(); - instr.constant.type = prop.userType(); - - } else if (d1Idx != -1) { - - instr.type = ScriptInstruction::FetchD1Constant; - instr.constant.idx = d1Idx; - QMetaProperty prop = component->metaObject()->property(d1Idx); - if (prop.isConstant()) - instr.constant.notify = 0; - else - instr.constant.notify = prop.notifySignalIndex(); - instr.constant.type = prop.userType(); - - } else { - - int nref = data.count(); - data.append(name.toUtf8()); - data.append('\0'); - instr.type = ScriptInstruction::Load; - instr.fetch.idx = nref; - ++stateSize; + QmlParser::Object *absType = 0; + const QMetaObject *metaType = 0; + + for (int ii = 0; ii < nameParts.count(); ++ii) { + const QString &name = nameParts.at(ii); + + // We don't handle signal properties + if (name.length() > 2 && name.startsWith(QLatin1String("on")) && + name.at(2).isUpper()) + return false; + + if (ii == 0) { + + if (0) { + // ### - Must test for an attached type name + } else if (ids.contains(name)) { + ScriptInstruction instr; + instr.type = ScriptInstruction::LoadIdObject; + instr.fetch.idx = ids.value(name)->idIndex; + bytecode << instr; + absType = ids.value(name); + } else if(name.at(0).isLower()) { + + QByteArray utf8Name = name.toUtf8(); + const char *cname = utf8Name.constData(); + + int d0Idx = context->metaObject()->indexOfProperty(cname); + int d1Idx = -1; + if (d0Idx == -1) + d1Idx = component->metaObject()->indexOfProperty(cname); + + if (d0Idx != -1) { + metaType = fetch(ScriptInstruction::FetchContextConstant, + context->metaObject(), d0Idx); + } else if(d1Idx != -1) { + metaType = fetch(ScriptInstruction::FetchRootConstant, + component->metaObject(), d1Idx); + } else { + return false; + } } - } + } else { - } else { + if (!name.at(0).isLower()) + return false; - int idx = -1; - if (loadedType) - idx = loadedType->metaObject()->indexOfProperty(name.toUtf8().constData()); - if (idx != -1) { - instr.type = ScriptInstruction::FetchConstant; - instr.constant.idx = idx; - QMetaProperty prop = loadedType->metaObject()->property(idx); - if (prop.isConstant()) - instr.constant.notify = 0; + const QMetaObject *mo = 0; + if (absType) + mo = absType->metaObject(); + else if(metaType) + mo = metaType; else - instr.constant.notify = prop.notifySignalIndex(); - instr.constant.type = prop.userType(); - } else { - int nref = data.count(); - data.append(name.toUtf8()); - data.append('\0'); - instr.type = ScriptInstruction::Fetch; - instr.fetch.idx = nref; - ++stateSize; - } + return false; + + QByteArray utf8Name = name.toUtf8(); + const char *cname = utf8Name.constData(); + int idx = mo->indexOfProperty(cname); + if (idx == -1) + return false; + + if (absType || mo->property(idx).isFinal()) { + absType = 0; metaType = 0; + metaType = fetch(ScriptInstruction::FetchConstant, mo, idx); + } else { + return false; + } + } } - bytecode.append(instr); return true; } @@ -711,44 +632,6 @@ bool QmlBasicScriptCompiler::compileBinaryExpression(AST::Node *node) } /*! - \internal -*/ -void QmlBasicScript::clearCache(void *voidCache) -{ - QmlBasicScriptNodeCache *dataCache = - reinterpret_cast(voidCache); - - for (int ii = 0; ii < d->stateSize; ++ii) { - if (!dataCache[ii].isCore() && !dataCache[ii].isVariant() && - dataCache[ii].object) { - QMetaObject::removeGuard(&dataCache[ii].object); - dataCache[ii].object = 0; - } - dataCache[ii].clear(); - } -} - -void QmlBasicScript::guard(QmlBasicScriptNodeCache &n) -{ - if (n.object) { - if (n.isVariant()) { - } else if (n.isCore()) { - n.metaObject = - n.object->metaObject(); - } else { - QMetaObject::addGuard(&n.object); - } - } -} - -bool QmlBasicScript::valid(QmlBasicScriptNodeCache &n, QObject *obj) -{ - return n.object == obj && - (!n.isCore() || obj->metaObject() == n.metaObject); -} - - -/*! \enum QmlBasicScript::CacheState \value NoChange The query has not change. Any previous monitoring is still valid. @@ -765,31 +648,17 @@ bool QmlBasicScript::valid(QmlBasicScriptNodeCache &n, QObject *obj) */ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *cached) { + Q_UNUSED(voidCache); if (!isValid()) return QVariant(); QmlContextPrivate *contextPrivate = context->d_func(); QmlEnginePrivate *enginePrivate = context->engine()->d_func(); - QmlBasicScriptNodeCache *dataCache = - reinterpret_cast(voidCache); - int dataCacheItem; - QStack stack; - bool resetting = false; - bool hasReset = false; - - const char *data = d->data(); - - if (dataCache[0].type == QmlBasicScriptNodeCache::Invalid) { - resetting = true; - hasReset = true; - } - CacheState state = NoChange; - dataCacheItem = 0; for (int idx = 0; idx < d->instructionCount; ++idx) { const ScriptInstruction &instr = d->instructions()[idx]; @@ -803,7 +672,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c } break; - case ScriptInstruction::FetchD0Constant: + case ScriptInstruction::FetchContextConstant: { QObject *obj = contextPrivate->defaultObjects.at(0); @@ -815,7 +684,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c } break; - case ScriptInstruction::FetchD1Constant: + case ScriptInstruction::FetchRootConstant: { QObject *obj = contextPrivate->defaultObjects.at(1); @@ -840,64 +709,14 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c } break; - case ScriptInstruction::Load: // either an object or a property - case ScriptInstruction::Fetch: // can only be a property - { - const char *id = data + instr.fetch.idx; - QmlBasicScriptNodeCache &n = dataCache[dataCacheItem]; - - if (instr.type == ScriptInstruction::Load) { - - if (n.type == QmlBasicScriptNodeCache::Invalid || state == Reset) { - context->engine()->d_func()->loadCache(n, QLatin1String(id), static_cast(context->d_ptr)); - if (state != Reset) - state = Incremental; - } - - if(!n.isValid()) - qWarning("ReferenceError: %s is not defined", id); - - } else { // instr.type == ScriptInstruction::Fetch - - QVariant o = stack.pop(); - QObject *obj = qvariant_cast(o); - if (!obj) { - if (n.type == QmlBasicScriptNodeCache::Invalid) { - if (scriptWarnings()) - qWarning() << "QmlBasicScript: Unable to convert" << o; - *cached = state; - return QVariant(); - } else { - clearCache(dataCache); - *cached = Reset; - CacheState dummy; - return run(context, voidCache, &dummy); - } - } else if (n.type == QmlBasicScriptNodeCache::Invalid || state == Reset) { - context->engine()->d_func()->fetchCache(n, QLatin1String(id), obj); - guard(n); - if (state != Reset) - state = Incremental; - } else if (!valid(n, obj)) { - clearCache(dataCache); - *cached = Reset; - CacheState dummy; - return run(context, voidCache, &dummy); - } - - } - - QVariant var = n.value(id); - stack.push(var); - ++dataCacheItem; - } - break; case ScriptInstruction::Int: stack.push(QVariant(instr.integer.value)); break; + case ScriptInstruction::Bool: stack.push(QVariant(instr.boolean.value)); break; + case ScriptInstruction::Equals: { QVariant rhs = stack.pop(); @@ -911,7 +730,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c } } - *cached = state; + *cached = Reset; if (stack.isEmpty()) return QVariant(); @@ -939,23 +758,4 @@ unsigned int QmlBasicScript::compileDataSize() const return 0; } -bool QmlBasicScript::isSingleLoad() const -{ - if (!d) - return false; - - return d->instructionCount == 1 && - d->instructions()[0].type == ScriptInstruction::Load; -} - -QByteArray QmlBasicScript::singleLoadTarget() const -{ - if (!isSingleLoad()) - return QByteArray(); - - // We know there is one instruction and it is a load - return QByteArray(d->data() + d->instructions()[0].fetch.idx); -} - - QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbasicscript_p.h b/src/declarative/qml/qmlbasicscript_p.h index 77d59eb..eacd1d8 100644 --- a/src/declarative/qml/qmlbasicscript_p.h +++ b/src/declarative/qml/qmlbasicscript_p.h @@ -100,50 +100,12 @@ public: enum CacheState { NoChange, Incremental, Reset }; QVariant run(QmlContext *, void *, CacheState *); - // Optimization opportunities - bool isSingleLoad() const; - QByteArray singleLoadTarget() const; - private: int flags; QmlBasicScriptPrivate *d; QmlRefCount *rc; - - void clearCache(void *); - void guard(QmlBasicScriptNodeCache &); - bool valid(QmlBasicScriptNodeCache &, QObject *); -}; - -class QmlContextPrivate; -class QDebug; -class QmlBasicScriptNodeCache -{ -public: - QObject *object; - const QMetaObject *metaObject; - enum { Invalid, - Core, - Attached, - SignalProperty, - Variant - } type; - union { - int core; - QObject *attached; - QmlContextPrivate *context; - }; - int coreType; - int contextIndex; - - bool isValid() const { return type != Invalid; } - bool isCore() const { return type == Core; } - bool isVariant() const { return type == Variant; } - void clear(); - QVariant value(const char *) const; }; -QDebug operator<<(QDebug, const QmlBasicScriptNodeCache &); - QT_END_NAMESPACE QT_END_HEADER diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index a6f5b28..429e3b0 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -254,74 +254,6 @@ QScriptValue QmlEnginePrivate::propertyObject(const QScriptString &propName, return QScriptValue(); } -//////////////////////////////////////////////////////////////////// - -bool QmlEnginePrivate::fetchCache(QmlBasicScriptNodeCache &cache, const QString &propName, QObject *obj) -{ - QmlMetaProperty prop(obj, propName); - - if (!prop.isValid()) - return false; - - if (prop.needsChangedNotifier()) - capturedProperties << CapturedProperty(prop); - - if (prop.type() & QmlMetaProperty::Attached) { - - cache.object = obj; - cache.type = QmlBasicScriptNodeCache::Attached; - cache.attached = prop.d->attachedObject(); - return true; - - } else if (prop.type() & QmlMetaProperty::Property) { - - cache.object = obj; - cache.type = QmlBasicScriptNodeCache::Core; - cache.core = prop.property().propertyIndex(); - cache.coreType = prop.propertyType(); - return true; - - } else if (prop.type() & QmlMetaProperty::SignalProperty) { - - cache.object = obj; - cache.type = QmlBasicScriptNodeCache::SignalProperty; - cache.core = prop.coreIndex(); - return true; - - } - - return false; -} - -bool QmlEnginePrivate::loadCache(QmlBasicScriptNodeCache &cache, const QString &propName, QmlContextPrivate *context) -{ - while(context) { - - QHash::ConstIterator iter = - context->propertyNames.find(propName); - if (iter != context->propertyNames.end()) { - cache.object = 0; - cache.type = QmlBasicScriptNodeCache::Variant; - cache.context = context; - cache.contextIndex = *iter; - capturedProperties << CapturedProperty(context->q_ptr, -1, *iter + context->notifyIndex); - return true; - } - - foreach(QObject *obj, context->defaultObjects) { - if (fetchCache(cache, propName, obj)) - return true; - } - - if (context->parent) - context = context->parent->d_func(); - else - context = 0; - } - return false; -} - - /*! \class QmlEngine \brief The QmlEngine class provides an environment for instantiating QML components. diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index f459dc5..4bef85a 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -93,11 +93,10 @@ public: void init(); - bool fetchCache(QmlBasicScriptNodeCache &cache, const QString &propName, QObject *); - bool loadCache(QmlBasicScriptNodeCache &cache, const QString &propName, QmlContextPrivate *context); - - QScriptClass::QueryFlags queryObject(const QString &name, uint *id, QObject *); - QScriptValue propertyObject(const QScriptString &propName, QObject *, uint id = 0); + QScriptClass::QueryFlags queryObject(const QString &name, uint *id, + QObject *); + QScriptValue propertyObject(const QScriptString &propName, QObject *, + uint id = 0); struct CapturedProperty { CapturedProperty(QObject *o, int c, int n) -- cgit v0.12 From 275d2a37c0c7179e7f34cc467192a8838705d7c2 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 20 Jul 2009 13:30:31 +1000 Subject: Rename QmlBindableValue to QmlBinding --- src/declarative/fx/qfxanchors.cpp | 1 - src/declarative/fx/qfxpathview.cpp | 1 - src/declarative/fx/qfxwebview.cpp | 1 - src/declarative/qml/qml.pri | 6 +- src/declarative/qml/qmlbindablevalue.cpp | 186 -------------------------- src/declarative/qml/qmlbindablevalue.h | 98 -------------- src/declarative/qml/qmlbindablevalue_p.h | 79 ----------- src/declarative/qml/qmlbinding.cpp | 186 ++++++++++++++++++++++++++ src/declarative/qml/qmlbinding.h | 98 ++++++++++++++ src/declarative/qml/qmlbinding_p.h | 79 +++++++++++ src/declarative/qml/qmlcomponent.cpp | 4 +- src/declarative/qml/qmlcomponent_p.h | 2 +- src/declarative/qml/qmlengine.cpp | 10 +- src/declarative/qml/qmlengine_p.h | 4 +- src/declarative/qml/qmlmetaproperty.cpp | 20 +-- src/declarative/qml/qmlmetaproperty.h | 6 +- src/declarative/qml/qmlparser.cpp | 1 - src/declarative/qml/qmlvme.cpp | 20 +-- src/declarative/util/qfxperf.cpp | 2 +- src/declarative/util/qfxview.cpp | 1 - src/declarative/util/qmlbind.cpp | 1 - src/declarative/util/qmllistmodel.cpp | 1 - src/declarative/util/qmlscript.cpp | 1 - src/declarative/util/qmlsetproperties.cpp | 4 +- src/declarative/util/qmlstate.cpp | 6 +- src/declarative/util/qmlstate.h | 14 +- src/declarative/util/qmlstate_p.h | 4 +- src/declarative/util/qmlstategroup.cpp | 2 +- src/declarative/util/qmlstateoperations.cpp | 2 +- src/declarative/util/qmltransition.cpp | 1 - src/declarative/util/qmltransitionmanager.cpp | 2 +- 31 files changed, 417 insertions(+), 426 deletions(-) delete mode 100644 src/declarative/qml/qmlbindablevalue.cpp delete mode 100644 src/declarative/qml/qmlbindablevalue.h delete mode 100644 src/declarative/qml/qmlbindablevalue_p.h create mode 100644 src/declarative/qml/qmlbinding.cpp create mode 100644 src/declarative/qml/qmlbinding.h create mode 100644 src/declarative/qml/qmlbinding_p.h diff --git a/src/declarative/fx/qfxanchors.cpp b/src/declarative/fx/qfxanchors.cpp index e1b450d..350cbc0 100644 --- a/src/declarative/fx/qfxanchors.cpp +++ b/src/declarative/fx/qfxanchors.cpp @@ -44,7 +44,6 @@ #include "qfxitem_p.h" #include #include -#include QT_BEGIN_NAMESPACE diff --git a/src/declarative/fx/qfxpathview.cpp b/src/declarative/fx/qfxpathview.cpp index f940f68..3c61050 100644 --- a/src/declarative/fx/qfxpathview.cpp +++ b/src/declarative/fx/qfxpathview.cpp @@ -42,7 +42,6 @@ #include #include #include -#include "qmlbindablevalue.h" #include "qmlstate.h" #include "qlistmodelinterface.h" #include "qmlopenmetaobject.h" diff --git a/src/declarative/fx/qfxwebview.cpp b/src/declarative/fx/qfxwebview.cpp index a3dca79e..42b8d2c 100644 --- a/src/declarative/fx/qfxwebview.cpp +++ b/src/declarative/fx/qfxwebview.cpp @@ -53,7 +53,6 @@ #include #include "qml.h" -#include "qmlbindablevalue.h" #include "qmlengine.h" #include "qmlstate.h" #include "qfxtransform.h" diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index eecf8cd..b3fa063 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -3,7 +3,7 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlvmemetaobject.cpp \ qml/qmlengine.cpp \ qml/qmlexpression.cpp \ - qml/qmlbindablevalue.cpp \ + qml/qmlbinding.cpp \ qml/qmlmetaproperty.cpp \ qml/qmlcomponent.cpp \ qml/qmlcontext.cpp \ @@ -33,8 +33,8 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ qml/qmlvmemetaobject_p.h \ qml/qml.h \ - qml/qmlbindablevalue.h \ - qml/qmlbindablevalue_p.h \ + qml/qmlbinding.h \ + qml/qmlbinding_p.h \ qml/qmlmetaproperty.h \ qml/qmlcomponent.h \ qml/qmlcomponent_p.h \ diff --git a/src/declarative/qml/qmlbindablevalue.cpp b/src/declarative/qml/qmlbindablevalue.cpp deleted file mode 100644 index 6dda5e3..0000000 --- a/src/declarative/qml/qmlbindablevalue.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include "qmlbindablevalue.h" -#include "qmlbindablevalue_p.h" -#include -#include -#include -#include -#include - -Q_DECLARE_METATYPE(QList); - -QT_BEGIN_NAMESPACE - -DEFINE_BOOL_CONFIG_OPTION(scriptWarnings, QML_SCRIPT_WARNINGS); - -QmlBindableValuePrivate::QmlBindableValuePrivate() -: inited(false), updating(false), enabled(true), mePtr(0) -{ -} - -QML_DEFINE_NOCREATE_TYPE(QmlBindableValue); -QmlBindableValue::QmlBindableValue(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ctxt, QObject *parent) -: QmlPropertyValueSource(*new QmlBindableValuePrivate, parent), QmlExpression(ctxt, data, rc, obj) -{ -} - -QmlBindableValue::QmlBindableValue(const QString &str, QObject *obj, QmlContext *ctxt, QObject *parent) -: QmlPropertyValueSource(*new QmlBindableValuePrivate, parent), QmlExpression(ctxt, str, obj) -{ -} - -QmlBindableValue::~QmlBindableValue() -{ - Q_D(QmlBindableValue); - if(d->mePtr) - *(d->mePtr) = 0; -} - -void QmlBindableValue::setTarget(const QmlMetaProperty &prop) -{ - Q_D(QmlBindableValue); - d->property = prop; - - update(); -} - -QmlMetaProperty QmlBindableValue::property() const -{ - Q_D(const QmlBindableValue); - return d->property; -} - -void QmlBindableValue::init() -{ - Q_D(QmlBindableValue); - - if (d->inited) - return; - d->inited = true; - update(); -} - -void QmlBindableValue::setExpression(const QString &expr) -{ - QmlExpression::setExpression(expr); - update(); -} - -void QmlBindableValue::forceUpdate() -{ - Q_D(QmlBindableValue); - if (!d->inited) - init(); - else - update(); -} - -void QmlBindableValue::update() -{ - Q_D(QmlBindableValue); - -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxPerfTimer bu; -#endif - if (!d->inited || !d->enabled) - return; - - if (!d->updating) { - d->updating = true; - - if (d->property.propertyCategory() == QmlMetaProperty::Bindable) { - - int idx = d->property.coreIndex(); - Q_ASSERT(idx != -1); - - void *a[1]; - QmlBindableValue *t = this; - a[0] = (void *)&t; - QMetaObject::metacall(d->property.object(), - QMetaObject::WriteProperty, - idx, a); - - } else { - - QVariant value = this->value(); - if ((uint)d->property.propertyType() >= QVariant::UserType && - value.type() == QVariant::String) { - QmlMetaType::StringConverter con = QmlMetaType::customStringConverter(d->property.propertyType()); - if (con) - value = con(value.toString()); - } - - if (d->property.propertyType() == QVariant::Url && - (value.type() == QVariant::String || value.type() == QVariant::ByteArray) && !value.isNull()) - value.setValue(context()->resolvedUrl(QUrl(value.toString()))); - - d->property.write(value); - } - - d->updating = false; - } else { - qmlInfo(d->property.object()) << "Binding loop detected for property" << d->property.name(); - } -} - -void QmlBindableValue::valueChanged() -{ - update(); -} - -void QmlBindableValue::setEnabled(bool e) -{ - Q_D(QmlBindableValue); - d->enabled = e; - setTrackChange(e); -} - -bool QmlBindableValue::enabled() const -{ - Q_D(const QmlBindableValue); - - return d->enabled; -} - -QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbindablevalue.h b/src/declarative/qml/qmlbindablevalue.h deleted file mode 100644 index 12da9f6..0000000 --- a/src/declarative/qml/qmlbindablevalue.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QMLBINDABLEVALUE_H -#define QMLBINDABLEVALUE_H - -#include -#include -#include -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QmlExpression; -class QmlContext; -class QmlBindableValuePrivate; -class Q_DECLARATIVE_EXPORT QmlBindableValue : public QmlPropertyValueSource, - public QmlExpression -{ -Q_OBJECT -public: - QmlBindableValue(const QString &, QObject *, QmlContext *, QObject *parent=0); - QmlBindableValue(void *, QmlRefCount *, QObject *, QmlContext *, QObject *parent); - ~QmlBindableValue(); - - virtual void setTarget(const QmlMetaProperty &); - QmlMetaProperty property() const; - - Q_CLASSINFO("DefaultProperty", "expression") - Q_PROPERTY(QString expression READ expression WRITE setExpression) - virtual void setExpression(const QString &); - - void init(); - void forceUpdate(); - - void setEnabled(bool); - bool enabled() const; - -public Q_SLOTS: - void update(); - -protected: - virtual void valueChanged(); - -private: - Q_DECLARE_PRIVATE(QmlBindableValue) -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QmlBindableValue) - -QT_END_HEADER - -#endif // QMLBINDABLEVALUE_H diff --git a/src/declarative/qml/qmlbindablevalue_p.h b/src/declarative/qml/qmlbindablevalue_p.h deleted file mode 100644 index a37b2c0..0000000 --- a/src/declarative/qml/qmlbindablevalue_p.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QMLBINDABLEVALUE_P_H -#define QMLBINDABLEVALUE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QmlBindableValuePrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QmlBindableValue) -public: - QmlBindableValuePrivate(); - - bool inited:1; - bool updating:1; - bool enabled:1; - - QmlMetaProperty property; - - QmlBindableValue **mePtr; -}; - -QT_END_NAMESPACE - -#endif // QMLBINDABLEVALUE_P_H diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp new file mode 100644 index 0000000..6a8a027 --- /dev/null +++ b/src/declarative/qml/qmlbinding.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qmlbinding.h" +#include "qmlbinding_p.h" +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QList); + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(scriptWarnings, QML_SCRIPT_WARNINGS); + +QmlBindingPrivate::QmlBindingPrivate() +: inited(false), updating(false), enabled(true), mePtr(0) +{ +} + +QML_DEFINE_NOCREATE_TYPE(QmlBinding); +QmlBinding::QmlBinding(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ctxt, QObject *parent) +: QmlPropertyValueSource(*new QmlBindingPrivate, parent), QmlExpression(ctxt, data, rc, obj) +{ +} + +QmlBinding::QmlBinding(const QString &str, QObject *obj, QmlContext *ctxt, QObject *parent) +: QmlPropertyValueSource(*new QmlBindingPrivate, parent), QmlExpression(ctxt, str, obj) +{ +} + +QmlBinding::~QmlBinding() +{ + Q_D(QmlBinding); + if(d->mePtr) + *(d->mePtr) = 0; +} + +void QmlBinding::setTarget(const QmlMetaProperty &prop) +{ + Q_D(QmlBinding); + d->property = prop; + + update(); +} + +QmlMetaProperty QmlBinding::property() const +{ + Q_D(const QmlBinding); + return d->property; +} + +void QmlBinding::init() +{ + Q_D(QmlBinding); + + if (d->inited) + return; + d->inited = true; + update(); +} + +void QmlBinding::setExpression(const QString &expr) +{ + QmlExpression::setExpression(expr); + update(); +} + +void QmlBinding::forceUpdate() +{ + Q_D(QmlBinding); + if (!d->inited) + init(); + else + update(); +} + +void QmlBinding::update() +{ + Q_D(QmlBinding); + +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer bu; +#endif + if (!d->inited || !d->enabled) + return; + + if (!d->updating) { + d->updating = true; + + if (d->property.propertyCategory() == QmlMetaProperty::Bindable) { + + int idx = d->property.coreIndex(); + Q_ASSERT(idx != -1); + + void *a[1]; + QmlBinding *t = this; + a[0] = (void *)&t; + QMetaObject::metacall(d->property.object(), + QMetaObject::WriteProperty, + idx, a); + + } else { + + QVariant value = this->value(); + if ((uint)d->property.propertyType() >= QVariant::UserType && + value.type() == QVariant::String) { + QmlMetaType::StringConverter con = QmlMetaType::customStringConverter(d->property.propertyType()); + if (con) + value = con(value.toString()); + } + + if (d->property.propertyType() == QVariant::Url && + (value.type() == QVariant::String || value.type() == QVariant::ByteArray) && !value.isNull()) + value.setValue(context()->resolvedUrl(QUrl(value.toString()))); + + d->property.write(value); + } + + d->updating = false; + } else { + qmlInfo(d->property.object()) << "Binding loop detected for property" << d->property.name(); + } +} + +void QmlBinding::valueChanged() +{ + update(); +} + +void QmlBinding::setEnabled(bool e) +{ + Q_D(QmlBinding); + d->enabled = e; + setTrackChange(e); +} + +bool QmlBinding::enabled() const +{ + Q_D(const QmlBinding); + + return d->enabled; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h new file mode 100644 index 0000000..e208277 --- /dev/null +++ b/src/declarative/qml/qmlbinding.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBINDING_H +#define QMLBINDING_H + +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlExpression; +class QmlContext; +class QmlBindingPrivate; +class Q_DECLARATIVE_EXPORT QmlBinding : public QmlPropertyValueSource, + public QmlExpression +{ +Q_OBJECT +public: + QmlBinding(const QString &, QObject *, QmlContext *, QObject *parent=0); + QmlBinding(void *, QmlRefCount *, QObject *, QmlContext *, QObject *parent); + ~QmlBinding(); + + virtual void setTarget(const QmlMetaProperty &); + QmlMetaProperty property() const; + + Q_CLASSINFO("DefaultProperty", "expression") + Q_PROPERTY(QString expression READ expression WRITE setExpression) + virtual void setExpression(const QString &); + + void init(); + void forceUpdate(); + + void setEnabled(bool); + bool enabled() const; + +public Q_SLOTS: + void update(); + +protected: + virtual void valueChanged(); + +private: + Q_DECLARE_PRIVATE(QmlBinding) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QmlBinding) + +QT_END_HEADER + +#endif // QMLBINDING_H diff --git a/src/declarative/qml/qmlbinding_p.h b/src/declarative/qml/qmlbinding_p.h new file mode 100644 index 0000000..470a62a --- /dev/null +++ b/src/declarative/qml/qmlbinding_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBINDING_P_H +#define QMLBINDING_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlBindingPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlBinding) +public: + QmlBindingPrivate(); + + bool inited:1; + bool updating:1; + bool enabled:1; + + QmlMetaProperty property; + + QmlBinding **mePtr; +}; + +QT_END_NAMESPACE + +#endif // QMLBINDING_P_H diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index c7d45fd..4e39d7f 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -51,7 +51,7 @@ #include #include #include -#include +#include "qmlbinding.h" #include #include @@ -578,7 +578,7 @@ void QmlComponent::completeCreate() QFxPerfTimer bi; #endif for (int ii = 0; ii < d->bindValues.count(); ++ii) { - QmlEnginePrivate::SimpleList bv = + QmlEnginePrivate::SimpleList bv = d->bindValues.at(ii); for (int jj = 0; jj < bv.count; ++jj) { if(bv.at(jj)) diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h index 25af342..a7a3230 100644 --- a/src/declarative/qml/qmlcomponent_p.h +++ b/src/declarative/qml/qmlcomponent_p.h @@ -88,7 +88,7 @@ public: int count; QmlCompiledData *cc; - QList > bindValues; + QList > bindValues; QList > parserStatus; bool completePending; diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 429e3b0..8b21290 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -72,7 +72,7 @@ #include #include #include "private/qmlmetaproperty_p.h" -#include +#include #include #include @@ -118,13 +118,13 @@ QmlEnginePrivate::~QmlEnginePrivate() clear(parserStatus[ii]); } -void QmlEnginePrivate::clear(SimpleList &bvs) +void QmlEnginePrivate::clear(SimpleList &bvs) { for (int ii = 0; ii < bvs.count; ++ii) { - QmlBindableValue *bv = bvs.at(ii); + QmlBinding *bv = bvs.at(ii); if(bv) { - QmlBindableValuePrivate *p = - static_cast(QObjectPrivate::get(bv)); + QmlBindingPrivate *p = + static_cast(QObjectPrivate::get(bv)); p->mePtr = 0; } } diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 4bef85a..47d2397 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -151,10 +151,10 @@ public: } }; - static void clear(SimpleList &); + static void clear(SimpleList &); static void clear(SimpleList &); - QList > bindValues; + QList > bindValues; QList > parserStatus; QmlComponent *rootComponent; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index dea3467..daa4242 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -44,7 +44,7 @@ #include #include #include -#include +#include "qmlbinding.h" #include #include "qmlboundsignal_p.h" #include @@ -260,7 +260,7 @@ QmlMetaProperty::QmlMetaProperty(const QmlMetaProperty &other) \value Unknown The category is unknown. This will never be returned from propertyCategory() \value InvalidProperty The property is invalid. - \value Bindable The property is a QmlBindableValue. + \value Bindable The property is a QmlBinding. \value List The property is a QList pointer \value QmlList The property is a QmlList pointer \value Object The property is a QObject derived type pointer @@ -294,7 +294,7 @@ QmlMetaPropertyPrivate::propertyCategory() const int type = propertyType(); if (type == QmlMetaProperty::Invalid) category = QmlMetaProperty::InvalidProperty; - else if (type == qMetaTypeId()) + else if (type == qMetaTypeId()) category = QmlMetaProperty::Bindable; else if (QmlMetaType::isList(type)) category = QmlMetaProperty::List; @@ -323,7 +323,7 @@ QmlMetaProperty::propertyCategory(const QMetaProperty &prop) else type = prop.type(); - if (type == qMetaTypeId()) + if (type == qMetaTypeId()) return Bindable; else if (QmlMetaType::isList(type)) return List; @@ -510,7 +510,7 @@ QMetaProperty QmlMetaProperty::property() const Returns the binding associated with this property, or 0 if no binding exists. */ -QmlBindableValue *QmlMetaProperty::binding() const +QmlBinding *QmlMetaProperty::binding() const { if (!isProperty() || type() & Attached) return 0; @@ -519,8 +519,8 @@ QmlBindableValue *QmlMetaProperty::binding() const for (QObjectList::ConstIterator iter = children.begin(); iter != children.end(); ++iter) { QObject *child = *iter; - if (child->metaObject() == &QmlBindableValue::staticMetaObject) { - QmlBindableValue *v = static_cast(child); + if (child->metaObject() == &QmlBinding::staticMetaObject) { + QmlBinding *v = static_cast(child); if (v->property() == *this) return v; } @@ -535,7 +535,7 @@ QmlBindableValue *QmlMetaProperty::binding() const \a binding will be enabled, and the returned binding (if any) will be disabled. */ -QmlBindableValue *QmlMetaProperty::setBinding(QmlBindableValue *binding) const +QmlBinding *QmlMetaProperty::setBinding(QmlBinding *binding) const { if (!isProperty() || type() & Attached) return 0; @@ -544,8 +544,8 @@ QmlBindableValue *QmlMetaProperty::setBinding(QmlBindableValue *binding) const for (QObjectList::ConstIterator iter = children.begin(); iter != children.end(); ++iter) { QObject *child = *iter; - if (child->metaObject() == &QmlBindableValue::staticMetaObject) { - QmlBindableValue *v = static_cast(child); + if (child->metaObject() == &QmlBinding::staticMetaObject) { + QmlBinding *v = static_cast(child); if (v->property() == *this && v->enabled()) { v->setEnabled(false); diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h index 688c4fd..fdcf9be 100644 --- a/src/declarative/qml/qmlmetaproperty.h +++ b/src/declarative/qml/qmlmetaproperty.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QObject; -class QmlBindableValue; +class QmlBinding; class QStringList; class QVariant; struct QMetaObject; @@ -121,8 +121,8 @@ public: QMetaProperty property() const; - QmlBindableValue *binding() const; - QmlBindableValue *setBinding(QmlBindableValue *) const; + QmlBinding *binding() const; + QmlBinding *setBinding(QmlBinding *) const; static QmlMetaProperty createProperty(QObject *, const QString &); diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index 8eb58c8..9eed3f1 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include "private/qmlcomponent_p.h" diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index f468cd0..58b8689 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -57,13 +57,13 @@ #include #include #include -#include +#include #include #include #include "private/qmlvmemetaobject_p.h" #include #include -#include +#include QT_BEGIN_NAMESPACE @@ -137,7 +137,7 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledData const QList &floatData = comp->floatData; - QmlEnginePrivate::SimpleList bindValues; + QmlEnginePrivate::SimpleList bindValues; QmlEnginePrivate::SimpleList parserStatus; QStack qliststack; @@ -153,7 +153,7 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledData case QmlInstruction::Init: { if (instr.init.bindingsSize) - bindValues = QmlEnginePrivate::SimpleList(instr.init.bindingsSize); + bindValues = QmlEnginePrivate::SimpleList(instr.init.bindingsSize); if (instr.init.parserStatusSize) parserStatus = QmlEnginePrivate::SimpleList(instr.init.parserStatusSize); } @@ -540,10 +540,10 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledData QmlMetaProperty mp(target, instr.assignBinding.property, (QmlMetaProperty::PropertyCategory)instr.assignBinding.category); - QmlBindableValue *bind = new QmlBindableValue((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, 0); + QmlBinding *bind = new QmlBinding((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, 0); bindValues.append(bind); - QmlBindableValuePrivate *p = - static_cast(QObjectPrivate::get(bind)); + QmlBindingPrivate *p = + static_cast(QObjectPrivate::get(bind)); p->mePtr = &bindValues.values[bindValues.count - 1]; QFx_setParent_noEvent(bind, target); @@ -560,10 +560,10 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledData QmlMetaProperty mp(target, instr.assignBinding.property, (QmlMetaProperty::PropertyCategory)instr.assignBinding.category); - QmlBindableValue *bind = new QmlBindableValue(primitives.at(instr.assignBinding.value), context, ctxt); + QmlBinding *bind = new QmlBinding(primitives.at(instr.assignBinding.value), context, ctxt); bindValues.append(bind); - QmlBindableValuePrivate *p = - static_cast(QObjectPrivate::get(bind)); + QmlBindingPrivate *p = + static_cast(QObjectPrivate::get(bind)); p->mePtr = &bindValues.values[bindValues.count - 1]; QFx_setParent_noEvent(bind, target); diff --git a/src/declarative/util/qfxperf.cpp b/src/declarative/util/qfxperf.cpp index db56b37..f768827 100644 --- a/src/declarative/util/qfxperf.cpp +++ b/src/declarative/util/qfxperf.cpp @@ -51,7 +51,7 @@ Q_DEFINE_PERFORMANCE_LOG(QFxPerf, "QFx") { Q_DEFINE_PERFORMANCE_METRIC(BindValue, "BindValue execution") Q_DEFINE_PERFORMANCE_METRIC(BindValueSSE, "BindValue execution SSE") Q_DEFINE_PERFORMANCE_METRIC(BindValueQt, "BindValue execution QtScript") - Q_DEFINE_PERFORMANCE_METRIC(BindableValueUpdate, "QmlBindableValue::update") + Q_DEFINE_PERFORMANCE_METRIC(BindableValueUpdate, "QmlBinding::update") Q_DEFINE_PERFORMANCE_METRIC(PixmapLoad, "Pixmap loading") Q_DEFINE_PERFORMANCE_METRIC(FontDatabase, "Font database creation") Q_DEFINE_PERFORMANCE_METRIC(QFxPathViewPathCache, "FX Items: QFxPathView: Path cache") diff --git a/src/declarative/util/qfxview.cpp b/src/declarative/util/qfxview.cpp index d83de28..96d9e8e 100644 --- a/src/declarative/util/qfxview.cpp +++ b/src/declarative/util/qfxview.cpp @@ -51,7 +51,6 @@ #include "qboxlayout.h" #include "qbasictimer.h" -#include "qmlbindablevalue.h" #include "qml.h" #include "qfxitem.h" #include "private/qperformancelog_p.h" diff --git a/src/declarative/util/qmlbind.cpp b/src/declarative/util/qmlbind.cpp index bb342bc..7493b12 100644 --- a/src/declarative/util/qmlbind.cpp +++ b/src/declarative/util/qmlbind.cpp @@ -39,7 +39,6 @@ ** ****************************************************************************/ -#include #include #include #include diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp index 61d32f4..a969100 100644 --- a/src/declarative/util/qmllistmodel.cpp +++ b/src/declarative/util/qmllistmodel.cpp @@ -46,7 +46,6 @@ #include #include "qmlopenmetaobject.h" #include -#include #include "qmllistmodel.h" Q_DECLARE_METATYPE(QListModelInterface *) diff --git a/src/declarative/util/qmlscript.cpp b/src/declarative/util/qmlscript.cpp index 8d03804..7199341 100644 --- a/src/declarative/util/qmlscript.cpp +++ b/src/declarative/util/qmlscript.cpp @@ -39,7 +39,6 @@ ** ****************************************************************************/ -#include #include #include #include diff --git a/src/declarative/util/qmlsetproperties.cpp b/src/declarative/util/qmlsetproperties.cpp index 6464e33..ffd1e6a 100644 --- a/src/declarative/util/qmlsetproperties.cpp +++ b/src/declarative/util/qmlsetproperties.cpp @@ -47,7 +47,7 @@ #include #include #include -#include +#include QT_BEGIN_NAMESPACE @@ -334,7 +334,7 @@ QmlSetProperties::ActionList QmlSetProperties::actions() if (d->isExplicit) { a.toValue = d->expressions.at(ii).second->value(); } else { - a.toBinding = new QmlBindableValue(d->expressions.at(ii).second->expression(), object(), qmlContext(this)); + a.toBinding = new QmlBinding(d->expressions.at(ii).second->expression(), object(), qmlContext(this)); a.toBinding->setTarget(prop); } diff --git a/src/declarative/util/qmlstate.cpp b/src/declarative/util/qmlstate.cpp index e3cff38..73ea9c2 100644 --- a/src/declarative/util/qmlstate.cpp +++ b/src/declarative/util/qmlstate.cpp @@ -42,7 +42,7 @@ #include "qmltransition.h" #include "qmlstategroup.h" #include "qmlstate_p.h" -#include "qmlbindablevalue.h" +#include "qmlbinding.h" #include "qmlstateoperations.h" #include "qmlanimation.h" #include "qmlanimation_p.h" @@ -175,13 +175,13 @@ bool QmlState::isWhenKnown() const This should be set to an expression that evaluates to true when you want the state to be applied. */ -QmlBindableValue *QmlState::when() const +QmlBinding *QmlState::when() const { Q_D(const QmlState); return d->when; } -void QmlState::setWhen(QmlBindableValue *when) +void QmlState::setWhen(QmlBinding *when) { Q_D(QmlState); d->when = when; diff --git a/src/declarative/util/qmlstate.h b/src/declarative/util/qmlstate.h index 7532430..90649a1 100644 --- a/src/declarative/util/qmlstate.h +++ b/src/declarative/util/qmlstate.h @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class ActionEvent; -class QmlBindableValue; +class QmlBinding; class Action { public: @@ -68,8 +68,8 @@ public: QVariant fromValue; QVariant toValue; - QmlBindableValue *fromBinding; - QmlBindableValue *toBinding; + QmlBinding *fromBinding; + QmlBinding *toBinding; ActionEvent *event; QObject *specifiedObject; @@ -111,7 +111,7 @@ class Q_DECLARATIVE_EXPORT QmlState : public QObject Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName) - Q_PROPERTY(QmlBindableValue *when READ when WRITE setWhen) + Q_PROPERTY(QmlBinding *when READ when WRITE setWhen) Q_PROPERTY(QString extends READ extends WRITE setExtends) Q_PROPERTY(QmlList* operations READ operations) Q_CLASSINFO("DefaultProperty", "operations") @@ -123,11 +123,11 @@ public: QString name() const; void setName(const QString &); - /*'when' is a QmlBindableValue to limit state changes oscillation + /*'when' is a QmlBinding to limit state changes oscillation due to the unpredictable order of evaluation of bound expressions*/ bool isWhenKnown() const; - QmlBindableValue *when() const; - void setWhen(QmlBindableValue *); + QmlBinding *when() const; + void setWhen(QmlBinding *); QString extends() const; void setExtends(const QString &); diff --git a/src/declarative/util/qmlstate_p.h b/src/declarative/util/qmlstate_p.h index 414ec08..73e2377 100644 --- a/src/declarative/util/qmlstate_p.h +++ b/src/declarative/util/qmlstate_p.h @@ -80,7 +80,7 @@ public: QmlMetaProperty property; QVariant value; - QmlBindableValue *binding; + QmlBinding *binding; QObject *specifiedObject; QString specifiedProperty; }; @@ -96,7 +96,7 @@ public: typedef QList SimpleActionList; QString name; - QmlBindableValue *when; + QmlBinding *when; QmlConcreteList operations; QmlTransitionManager transitionManager; diff --git a/src/declarative/util/qmlstategroup.cpp b/src/declarative/util/qmlstategroup.cpp index 2b1cf7d..946569c 100644 --- a/src/declarative/util/qmlstategroup.cpp +++ b/src/declarative/util/qmlstategroup.cpp @@ -40,9 +40,9 @@ ****************************************************************************/ #include "private/qobject_p.h" -#include "qmlbindablevalue.h" #include "qmlstategroup.h" #include "qmltransition.h" +#include #include QT_BEGIN_NAMESPACE diff --git a/src/declarative/util/qmlstateoperations.cpp b/src/declarative/util/qmlstateoperations.cpp index 5bb2cb6..8d6abe6 100644 --- a/src/declarative/util/qmlstateoperations.cpp +++ b/src/declarative/util/qmlstateoperations.cpp @@ -42,7 +42,7 @@ #include #include #include -#include "qmlbindablevalue.h" +#include #include "qmlstateoperations.h" #include #include diff --git a/src/declarative/util/qmltransition.cpp b/src/declarative/util/qmltransition.cpp index d793c7d..dffa6b5 100644 --- a/src/declarative/util/qmltransition.cpp +++ b/src/declarative/util/qmltransition.cpp @@ -42,7 +42,6 @@ #include "qmlstate.h" #include "qmlstategroup.h" #include "qmlstate_p.h" -#include "qmlbindablevalue.h" #include "qmlstateoperations.h" #include "qmlanimation.h" #include "qmlanimation_p.h" diff --git a/src/declarative/util/qmltransitionmanager.cpp b/src/declarative/util/qmltransitionmanager.cpp index ba4e160..6f1a8e3 100644 --- a/src/declarative/util/qmltransitionmanager.cpp +++ b/src/declarative/util/qmltransitionmanager.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include +#include #include #include -- cgit v0.12 From 86529642cfdc5cc5a94b735042d0807e3b57e9e1 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 20 Jul 2009 16:06:19 +1000 Subject: Rework expression stuff to use a more efficient notify handler --- src/corelib/kernel/qguard.cpp | 1 + src/declarative/qml/qmlbasicscript.cpp | 12 +- src/declarative/qml/qmlbasicscript_p.h | 3 +- src/declarative/qml/qmlbinding.cpp | 6 +- src/declarative/qml/qmlbinding.h | 3 +- src/declarative/qml/qmlbinding_p.h | 4 +- src/declarative/qml/qmlboundsignal.cpp | 6 +- src/declarative/qml/qmlboundsignal_p.h | 2 +- src/declarative/qml/qmlcontext.cpp | 2 +- src/declarative/qml/qmlexpression.cpp | 412 ++++++++++++++------------------- src/declarative/qml/qmlexpression.h | 39 ++-- src/declarative/qml/qmlexpression_p.h | 81 +++---- src/declarative/qml/qpodvector_p.h | 2 +- tools/qmlviewer/qmlviewer.cpp | 1 - 14 files changed, 246 insertions(+), 328 deletions(-) diff --git a/src/corelib/kernel/qguard.cpp b/src/corelib/kernel/qguard.cpp index c61be00..ae4f3a5 100644 --- a/src/corelib/kernel/qguard.cpp +++ b/src/corelib/kernel/qguard.cpp @@ -19,6 +19,7 @@ void q_guard_addGuard(QGuard *g) void q_guard_removeGuard(QGuard *g) { + if (g->next) g->next->prev = g->prev; *g->prev = g->next; g->next = 0; g->prev = 0; diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp index fb52b91..073642f 100644 --- a/src/declarative/qml/qmlbasicscript.cpp +++ b/src/declarative/qml/qmlbasicscript.cpp @@ -265,7 +265,7 @@ QmlBasicScript::QmlBasicScript() } /*! - Create a new QmlBasicScript instance from saved \a data. + Load the QmlBasicScript instance with saved \a data. \a data \b must be data previously acquired from calling compileData() on a previously created QmlBasicScript instance. Any other data will almost @@ -277,9 +277,12 @@ QmlBasicScript::QmlBasicScript() If \a owner is set, it is referenced on creation and dereferenced on destruction of this instance. */ -QmlBasicScript::QmlBasicScript(const char *data, QmlRefCount *owner) -: flags(0), d((QmlBasicScriptPrivate *)data), rc(owner) + +void QmlBasicScript::load(const char *data, QmlRefCount *owner) { + clear(); + d = (QmlBasicScriptPrivate *)data; + rc = owner; if (rc) rc->addref(); } @@ -504,7 +507,6 @@ QmlBasicScriptCompiler::fetch(int type, const QMetaObject *mo, int idx) bool QmlBasicScriptCompiler::parseName(AST::Node *node) { - QStringList nameParts; if (!buildName(nameParts, node)) return false; @@ -550,6 +552,8 @@ bool QmlBasicScriptCompiler::parseName(AST::Node *node) return false; } + } else { + return false; } } else { diff --git a/src/declarative/qml/qmlbasicscript_p.h b/src/declarative/qml/qmlbasicscript_p.h index eacd1d8..539227f 100644 --- a/src/declarative/qml/qmlbasicscript_p.h +++ b/src/declarative/qml/qmlbasicscript_p.h @@ -70,9 +70,10 @@ class QmlBasicScript { public: QmlBasicScript(); - QmlBasicScript(const char *, QmlRefCount * = 0); ~QmlBasicScript(); + void load(const char *, QmlRefCount * = 0); + // Always 4-byte aligned const char *compileData() const; unsigned int compileDataSize() const; diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp index 6a8a027..e2f4682 100644 --- a/src/declarative/qml/qmlbinding.cpp +++ b/src/declarative/qml/qmlbinding.cpp @@ -61,13 +61,15 @@ QmlBindingPrivate::QmlBindingPrivate() QML_DEFINE_NOCREATE_TYPE(QmlBinding); QmlBinding::QmlBinding(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ctxt, QObject *parent) -: QmlPropertyValueSource(*new QmlBindingPrivate, parent), QmlExpression(ctxt, data, rc, obj) +: QmlExpression(ctxt, data, rc, obj, *new QmlBindingPrivate) { + setParent(parent); } QmlBinding::QmlBinding(const QString &str, QObject *obj, QmlContext *ctxt, QObject *parent) -: QmlPropertyValueSource(*new QmlBindingPrivate, parent), QmlExpression(ctxt, str, obj) +: QmlExpression(ctxt, str, obj, *new QmlBindingPrivate) { + setParent(parent); } QmlBinding::~QmlBinding() diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h index e208277..10d81b8 100644 --- a/src/declarative/qml/qmlbinding.h +++ b/src/declarative/qml/qmlbinding.h @@ -57,8 +57,7 @@ QT_MODULE(Declarative) class QmlExpression; class QmlContext; class QmlBindingPrivate; -class Q_DECLARATIVE_EXPORT QmlBinding : public QmlPropertyValueSource, - public QmlExpression +class Q_DECLARATIVE_EXPORT QmlBinding : public QmlExpression { Q_OBJECT public: diff --git a/src/declarative/qml/qmlbinding_p.h b/src/declarative/qml/qmlbinding_p.h index 470a62a..ec1a04a 100644 --- a/src/declarative/qml/qmlbinding_p.h +++ b/src/declarative/qml/qmlbinding_p.h @@ -53,13 +53,13 @@ // We mean it. // -#include #include #include +#include "qmlexpression_p.h" QT_BEGIN_NAMESPACE -class QmlBindingPrivate : public QObjectPrivate +class QmlBindingPrivate : public QmlExpressionPrivate { Q_DECLARE_PUBLIC(QmlBinding) public: diff --git a/src/declarative/qml/qmlboundsignal.cpp b/src/declarative/qml/qmlboundsignal.cpp index 9779e46..9af4003 100644 --- a/src/declarative/qml/qmlboundsignal.cpp +++ b/src/declarative/qml/qmlboundsignal.cpp @@ -53,14 +53,14 @@ QT_BEGIN_NAMESPACE int QmlBoundSignal::evaluateIdx = -1; QmlBoundSignal::QmlBoundSignal(QmlContext *ctxt, const QString &val, QObject *me, int idx, QObject *parent) -: QmlExpressionObject(ctxt, val, me, false), _idx(idx) +: QmlExpression(ctxt, val, me), _idx(idx) { - // A cached evaluation of the QmlExpressionObject::value() slot index. + // A cached evaluation of the QmlExpression::value() slot index. // // This is thread safe. Although it may be updated by two threads, they // will both set it to the same value - so the worst thing that can happen // is that they both do the work to figure it out. Boo hoo. - if (evaluateIdx == -1) evaluateIdx = QmlExpressionObject::staticMetaObject.indexOfMethod("value()"); + if (evaluateIdx == -1) evaluateIdx = QmlExpression::staticMetaObject.indexOfMethod("value()"); setTrackChange(false); QFx_setParent_noEvent(this, parent); diff --git a/src/declarative/qml/qmlboundsignal_p.h b/src/declarative/qml/qmlboundsignal_p.h index 39c0c46..de8f91d 100644 --- a/src/declarative/qml/qmlboundsignal_p.h +++ b/src/declarative/qml/qmlboundsignal_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE -class QmlBoundSignal : public QmlExpressionObject +class QmlBoundSignal : public QmlExpression { Q_OBJECT public: diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 5bc70bc..bc2e6bf 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -292,7 +292,7 @@ QmlContext::~QmlContext() d->childExpressions.begin(); iter != d->childExpressions.end(); ++iter) { - (*iter)->d->ctxt = 0; + (*iter)->d_func()->ctxt = 0; } for (int ii = 0; ii < d->contextObjects.count(); ++ii) { diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 2aa1a8a..b4f57eb 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -50,53 +50,72 @@ Q_DECLARE_METATYPE(QList); QT_BEGIN_NAMESPACE -DEFINE_BOOL_CONFIG_OPTION(qmlDebugger, QML_DEBUGGER) - -QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) -: q(b), ctxt(0), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) +QmlExpressionPrivate::QmlExpressionPrivate() +: ctxt(0), expressionFunctionValid(false), sseData(0), me(0), trackChange(true), line(-1), id(0), guardList(0), guardListLength(0) { } -QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc) -: q(b), ctxt(0), expressionFunctionValid(false), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +void QmlExpressionPrivate::init(QmlContext *ctxt, const QString &expr, + QObject *me) { + Q_Q(QmlExpression); + + expression = expr; + + this->ctxt = ctxt; + if (ctxt && ctxt->engine()) + id = ctxt->engine()->d_func()->getUniqueId(); + if (ctxt) + ctxt->d_func()->childExpressions.insert(q); + this->me = me; } -QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr) -: q(b), ctxt(0), expression(expr), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, + QObject *me) { + Q_Q(QmlExpression); + + sse.load((const char *)expr, rc); + + this->ctxt = ctxt; + if (ctxt && ctxt->engine()) + id = ctxt->engine()->d_func()->getUniqueId(); + if (ctxt) + ctxt->d_func()->childExpressions.insert(q); + this->me = me; } QmlExpressionPrivate::~QmlExpressionPrivate() { sse.deleteScriptState(sseData); sseData = 0; - delete proxy; - delete log; + if (guardList) { delete [] guardList; guardList = 0; } } /*! + \class QmlExpression + \brief The QmlExpression class evaluates ECMAScript in a QML context. +*/ + +/*! Create an invalid QmlExpression. As the expression will not have an associated QmlContext, this will be a null expression object and its value will always be an invalid QVariant. */ QmlExpression::QmlExpression() -: d(new QmlExpressionPrivate(this)) +: QObject(*new QmlExpressionPrivate, 0) { } -/*! \internal */ +/*! \internal */ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, - QmlRefCount *rc, QObject *me) -: d(new QmlExpressionPrivate(this, expr, rc)) + QmlRefCount *rc, QObject *me, + QmlExpressionPrivate &dd) +: QObject(dd, 0) { - d->ctxt = ctxt; - if(ctxt && ctxt->engine()) - d->id = ctxt->engine()->d_func()->getUniqueId(); - if(ctxt) - ctxt->d_func()->childExpressions.insert(this); - d->me = me; + Q_D(QmlExpression); + d->init(ctxt, expr, rc, me); } /*! @@ -108,14 +127,19 @@ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, */ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, QObject *scope) -: d(new QmlExpressionPrivate(this, expression)) +: QObject(*new QmlExpressionPrivate, 0) +{ + Q_D(QmlExpression); + d->init(ctxt, expression, scope); +} + +/*! \internal */ +QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, + QObject *scope, QmlExpressionPrivate &dd) +: QObject(dd, 0) { - d->ctxt = ctxt; - if(ctxt && ctxt->engine()) - d->id = ctxt->engine()->d_func()->getUniqueId(); - if(ctxt) - ctxt->d_func()->childExpressions.insert(this); - d->me = scope; + Q_D(QmlExpression); + d->init(ctxt, expression, scope); } /*! @@ -123,9 +147,9 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, */ QmlExpression::~QmlExpression() { + Q_D(QmlExpression); if (d->ctxt) d->ctxt->d_func()->childExpressions.remove(this); - delete d; d = 0; } /*! @@ -134,6 +158,7 @@ QmlExpression::~QmlExpression() */ QmlEngine *QmlExpression::engine() const { + Q_D(const QmlExpression); return d->ctxt?d->ctxt->engine():0; } @@ -143,6 +168,7 @@ QmlEngine *QmlExpression::engine() const */ QmlContext *QmlExpression::context() const { + Q_D(const QmlExpression); return d->ctxt; } @@ -151,6 +177,7 @@ QmlContext *QmlExpression::context() const */ QString QmlExpression::expression() const { + Q_D(const QmlExpression); if (d->sse.isValid()) return QLatin1String(d->sse.expression()); else @@ -170,12 +197,13 @@ void QmlExpression::clearExpression() */ void QmlExpression::setExpression(const QString &expression) { + Q_D(QmlExpression); if (d->sseData) { d->sse.deleteScriptState(d->sseData); d->sseData = 0; } - delete d->proxy; d->proxy = 0; + d->clearGuards(); d->expression = expression; d->expressionFunctionValid = false; @@ -184,18 +212,6 @@ void QmlExpression::setExpression(const QString &expression) d->sse.clear(); } -/*! - Called by QmlExpression each time the expression value changes from the - last time it was evaluated. The expression must have been evaluated at - least once (by calling QmlExpression::value()) before this callback will - be made. - - The default implementation does nothing. -*/ -void QmlExpression::valueChanged() -{ -} - QVariant QmlExpressionPrivate::evalSSE(QmlBasicScript::CacheState &cacheState) { #ifdef Q_ENABLE_PERFORMANCE_LOG @@ -318,6 +334,8 @@ QVariant QmlExpressionPrivate::evalQtScript() */ QVariant QmlExpression::value() { + Q_D(QmlExpression); + QVariant rv; if (!d->ctxt || !engine() || (!d->sse.isValid() && d->expression.isEmpty())) return rv; @@ -340,87 +358,10 @@ QVariant QmlExpression::value() ep->currentExpression = lastCurrentExpression; - if (cacheState != QmlBasicScript::NoChange) { - if (cacheState != QmlBasicScript::Incremental && d->proxy) { - delete d->proxy; - d->proxy = 0; - } - - if (trackChange() && ep->capturedProperties.count()) { - if (!d->proxy) - d->proxy = new QmlExpressionBindProxy(this); - - static int changedIndex = -1; - if (changedIndex == -1) - changedIndex = QmlExpressionBindProxy::staticMetaObject.indexOfSlot("changed()"); - - if(qmlDebugger()) { - QmlExpressionLog log; - log.setTime(engine()->d_func()->getUniqueId()); - log.setExpression(expression()); - log.setResult(rv); - - for (int ii = 0; ii < ep->capturedProperties.count(); ++ii) { - const QmlEnginePrivate::CapturedProperty &prop = - ep->capturedProperties.at(ii); - - if (prop.notifyIndex != -1) { - QMetaObject::connect(prop.object, prop.notifyIndex, - d->proxy, changedIndex); - } else { - const QMetaObject *metaObj = prop.object->metaObject(); - QMetaProperty metaProp = - metaObj->property(prop.coreIndex); - - QString warn = QLatin1String("Expression depends on non-NOTIFYable property: ") + - QLatin1String(metaObj->className()) + - QLatin1String("::") + - QLatin1String(metaProp.name()); - log.addWarning(warn); - } - } - d->addLog(log); - - } else { - bool outputWarningHeader = false; - for (int ii = 0; ii < ep->capturedProperties.count(); ++ii) { - const QmlEnginePrivate::CapturedProperty &prop = - ep->capturedProperties.at(ii); - - if (prop.notifyIndex != -1) { - QMetaObject::connect(prop.object, prop.notifyIndex, - d->proxy, changedIndex); - } else { - if (!outputWarningHeader) { - outputWarningHeader = true; - qWarning() << "QmlExpression: Expression" << expression() << "depends on non-NOTIFYable properties:"; - } - - const QMetaObject *metaObj = prop.object->metaObject(); - QMetaProperty metaProp = - metaObj->property(prop.coreIndex); - - qWarning().nospace() << " " << metaObj->className() - << "::" << metaProp.name(); - } - } - } - } else { - QmlExpressionLog log; - log.setTime(engine()->d_func()->getUniqueId()); - log.setExpression(expression()); - log.setResult(rv); - d->addLog(log); - } - - } else { - if(qmlDebugger()) { - QmlExpressionLog log; - log.setTime(engine()->d_func()->getUniqueId()); - log.setExpression(expression()); - log.setResult(rv); - d->addLog(log); - } + if ((!trackChange() || !ep->capturedProperties.count()) && d->guardList) { + d->clearGuards(); + } else if(trackChange()) { + d->updateGuards(ep->capturedProperties); } ep->capturedProperties.clear(); @@ -435,7 +376,8 @@ QVariant QmlExpression::value() */ bool QmlExpression::isConstant() const { - return d->proxy == 0; + Q_D(const QmlExpression); + return !d->guardList; } /*! @@ -443,6 +385,7 @@ bool QmlExpression::isConstant() const */ bool QmlExpression::trackChange() const { + Q_D(const QmlExpression); return d->trackChange; } @@ -463,6 +406,7 @@ bool QmlExpression::trackChange() const */ void QmlExpression::setTrackChange(bool trackChange) { + Q_D(QmlExpression); d->trackChange = trackChange; } @@ -472,6 +416,7 @@ void QmlExpression::setTrackChange(bool trackChange) */ void QmlExpression::setSourceLocation(const QUrl &fileName, int line) { + Q_D(QmlExpression); d->fileName = fileName; d->line = line; } @@ -484,6 +429,7 @@ void QmlExpression::setSourceLocation(const QUrl &fileName, int line) */ QObject *QmlExpression::scopeObject() const { + Q_D(const QmlExpression); return d->me; } @@ -492,144 +438,138 @@ QObject *QmlExpression::scopeObject() const */ quint32 QmlExpression::id() const { + Q_D(const QmlExpression); return d->id; } -/*! - \class QmlExpression - \brief The QmlExpression class evaluates ECMAScript in a QML context. -*/ - -/*! - \class QmlExpressionObject - \brief The QmlExpressionObject class extends QmlExpression with signals and slots. - - To remain as lightweight as possible, QmlExpression does not inherit QObject - and consequently cannot use signals or slots. For the cases where this is - more convenient in an application, QmlExpressionObject can be used instead. - - QmlExpressionObject behaves identically to QmlExpression, except that the - QmlExpressionObject::value() method is a slot, and the - QmlExpressionObject::valueChanged() callback is a signal. -*/ -/*! - Create a QmlExpression with the specified \a parent. - - As the expression will not have an associated QmlContext, this will be a - null expression object and its value will always be an invalid QVariant. -*/ -QmlExpressionObject::QmlExpressionObject(QObject *parent) -: QObject(parent) -{ -} - -/*! - Create a QmlExpressionObject with the specified \a parent. - - The \a expression ECMAScript will be executed in the \a ctxt QmlContext. - If specified, the \a scope object's properties will also be in scope during - the expression's execution. -*/ -QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, const QString &expression, QObject *scope, QObject *parent) -: QObject(parent), QmlExpression(ctxt, expression, scope) -{ -} - -/*! \internal */ -QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, void *d, QmlRefCount *rc, QObject *me) -: QmlExpression(ctxt, d, rc, me) +/*! \internal */ +void QmlExpression::__q_notify() { + valueChanged(); } -/*! - Returns the value of the expression, or an invalid QVariant if the - expression is invalid or has an error. -*/ -QVariant QmlExpressionObject::value() +void QmlExpressionPrivate::clearGuards() { - return QmlExpression::value(); -} - -/*! - \fn void QmlExpressionObject::valueChanged() + Q_Q(QmlExpression); - Emitted each time the expression value changes from the last time it was - evaluated. The expression must have been evaluated at least once (by - calling QmlExpressionObject::value()) before this signal will be emitted. -*/ + static int notifyIdx = -1; + if (notifyIdx == -1) + notifyIdx = + QmlExpression::staticMetaObject.indexOfMethod("__q_notify()"); -void QmlExpressionPrivate::addLog(const QmlExpressionLog &l) -{ - if (!log) - log = new QList(); - log->append(l); -} + for (int ii = 0; ii < guardListLength; ++ii) { + if (guardList[ii].data()) { + QMetaObject::disconnect(guardList[ii].data(), + guardList[ii].notifyIndex, + q, notifyIdx); + } + } -QmlExpressionLog::QmlExpressionLog() -{ + delete [] guardList; guardList = 0; + guardListLength = 0; } -QmlExpressionLog::QmlExpressionLog(const QmlExpressionLog &o) -: m_time(o.m_time), - m_expression(o.m_expression), - m_result(o.m_result), - m_warnings(o.m_warnings) +void QmlExpressionPrivate::updateGuards(const QPODVector &properties) { -} + Q_Q(QmlExpression); -QmlExpressionLog::~QmlExpressionLog() -{ -} + static int notifyIdx = -1; + if (notifyIdx == -1) + notifyIdx = + QmlExpression::staticMetaObject.indexOfMethod("__q_notify()"); -QmlExpressionLog &QmlExpressionLog::operator=(const QmlExpressionLog &o) -{ - m_time = o.m_time; - m_expression = o.m_expression; - m_result = o.m_result; - m_warnings = o.m_warnings; - return *this; -} + SignalGuard *newGuardList = 0; + + if (properties.count() != guardListLength) + newGuardList = new SignalGuard[properties.count()]; -void QmlExpressionLog::setTime(quint32 time) -{ - m_time = time; -} + bool outputWarningHeader = false; + int hit = 0; + for (int ii = 0; ii < properties.count(); ++ii) { + const QmlEnginePrivate::CapturedProperty &property = properties.at(ii); -quint32 QmlExpressionLog::time() const -{ - return m_time; -} + bool needGuard = true; + if (ii >= guardListLength) { + // New guard + } else if(guardList[ii].data() == property.object && + guardList[ii].notifyIndex == property.notifyIndex) { + // Cache hit + if (!guardList[ii].isDuplicate || + (guardList[ii].isDuplicate && hit == ii)) { + needGuard = false; + ++hit; + } + } else if(guardList[ii].data()) { + // Cache miss + QMetaObject::disconnect(guardList[ii].data(), + guardList[ii].notifyIndex, + q, notifyIdx); + } + /* else { + // Cache miss, but nothing to do + } */ + + if (needGuard) { + if (!newGuardList) { + newGuardList = new SignalGuard[properties.count()]; + for (int jj = 0; jj < ii; ++jj) + newGuardList[jj] = guardList[jj]; + } -QString QmlExpressionLog::expression() const -{ - return m_expression; -} + if (property.notifyIndex != -1) { + bool existing = false; + for (int jj = 0; !existing && jj < ii; ++jj) + existing = newGuardList[jj].data() == property.object && + newGuardList[jj].notifyIndex == property.notifyIndex; + + newGuardList[ii] = property.object; + newGuardList[ii].notifyIndex = property.notifyIndex; + if (existing) + newGuardList[ii].isDuplicate = true; + else + QMetaObject::connect(property.object, property.notifyIndex, + q, notifyIdx); + } else { + if (!outputWarningHeader) { + outputWarningHeader = true; + qWarning() << "QmlExpression: Expression" << q->expression() + << "depends on non-NOTIFYable properties:"; + } -void QmlExpressionLog::setExpression(const QString &e) -{ - m_expression = e; -} + const QMetaObject *metaObj = property.object->metaObject(); + QMetaProperty metaProp = metaObj->property(property.coreIndex); -QStringList QmlExpressionLog::warnings() const -{ - return m_warnings; -} + qWarning().nospace() << " " << metaObj->className() + << "::" << metaProp.name(); + } + } else if (newGuardList) { + newGuardList[ii] = guardList[ii]; + } + } -void QmlExpressionLog::addWarning(const QString &w) -{ - m_warnings << w; -} + for (int ii = properties.count(); ii < guardListLength; ++ii) { + if (guardList[ii].data()) { + QMetaObject::disconnect(guardList[ii].data(), + guardList[ii].notifyIndex, + q, notifyIdx); + } + } -QVariant QmlExpressionLog::result() const -{ - return m_result; + if (newGuardList) { + if (guardList) delete [] guardList; + guardList = newGuardList; + guardListLength = properties.count(); + } + //qWarning() << hit << properties.count() << q->expression(); } -void QmlExpressionLog::setResult(const QVariant &r) -{ - m_result = r; -} +/*! + \fn void QmlExpression::valueChanged() + Emitted each time the expression value changes from the last time it was + evaluated. The expression must have been evaluated at least once (by + calling QmlExpression::value()) before this signal will be emitted. +*/ QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h index 3d8f8df..6db6ef9 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -57,12 +57,12 @@ class QmlEngine; class QmlContext; class QmlExpressionPrivate; class QmlBasicScript; -class Q_DECLARATIVE_EXPORT QmlExpression +class Q_DECLARATIVE_EXPORT QmlExpression : public QObject { + Q_OBJECT public: QmlExpression(); QmlExpression(QmlContext *, const QString &, QObject *); - QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me); virtual ~QmlExpression(); QmlEngine *engine() const; @@ -71,7 +71,6 @@ public: QString expression() const; void clearExpression(); virtual void setExpression(const QString &); - QVariant value(); bool isConstant() const; bool trackChange() const; @@ -82,31 +81,27 @@ public: QObject *scopeObject() const; quint32 id() const; -protected: + +public Q_SLOTS: + QVariant value(); + +Q_SIGNALS: virtual void valueChanged(); +protected: + QmlExpression(QmlContext *, const QString &, QObject *, + QmlExpressionPrivate &dd); + QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me, + QmlExpressionPrivate &dd); + +private Q_SLOTS: + void __q_notify(); + private: + Q_DECLARE_PRIVATE(QmlExpression) friend class QmlExpressionBindProxy; friend class QmlDebugger; friend class QmlContext; - QmlExpressionPrivate *d; -}; - -// LK: can't we merge with QmlExpression???? -class Q_DECLARATIVE_EXPORT QmlExpressionObject : public QObject, - public QmlExpression -{ - Q_OBJECT -public: - QmlExpressionObject(QObject *parent = 0); - QmlExpressionObject(QmlContext *, const QString &, QObject *scope, QObject *parent = 0); - QmlExpressionObject(QmlContext *, void *, QmlRefCount *, QObject *); - -public Q_SLOTS: - QVariant value(); - -Q_SIGNALS: - void valueChanged(); }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index 09745a3..41b7749 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -55,23 +55,24 @@ #include "qmlbasicscript_p.h" #include "qmlexpression.h" +#include "qmlengine_p.h" +#include #include QT_BEGIN_NAMESPACE class QmlExpression; class QString; -class QmlExpressionLog; -class QmlExpressionBindProxy; -class QmlExpressionPrivate +class QmlExpressionPrivate : public QObjectPrivate { + Q_DECLARE_PUBLIC(QmlExpression) public: - QmlExpressionPrivate(QmlExpression *); - QmlExpressionPrivate(QmlExpression *, const QString &expr); - QmlExpressionPrivate(QmlExpression *, void *expr, QmlRefCount *rc); + QmlExpressionPrivate(); ~QmlExpressionPrivate(); - QmlExpression *q; + void init(QmlContext *, const QString &, QObject *); + void init(QmlContext *, void *, QmlRefCount *, QObject *); + QmlContext *ctxt; QString expression; bool expressionFunctionValid; @@ -79,7 +80,6 @@ public: QmlBasicScript sse; void *sseData; - QmlExpressionBindProxy *proxy; QObject *me; bool trackChange; @@ -88,53 +88,30 @@ public: quint32 id; - void addLog(const QmlExpressionLog &); - QList *log; - QVariant evalSSE(QmlBasicScript::CacheState &cacheState); QVariant evalQtScript(); -}; - -class QmlExpressionBindProxy : public QObject -{ -Q_OBJECT -public: - QmlExpressionBindProxy(QmlExpression *be) - :e(be) { } - -private: - QmlExpression *e; - -private Q_SLOTS: - void changed() { e->valueChanged(); } -}; - -class QmlExpressionLog -{ -public: - QmlExpressionLog(); - QmlExpressionLog(const QmlExpressionLog &); - ~QmlExpressionLog(); - - QmlExpressionLog &operator=(const QmlExpressionLog &); - - void setTime(quint32); - quint32 time() const; - - QString expression() const; - void setExpression(const QString &); - - QStringList warnings() const; - void addWarning(const QString &); - - QVariant result() const; - void setResult(const QVariant &); -private: - quint32 m_time; - QString m_expression; - QVariant m_result; - QStringList m_warnings; + struct SignalGuard : public QGuard { + SignalGuard() : isDuplicate(false), notifyIndex(-1) {} + + SignalGuard &operator=(QObject *obj) { + QGuard::operator=(obj); + return *this; + } + SignalGuard &operator=(const SignalGuard &o) { + QGuard::operator=(o); + isDuplicate = o.isDuplicate; + notifyIndex = o.notifyIndex; + return *this; + } + + bool isDuplicate:1; + int notifyIndex:31; + }; + SignalGuard *guardList; + int guardListLength; + void updateGuards(const QPODVector &properties); + void clearGuards(); }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qpodvector_p.h b/src/declarative/qml/qpodvector_p.h index 101c62d..e74f9f6 100644 --- a/src/declarative/qml/qpodvector_p.h +++ b/src/declarative/qml/qpodvector_p.h @@ -64,7 +64,7 @@ public: QPODVector() : m_count(0), m_capacity(0), m_data(0) {} - const T &at(int idx) { + const T &at(int idx) const { return m_data[idx]; } diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index c9d70e8..2eb8845 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -13,7 +13,6 @@ #include -#include "qmlbindablevalue.h" #include "qmlviewer.h" #include #include -- cgit v0.12 From 6ed6b740e1ea9cfa64990bb2805d37197f4da45e Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 20 Jul 2009 19:22:50 +1000 Subject: Prevent expression evaluation data from overlapping --- src/declarative/fx/qfxkeyactions.cpp | 1 + src/declarative/qml/qmlexpression.cpp | 12 ++++++++---- src/declarative/qml/qpodvector_p.h | 11 +++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/declarative/fx/qfxkeyactions.cpp b/src/declarative/fx/qfxkeyactions.cpp index 2c662a6..5de1f0b 100644 --- a/src/declarative/fx/qfxkeyactions.cpp +++ b/src/declarative/fx/qfxkeyactions.cpp @@ -900,6 +900,7 @@ void QFxKeyActions::keyPressEvent(QKeyEvent *event) Qt::Key key = (Qt::Key)event->key(); if (d->enabled && d->key(key)) { QmlExpression b(qmlContext(this), d->action(key), this); + b.setTrackChange(false); b.value(); event->accept(); } else { diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index b4f57eb..ea0e9aa 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -347,7 +347,11 @@ QVariant QmlExpression::value() QmlBasicScript::CacheState cacheState = QmlBasicScript::Reset; QmlEnginePrivate *ep = engine()->d_func(); + QmlExpression *lastCurrentExpression = ep->currentExpression; + QPODVector lastCapturedProperties; + ep->capturedProperties.copyAndClear(lastCapturedProperties); + ep->currentExpression = this; if (d->sse.isValid()) { @@ -364,7 +368,7 @@ QVariant QmlExpression::value() d->updateGuards(ep->capturedProperties); } - ep->capturedProperties.clear(); + lastCapturedProperties.copyAndClear(ep->capturedProperties); return rv; } @@ -471,6 +475,7 @@ void QmlExpressionPrivate::clearGuards() void QmlExpressionPrivate::updateGuards(const QPODVector &properties) { + //clearGuards(); Q_Q(QmlExpression); static int notifyIdx = -1; @@ -499,7 +504,7 @@ void QmlExpressionPrivate::updateGuards(const QPODVectorexpression(); } /*! diff --git a/src/declarative/qml/qpodvector_p.h b/src/declarative/qml/qpodvector_p.h index e74f9f6..77f7425 100644 --- a/src/declarative/qml/qpodvector_p.h +++ b/src/declarative/qml/qpodvector_p.h @@ -63,6 +63,7 @@ class QPODVector public: QPODVector() : m_count(0), m_capacity(0), m_data(0) {} + ~QPODVector() { if (m_data) ::free(m_data); } const T &at(int idx) const { return m_data[idx]; @@ -122,6 +123,16 @@ public: return m_count; } + void copyAndClear(QPODVector &other) { + if (other.m_data) ::free(other.m_data); + other.m_count = m_count; + other.m_capacity = m_capacity; + other.m_data = m_data; + m_count = 0; + m_capacity = 0; + m_data = 0; + } + QPODVector &operator<<(const T &v) { append(v); return *this; } private: QPODVector(const QPODVector &); -- cgit v0.12 From 84aaee9b4514f70bf0abfd11e9b4fd3c66ceb1f1 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 20 Jul 2009 19:26:37 +1000 Subject: Remove unnecessary methods from QmlBinding QmlBinding is no longer instantiable from QML, so this stuff isn't needed. --- src/declarative/qml/qmlbinding.cpp | 7 ------- src/declarative/qml/qmlbinding.h | 10 +++------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp index e2f4682..57c1187 100644 --- a/src/declarative/qml/qmlbinding.cpp +++ b/src/declarative/qml/qmlbinding.cpp @@ -59,7 +59,6 @@ QmlBindingPrivate::QmlBindingPrivate() { } -QML_DEFINE_NOCREATE_TYPE(QmlBinding); QmlBinding::QmlBinding(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ctxt, QObject *parent) : QmlExpression(ctxt, data, rc, obj, *new QmlBindingPrivate) { @@ -103,12 +102,6 @@ void QmlBinding::init() update(); } -void QmlBinding::setExpression(const QString &expr) -{ - QmlExpression::setExpression(expr); - update(); -} - void QmlBinding::forceUpdate() { Q_D(QmlBinding); diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h index 10d81b8..5f6d6f4 100644 --- a/src/declarative/qml/qmlbinding.h +++ b/src/declarative/qml/qmlbinding.h @@ -65,13 +65,9 @@ public: QmlBinding(void *, QmlRefCount *, QObject *, QmlContext *, QObject *parent); ~QmlBinding(); - virtual void setTarget(const QmlMetaProperty &); + void setTarget(const QmlMetaProperty &); QmlMetaProperty property() const; - Q_CLASSINFO("DefaultProperty", "expression") - Q_PROPERTY(QString expression READ expression WRITE setExpression) - virtual void setExpression(const QString &); - void init(); void forceUpdate(); @@ -88,9 +84,9 @@ private: Q_DECLARE_PRIVATE(QmlBinding) }; -QT_END_NAMESPACE +Q_DECLARE_METATYPE(QmlBinding*); -QML_DECLARE_TYPE(QmlBinding) +QT_END_NAMESPACE QT_END_HEADER -- cgit v0.12