aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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()