aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2014-04-25 16:19:02 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-06-04 08:25:52 +0200
commit52e07d564b65ed6ce26955a676c7692ad67686c1 (patch)
tree04354cdf1d56776e9b52819f4329b70c57e235dc
parent481447ae664fa2998cb03f93f0c066caa2782bf0 (diff)
Rework custom parser integration
The custom parser design used to be so that the custom parser operates on the "AST", creates its own binary representation of the data it needs, stores it in a QByteArray and gets that at object instantiation time. That meant serializing everything necessary. With the introduction of the "binary" QML data structure, that process of serialization becomes obsolete and would require extra work in the custom parsers for example for QQuickStates to store the translation parameters. The clean solution is to eliminate this unnecessary serialization process and instead let the custom parsers do a verification pass at type compile time and then simply operate directly on the QV4::CompiledData::Bindings at object instantiation time. That simplifies the code, and allows for support of translations throughout all list model properties. Additionally this speeds up the creation of state objects and reduces memory consumption. Previously a text: qsTr("foo") binding in states would result in an actual java script binding. After this patch it is merely stored as a string and translated at object instantiation time. Change-Id: I7550274513f54abb09a0ab4de51c4c0bcdb23cae Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp27
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h7
-rw-r--r--src/qml/jsruntime/qv4script_p.h2
-rw-r--r--src/qml/qml/qqmlbinding.cpp28
-rw-r--r--src/qml/qml/qqmlbinding_p.h2
-rw-r--r--src/qml/qml/qqmlcompiler_p.h12
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp46
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h10
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp17
-rw-r--r--src/qml/types/qqmlconnections.cpp53
-rw-r--r--src/qml/types/qqmlconnections_p.h4
-rw-r--r--src/qml/types/qqmllistmodel.cpp240
-rw-r--r--src/qml/types/qqmllistmodel_p.h33
-rw-r--r--src/quick/util/qquickpropertychanges.cpp193
-rw-r--r--src/quick/util/qquickpropertychanges_p.h6
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp81
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h20
-rw-r--r--tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp4
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()