aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-09-16 17:25:53 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-20 14:26:43 +0200
commitf7cd6238ada2745eea13ceff168e7d65b7263866 (patch)
tree5c91c251eb3c2ddf1d56dae4ede28af3539b2345
parent2b832d20185aff91dfa0515cc3f9268240c917a7 (diff)
[new compiler] Finish support for initializing list properties
Setting a value on a list property is always just appending to the list instead of replacing it. Based on that, initializing list properties with multiple items is done with one binding per item to the same list property. So myList: [ Item{}, Item{} ] is mapped to myList: Item {} myList: Item {} Change-Id: Iadc048ab3a8d73ac824aa6b2ae5dec33731fa362 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp37
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h4
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp279
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h2
4 files changed, 181 insertions, 141 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index 3c525668f4..9d7af90b81 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -151,7 +151,7 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
qSwap(_objects, output->objects);
qSwap(_functions, output->functions);
qSwap(_typeReferences, output->typeReferences);
- return true;
+ return errors.isEmpty();
}
bool QQmlCodeGenerator::isSignalPropertyName(const QString &name)
@@ -216,9 +216,24 @@ bool QQmlCodeGenerator::visit(AST::UiScriptBinding *node)
return false;
}
-bool QQmlCodeGenerator::visit(AST::UiArrayBinding*)
+bool QQmlCodeGenerator::visit(AST::UiArrayBinding *node)
{
- return true;
+ QmlObject *object = 0;
+ AST::UiQualifiedId *name = resolveQualifiedId(node->qualifiedId, &object);
+ qSwap(_object, object);
+
+ AST::UiArrayMemberList *member = node->members;
+ while (member) {
+ AST::UiObjectDefinition *def = AST::cast<AST::UiObjectDefinition*>(member->member);
+
+ int idx = defineQMLObject(def);
+ appendBinding(name->identifierToken, registerString(name->name.toString()), idx, /*isListItem*/ true);
+
+ member = member->next;
+ }
+
+ qSwap(_object, object);
+ return false;
}
bool QQmlCodeGenerator::visit(AST::UiImportList *list)
@@ -603,7 +618,6 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
}
// process QML-like initializers (e.g. property Object o: Object {})
- // ### check if this is correct?
AST::Node::accept(node->binding, this);
}
@@ -749,9 +763,9 @@ void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, i
_object->bindings->append(binding);
}
-void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex)
+void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex, bool isListItem)
{
- if (!sanityCheckPropertyName(nameLocation, propertyNameIndex))
+ if (!sanityCheckPropertyName(nameLocation, propertyNameIndex, isListItem))
return;
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
@@ -828,16 +842,19 @@ AST::UiQualifiedId *QQmlCodeGenerator::resolveQualifiedId(AST::UiQualifiedId *na
return name;
}
-bool QQmlCodeGenerator::sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex)
+bool QQmlCodeGenerator::sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex, bool isListItem)
{
const QString &name = jsGenerator->strings.at(nameIndex);
if (name.isEmpty())
return true;
- if (_propertyNames.contains(name))
- COMPILE_EXCEPTION(nameLocation, tr("Duplicate property name"));
+ // List items are implement by multiple bindings to the same name, so allow duplicates.
+ if (!isListItem) {
+ if (_propertyNames.contains(name))
+ COMPILE_EXCEPTION(nameLocation, tr("Duplicate property name"));
- _propertyNames.insert(name);
+ _propertyNames.insert(name);
+ }
if (name.at(0).isUpper())
COMPILE_EXCEPTION(nameLocation, tr("Property names cannot begin with an upper case letter"));
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index 7569b9cc7d..4562e88d34 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -224,7 +224,7 @@ public:
void appendBinding(AST::UiQualifiedId *name, AST::Statement *value);
void appendBinding(AST::UiQualifiedId *name, int objectIndex);
void appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, AST::Statement *value);
- void appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex);
+ void appendBinding(const AST::SourceLocation &nameLocation, int propertyNameIndex, int objectIndex, bool isListItem = false);
bool setId(AST::Statement *value);
@@ -232,7 +232,7 @@ public:
// with the object any right-hand-side of a binding should apply to.
AST::UiQualifiedId *resolveQualifiedId(AST::UiQualifiedId *name, QmlObject **object);
- bool sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex);
+ bool sanityCheckPropertyName(const AST::SourceLocation &nameLocation, int nameIndex, bool isListItem = false);
void recordError(const AST::SourceLocation &location, const QString &description);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 9aaf3e4b6c..9260c1609e 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -881,164 +881,185 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C
void QmlObjectCreator::setupBindings(QV4::ExecutionContext *qmlContext)
{
+ QQmlListProperty<void> savedList;
+ qSwap(_currentList, savedList);
+
+ QQmlPropertyData *property = 0;
+
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- const QV4::CompiledData::Object *obj = unit->objectAt(binding->value.objectIndex);
- Q_ASSERT(stringAt(obj->inheritedTypeNameIndex).isEmpty());
- QQmlType *attachedType = resolvedTypes.value(binding->propertyNameIndex).type;
- const int id = attachedType->attachedPropertiesId();
- QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject);
- QQmlRefPointer<QQmlPropertyCache> cache = QQmlEnginePrivate::get(engine)->cache(qmlObject);
- if (!populateInstance(binding->value.objectIndex, qmlObject, cache))
- break;
- continue;
- }
- QString name = stringAt(binding->propertyNameIndex);
+ if (!property || (i > 0 && (binding - 1)->propertyNameIndex != binding->propertyNameIndex)) {
+ QString name = stringAt(binding->propertyNameIndex);
+ if (!name.isEmpty())
+ property = _propertyCache->property(name, _qobject, context);
+ else
+ property = 0;
- QObject *createdSubObject = 0;
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- createdSubObject = create(binding->value.objectIndex, _qobject);
- if (!createdSubObject)
- return;
- }
+ if (property && property->isQList()) {
+ void *argv[1] = { (void*)&_currentList };
+ QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv);
+ } else if (_currentList.object)
+ _currentList = QQmlListProperty<void>();
- // Child item:
- // ...
- // Item {
- // ...
- // }
- if (name.isEmpty())
- continue;
+ }
- QQmlPropertyData *property = _propertyCache->property(name, _qobject, context);
+ if (!setPropertyValue(qmlContext, property, i, binding))
+ return;
+ }
- if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
- const QV4::CompiledData::Object *obj = unit->objectAt(binding->value.objectIndex);
- if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) {
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(property->propType);
+ qSwap(_currentList, savedList);
+}
- valueType->read(_qobject, property->coreIndex);
+bool QmlObjectCreator::setPropertyValue(QV4::ExecutionContext *qmlContext, QQmlPropertyData *property,
+ int bindingIndex, const QV4::CompiledData::Binding *binding)
+{
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ const QV4::CompiledData::Object *obj = unit->objectAt(binding->value.objectIndex);
+ Q_ASSERT(stringAt(obj->inheritedTypeNameIndex).isEmpty());
+ QQmlType *attachedType = resolvedTypes.value(binding->propertyNameIndex).type;
+ const int id = attachedType->attachedPropertiesId();
+ QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject);
+ QQmlRefPointer<QQmlPropertyCache> cache = QQmlEnginePrivate::get(engine)->cache(qmlObject);
+ if (!populateInstance(binding->value.objectIndex, qmlObject, cache))
+ return false;
+ return true;
+ }
- QQmlRefPointer<QQmlPropertyCache> cache = QQmlEnginePrivate::get(engine)->cache(valueType);
- if (!populateInstance(binding->value.objectIndex, valueType, cache))
- break;
+ QObject *createdSubObject = 0;
+ if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ createdSubObject = create(binding->value.objectIndex, _qobject);
+ if (!createdSubObject)
+ return false;
+ }
- valueType->write(_qobject, property->coreIndex, QQmlPropertyPrivate::BypassInterceptor);
- continue;
- }
- }
+ // Child item:
+ // ...
+ // Item {
+ // ...
+ // }
+ if (!property)
+ return true;
- if (_ddata->hasBindingBit(property->coreIndex))
- removeBindingOnProperty(_qobject, property->coreIndex);
+ if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ const QV4::CompiledData::Object *obj = unit->objectAt(binding->value.objectIndex);
+ if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) {
+ QQmlValueType *valueType = QQmlValueTypeFactory::valueType(property->propType);
- if (binding->type == QV4::CompiledData::Binding::Type_Script) {
- QV4::Function *runtimeFunction = jsUnit->runtimeFunctions[binding->value.compiledScriptIndex];
- QV4::Value function = QV4::Value::fromObject(QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction));
+ valueType->read(_qobject, property->coreIndex);
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
- int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex);
- QQmlBoundSignal *bs = new QQmlBoundSignal(_qobject, signalIndex, _qobject, engine);
- QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_qobject, signalIndex,
- context, _qobject, function);
+ QQmlRefPointer<QQmlPropertyCache> cache = QQmlEnginePrivate::get(engine)->cache(valueType);
+ if (!populateInstance(binding->value.objectIndex, valueType, cache))
+ return false;
- bs->takeExpression(expr);
- } else {
- QQmlBinding *qmlBinding = new QQmlBinding(function, _qobject, context,
- QString(), 0, 0); // ###
+ valueType->write(_qobject, property->coreIndex, QQmlPropertyPrivate::BypassInterceptor);
+ return true;
+ }
+ }
- qmlBinding->setTarget(_qobject, *property, context);
- qmlBinding->addToObject();
+ if (_ddata->hasBindingBit(property->coreIndex))
+ removeBindingOnProperty(_qobject, property->coreIndex);
- _createdBindings[i] = qmlBinding;
- qmlBinding->m_mePtr = &_createdBindings[i];
- }
- continue;
- }
+ if (binding->type == QV4::CompiledData::Binding::Type_Script) {
+ QV4::Function *runtimeFunction = jsUnit->runtimeFunctions[binding->value.compiledScriptIndex];
+ QV4::Value function = QV4::Value::fromObject(QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction));
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
- int propertyWriteStatus = -1;
- void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags };
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
+ int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex);
+ QQmlBoundSignal *bs = new QQmlBoundSignal(_qobject, signalIndex, _qobject, engine);
+ QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_qobject, signalIndex,
+ context, _qobject, function);
- if (const char *iid = QQmlMetaType::interfaceIId(property->propType)) {
- void *ptr = createdSubObject->qt_metacast(iid);
- if (ptr) {
- argv[0] = &ptr;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Cannot assign object to interface property"));
- break;
- }
- } else if (property->propType == QMetaType::QVariant) {
- if (property->isVarProperty()) {
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
- QV4::Scope scope(v4);
- QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(QV8Engine::getV4(engine), createdSubObject));
- _vmeMetaObject->setVMEProperty(property->coreIndex, wrappedObject);
- } else {
- QVariant value = QVariant::fromValue(createdSubObject);
- argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- }
- } else if (property->isQList()) {
- QQmlListProperty<void> list;
- argv[0] = (void*)&list;
- QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv);
+ bs->takeExpression(expr);
+ } else {
+ QQmlBinding *qmlBinding = new QQmlBinding(function, _qobject, context,
+ QString(), 0, 0); // ###
+ qmlBinding->setTarget(_qobject, *property, context);
+ qmlBinding->addToObject();
- void *itemToAdd = createdSubObject;
+ _createdBindings[bindingIndex] = qmlBinding;
+ qmlBinding->m_mePtr = &_createdBindings[bindingIndex];
+ }
+ return true;
+ }
- const char *iid = 0;
- int listItemType = QQmlEnginePrivate::get(engine)->listType(property->propType);
- if (listItemType != -1)
- iid = QQmlMetaType::interfaceIId(listItemType);
- if (iid)
- itemToAdd = createdSubObject->qt_metacast(iid);
+ if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
+ QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
+ int propertyWriteStatus = -1;
+ void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags };
- if (list.append)
- list.append(&list, itemToAdd);
+ if (const char *iid = QQmlMetaType::interfaceIId(property->propType)) {
+ void *ptr = createdSubObject->qt_metacast(iid);
+ if (ptr) {
+ argv[0] = &ptr;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
} else {
- QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
-
- // We want to raw metaObject here as the raw metaobject is the
- // actual property type before we applied any extensions that might
- // effect the properties on the type, but don't effect assignability
- QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType);
-
- // Will be true if the assgned type inherits propertyMetaObject
- bool isAssignable = false;
- // Determine isAssignable value
- if (propertyMetaObject) {
- QQmlPropertyCache *c = enginePrivate->cache(createdSubObject);
- while (c && !isAssignable) {
- isAssignable |= c == propertyMetaObject;
- c = c->parent();
- }
- }
+ recordError(binding->location, tr("Cannot assign object to interface property"));
+ return false;
+ }
+ } else if (property->propType == QMetaType::QVariant) {
+ if (property->isVarProperty()) {
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::Scope scope(v4);
+ QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(QV8Engine::getV4(engine), createdSubObject));
+ _vmeMetaObject->setVMEProperty(property->coreIndex, wrappedObject);
+ } else {
+ QVariant value = QVariant::fromValue(createdSubObject);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ }
+ } else if (property->isQList()) {
+ Q_ASSERT(_currentList.object);
- if (isAssignable) {
- argv[0] = &createdSubObject;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
- } else {
- recordError(binding->location, tr("Cannot assign object to property"));
- break;
+ void *itemToAdd = createdSubObject;
+
+ const char *iid = 0;
+ int listItemType = QQmlEnginePrivate::get(engine)->listType(property->propType);
+ if (listItemType != -1)
+ iid = QQmlMetaType::interfaceIId(listItemType);
+ if (iid)
+ itemToAdd = createdSubObject->qt_metacast(iid);
+
+ if (_currentList.append)
+ _currentList.append(&_currentList, itemToAdd);
+ } else {
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
+
+ // We want to raw metaObject here as the raw metaobject is the
+ // actual property type before we applied any extensions that might
+ // effect the properties on the type, but don't effect assignability
+ QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType);
+
+ // Will be true if the assgned type inherits propertyMetaObject
+ bool isAssignable = false;
+ // Determine isAssignable value
+ if (propertyMetaObject) {
+ QQmlPropertyCache *c = enginePrivate->cache(createdSubObject);
+ while (c && !isAssignable) {
+ isAssignable |= c == propertyMetaObject;
+ c = c->parent();
}
}
- continue;
- }
- if (property->isQList()) {
- recordError(binding->location, tr("Cannot assign primitives to lists"));
- break;
+ if (isAssignable) {
+ argv[0] = &createdSubObject;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
+ } else {
+ recordError(binding->location, tr("Cannot assign object to property"));
+ return false;
+ }
}
+ return true;
+ }
- setPropertyValue(property, binding);
-
- if (!errors.isEmpty())
- break;
+ if (property->isQList()) {
+ recordError(binding->location, tr("Cannot assign primitives to lists"));
+ return false;
}
+
+ setPropertyValue(property, binding);
+ return true;
}
void QmlObjectCreator::setupFunctions(QV4::ExecutionContext *qmlContext)
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index f3ff6f6e08..62c344194e 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -97,6 +97,7 @@ private:
bool populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache);
void setupBindings(QV4::ExecutionContext *qmlContext);
+ bool setPropertyValue(QV4::ExecutionContext *qmlContext, QQmlPropertyData *property, int index, const QV4::CompiledData::Binding *binding);
void setPropertyValue(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setupFunctions(QV4::ExecutionContext *qmlContext);
@@ -120,6 +121,7 @@ private:
QQmlRefPointer<QQmlPropertyCache> _propertyCache;
QQmlVMEMetaObject *_vmeMetaObject;
QVector<QQmlAbstractBinding*> _createdBindings;
+ QQmlListProperty<void> _currentList;
};
QT_END_NAMESPACE