[new compiler] Fix timing of property assignment error handling
[qt:qtdeclarative.git] / src / qml / qml / qqmlobjectcreator.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the tools applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlobjectcreator_p.h"
43
44 #include <private/qqmlengine_p.h>
45 #include <private/qqmlvmemetaobject_p.h>
46 #include <private/qv4function_p.h>
47 #include <private/qv4functionobject_p.h>
48 #include <private/qqmlcontextwrapper_p.h>
49 #include <private/qqmlbinding_p.h>
50 #include <private/qqmlstringconverters_p.h>
51 #include <private/qqmlboundsignal_p.h>
52 #include <private/qqmltrace_p.h>
53 #include <private/qqmlcomponentattached_p.h>
54 #include <private/qqmlcomponent_p.h>
55 #include <private/qqmlcustomparser_p.h>
56 #include <private/qqmlscriptstring_p.h>
57 #include <private/qqmlpropertyvalueinterceptor_p.h>
58
59 QT_USE_NAMESPACE
60
61 namespace {
62 struct ActiveOCRestorer
63 {
64     ActiveOCRestorer(QmlObjectCreator *creator, QQmlEnginePrivate *ep)
65     : ep(ep), oldCreator(ep->activeObjectCreator) { ep->activeObjectCreator = creator; }
66     ~ActiveOCRestorer() { ep->activeObjectCreator = oldCreator; }
67
68     QQmlEnginePrivate *ep;
69     QmlObjectCreator *oldCreator;
70 };
71 }
72
73 static void removeBindingOnProperty(QObject *o, int index)
74 {
75     int coreIndex = index & 0x0000FFFF;
76     int valueTypeIndex = (index & 0xFFFF0000 ? index >> 16 : -1);
77
78     QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, coreIndex, valueTypeIndex, 0);
79     if (binding) binding->destroy();
80 }
81
82 QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData)
83     : componentAttached(0)
84     , url(compiledData->url)
85     , engine(parentContext->engine)
86     , qmlUnit(compiledData->qmlUnit)
87     , jsUnit(compiledData->compilationUnit)
88     , parentContext(parentContext)
89     , context(0)
90     , resolvedTypes(compiledData->resolvedTypes)
91     , propertyCaches(compiledData->propertyCaches)
92     , vmeMetaObjectData(compiledData->datas)
93     , compiledData(compiledData)
94     , rootContext(0)
95     , _qobject(0)
96     , _scopeObject(0)
97     , _valueTypeProperty(0)
98     , _compiledObject(0)
99     , _ddata(0)
100     , _propertyCache(0)
101     , _vmeMetaObject(0)
102     , _qmlContext(0)
103 {
104     if (!compiledData->isInitialized())
105         compiledData->initialize(engine);
106 }
107
108 QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
109 {
110     int objectToCreate;
111
112     if (subComponentIndex == -1) {
113         objectIndexToId = compiledData->objectIndexToIdForRoot;
114         objectToCreate = qmlUnit->indexOfRootObject;
115     } else {
116         objectIndexToId = compiledData->objectIndexToIdPerComponent[subComponentIndex];
117         const QV4::CompiledData::Object *compObj = qmlUnit->objectAt(subComponentIndex);
118         objectToCreate = compObj->bindingTable()->value.objectIndex;
119     }
120
121     context = new QQmlContextData;
122     context->isInternal = true;
123     context->url = compiledData->url;
124     context->urlString = compiledData->name;
125     context->imports = compiledData->importCache;
126     context->imports->addref();
127     context->setParent(parentContext);
128
129     if (!rootContext)
130         rootContext = context;
131
132     QVector<QQmlContextData::ObjectIdMapping> mapping(objectIndexToId.count());
133     for (QHash<int, int>::ConstIterator it = objectIndexToId.constBegin(), end = objectIndexToId.constEnd();
134          it != end; ++it) {
135         const QV4::CompiledData::Object *obj = qmlUnit->objectAt(it.key());
136
137         QQmlContextData::ObjectIdMapping m;
138         m.id = it.value();
139         m.name = stringAt(obj->idIndex);
140         mapping[m.id] = m;
141     }
142     context->setIdPropertyData(mapping);
143
144     if (subComponentIndex == -1) {
145         QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
146         QV4::Scope scope(v4);
147         QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->scripts.count()));
148         for (int i = 0; i < compiledData->scripts.count(); ++i) {
149             QQmlScriptData *s = compiledData->scripts.at(i);
150             scripts->putIndexed(i, s->scriptValueForContext(context));
151         }
152         context->importedScripts = scripts;
153     } else if (parentContext) {
154         context->importedScripts = parentContext->importedScripts;
155     }
156
157     QVector<QQmlParserStatus*> parserStatusCallbacks;
158     parserStatusCallbacks.resize(qmlUnit->nObjects);
159     qSwap(_parserStatusCallbacks, parserStatusCallbacks);
160
161     QObject *instance = createInstance(objectToCreate, parent);
162     if (instance) {
163         QQmlData *ddata = QQmlData::get(instance);
164         Q_ASSERT(ddata);
165         ddata->compiledData = compiledData;
166         ddata->compiledData->addref();
167
168         context->contextObject = instance;
169     }
170
171     qSwap(_parserStatusCallbacks, parserStatusCallbacks);
172     allParserStatusCallbacks.prepend(parserStatusCallbacks);
173
174     return instance;
175 }
176
177 void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
178 {
179     QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
180                                                                QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
181     int propertyWriteStatus = -1;
182     void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags };
183
184     QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
185     QV4::Scope scope(v4);
186
187     // ### This should be resolved earlier at compile time and the binding value should be changed accordingly.
188     if (property->isEnum()) {
189         QVariant value = binding->valueAsString(&qmlUnit->header);
190         bool ok = QQmlPropertyPrivate::write(_qobject, *property, value, context);
191         Q_ASSERT(ok);
192         Q_UNUSED(ok);
193         return;
194     }
195
196     switch (property->propType) {
197     case QMetaType::QVariant: {
198         if (binding->type == QV4::CompiledData::Binding::Type_Number) {
199             double n = binding->valueAsNumber();
200             if (double(int(n)) == n) {
201                 if (property->isVarProperty()) {
202                     _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Primitive::fromInt32(int(n)));
203                 } else {
204                     int i = int(n);
205                     QVariant value(i);
206                     argv[0] = &value;
207                     QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
208                 }
209             } else {
210                 if (property->isVarProperty()) {
211                     _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Primitive::fromDouble(n));
212                 } else {
213                     QVariant value(n);
214                     argv[0] = &value;
215                     QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
216                 }
217             }
218         } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
219             if (property->isVarProperty()) {
220                 _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Primitive::fromBoolean(binding->valueAsBoolean()));
221             } else {
222                 QVariant value(binding->valueAsBoolean());
223                 argv[0] = &value;
224                 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
225             }
226         } else {
227             QString stringValue = binding->valueAsString(&qmlUnit->header);
228             if (property->isVarProperty()) {
229                 QV4::ScopedString s(scope, v4->newString(stringValue));
230                 _vmeMetaObject->setVMEProperty(property->coreIndex, s);
231             } else {
232                 QVariant value = QQmlStringConverters::variantFromString(stringValue);
233                 argv[0] = &value;
234                 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
235             }
236         }
237     }
238     break;
239     case QVariant::String: {
240         Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
241         QString value = binding->valueAsString(&qmlUnit->header);
242         argv[0] = &value;
243         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
244     }
245     break;
246     case QVariant::StringList: {
247         Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
248         QStringList value(binding->valueAsString(&qmlUnit->header));
249         argv[0] = &value;
250         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
251     }
252     break;
253     case QVariant::ByteArray: {
254         Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
255         QByteArray value(binding->valueAsString(&qmlUnit->header).toUtf8());
256         argv[0] = &value;
257         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
258     }
259     break;
260     case QVariant::Url: {
261         Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
262         QString string = binding->valueAsString(&qmlUnit->header);
263         // Encoded dir-separators defeat QUrl processing - decode them first
264         string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
265         QUrl value = string.isEmpty() ? QUrl() : this->url.resolved(QUrl(string));
266         // Apply URL interceptor
267         if (engine->urlInterceptor())
268             value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
269         argv[0] = &value;
270         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
271     }
272     break;
273     case QVariant::UInt: {
274         Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
275         double d = binding->valueAsNumber();
276         uint value = uint(d);
277         argv[0] = &value;
278         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
279         break;
280     }
281     break;
282     case QVariant::Int: {
283         Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
284         double d = binding->valueAsNumber();
285         int value = int(d);
286         argv[0] = &value;
287         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
288         break;
289     }
290     break;
291     case QMetaType::Float: {
292         Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
293         float value = float(binding->valueAsNumber());
294         argv[0] = &value;
295         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
296     }
297     break;
298     case QVariant::Double: {
299         Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
300         double value = binding->valueAsNumber();
301         argv[0] = &value;
302         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
303     }
304     break;
305     case QVariant::Color: {
306         bool ok = false;
307         uint colorValue = QQmlStringConverters::rgbaFromString(binding->valueAsString(&qmlUnit->header), &ok);
308         Q_ASSERT(ok);
309         struct { void *data[4]; } buffer;
310         if (QQml_valueTypeProvider()->storeValueType(property->propType, &colorValue, &buffer, sizeof(buffer))) {
311             argv[0] = reinterpret_cast<void *>(&buffer);
312             QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
313         }
314     }
315     break;
316 #ifndef QT_NO_DATESTRING
317     case QVariant::Date: {
318         bool ok = false;
319         QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(&qmlUnit->header), &ok);
320         Q_ASSERT(ok);
321         argv[0] = &value;
322         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
323     }
324     break;
325     case QVariant::Time: {
326         bool ok = false;
327         QTime value = QQmlStringConverters::timeFromString(binding->valueAsString(&qmlUnit->header), &ok);
328         Q_ASSERT(ok);
329         argv[0] = &value;
330         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
331     }
332     break;
333     case QVariant::DateTime: {
334         bool ok = false;
335         QDateTime value = QQmlStringConverters::dateTimeFromString(binding->valueAsString(&qmlUnit->header), &ok);
336         Q_ASSERT(ok);
337         argv[0] = &value;
338         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
339     }
340     break;
341 #endif // QT_NO_DATESTRING
342     case QVariant::Point: {
343         bool ok = false;
344         QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok).toPoint();
345         Q_ASSERT(ok);
346         argv[0] = &value;
347         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
348     }
349     break;
350     case QVariant::PointF: {
351         bool ok = false;
352         QPointF value = QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok);
353         Q_ASSERT(ok);
354         argv[0] = &value;
355         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
356     }
357     break;
358     case QVariant::Size: {
359         bool ok = false;
360         QSize value = QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok).toSize();
361         Q_ASSERT(ok);
362         argv[0] = &value;
363         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
364     }
365     break;
366     case QVariant::SizeF: {
367         bool ok = false;
368         QSizeF value = QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok);
369         Q_ASSERT(ok);
370         argv[0] = &value;
371         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
372     }
373     break;
374     case QVariant::Rect: {
375         bool ok = false;
376         QRect value = QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok).toRect();
377         Q_ASSERT(ok);
378         argv[0] = &value;
379         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
380     }
381     break;
382     case QVariant::RectF: {
383         bool ok = false;
384         QRectF value = QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok);
385         Q_ASSERT(ok);
386         argv[0] = &value;
387         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
388     }
389     break;
390     case QVariant::Bool: {
391         Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
392         bool value = binding->valueAsBoolean();
393         argv[0] = &value;
394         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
395     }
396     break;
397     case QVariant::Vector3D: {
398         struct {
399             float xp;
400             float yp;
401             float zy;
402         } vec;
403         bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec));
404         Q_ASSERT(ok);
405         Q_UNUSED(ok);
406         argv[0] = reinterpret_cast<void *>(&vec);
407         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
408     }
409     break;
410     case QVariant::Vector4D: {
411         struct {
412             float xp;
413             float yp;
414             float zy;
415             float wp;
416         } vec;
417         bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec));
418         Q_ASSERT(ok);
419         Q_UNUSED(ok);
420         argv[0] = reinterpret_cast<void *>(&vec);
421         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
422     }
423     break;
424     case QVariant::RegExp:
425         Q_ASSERT(!"not possible");
426         break;
427     default: {
428         // generate single literal value assignment to a list property if required
429         if (property->propType == qMetaTypeId<QList<qreal> >()) {
430             Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
431             QList<qreal> value;
432             value.append(binding->valueAsNumber());
433             argv[0] = reinterpret_cast<void *>(&value);
434             QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
435             break;
436         } else if (property->propType == qMetaTypeId<QList<int> >()) {
437             Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
438             double n = binding->valueAsNumber();
439             QList<int> value;
440             value.append(int(n));
441             argv[0] = reinterpret_cast<void *>(&value);
442             QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
443             break;
444         } else if (property->propType == qMetaTypeId<QList<bool> >()) {
445             Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
446             QList<bool> value;
447             value.append(binding->valueAsBoolean());
448             argv[0] = reinterpret_cast<void *>(&value);
449             QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
450             break;
451         } else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
452             Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
453             QString urlString = binding->valueAsString(&qmlUnit->header);
454             QUrl u = urlString.isEmpty() ? QUrl() : this->url.resolved(QUrl(urlString));
455             QList<QUrl> value;
456             value.append(u);
457             argv[0] = reinterpret_cast<void *>(&value);
458             QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
459             break;
460         } else if (property->propType == qMetaTypeId<QList<QString> >()) {
461             Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
462             QList<QString> value;
463             value.append(binding->valueAsString(&qmlUnit->header));
464             argv[0] = reinterpret_cast<void *>(&value);
465             QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
466             break;
467         } else if (property->propType == qMetaTypeId<QJSValue>()) {
468             QJSValue value;
469             if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
470                 value = QJSValue(binding->valueAsBoolean());
471             } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
472                 double n = binding->valueAsNumber();
473                 if (double(int(n)) == n) {
474                     value = QJSValue(int(n));
475                 } else
476                     value = QJSValue(n);
477             } else {
478                 value = QJSValue(binding->valueAsString(&qmlUnit->header));
479             }
480             argv[0] = reinterpret_cast<void *>(&value);
481             QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
482             break;
483         }
484
485         // otherwise, try a custom type assignment
486         QString stringValue = binding->valueAsString(&qmlUnit->header);
487         QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType);
488         Q_ASSERT(converter);
489         QVariant value = (*converter)(stringValue);
490
491         QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex);
492         if (value.isNull() || ((int)metaProperty.type() != property->propType && metaProperty.userType() != property->propType)) {
493             recordError(binding->location, tr("Cannot assign value %1 to property %2").arg(stringValue).arg(QString::fromUtf8(metaProperty.name())));
494             break;
495         }
496
497         argv[0] = value.data();
498         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
499     }
500     break;
501     }
502 }
503
504 void QmlObjectCreator::setupBindings()
505 {
506     QQmlListProperty<void> savedList;
507     qSwap(_currentList, savedList);
508
509     QQmlPropertyData *property = 0;
510     QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultProperty != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty();
511
512     QString id = stringAt(_compiledObject->idIndex);
513     if (!id.isEmpty()) {
514         QQmlPropertyData *idProperty = _propertyCache->property(QStringLiteral("id"), _qobject, context);
515         if (idProperty && idProperty->isWritable()) {
516             QV4::CompiledData::Binding idBinding;
517             idBinding.propertyNameIndex = 0; // Not used
518             idBinding.flags = 0;
519             idBinding.type = QV4::CompiledData::Binding::Type_String;
520             idBinding.stringIndex = _compiledObject->idIndex;
521             idBinding.location = _compiledObject->location; // ###
522             setPropertyValue(idProperty, &idBinding);
523         }
524     }
525
526     const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
527     for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
528
529         QString name = stringAt(binding->propertyNameIndex);
530         if (name.isEmpty())
531             property = 0;
532
533         if (!property || (i > 0 && (binding - 1)->propertyNameIndex != binding->propertyNameIndex)) {
534             if (!name.isEmpty())
535                 property = _propertyCache->property(name, _qobject, context);
536             else
537                 property = defaultProperty;
538
539             if (property && property->isQList()) {
540                 void *argv[1] = { (void*)&_currentList };
541                 QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv);
542             } else if (_currentList.object)
543                 _currentList = QQmlListProperty<void>();
544
545         }
546
547         if (!setPropertyValue(property, i, binding))
548             return;
549     }
550
551     qSwap(_currentList, savedList);
552 }
553
554 bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingIndex, const QV4::CompiledData::Binding *binding)
555 {
556     if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
557         Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
558         QQmlCompiledData::TypeReference *tr = resolvedTypes.value(binding->propertyNameIndex);
559         Q_ASSERT(tr);
560         QQmlType *attachedType = tr->type;
561         const int id = attachedType->attachedPropertiesId();
562         QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject);
563         QQmlRefPointer<QQmlPropertyCache> cache = QQmlEnginePrivate::get(engine)->cache(qmlObject);
564         if (!populateInstance(binding->value.objectIndex, qmlObject, cache, qmlObject, /*value type property*/0))
565             return false;
566         return true;
567     }
568
569     // ### resolve this at compile time
570     if (property && property->propType == qMetaTypeId<QQmlScriptString>()) {
571         QQmlScriptString ss(binding->valueAsScriptString(&qmlUnit->header), context->asQQmlContext(), _scopeObject);
572         ss.d.data()->bindingId = QQmlBinding::Invalid;
573         ss.d.data()->lineNumber = binding->location.line;
574         ss.d.data()->columnNumber = binding->location.column;
575         ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String;
576         ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number;
577         ss.d.data()->numberValue = binding->valueAsNumber();
578
579         QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
580                                                                    QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
581         int propertyWriteStatus = -1;
582         void *argv[] = { &ss, 0, &propertyWriteStatus, &propertyWriteFlags };
583         QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
584         return true;
585     }
586
587     QObject *createdSubObject = 0;
588     if (binding->type == QV4::CompiledData::Binding::Type_Object) {
589         Q_ASSERT(!_valueTypeProperty);
590         createdSubObject = createInstance(binding->value.objectIndex, _bindingTarget);
591         if (!createdSubObject)
592             return false;
593     }
594
595     if (!property) // ### error
596         return true;
597
598     if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
599         const QV4::CompiledData::Object *obj = qmlUnit->objectAt(binding->value.objectIndex);
600         if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) {
601
602             QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
603             QQmlRefPointer<QQmlPropertyCache> groupObjectPropertyCache;
604             QObject *groupObject = 0;
605             QQmlValueType *valueType = 0;
606             QQmlPropertyData *valueTypeProperty = 0;
607             QObject *bindingTarget = _bindingTarget;
608
609             if (QQmlValueTypeFactory::isValueType(property->propType)) {
610                 valueType = QQmlValueTypeFactory::valueType(property->propType);
611                 if (!valueType) {
612                     recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
613                     return false;
614                 }
615
616                 valueType->read(_qobject, property->coreIndex);
617
618                 groupObjectPropertyCache = enginePrivate->cache(valueType);
619                 groupObject = valueType;
620                 valueTypeProperty = property;
621             } else {
622                 groupObjectPropertyCache = enginePrivate->propertyCacheForType(property->propType);
623                 if (!groupObjectPropertyCache) {
624                     recordError(binding->location, tr("Invalid grouped property access"));
625                     return false;
626                 }
627
628                 void *argv[1] = { &groupObject };
629                 QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv);
630                 if (!groupObject) {
631                     recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
632                     return false;
633                 }
634
635                 bindingTarget = groupObject;
636             }
637
638             if (!populateInstance(binding->value.objectIndex, groupObject, groupObjectPropertyCache, bindingTarget, valueTypeProperty))
639                 return false;
640
641             if (valueType)
642                 valueType->write(_qobject, property->coreIndex, QQmlPropertyPrivate::BypassInterceptor);
643
644             return true;
645         }
646     }
647
648     if (_ddata->hasBindingBit(property->coreIndex) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
649         && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment))
650         removeBindingOnProperty(_bindingTarget, property->coreIndex);
651
652     if (binding->type == QV4::CompiledData::Binding::Type_Script) {
653         QV4::Function *runtimeFunction = jsUnit->runtimeFunctions[binding->value.compiledScriptIndex];
654
655         QV4::Scope scope(_qmlContext);
656         QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction));
657
658         if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
659             int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex);
660             QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
661             QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex,
662                                                                             context, _scopeObject, function);
663
664             bs->takeExpression(expr);
665         } else {
666             QQmlBinding *qmlBinding = new QQmlBinding(function, _scopeObject, context,
667                                                       context->urlString, binding->location.line, binding->location.column);
668
669             // When writing bindings to grouped properties implemented as value types,
670             // such as point.x: { someExpression; }, then the binding is installed on
671             // the point property (_qobjectForBindings) and after evaluating the expression,
672             // the result is written to a value type virtual property, that contains the sub-index
673             // of the "x" property.
674             QQmlPropertyData targetCorePropertyData = *property;
675             if (_valueTypeProperty)
676                 targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine);
677
678             qmlBinding->setTarget(_bindingTarget, targetCorePropertyData, context);
679             qmlBinding->addToObject();
680
681             _createdBindings[bindingIndex] = qmlBinding;
682             qmlBinding->m_mePtr = &_createdBindings[bindingIndex];
683         }
684         return true;
685     }
686
687     if (binding->type == QV4::CompiledData::Binding::Type_Object) {
688         if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
689             // ### determine value source and interceptor casts ahead of time.
690             QQmlType *type = 0;
691             const QMetaObject *mo = createdSubObject->metaObject();
692             while (mo && !type) {
693                 type = QQmlMetaType::qmlType(mo);
694                 mo = mo->superClass();
695             }
696             Q_ASSERT(type);
697
698             QQmlPropertyData targetCorePropertyData = *property;
699             if (_valueTypeProperty)
700                 targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine);
701
702             int valueSourceCast = type->propertyValueSourceCast();
703             if (valueSourceCast != -1) {
704                 QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(createdSubObject) + valueSourceCast);
705                 QObject *target = createdSubObject->parent();
706                 vs->setTarget(QQmlPropertyPrivate::restore(target, targetCorePropertyData, context));
707                 return true;
708             }
709             int valueInterceptorCast = type->propertyValueInterceptorCast();
710             if (valueInterceptorCast != -1) {
711                 QQmlPropertyValueInterceptor *vi = reinterpret_cast<QQmlPropertyValueInterceptor *>(reinterpret_cast<char *>(createdSubObject) + valueInterceptorCast);
712                 QObject *target = createdSubObject->parent();
713
714                 QQmlProperty prop =
715                     QQmlPropertyPrivate::restore(target, targetCorePropertyData, context);
716                 vi->setTarget(prop);
717                 QQmlVMEMetaObject *mo = QQmlVMEMetaObject::get(target);
718                 Q_ASSERT(mo);
719                 mo->registerInterceptor(prop.index(), QQmlPropertyPrivate::valueTypeCoreIndex(prop), vi);
720                 return true;
721             }
722             return false;
723         }
724
725         QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor |
726                                                                    QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
727         int propertyWriteStatus = -1;
728         void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags };
729
730         if (const char *iid = QQmlMetaType::interfaceIId(property->propType)) {
731             void *ptr = createdSubObject->qt_metacast(iid);
732             if (ptr) {
733                 argv[0] = &ptr;
734                 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
735             } else {
736                 recordError(binding->location, tr("Cannot assign object to interface property"));
737                 return false;
738             }
739         } else if (property->propType == QMetaType::QVariant) {
740             if (property->isVarProperty()) {
741                 QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
742                 QV4::Scope scope(v4);
743                 QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(QV8Engine::getV4(engine), createdSubObject));
744                 _vmeMetaObject->setVMEProperty(property->coreIndex, wrappedObject);
745             } else {
746                 QVariant value = QVariant::fromValue(createdSubObject);
747                 argv[0] = &value;
748                 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
749             }
750         } else if (property->isQList()) {
751             Q_ASSERT(_currentList.object);
752
753             void *itemToAdd = createdSubObject;
754
755             const char *iid = 0;
756             int listItemType = QQmlEnginePrivate::get(engine)->listType(property->propType);
757             if (listItemType != -1)
758                 iid = QQmlMetaType::interfaceIId(listItemType);
759             if (iid)
760                 itemToAdd = createdSubObject->qt_metacast(iid);
761
762             if (_currentList.append)
763                 _currentList.append(&_currentList, itemToAdd);
764         } else {
765             // pointer compatibility was tested in QQmlPropertyValidator at type compile time
766             argv[0] = &createdSubObject;
767             QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
768         }
769         return true;
770     }
771
772     if (property->isQList()) {
773         recordError(binding->location, tr("Cannot assign primitives to lists"));
774         return false;
775     }
776
777     setPropertyValue(property, binding);
778     return true;
779 }
780
781 void QmlObjectCreator::setupFunctions()
782 {
783     QV4::Scope scope(_qmlContext);
784     QV4::ScopedValue function(scope);
785
786     const quint32 *functionIdx = _compiledObject->functionOffsetTable();
787     for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) {
788         QV4::Function *runtimeFunction = jsUnit->runtimeFunctions[*functionIdx];
789         const QString name = runtimeFunction->name->toQString();
790
791         QQmlPropertyData *property = _propertyCache->property(name, _qobject, context);
792         if (!property->isVMEFunction())
793             continue;
794
795         function = QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction);
796         _vmeMetaObject->setVmeMethod(property->coreIndex, function);
797     }
798 }
799
800 void QmlObjectCreator::recordError(const QV4::CompiledData::Location &location, const QString &description)
801 {
802     QQmlError error;
803     error.setUrl(url);
804     error.setLine(location.line);
805     error.setColumn(location.column);
806     error.setDescription(description);
807     errors << error;
808 }
809
810 QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
811 {
812     ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
813
814     bool isComponent = false;
815     QObject *instance = 0;
816     QQmlCustomParser *customParser = 0;
817
818     if (compiledData->isComponent(index)) {
819         isComponent = true;
820         QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent);
821         QQmlComponentPrivate::get(component)->creationContext = context;
822         instance = component;
823     } else {
824         const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
825
826         QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
827         Q_ASSERT(typeRef);
828         QQmlType *type = typeRef->type;
829         if (type) {
830             instance = type->create();
831             if (!instance) {
832                 recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex)));
833                 return 0;
834             }
835
836             const int parserStatusCast = type->parserStatusCast();
837             if (parserStatusCast != -1) {
838                 QQmlParserStatus *parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast);
839                 parserStatus->classBegin();
840                 _parserStatusCallbacks[index] = parserStatus;
841                 parserStatus->d = &_parserStatusCallbacks[index];
842             }
843
844             customParser = type->customParser();
845         } else {
846             Q_ASSERT(typeRef->component);
847             if (typeRef->component->qmlUnit->isSingleton())
848             {
849                 recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
850                 return 0;
851             }
852             QmlObjectCreator subCreator(context, typeRef->component);
853             instance = subCreator.create();
854             if (!instance) {
855                 errors += subCreator.errors;
856                 return 0;
857             }
858             if (subCreator.componentAttached)
859                 subCreator.componentAttached->add(&componentAttached);
860             allCreatedBindings << subCreator.allCreatedBindings;
861             allParserStatusCallbacks << subCreator.allParserStatusCallbacks;
862         }
863         // ### use no-event variant
864         if (parent)
865             instance->setParent(parent);
866     }
867
868     QQmlData *ddata = QQmlData::get(instance, /*create*/true);
869     if (static_cast<quint32>(index) == qmlUnit->indexOfRootObject) {
870         if (ddata->context) {
871             Q_ASSERT(ddata->context != context);
872             Q_ASSERT(ddata->outerContext);
873             Q_ASSERT(ddata->outerContext != context);
874             QQmlContextData *c = ddata->context;
875             while (c->linkedContext) c = c->linkedContext;
876             c->linkedContext = context;
877         } else
878             context->addObject(instance);
879         ddata->ownContext = true;
880     } else if (!ddata->context)
881         context->addObject(instance);
882
883     ddata->outerContext = context;
884
885     QHash<int, int>::ConstIterator idEntry = objectIndexToId.find(index);
886     if (idEntry != objectIndexToId.constEnd())
887         context->setIdProperty(idEntry.value(), instance);
888
889     if (customParser) {
890         QHash<int, QByteArray>::ConstIterator entry = compiledData->customParserData.find(index);
891         if (entry != compiledData->customParserData.constEnd())
892             customParser->setCustomData(instance, *entry);
893     }
894
895     if (isComponent)
896         return instance;
897
898     QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index);
899     Q_ASSERT(!cache.isNull());
900
901     QObject *scopeObject = instance;
902     qSwap(_scopeObject, scopeObject);
903
904     QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
905     QV4::Scope valueScope(v4);
906     QV4::ScopedObject jsScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _scopeObject));
907     QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, jsScopeObject));
908     QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context();
909
910     qSwap(_qmlContext, qmlContext);
911
912     bool result = populateInstance(index, instance, cache, /*binding target*/instance, /*value type property*/0);
913
914     qSwap(_qmlContext, qmlContext);
915     qSwap(_scopeObject, scopeObject);
916
917     return result ? instance : 0;
918 }
919
920 QQmlContextData *QmlObjectCreator::finalize()
921 {
922     {
923     QQmlTrace trace("VME Binding Enable");
924     trace.event("begin binding eval");
925
926     Q_ASSERT(allCreatedBindings.isEmpty() || allCreatedBindings.isDetached());
927
928     for (QLinkedList<QVector<QQmlAbstractBinding*> >::Iterator it = allCreatedBindings.begin(), end = allCreatedBindings.end();
929          it != end; ++it) {
930         const QVector<QQmlAbstractBinding *> &bindings = *it;
931         for (int i = 0; i < bindings.count(); ++i) {
932             QQmlAbstractBinding *b = bindings.at(i);
933             if (!b)
934                 continue;
935             b->m_mePtr = 0;
936             QQmlData *data = QQmlData::get(b->object());
937             Q_ASSERT(data);
938             data->clearPendingBindingBit(b->propertyIndex());
939             b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
940                           QQmlPropertyPrivate::DontRemoveBinding);
941         }
942     }
943     }
944
945     if (true /* ### componentCompleteEnabled()*/) { // the qml designer does the component complete later
946         QQmlTrace trace("VME Component Complete");
947         for (QLinkedList<QVector<QQmlParserStatus*> >::ConstIterator it = allParserStatusCallbacks.constBegin(), end = allParserStatusCallbacks.constEnd();
948              it != end; ++it) {
949             const QVector<QQmlParserStatus *> &parserStatusCallbacks = *it;
950             for (int i = parserStatusCallbacks.count() - 1; i >= 0; --i) {
951                 QQmlParserStatus *status = parserStatusCallbacks.at(i);
952
953                 if (status && status->d) {
954                     status->d = 0;
955                     status->componentComplete();
956                 }
957
958     #if 0 // ###
959                 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
960                     return 0;
961     #endif
962             }
963         }
964         allParserStatusCallbacks.clear();
965     }
966
967     {
968     QQmlTrace trace("VME Finalize Callbacks");
969     for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) {
970         QQmlEnginePrivate::FinalizeCallback callback = finalizeCallbacks.at(ii);
971         QObject *obj = callback.first;
972         if (obj) {
973             void *args[] = { 0 };
974             QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
975         }
976 #if 0 // ###
977         if (watcher.hasRecursed())
978             return 0;
979 #endif
980     }
981     finalizeCallbacks.clear();
982     }
983
984     {
985     QQmlTrace trace("VME Component.onCompleted Callbacks");
986     while (componentAttached) {
987         QQmlComponentAttached *a = componentAttached;
988         a->rem();
989         QQmlData *d = QQmlData::get(a->parent());
990         Q_ASSERT(d);
991         Q_ASSERT(d->context);
992         a->add(&d->context->componentAttached);
993         // ### designer if (componentCompleteEnabled())
994             emit a->completed();
995
996 #if 0 // ###
997         if (watcher.hasRecursed() || interrupt.shouldInterrupt())
998             return 0;
999 #endif
1000     }
1001     }
1002
1003     return rootContext;
1004 }
1005
1006 bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty)
1007 {
1008     const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
1009
1010     QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
1011
1012     qSwap(_propertyCache, cache);
1013     qSwap(_qobject, instance);
1014     qSwap(_valueTypeProperty, valueTypeProperty);
1015     qSwap(_compiledObject, obj);
1016     qSwap(_ddata, declarativeData);
1017     qSwap(_bindingTarget, bindingTarget);
1018
1019     QQmlVMEMetaObject *vmeMetaObject = 0;
1020     const QByteArray data = vmeMetaObjectData.value(index);
1021     if (!data.isEmpty()) {
1022         // install on _object
1023         vmeMetaObject = new QQmlVMEMetaObject(_qobject, _propertyCache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData()));
1024         if (_ddata->propertyCache)
1025             _ddata->propertyCache->release();
1026         _ddata->propertyCache = _propertyCache;
1027         _ddata->propertyCache->addref();
1028     } else {
1029         vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
1030     }
1031
1032     _ddata->lineNumber = _compiledObject->location.line;
1033     _ddata->columnNumber = _compiledObject->location.column;
1034
1035     qSwap(_vmeMetaObject, vmeMetaObject);
1036
1037     QVector<QQmlAbstractBinding*> createdBindings(_compiledObject->nBindings, 0);
1038     qSwap(_createdBindings, createdBindings);
1039
1040     setupBindings();
1041     setupFunctions();
1042
1043     allCreatedBindings.append(_createdBindings);
1044
1045     qSwap(_createdBindings, createdBindings);
1046     qSwap(_vmeMetaObject, vmeMetaObject);
1047     qSwap(_bindingTarget, bindingTarget);
1048     qSwap(_ddata, declarativeData);
1049     qSwap(_compiledObject, obj);
1050     qSwap(_valueTypeProperty, valueTypeProperty);
1051     qSwap(_qobject, instance);
1052     qSwap(_propertyCache, cache);
1053
1054     return errors.isEmpty();
1055 }
1056
1057