diff options
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 27 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler_p.h | 7 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlbinding.cpp | 28 | ||||
-rw-r--r-- | src/qml/qml/qqmlbinding_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlcompiler_p.h | 12 | ||||
-rw-r--r-- | src/qml/qml/qqmlcustomparser.cpp | 46 | ||||
-rw-r--r-- | src/qml/qml/qqmlcustomparser_p.h | 10 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 17 | ||||
-rw-r--r-- | src/qml/types/qqmlconnections.cpp | 53 | ||||
-rw-r--r-- | src/qml/types/qqmlconnections_p.h | 4 | ||||
-rw-r--r-- | src/qml/types/qqmllistmodel.cpp | 240 | ||||
-rw-r--r-- | src/qml/types/qqmllistmodel_p.h | 33 | ||||
-rw-r--r-- | src/quick/util/qquickpropertychanges.cpp | 193 | ||||
-rw-r--r-- | src/quick/util/qquickpropertychanges_p.h | 6 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.cpp | 81 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.h | 20 | ||||
-rw-r--r-- | tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp | 4 |
18 files changed, 288 insertions, 497 deletions
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index ede150c67b..45fdab3fd1 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -378,9 +378,9 @@ QHash<int, QHash<int, int> > *QQmlTypeCompiler::objectIndexToIdPerComponent() return &compiledData->objectIndexToIdPerComponent; } -QHash<int, QQmlCompiledData::CustomParserData> *QQmlTypeCompiler::customParserData() +QHash<int, QBitArray> *QQmlTypeCompiler::customParserBindings() { - return &compiledData->customParserData; + return &compiledData->customParserBindings; } QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool() @@ -398,11 +398,6 @@ const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const return &document->jsGenerator.stringTable; } -void QQmlTypeCompiler::setCustomParserBindings(const QVector<int> &bindings) -{ - compiledData->customParserBindings = bindings; -} - void QQmlTypeCompiler::setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject) { compiledData->deferredBindingsPerObject = deferredBindingsPerObject; @@ -1720,7 +1715,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler) , customParsers(typeCompiler->customParserCache()) , propertyCaches(typeCompiler->propertyCaches()) , objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent()) - , customParserData(typeCompiler->customParserData()) + , customParserBindingsPerObject(typeCompiler->customParserBindings()) , _seenObjectWithId(false) { } @@ -1729,7 +1724,6 @@ bool QQmlPropertyValidator::validate() { if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0)) return false; - compiler->setCustomParserBindings(customParserBindings); compiler->setDeferredBindingsPerObject(deferredBindingsPerObject); return true; } @@ -1739,13 +1733,6 @@ const QQmlImports &QQmlPropertyValidator::imports() const return *compiler->imports(); } -QQmlBinding::Identifier QQmlPropertyValidator::bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *) -{ - const int id = customParserBindings.count(); - customParserBindings.append(binding->value.compiledScriptIndex); - return id; -} - QString QQmlPropertyValidator::bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const { const QmlIR::Object *object = compiler->qmlObjects()->value(objectIndex); @@ -2005,11 +1992,11 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD if (customParser && !customBindings.isEmpty()) { customParser->clearErrors(); customParser->compiler = this; - QQmlCompiledData::CustomParserData data; - data.bindings = customParserBindings; - data.compilationArtifact = customParser->compile(qmlUnit, customBindings); + customParser->imports = compiler->imports(); + customParser->verifyBindings(qmlUnit, customBindings); customParser->compiler = 0; - customParserData->insert(objectIndex, data); + customParser->imports = (QQmlImports*)0; + customParserBindingsPerObject->insert(objectIndex, customParserBindings); const QList<QQmlError> parserErrors = customParser->errors(); if (!parserErrors.isEmpty()) { foreach (QQmlError error, parserErrors) diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 3d8c35781f..3f311d8693 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -96,11 +96,10 @@ public: QVector<QByteArray> *vmeMetaObjects() const; QHash<int, int> *objectIndexToIdForRoot(); QHash<int, QHash<int, int> > *objectIndexToIdPerComponent(); - QHash<int, QQmlCompiledData::CustomParserData> *customParserData(); + QHash<int, QBitArray> *customParserBindings(); QQmlJS::MemoryPool *memoryPool(); QStringRef newStringRef(const QString &string); const QV4::Compiler::StringTableGenerator *stringPool() const; - void setCustomParserBindings(const QVector<int> &bindings); void setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject); const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; } @@ -282,7 +281,6 @@ public: // Re-implemented for QQmlCustomParser virtual const QQmlImports &imports() const; - virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *parser); virtual QString bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const; private: @@ -300,8 +298,7 @@ private: const QHash<int, QQmlCustomParser*> &customParsers; const QVector<QQmlPropertyCache *> &propertyCaches; const QHash<int, QHash<int, int> > objectIndexToIdPerComponent; - QHash<int, QQmlCompiledData::CustomParserData> *customParserData; - QVector<int> customParserBindings; + QHash<int, QBitArray> *customParserBindingsPerObject; QHash<int, QBitArray> deferredBindingsPerObject; bool _seenObjectWithId; diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index de582f9674..b2c0efc75f 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -55,7 +55,7 @@ namespace QV4 { struct ExecutionContext; -struct QmlBindingWrapper : FunctionObject { +struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject { V4_OBJECT QmlBindingWrapper(ExecutionContext *scope, Function *f, ObjectRef qml); diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 571d78312e..074f568d09 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -71,34 +71,6 @@ QQmlAbstractBinding::VTable QQmlBinding_vtable = { QQmlBinding::Identifier QQmlBinding::Invalid = -1; -QQmlBinding * -QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt) -{ - if (id < 0) - return 0; - - QQmlBinding *rv = 0; - - QQmlContextData *ctxtdata = QQmlContextData::get(ctxt); - QQmlEnginePrivate *engine = QQmlEnginePrivate::get(ctxt->engine()); - if (engine && ctxtdata && !ctxtdata->url.isEmpty()) { - QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url); - Q_ASSERT(typeData); - - if (QQmlCompiledData *cdata = typeData->compiledData()) { - QV4::ExecutionEngine *v4 = engine->v4engine(); - QV4::Scope valueScope(v4); - QV4::Function *runtimeFunction = cdata->compilationUnit->runtimeFunctions[cdata->customParserBindings[id]]; - QV4::ScopedValue function(valueScope, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, obj, runtimeFunction)); - rv = new QQmlBinding(function, obj, ctxtdata); - } - - typeData->release(); - } - - return rv; -} - static QQmlJavaScriptExpression::VTable QQmlBinding_jsvtable = { QQmlBinding::expressionIdentifier, QQmlBinding::expressionChanged diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 3c2c832e0c..879129fe85 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -112,8 +112,6 @@ public: typedef int Identifier; static Identifier Invalid; - static QQmlBinding *createBinding(Identifier, QObject *, QQmlContext *); - QVariant evaluate(); static QString expressionIdentifier(QQmlJavaScriptExpression *); diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index f3b6f621ce..9f0f80063b 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -136,13 +136,8 @@ public: // index in first hash is component index, hash inside maps from object index in that scope to integer id QHash<int, QHash<int, int> > objectIndexToIdPerComponent; QHash<int, int> objectIndexToIdForRoot; - // hash key is object index - struct CustomParserData { - QByteArray compilationArtifact; // produced by custom parser - QBitArray bindings; // bindings covered by the custom parser - }; - QHash<int, CustomParserData> customParserData; - QVector<int> customParserBindings; // index is binding identifier, value is compiled function index. + // hash key is object index, value is indicies of bindings covered by custom parser + QHash<int, QBitArray> customParserBindings; QHash<int, QBitArray> deferredBindingsPerObject; // index is object index int totalBindingsCount; // Number of bindings used in this type int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses @@ -154,9 +149,6 @@ public: bool isInitialized() const { return hasEngine(); } void initialize(QQmlEngine *); - QV4::Function *functionForBindingId(int bindingId) const - { return compilationUnit->runtimeFunctions[customParserBindings[bindingId]]; } - protected: virtual void destroy(); // From QQmlRefCount virtual void clear(); // From QQmlCleanup diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 75acbdb778..312c4a8a10 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -109,6 +109,12 @@ void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const exceptions << error; } +struct StaticQtMetaObject : public QObject +{ + static const QMetaObject *get() + { return &staticQtMetaObject; } +}; + /*! If \a script is a simple enumeration expression (eg. Text.AlignLeft), returns the integer equivalent (eg. 1), and sets \a ok to true. @@ -125,7 +131,34 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const if (dot == -1) return -1; - return compiler->evaluateEnum(QString::fromUtf8(script.left(dot)), script.mid(dot+1), ok); + + QString scope = QString::fromUtf8(script.left(dot)); + QByteArray enumValue = script.mid(dot+1); + + if (scope != QLatin1String("Qt")) { + if (imports.isNull()) + return -1; + QQmlType *type = 0; + + if (imports.isT1()) { + imports.asT1()->resolveType(scope, &type, 0, 0, 0); + } else { + QQmlTypeNameCache::Result result = imports.asT2()->query(scope); + if (result.isValid()) + type = result.type; + } + + return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; + } + + const QMetaObject *mo = StaticQtMetaObject::get(); + int i = mo->enumeratorCount(); + while (i--) { + int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok); + if (*ok) + return v; + } + return -1; } /*! @@ -137,17 +170,6 @@ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const return compiler->resolveType(name); } -QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QV4::CompiledData::Binding *binding) -{ - return compiler->bindingIdentifier(binding, this); -} - -struct StaticQtMetaObject : public QObject -{ - static const QMetaObject *get() - { return &staticQtMetaObject; } -}; - int QQmlCustomParserCompilerBackend::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const { Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer"); diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h index 2ce6375870..9e3f810738 100644 --- a/src/qml/qml/qqmlcustomparser_p.h +++ b/src/qml/qml/qqmlcustomparser_p.h @@ -71,8 +71,6 @@ struct QQmlCustomParserCompilerBackend int evaluateEnum(const QString &scope, const QByteArray& enumValue, bool *ok) const; const QMetaObject *resolveType(const QString& name) const; - - virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *, QQmlCustomParser *) { return QQmlBinding::Invalid; } }; class Q_QML_PRIVATE_EXPORT QQmlCustomParser @@ -92,8 +90,8 @@ public: void clearErrors(); Flags flags() const { return m_flags; } - virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) = 0; - virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *cdata) = 0; + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) = 0; + virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) = 0; QList<QQmlError> errors() const { return exceptions; } @@ -108,13 +106,13 @@ protected: const QMetaObject *resolveType(const QString&) const; - QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding); - private: QList<QQmlError> exceptions; QQmlCustomParserCompilerBackend *compiler; Flags m_flags; + QBiPointer<const QQmlImports, QQmlTypeNameCache> imports; friend class QQmlPropertyValidator; + friend class QQmlObjectCreator; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlCustomParser::Flags) diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 2ebf90c9be..efdf4d86da 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -1123,10 +1123,19 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo QBitArray bindingsToSkip; if (customParser) { - QHash<int, QQmlCompiledData::CustomParserData>::ConstIterator entry = compiledData->customParserData.find(index); - if (entry != compiledData->customParserData.constEnd()) { - customParser->setCustomData(instance, entry->compilationArtifact, compiledData); - bindingsToSkip = entry->bindings; + QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.find(index); + if (customParserBindings != compiledData->customParserBindings.constEnd()) { + customParser->imports = compiledData->importCache; + + QList<const QV4::CompiledData::Binding *> bindings; + const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); + for (int i = 0; i < customParserBindings->count(); ++i) + if (customParserBindings->testBit(i)) + bindings << obj->bindingTable() + i; + customParser->applyBindings(instance, compiledData, bindings); + + customParser->imports = (QQmlTypeNameCache*)0; + bindingsToSkip = *customParserBindings; } } diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 99ec0b55de..b0e814d285 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -68,8 +68,8 @@ public: bool ignoreUnknownSignals; bool componentcomplete; - QByteArray data; QQmlRefPointer<QQmlCompiledData> cdata; + QList<const QV4::CompiledData::Binding *> bindings; }; /*! @@ -205,18 +205,15 @@ void QQmlConnections::setIgnoreUnknownSignals(bool ignore) d->ignoreUnknownSignals = ignore; } -QByteArray QQmlConnectionsParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props) +void QQmlConnectionsParser::verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props) { - QByteArray rv; - QDataStream ds(&rv, QIODevice::WriteOnly); - for (int ii = 0; ii < props.count(); ++ii) { const QV4::CompiledData::Binding *binding = props.at(ii); QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex); if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) { error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName)); - return QByteArray(); + return; } @@ -226,56 +223,48 @@ QByteArray QQmlConnectionsParser::compile(const QV4::CompiledData::QmlUnit *qmlU error(binding, QQmlConnections::tr("Connections: nested objects not allowed")); else error(binding, QQmlConnections::tr("Connections: syntax error")); - return QByteArray(); + return; } if (binding->type != QV4::CompiledData::Binding::Type_Script) { error(binding, QQmlConnections::tr("Connections: script expected")); - return QByteArray(); - } else { - ds << propName; - ds << bindingIdentifier(binding); + return; } } - - return rv; } -void QQmlConnectionsParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *cdata) +void QQmlConnectionsParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) { QQmlConnectionsPrivate *p = static_cast<QQmlConnectionsPrivate *>(QObjectPrivate::get(object)); - p->data = data; p->cdata = cdata; + p->bindings = bindings; } - void QQmlConnections::connectSignals() { Q_D(QQmlConnections); if (!d->componentcomplete || (d->targetSet && !target())) return; - QDataStream ds(d->data); - while (!ds.atEnd()) { - QString propName; - ds >> propName; - int bindingId; - ds >> bindingId; + if (d->bindings.isEmpty()) + return; + QObject *target = this->target(); + QQmlData *ddata = QQmlData::get(this); + QQmlContextData *ctxtdata = ddata ? ddata->outerContext : 0; + + const QV4::CompiledData::QmlUnit *qmlUnit = d->cdata->qmlUnit; + foreach (const QV4::CompiledData::Binding *binding, d->bindings) { + Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script); + QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex); - QQmlProperty prop(target(), propName); + QQmlProperty prop(target, propName); if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) { int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex(); QQmlBoundSignal *signal = - new QQmlBoundSignal(target(), signalIndex, this, qmlEngine(this)); - - QQmlContextData *ctxtdata = 0; - QQmlData *ddata = QQmlData::get(this); - if (ddata) { - ctxtdata = ddata->outerContext; - } + new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this)); QQmlBoundSignalExpression *expression = ctxtdata ? - new QQmlBoundSignalExpression(target(), signalIndex, - ctxtdata, this, d->cdata->functionForBindingId(bindingId)) : 0; + new QQmlBoundSignalExpression(target, signalIndex, + ctxtdata, this, d->cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0; signal->takeExpression(expression); d->boundsignals += signal; } else { diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h index f169eeb53f..e829828bd8 100644 --- a/src/qml/types/qqmlconnections_p.h +++ b/src/qml/types/qqmlconnections_p.h @@ -84,8 +84,8 @@ private: class QQmlConnectionsParser : public QQmlCustomParser { public: - virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props); - virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *cdata); + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props); + virtual void applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings); }; diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 0056276d52..1b074efd56 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -44,7 +44,7 @@ #include <private/qqmlopenmetaobject_p.h> #include <private/qqmljsast_p.h> #include <private/qqmljsengine_p.h> - +#include <private/qqmlcompiler_p.h> #include <private/qqmlcustomparser_p.h> #include <private/qqmlengine_p.h> @@ -1430,11 +1430,6 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index) } } -QQmlListModelParser::ListInstruction *QQmlListModelParser::ListModelData::instructions() const -{ - return (QQmlListModelParser::ListInstruction *)((char *)this + sizeof(ListModelData)); -} - /*! \qmltype ListModel \instantiates QQmlListModel @@ -2254,7 +2249,7 @@ void QQmlListModel::sync() qmlInfo(this) << "List sync() can only be called from a WorkerScript"; } -bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, QList<QQmlListModelParser::ListInstruction> &instr, QByteArray &data) +bool QQmlListModelParser::verifyProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding) { if (binding->type >= QV4::CompiledData::Binding::Type_Object) { const quint32 targetObjectIndex = binding->value.objectIndex; @@ -2269,13 +2264,6 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU listElementTypeName = objName; // cache right name for next time } - { - ListInstruction li; - li.type = ListInstruction::Push; - li.dataIdx = -1; - instr << li; - } - if (!qmlUnit->header.stringAt(target->idIndex).isEmpty()) { error(target->locationOfIdProperty, QQmlListModel::tr("ListElement: cannot use reserved \"id\" property")); return false; @@ -2288,208 +2276,116 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU error(binding, QQmlListModel::tr("ListElement: cannot contain nested elements")); return false; } - ListInstruction li; - int ref = data.count(); - data.append(propName.toUtf8()); - data.append('\0'); - li.type = ListInstruction::Set; - li.dataIdx = ref; - instr << li; - - if (!compileProperty(qmlUnit, binding, instr, data)) + if (!verifyProperty(qmlUnit, binding)) + return false; + } + } else if (binding->type == QV4::CompiledData::Binding::Type_Script) { + QString scriptStr = binding->valueAsScriptString(&qmlUnit->header); + if (!definesEmptyList(scriptStr)) { + QByteArray script = scriptStr.toUtf8(); + bool ok; + evaluateEnum(script, &ok); + if (!ok) { + error(binding, QQmlListModel::tr("ListElement: cannot use script for property value")); return false; + } + } + } + + return true; +} + +bool QQmlListModelParser::applyProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, ListModel *model, int outterElementIndex) +{ + const QString elementName = qmlUnit->header.stringAt(binding->propertyNameIndex); - li.type = ListInstruction::Pop; - li.dataIdx = -1; - instr << li; + bool roleSet = false; + if (binding->type >= QV4::CompiledData::Binding::Type_Object) { + const quint32 targetObjectIndex = binding->value.objectIndex; + const QV4::CompiledData::Object *target = qmlUnit->objectAt(targetObjectIndex); + + ListModel *subModel = 0; + if (outterElementIndex == -1) { + subModel = model; + } else { + const ListLayout::Role &role = model->getOrCreateListRole(elementName); + if (role.type == ListLayout::Role::List) { + subModel = model->getListProperty(outterElementIndex, role); + if (subModel == 0) { + subModel = new ListModel(role.subLayout, 0, -1); + QVariant vModel = QVariant::fromValue(subModel); + model->setOrCreateProperty(outterElementIndex, elementName, vModel); + } + } } - { - ListInstruction li; - li.type = ListInstruction::Pop; - li.dataIdx = -1; - instr << li; + int elementIndex = subModel ? subModel->appendElement() : -1; + + const QV4::CompiledData::Binding *subBinding = target->bindingTable(); + for (quint32 i = 0; i < target->nBindings; ++i, ++subBinding) { + roleSet |= applyProperty(qmlUnit, subBinding, subModel, elementIndex); } } else { - int ref = data.count(); - - QByteArray d; + QVariant value; - if (binding->type == QV4::CompiledData::Binding::Type_String) { - d += char(String); - d += binding->valueAsString(&qmlUnit->header).toUtf8(); + if (binding->evaluatesToString()) { + value = binding->valueAsString(&qmlUnit->header); } else if (binding->type == QV4::CompiledData::Binding::Type_Number) { - d += char(Number); - d += QByteArray::number(binding->valueAsNumber(),'g',20); + value = binding->valueAsNumber(); } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) { - d += char(Boolean); - d += char(binding->valueAsBoolean()); - } else if (binding->type == QV4::CompiledData::Binding::Type_Translation - || binding->type == QV4::CompiledData::Binding::Type_TranslationById) { - error(binding, QQmlListModel::tr("ListElement: cannot use script for property value")); - return false; + value = binding->valueAsBoolean(); } else if (binding->type == QV4::CompiledData::Binding::Type_Script) { QString scriptStr = binding->valueAsScriptString(&qmlUnit->header); if (definesEmptyList(scriptStr)) { - d[0] = char(Invalid); // marks empty list + const ListLayout::Role &role = model->getOrCreateListRole(elementName); + ListModel *emptyModel = new ListModel(role.subLayout, 0, -1); + value = QVariant::fromValue(emptyModel); } else { QByteArray script = scriptStr.toUtf8(); bool ok; - int v = evaluateEnum(script, &ok); - if (!ok) { - error(binding, QQmlListModel::tr("ListElement: cannot use script for property value")); - return false; - } else { - d[0] = char(Number); - d += QByteArray::number(v); - } + value = evaluateEnum(script, &ok); } } else { Q_UNREACHABLE(); } - d.append('\0'); - data.append(d); - - ListInstruction li; - li.type = ListInstruction::Value; - li.dataIdx = ref; - instr << li; + model->setOrCreateProperty(outterElementIndex, elementName, value); + roleSet = true; } - - return true; + return roleSet; } -QByteArray QQmlListModelParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) +void QQmlListModelParser::verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) { - QList<ListInstruction> instr; - QByteArray data; listElementTypeName = QString(); // unknown foreach (const QV4::CompiledData::Binding *binding, bindings) { QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex); if (!propName.isEmpty()) { // isn't default property error(binding, QQmlListModel::tr("ListModel: undefined property '%1'").arg(propName)); - return QByteArray(); + return; } - if (!compileProperty(qmlUnit, binding, instr, data)) - return QByteArray(); + if (!verifyProperty(qmlUnit, binding)) + return; } - - int size = sizeof(ListModelData) + - instr.count() * sizeof(ListInstruction) + - data.count(); - - QByteArray rv; - rv.resize(size); - - ListModelData *lmd = (ListModelData *)rv.data(); - lmd->dataOffset = sizeof(ListModelData) + - instr.count() * sizeof(ListInstruction); - lmd->instrCount = instr.count(); - for (int ii = 0; ii < instr.count(); ++ii) - lmd->instructions()[ii] = instr.at(ii); - ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count()); - - return rv; } -void QQmlListModelParser::setCustomData(QObject *obj, const QByteArray &d, QQmlCompiledData *) +void QQmlListModelParser::applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) { QQmlListModel *rv = static_cast<QQmlListModel *>(obj); QV8Engine *engine = QQmlEnginePrivate::getV8Engine(qmlEngine(rv)); rv->m_engine = engine; - const ListModelData *lmd = (const ListModelData *)d.constData(); - const char *data = ((const char *)lmd) + lmd->dataOffset; + const QV4::CompiledData::QmlUnit *qmlUnit = cdata->qmlUnit; bool setRoles = false; - QStack<DataStackElement> stack; - - for (int ii = 0; ii < lmd->instrCount; ++ii) { - const ListInstruction &instr = lmd->instructions()[ii]; - - switch(instr.type) { - case ListInstruction::Push: - { - Q_ASSERT(!rv->m_dynamicRoles); - - ListModel *subModel = 0; - - if (stack.count() == 0) { - subModel = rv->m_listModel; - } else { - const DataStackElement &e0 = stack.at(stack.size() - 1); - DataStackElement &e1 = stack[stack.size() - 2]; - - const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name); - if (role.type == ListLayout::Role::List) { - subModel = e1.model->getListProperty(e1.elementIndex, role); - - if (subModel == 0) { - subModel = new ListModel(role.subLayout, 0, -1); - QVariant vModel = QVariant::fromValue(subModel); - e1.model->setOrCreateProperty(e1.elementIndex, e0.name, vModel); - } - } - } - - DataStackElement e; - e.model = subModel; - e.elementIndex = subModel ? subModel->appendElement() : -1; - stack.push(e); - } - break; - - case ListInstruction::Pop: - stack.pop(); - break; - - case ListInstruction::Value: - { - const DataStackElement &e0 = stack.at(stack.size() - 1); - DataStackElement &e1 = stack[stack.size() - 2]; - - QString name = e0.name; - QVariant value; - - switch (PropertyType(data[instr.dataIdx])) { - case Invalid: - { - const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name); - ListModel *emptyModel = new ListModel(role.subLayout, 0, -1); - value = QVariant::fromValue(emptyModel); - } - break; - case Boolean: - value = bool(data[1 + instr.dataIdx]); - break; - case Number: - value = QByteArray(data + 1 + instr.dataIdx).toDouble(); - break; - case String: - value = QString::fromUtf8(data + 1 + instr.dataIdx); - break; - default: - Q_ASSERT("Format error in ListInstruction"); - } - - e1.model->setOrCreateProperty(e1.elementIndex, name, value); - setRoles = true; - } - break; - - case ListInstruction::Set: - { - DataStackElement e; - e.name = QString::fromUtf8(data + instr.dataIdx); - stack.push(e); - } - break; - } + foreach (const QV4::CompiledData::Binding *binding, bindings) { + if (binding->type != QV4::CompiledData::Binding::Type_Object) + continue; + setRoles |= applyProperty(qmlUnit, binding, rv->m_listModel, /*outter element index*/-1); } if (setRoles == false) diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h index 54ed18865f..59cfce81e5 100644 --- a/src/qml/types/qqmllistmodel_p.h +++ b/src/qml/types/qqmllistmodel_p.h @@ -168,41 +168,20 @@ public: QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {} - QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); - void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *); + + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); + virtual void applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings); private: - struct ListInstruction - { - enum { Push, Pop, Value, Set } type; - int dataIdx; - }; - struct ListModelData - { - int dataOffset; - int instrCount; - ListInstruction *instructions() const; - }; - bool compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, QList<ListInstruction> &instr, QByteArray &data); + bool verifyProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding); + // returns true if a role was set + bool applyProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, ListModel *model, int outterElementIndex); bool definesEmptyList(const QString &); QString listElementTypeName; - - struct DataStackElement - { - DataStackElement() : model(0), elementIndex(0) {} - - QString name; - ListModel *model; - int elementIndex; - }; - - friend class QTypeInfo<QQmlListModelParser::ListInstruction>; }; -Q_DECLARE_TYPEINFO(QQmlListModelParser::ListInstruction, Q_PRIMITIVE_TYPE); - QT_END_NAMESPACE QML_DECLARE_TYPE(QQmlListModel) diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp index 1a631703fb..5b5b8cac3c 100644 --- a/src/quick/util/qquickpropertychanges.cpp +++ b/src/quick/util/qquickpropertychanges.cpp @@ -204,7 +204,7 @@ public: isExplicit(false) {} QPointer<QObject> object; - QByteArray data; + QList<const QV4::CompiledData::Binding *> bindings; QQmlRefPointer<QQmlCompiledData> cdata; bool decoded : 1; @@ -212,6 +212,7 @@ public: bool isExplicit : 1; void decode(); + void decodeBinding(const QString &propertyPrefix, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding); class ExpressionChange { public: @@ -237,10 +238,8 @@ public: QQmlProperty property(const QString &); }; -void QQuickPropertyChangesParser::compileList(QList<QPair<QString, const QV4::CompiledData::Binding*> > &list, const QString &pre, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding) +void QQuickPropertyChangesParser::verifyList(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding) { - QString propName = pre + qmlUnit->header.stringAt(binding->propertyNameIndex); - if (binding->type == QV4::CompiledData::Binding::Type_Object) { error(qmlUnit->objectAt(binding->value.objectIndex), QQuickPropertyChanges::tr("PropertyChanges does not support creating state-specific objects.")); return; @@ -248,129 +247,105 @@ void QQuickPropertyChangesParser::compileList(QList<QPair<QString, const QV4::Co if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { - QString pre = propName + QLatin1Char('.'); const QV4::CompiledData::Object *subObj = qmlUnit->objectAt(binding->value.objectIndex); const QV4::CompiledData::Binding *subBinding = subObj->bindingTable(); for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) { - compileList(list, pre, qmlUnit, subBinding); + verifyList(qmlUnit, subBinding); } - return; } - - list << qMakePair(propName, binding); } -QByteArray QQuickPropertyChangesParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props) +void QQuickPropertyChangesPrivate::decode() { - QList<QPair<QString, const QV4::CompiledData::Binding *> > data; - for (int ii = 0; ii < props.count(); ++ii) - compileList(data, QString(), qmlUnit, props.at(ii)); - - QByteArray rv; - QDataStream ds(&rv, QIODevice::WriteOnly); - - ds << data.count(); - for (int ii = 0; ii < data.count(); ++ii) { - const QV4::CompiledData::Binding *binding = data.at(ii).second; - ds << data.at(ii).first << int(binding->type); - QVariant var; - switch (binding->type) { - case QV4::CompiledData::Binding::Type_Script: - ds << bindingIdentifier(binding); - // Fall through as we also need the expression string. - // Signal handlers still need to be constructed by string ;( - case QV4::CompiledData::Binding::Type_String: - var = binding->valueAsString(&qmlUnit->header); - break; - case QV4::CompiledData::Binding::Type_Number: - var = binding->valueAsNumber(); - break; - case QV4::CompiledData::Binding::Type_Boolean: - var = binding->valueAsBoolean(); - break; - case QV4::CompiledData::Binding::Type_Translation: - case QV4::CompiledData::Binding::Type_TranslationById: - ds << binding->value.translationData.commentIndex << binding->value.translationData.number; - var = binding->stringIndex; - default: - break; - } - ds << var; - } + if (decoded) + return; + + foreach (const QV4::CompiledData::Binding *binding, bindings) + decodeBinding(QString(), cdata->qmlUnit, binding); + + bindings.clear(); - return rv; + decoded = true; } -void QQuickPropertyChangesPrivate::decode() +void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding) { Q_Q(QQuickPropertyChanges); - if (decoded) - return; - QDataStream ds(&data, QIODevice::ReadOnly); + QString propertyName = propertyPrefix + qmlUnit->header.stringAt(binding->propertyNameIndex); - int count; - ds >> count; - for (int ii = 0; ii < count; ++ii) { - QString name; - int type; - QVariant data; - QQmlBinding::Identifier id = QQmlBinding::Invalid; - QV4::CompiledData::TranslationData tsd; - ds >> name; - ds >> type; - - if (type == QV4::CompiledData::Binding::Type_Script) { - ds >> id; - } else if (type == QV4::CompiledData::Binding::Type_Translation - || type == QV4::CompiledData::Binding::Type_TranslationById) { - ds >> tsd.commentIndex >> tsd.number; + if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty + || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { + QString pre = propertyName + QLatin1Char('.'); + const QV4::CompiledData::Object *subObj = qmlUnit->objectAt(binding->value.objectIndex); + const QV4::CompiledData::Binding *subBinding = subObj->bindingTable(); + for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) { + decodeBinding(pre, qmlUnit, subBinding); } + return; + } - ds >> data; - - QQmlProperty prop = property(name); //### better way to check for signal property? - if (prop.type() & QQmlProperty::SignalProperty) { - QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler; - handler->property = prop; - handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(), - QQmlContextData::get(qmlContext(q)), object, cdata->functionForBindingId(id))); - signalReplacements << handler; - } else if (type == QV4::CompiledData::Binding::Type_Script) { // binding - QString expression = data.toString(); - QUrl url = QUrl(); - int line = -1; - int column = -1; - - QQmlData *ddata = QQmlData::get(q); - if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) { - url = ddata->outerContext->url; - line = ddata->lineNumber; - column = ddata->columnNumber; - } + QQmlProperty prop = property(propertyName); //### better way to check for signal property? - expressions << ExpressionChange(name, id, expression, url, line, column); - } else { - if (type == QV4::CompiledData::Binding::Type_Translation - || type == QV4::CompiledData::Binding::Type_TranslationById) { - QV4::CompiledData::Binding tmpBinding; - tmpBinding.type = type; - tmpBinding.stringIndex = data.toInt(); - tmpBinding.value.translationData = tsd; - data = tmpBinding.valueAsString(&cdata->qmlUnit->header); - } - properties << qMakePair(name, data); + if (prop.type() & QQmlProperty::SignalProperty) { + QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler; + handler->property = prop; + handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(), + QQmlContextData::get(qmlContext(q)), object, cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex])); + signalReplacements << handler; + return; + } + + if (binding->type == QV4::CompiledData::Binding::Type_Script) { + QString expression = binding->valueAsString(&qmlUnit->header); + QUrl url = QUrl(); + int line = -1; + int column = -1; + + QQmlData *ddata = QQmlData::get(q); + if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) { + url = ddata->outerContext->url; + line = ddata->lineNumber; + column = ddata->columnNumber; } + + expressions << ExpressionChange(propertyName, binding->value.compiledScriptIndex, expression, url, line, column); + return; } - decoded = true; - data.clear(); + + QVariant var; + switch (binding->type) { + case QV4::CompiledData::Binding::Type_Script: + Q_UNREACHABLE(); + case QV4::CompiledData::Binding::Type_Translation: + case QV4::CompiledData::Binding::Type_TranslationById: + case QV4::CompiledData::Binding::Type_String: + var = binding->valueAsString(&qmlUnit->header); + break; + case QV4::CompiledData::Binding::Type_Number: + var = binding->valueAsNumber(); + break; + case QV4::CompiledData::Binding::Type_Boolean: + var = binding->valueAsBoolean(); + break; + default: + break; + } + + properties << qMakePair(propertyName, var); } -void QQuickPropertyChangesParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *cdata) +void QQuickPropertyChangesParser::verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props) +{ + for (int ii = 0; ii < props.count(); ++ii) + verifyList(qmlUnit, props.at(ii)); +} + +void QQuickPropertyChangesParser::applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) { QQuickPropertyChangesPrivate *p = - static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(object)); - p->data = data; + static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(obj)); + p->bindings = bindings; p->cdata = cdata; p->decoded = false; } @@ -479,9 +454,17 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions() a.specifiedObject = d->object; a.specifiedProperty = property; - QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this)) : 0; + QQmlContextData *context = QQmlContextData::get(qmlContext(this)); + + QQmlBinding *newBinding = 0; + if (e.id != QQmlBinding::Invalid) { + QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this))); + QV4::ScopedValue function(scope, QV4::QmlBindingWrapper::createQmlCallableForFunction(context, object(), d->cdata->compilationUnit->runtimeFunctions[e.id])); + newBinding = new QQmlBinding(function, object(), context); + } +// QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this)) : 0; if (!newBinding) - newBinding = new QQmlBinding(e.expression, object(), QQmlContextData::get(qmlContext(this)), e.url.toString(), e.line, e.column); + newBinding = new QQmlBinding(e.expression, object(), context, e.url.toString(), e.line, e.column); if (d->isExplicit) { // in this case, we don't want to assign a binding, per se, diff --git a/src/quick/util/qquickpropertychanges_p.h b/src/quick/util/qquickpropertychanges_p.h index 3eed151d11..971aade7f2 100644 --- a/src/quick/util/qquickpropertychanges_p.h +++ b/src/quick/util/qquickpropertychanges_p.h @@ -92,10 +92,10 @@ public: QQuickPropertyChangesParser() : QQmlCustomParser(AcceptsAttachedProperties) {} - void compileList(QList<QPair<QString, const QV4::CompiledData::Binding *> > &list, const QString &pre, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding); + void verifyList(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding); - virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props); - virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *); + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props); + virtual void applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings); }; diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index 8ffa327cf2..1498fba9e2 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -40,6 +40,8 @@ ****************************************************************************/ #include "testtypes.h" +#include <private/qqmlcompiler_p.h> + void registerTypes() { qmlRegisterInterface<MyInterface>("MyInterface"); @@ -105,105 +107,70 @@ QVariant myCustomVariantTypeConverter(const QString &data) } -QByteArray CustomBindingParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) -{ - QByteArray result; - QDataStream ds(&result, QIODevice::WriteOnly); - - ds << bindings.count(); - for (int i = 0; i < bindings.count(); ++i) { - const QV4::CompiledData::Binding *binding = bindings.at(i); - ds << qmlUnit->header.stringAt(binding->propertyNameIndex); - - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script); - int bindingId = bindingIdentifier(binding); - ds << bindingId; - - ds << binding->location.line; - } - - return result; -} - -void CustomBindingParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData*) +void CustomBindingParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) { CustomBinding *customBinding = qobject_cast<CustomBinding*>(object); Q_ASSERT(customBinding); - customBinding->m_bindingData = data; + customBinding->cdata = cdata; + customBinding->bindings = bindings; } void CustomBinding::componentComplete() { Q_ASSERT(m_target); - QDataStream ds(m_bindingData); - int count; - ds >> count; - for (int i = 0; i < count; ++i) { - QString name; - ds >> name; + foreach (const QV4::CompiledData::Binding *binding, bindings) { + QString name = cdata->compilationUnit->data->stringAt(binding->propertyNameIndex); - int bindingId; - ds >> bindingId; + int bindingId = binding->value.compiledScriptIndex; - int line; - ds >> line; + QQmlContextData *context = QQmlContextData::get(qmlContext(this)); - QQmlBinding *binding = QQmlBinding::createBinding(QQmlBinding::Identifier(bindingId), m_target, qmlContext(this)); + QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this))); + QV4::ScopedValue function(scope, QV4::QmlBindingWrapper::createQmlCallableForFunction(context, m_target, cdata->compilationUnit->runtimeFunctions[bindingId])); + QQmlBinding *qmlBinding = new QQmlBinding(function, m_target, context); QQmlProperty property(m_target, name, qmlContext(this)); - binding->setTarget(property); - QQmlPropertyPrivate::setBinding(property, binding); + qmlBinding->setTarget(property); + QQmlPropertyPrivate::setBinding(property, qmlBinding); } } -QByteArray EnumSupportingCustomParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) +void EnumSupportingCustomParser::verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) { - Q_UNUSED(qmlUnit) - if (bindings.count() != 1) { error(bindings.first(), QStringLiteral("Custom parser invoked incorrectly for unit test")); - return QByteArray(); + return; } const QV4::CompiledData::Binding *binding = bindings.first(); if (qmlUnit->header.stringAt(binding->propertyNameIndex) != QStringLiteral("foo")) { error(binding, QStringLiteral("Custom parser invoked with the wrong property name")); - return QByteArray(); + return; } if (binding->type != QV4::CompiledData::Binding::Type_Script) { error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Expected script that evaluates to enum")); - return QByteArray(); + return; } QByteArray script = qmlUnit->header.stringAt(binding->stringIndex).toUtf8(); bool ok; int v = evaluateEnum(script, &ok); if (!ok) { error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Script did not evaluate to enum")); - return QByteArray(); + return; } if (v != MyEnum1Class::A_13) { error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Enum value is not the expected value.")); - return QByteArray(); + return; } - - return QByteArray(); -} - - -QByteArray SimpleObjectCustomParser::compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &bindings) -{ - return QByteArray::number(bindings.count()); } -void SimpleObjectCustomParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData*) +void SimpleObjectCustomParser::applyBindings(QObject *object, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &bindings) { - SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object); - Q_ASSERT(o); - bool ok = false; - o->setCustomBindingsCount(data.toInt(&ok)); - Q_ASSERT(ok); + SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object); + Q_ASSERT(o); + o->setCustomBindingsCount(bindings.count()); } diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 1c13a2e21c..509cf40e47 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -54,7 +54,7 @@ #include <QtQml/qqmlpropertyvaluesource.h> #include <QtQml/qqmlscriptstring.h> #include <QtQml/qqmlproperty.h> - +#include <private/qqmlcompiler_p.h> #include <private/qqmlcustomparser_p.h> QVariant myCustomVariantTypeConverter(const QString &data); @@ -739,15 +739,15 @@ class MyCustomParserType : public QObject class MyCustomParserTypeParser : public QQmlCustomParser { public: - QByteArray compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) { return QByteArray(); } - void setCustomData(QObject *, const QByteArray &, QQmlCompiledData*) {} + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) {} + virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {} }; class EnumSupportingCustomParser : public QQmlCustomParser { public: - QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); - void setCustomData(QObject *, const QByteArray &, QQmlCompiledData*) {} + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &); + virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {} }; class MyParserStatus : public QObject, public QQmlParserStatus @@ -1112,13 +1112,15 @@ public: void setTarget(QObject *newTarget) { m_target = newTarget; } QPointer<QObject> m_target; + QQmlRefPointer<QQmlCompiledData> cdata; + QList<const QV4::CompiledData::Binding*> bindings; QByteArray m_bindingData; }; class CustomBindingParser : public QQmlCustomParser { - virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); - virtual void setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *); + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) {} + virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &); }; class SimpleObjectWithCustomParser : public QObject @@ -1144,8 +1146,8 @@ private: class SimpleObjectCustomParser : public QQmlCustomParser { - virtual QByteArray compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &bindings); - virtual void setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *); + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) {} + virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &); }; class RootObjectInCreationTester : public QObject diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp index 9b57eeffa9..22404aa862 100644 --- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp +++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp @@ -352,12 +352,12 @@ void tst_qqmllistmodel::dynamic_i18n_data() QTest::newRow("qsTr") << QString::fromUtf8("ListElement { foo: qsTr(\"test\") }") << QVariant(QString::fromUtf8("test")) - << QString("ListElement: cannot use script for property value"); + << QString(); QTest::newRow("qsTrId") << "ListElement { foo: qsTrId(\"qtn_test\") }" << QVariant(QString("qtn_test")) - << QString("ListElement: cannot use script for property value"); + << QString(); } void tst_qqmllistmodel::dynamic_i18n() |