diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-10-22 01:14:34 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-10-22 01:18:16 (GMT) |
commit | a3b3ba02f0eba2f435f552a9aa64fc9fceade972 (patch) | |
tree | b9987ed6bf8b1a213eac6964f3f8503754d369c7 | |
parent | 9570e6ada20e34a1427a151118a3c0e510423a2d (diff) | |
download | Qt-a3b3ba02f0eba2f435f552a9aa64fc9fceade972.zip Qt-a3b3ba02f0eba2f435f552a9aa64fc9fceade972.tar.gz Qt-a3b3ba02f0eba2f435f552a9aa64fc9fceade972.tar.bz2 |
Support assigning scripts to QML properties
-rw-r--r-- | src/declarative/qml/qml.pri | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompiler.cpp | 32 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompiler_p.h | 3 | ||||
-rw-r--r-- | src/declarative/qml/qmlengine.cpp | 10 | ||||
-rw-r--r-- | src/declarative/qml/qmlinstruction_p.h | 6 | ||||
-rw-r--r-- | src/declarative/qml/qmlparser.cpp | 10 | ||||
-rw-r--r-- | src/declarative/qml/qmlparser_p.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlscriptstring.cpp | 154 | ||||
-rw-r--r-- | src/declarative/qml/qmlscriptstring.h | 87 | ||||
-rw-r--r-- | src/declarative/qml/qmlvme.cpp | 16 | ||||
-rw-r--r-- | tests/auto/declarative/qmllanguage/data/scriptString.qml | 6 | ||||
-rw-r--r-- | tests/auto/declarative/qmllanguage/testtypes.cpp | 2 | ||||
-rw-r--r-- | tests/auto/declarative/qmllanguage/testtypes.h | 31 | ||||
-rw-r--r-- | tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp | 19 |
14 files changed, 375 insertions, 5 deletions
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 58a18a2..b6e86a8 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -40,6 +40,7 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlpropertycache.cpp \ qml/qmlintegercache.cpp \ qml/qmltypenamecache.cpp \ + qml/qmlscriptstring.cpp \ qml/qmlobjectscriptclass.cpp \ qml/qmlcontextscriptclass.cpp \ qml/qmlglobalscriptclass.cpp \ @@ -102,6 +103,7 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlpropertycache_p.h \ qml/qmlintegercache_p.h \ qml/qmltypenamecache_p.h \ + qml/qmlscriptstring.h \ qml/qmlobjectscriptclass_p.h \ qml/qmlcontextscriptclass_p.h \ qml/qmlglobalscriptclass_p.h \ diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index e2fd7cb..726051e 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -69,6 +69,7 @@ #include <private/qmlexpression_p.h> #include "qmlmetaproperty_p.h" #include "qmlrewrite_p.h" +#include <QtDeclarative/qmlscriptstring.h> #include "qmlscriptparser_p.h" @@ -860,6 +861,17 @@ void QmlCompiler::genObject(QmlParser::Object *obj) void QmlCompiler::genObjectBody(QmlParser::Object *obj) { + typedef QPair<Property *, int> PropPair; + foreach(const PropPair &prop, obj->scriptStringProperties) { + QmlInstruction ss; + ss.type = QmlInstruction::StoreScriptString; + ss.storeScriptString.propertyIndex = prop.first->index; + ss.storeScriptString.value = + output->indexForString(prop.first->values.at(0)->value.asScript()); + ss.storeScriptString.scope = prop.second; + output->bytecode << ss; + } + bool seenDefer = false; foreach(Property *prop, obj->valueProperties) { if (prop->isDeferred) { @@ -1371,6 +1383,10 @@ bool QmlCompiler::buildProperty(QmlParser::Property *prop, COMPILE_CHECK(buildListProperty(prop, obj, ctxt)); + } else if (prop->type == qMetaTypeId<QmlScriptString>()) { + + COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt)); + } else { COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); @@ -1823,6 +1839,22 @@ bool QmlCompiler::buildListProperty(QmlParser::Property *prop, return true; } +// Compiles an assignment to a QmlScriptString property +bool QmlCompiler::buildScriptStringProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) +{ + if (prop->values.count() > 1) + COMPILE_EXCEPTION(prop->values.at(1), qApp->translate("QmlCompiler", "Cannot assign multiple values to a script property")); + + if (prop->values.at(0)->object || !prop->values.at(0)->value.isScript()) + COMPILE_EXCEPTION(prop->values.at(0), qApp->translate("QmlCompiler", "Invalid property assignment: script expected")); + + obj->addScriptStringProperty(prop, ctxt.stack); + + return true; +} + // Compile regular property assignments of the form "property: <value>" // // ### The following problems exist diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index cff4937..8a9ca9c 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -197,6 +197,9 @@ private: bool buildListProperty(QmlParser::Property *prop, QmlParser::Object *obj, const BindingContext &ctxt); + bool buildScriptStringProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); bool buildPropertyAssignment(QmlParser::Property *prop, QmlParser::Object *obj, const BindingContext &ctxt); diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 6361da4..9fad80b 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -78,8 +78,8 @@ #include <QtGui/qvector3d.h> #include <QtGui/qsound.h> #include <qmlcomponent.h> -#include "private/qmlcomponentjs_p.h" -#include "private/qmlmetaproperty_p.h" +#include <private/qmlcomponentjs_p.h> +#include <private/qmlmetaproperty_p.h> #include <private/qmlbinding_p.h> #include <private/qmlvme_p.h> #include <private/qmlenginedebug_p.h> @@ -88,6 +88,7 @@ #include <private/qmlsqldatabase_p.h> #include <private/qmltypenamescriptclass_p.h> #include <private/qmllistscriptclass_p.h> +#include <QtDeclarative/qmlscriptstring.h> #ifdef Q_OS_WIN // for %APPDATA% #include "qt_windows.h" @@ -219,6 +220,9 @@ Q_GLOBAL_STATIC(QmlEngineDebugServer, qmlEngineDebugServer); void QmlEnginePrivate::init() { Q_Q(QmlEngine); + qRegisterMetaType<QVariant>("QVariant"); + qRegisterMetaType<QmlScriptString>("QmlScriptString"); + scriptEngine.installTranslatorFunctions(); contextClass = new QmlContextScriptClass(q); objectClass = new QmlObjectScriptClass(q); @@ -284,8 +288,6 @@ QmlEngine::QmlEngine(QObject *parent) { Q_D(QmlEngine); d->init(); - - qRegisterMetaType<QVariant>("QVariant"); } /*! diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 5265d42..dc18b05 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -119,6 +119,7 @@ public: StoreSignal, /* storeSignal */ StoreScript, /* storeScript */ + StoreScriptString, /* storeScriptString */ // // Unresolved single assignment @@ -245,6 +246,11 @@ public: int value; } storeString; struct { + int propertyIndex; + int value; + int scope; + } storeScriptString; + struct { int value; int fileName; int lineNumber; diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index bae263a..f9e3c50 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -80,6 +80,9 @@ QmlParser::Object::~Object() prop->release(); foreach(Property *prop, valueTypeProperties) prop->release(); + typedef QPair<Property *, int> PropPair; + foreach(const PropPair &prop, scriptStringProperties) + prop.first->release(); foreach(const DynamicProperty &prop, dynamicProperties) if (prop.defaultValue) prop.defaultValue->release(); foreach(Object *obj, scriptBlockObjects) @@ -142,6 +145,13 @@ void QmlParser::Object::addValueTypeProperty(Property *p) valueTypeProperties << p; } +void QmlParser::Object::addScriptStringProperty(Property *p, int stack) +{ + p->addref(); + scriptStringProperties << qMakePair(p, stack); +} + + Property *QmlParser::Object::getProperty(const QByteArray &name, bool create) { if (!properties.contains(name)) { diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index 88d7d77..f0867ea 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -160,11 +160,13 @@ namespace QmlParser void addAttachedProperty(Property *); void addGroupedProperty(Property *); void addValueTypeProperty(Property *); + void addScriptStringProperty(Property *, int = 0); QList<Property *> valueProperties; QList<Property *> signalProperties; QList<Property *> attachedProperties; QList<Property *> groupedProperties; QList<Property *> valueTypeProperties; + QList<QPair<Property *, int> > scriptStringProperties; // Script blocks that were nested under this object QStringList scriptBlocks; diff --git a/src/declarative/qml/qmlscriptstring.cpp b/src/declarative/qml/qmlscriptstring.cpp new file mode 100644 index 0000000..8a6afcc --- /dev/null +++ b/src/declarative/qml/qmlscriptstring.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** 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 "qmlscriptstring.h" + +QT_BEGIN_NAMESPACE + +class QmlScriptStringPrivate : public QSharedData +{ +public: + QmlScriptStringPrivate() : context(0), scope(0) {} + + QmlContext *context; + QObject *scope; + QString script; +}; + +/*! +\class QmlScriptString +\brief The QmlScriptString class encapsulates a script and its context. + +The QmlScriptString is used by properties that want to accept a script "assignment" from QML. + +Normally, the following code would result in a binding being established for the \c script +property. If the property had a type of QmlScriptString, the script - \e {print(1921)} - itself +would be passed to the property and it could choose how to handle it. + +\code +MyType { + script: print(1921) +} +\endcode +*/ + +/*! +Construct an empty instance. +*/ +QmlScriptString::QmlScriptString() +: d(new QmlScriptStringPrivate) +{ +} + +/*! +Copy \a other. +*/ +QmlScriptString::QmlScriptString(const QmlScriptString &other) +: d(other.d) +{ +} + +/*! +\internal +*/ +QmlScriptString::~QmlScriptString() +{ +} + +/*! +Assign \a other to this. +*/ +QmlScriptString &QmlScriptString::operator=(const QmlScriptString &other) +{ + d = other.d; + return *this; +} + +/*! +Return the context for the script. +*/ +QmlContext *QmlScriptString::context() const +{ + return d->context; +} + +/*! +Sets the \a context for the script. +*/ +void QmlScriptString::setContext(QmlContext *context) +{ + d->context = context; +} + +/*! +Returns the scope object for the script. +*/ +QObject *QmlScriptString::scopeObject() const +{ + return d->scope; +} + +/*! +Sets the scope \a object for the script. +*/ +void QmlScriptString::setScopeObject(QObject *object) +{ + d->scope = object; +} + +/*! +Returns the script text. +*/ +QString QmlScriptString::script() const +{ + return d->script; +} + +/*! +Sets the \a script text. +*/ +void QmlScriptString::setScript(const QString &script) +{ + d->script = script; +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlscriptstring.h b/src/declarative/qml/qmlscriptstring.h new file mode 100644 index 0000000..c6067ce --- /dev/null +++ b/src/declarative/qml/qmlscriptstring.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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 QMLSCRIPTSTRING_H +#define QMLSCRIPTSTRING_H + +#include <QtCore/qstring.h> +#include <QtCore/qshareddata.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QObject; +class QmlContext; +class QmlScriptStringPrivate; +class Q_DECLARATIVE_EXPORT QmlScriptString +{ +public: + QmlScriptString(); + QmlScriptString(const QmlScriptString &); + ~QmlScriptString(); + + QmlScriptString &operator=(const QmlScriptString &); + + QmlContext *context() const; + void setContext(QmlContext *); + + QObject *scopeObject() const; + void setScopeObject(QObject *); + + QString script() const; + void setScript(const QString &); + +private: + QSharedDataPointer<QmlScriptStringPrivate> d; +}; + +Q_DECLARE_METATYPE(QmlScriptString); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLSCRIPTSTRING_H + diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 1f3903d..7f673a2 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -67,6 +67,7 @@ #include <private/qmlbinding_p.h> #include <private/qmlcontext_p.h> #include <private/qmlbindingoptimizations_p.h> +#include <QtDeclarative/qmlscriptstring.h> QT_BEGIN_NAMESPACE @@ -552,6 +553,21 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, } break; + case QmlInstruction::StoreScriptString: + { + QObject *target = stack.top(); + QObject *scope = stack.at(stack.count() - 1 - instr.storeScriptString.scope); + QmlScriptString ss; + ss.setContext(ctxt); + ss.setScopeObject(scope); + ss.setScript(primitives.at(instr.storeScriptString.value)); + + void *a[] = { &ss, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeScriptString.propertyIndex, a); + } + break; + case QmlInstruction::BeginObject: { QObject *target = stack.top(); diff --git a/tests/auto/declarative/qmllanguage/data/scriptString.qml b/tests/auto/declarative/qmllanguage/data/scriptString.qml new file mode 100644 index 0000000..51e6e48 --- /dev/null +++ b/tests/auto/declarative/qmllanguage/data/scriptString.qml @@ -0,0 +1,6 @@ +import Test 1.0 + +MyTypeObject { + scriptProperty: foo + bar + grouped.script: print(1921) +} diff --git a/tests/auto/declarative/qmllanguage/testtypes.cpp b/tests/auto/declarative/qmllanguage/testtypes.cpp index c11e195..58d99f1 100644 --- a/tests/auto/declarative/qmllanguage/testtypes.cpp +++ b/tests/auto/declarative/qmllanguage/testtypes.cpp @@ -7,4 +7,4 @@ QML_DEFINE_TYPE(Test,1,0,0,MyContainer,MyContainer); QML_DEFINE_TYPE(Test,1,0,0,MyPropertyValueSource,MyPropertyValueSource); QML_DEFINE_TYPE(Test,1,0,0,MyDotPropertyObject,MyDotPropertyObject); QML_DEFINE_TYPE(Test,1,0,0,MyNamespacedType,MyNamespace::MyNamespacedType); - +QML_DEFINE_NOCREATE_TYPE(MyGroupedObject); diff --git a/tests/auto/declarative/qmllanguage/testtypes.h b/tests/auto/declarative/qmllanguage/testtypes.h index b1da9fb..355ff8b 100644 --- a/tests/auto/declarative/qmllanguage/testtypes.h +++ b/tests/auto/declarative/qmllanguage/testtypes.h @@ -10,6 +10,7 @@ #include <QtDeclarative/qmlcomponent.h> #include <QtDeclarative/qmlparserstatus.h> #include <QtDeclarative/qmlpropertyvaluesource.h> +#include <QtDeclarative/qmlscriptstring.h> class MyInterface { @@ -112,6 +113,21 @@ private: }; QML_DECLARE_TYPE(MyQmlObject); +class MyGroupedObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(QmlScriptString script READ script WRITE setScript); +public: + QmlScriptString script() const { return m_script; } + void setScript(const QmlScriptString &s) { m_script = s; } + +private: + QmlScriptString m_script; +}; + +QML_DECLARE_TYPE(MyGroupedObject); + + class MyTypeObject : public QObject { Q_OBJECT @@ -142,6 +158,9 @@ class MyTypeObject : public QObject Q_PROPERTY(bool boolProperty READ boolProperty WRITE setBoolProperty); Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty); + Q_PROPERTY(QmlScriptString scriptProperty READ scriptProperty WRITE setScriptProperty); + Q_PROPERTY(MyGroupedObject *grouped READ grouped CONSTANT); + public: MyTypeObject() : objectPropertyValue(0), componentPropertyValue(0) {} @@ -334,6 +353,17 @@ public: variantPropertyValue = v; } + QmlScriptString scriptPropertyValue; + QmlScriptString scriptProperty() const { + return scriptPropertyValue; + } + void setScriptProperty(const QmlScriptString &v) { + scriptPropertyValue = v; + } + + MyGroupedObject groupedValue; + MyGroupedObject *grouped() { return &groupedValue; } + void doAction() { emit action(); } signals: void action(); @@ -365,6 +395,7 @@ private: QML_DECLARE_TYPE(MyContainer); + class MyPropertyValueSource : public QObject, public QmlPropertyValueSource { Q_OBJECT diff --git a/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp b/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp index 8d4ae65..97038e6 100644 --- a/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp +++ b/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp @@ -63,6 +63,7 @@ private slots: void i18n(); void i18n_data(); void onCompleted(); + void scriptString(); void importsBuiltin_data(); void importsBuiltin(); @@ -739,6 +740,24 @@ void tst_qmllanguage::onCompleted() QVERIFY(object != 0); } +// Check that assignments to QmlScriptString properties work +void tst_qmllanguage::scriptString() +{ + QmlComponent component(&engine, TEST_FILE("scriptString.qml")); + VERIFY_ERRORS(0); + + MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->scriptProperty().script(), QString("foo + bar")); + QCOMPARE(object->scriptProperty().scopeObject(), object); + QCOMPARE(object->scriptProperty().context(), qmlContext(object)); + + QVERIFY(object->grouped() != 0); + QCOMPARE(object->grouped()->script().script(), QString("print(1921)")); + QCOMPARE(object->grouped()->script().scopeObject(), object); + QCOMPARE(object->grouped()->script().context(), qmlContext(object)); +} + // Check that first child of qml is of given type. Empty type insists on error. void tst_qmllanguage::testType(const QString& qml, const QString& type) { |