Implement strict mode for qmldir modules
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlproperty.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlproperty.h"
43 #include "qqmlproperty_p.h"
44
45 #include "qqml.h"
46 #include "qqmlbinding_p.h"
47 #include "qqmlcontext.h"
48 #include "qqmlcontext_p.h"
49 #include "qqmlboundsignal_p.h"
50 #include "qqmlengine.h"
51 #include "qqmlengine_p.h"
52 #include "qqmldata_p.h"
53 #include "qqmlstringconverters_p.h"
54 #include "qqmllist_p.h"
55 #include "qqmlcompiler_p.h"
56 #include "qqmlvmemetaobject_p.h"
57 #include "qqmlexpression_p.h"
58 #include "qqmlvaluetypeproxybinding_p.h"
59 #include <private/qv8bindings_p.h>
60
61 #include <QStringList>
62 #include <private/qmetaobject_p.h>
63 #include <QtCore/qdebug.h>
64
65 #include <math.h>
66
67 Q_DECLARE_METATYPE(QJSValue)
68 Q_DECLARE_METATYPE(QList<int>)
69 Q_DECLARE_METATYPE(QList<qreal>)
70 Q_DECLARE_METATYPE(QList<bool>)
71 Q_DECLARE_METATYPE(QList<QString>)
72 Q_DECLARE_METATYPE(QList<QUrl>)
73
74 QT_BEGIN_NAMESPACE
75
76 /*!
77 \class QQmlProperty
78 \since 5.0
79 \inmodule QtQml
80 \brief The QQmlProperty class abstracts accessing properties on objects created from  QML.
81
82 As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect
83 and interact with objects created by QML.  However, some of the new features provided by QML - such
84 as type safety and attached properties - are most easily used through the QQmlProperty class
85 that simplifies some of their natural complexity.
86
87 Unlike QMetaProperty which represents a property on a class type, QQmlProperty encapsulates
88 a property on a specific object instance.  To read a property's value, programmers create a
89 QQmlProperty instance and call the read() method.  Likewise to write a property value the
90 write() method is used.
91
92 For example, for the following QML code:
93
94 \qml
95 // MyItem.qml
96 import QtQuick 2.0
97
98 Text { text: "A bit of text" }
99 \endqml
100
101 The \l Text object's properties could be accessed using QQmlProperty, like this:
102
103 \code
104 #include <QQmlProperty>
105 #include <QGraphicsObject>
106
107 ...
108
109 QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
110 QQmlProperty property(view.rootObject(), "font.pixelSize");
111 qWarning() << "Current pixel size:" << property.read().toInt();
112 property.write(24);
113 qWarning() << "Pixel size should now be 24:" << property.read().toInt();
114 \endcode
115
116 The QtQuick 1 version of this class was named QDeclarativeProperty.
117 */
118
119 /*!
120     Create an invalid QQmlProperty.
121 */
122 QQmlProperty::QQmlProperty()
123 : d(0)
124 {
125 }
126
127 /*!  \internal */
128 QQmlProperty::~QQmlProperty()
129 {
130     if (d)
131         d->release();
132     d = 0;
133 }
134
135 /*!
136     Creates a QQmlProperty for the default property of \a obj. If there is no
137     default property, an invalid QQmlProperty will be created.
138  */
139 QQmlProperty::QQmlProperty(QObject *obj)
140 : d(new QQmlPropertyPrivate)
141 {
142     d->initDefault(obj);
143 }
144
145 /*!
146     Creates a QQmlProperty for the default property of \a obj
147     using the \l{QQmlContext} {context} \a ctxt. If there is
148     no default property, an invalid QQmlProperty will be
149     created.
150  */
151 QQmlProperty::QQmlProperty(QObject *obj, QQmlContext *ctxt)
152 : d(new QQmlPropertyPrivate)
153 {
154     d->context = ctxt?QQmlContextData::get(ctxt):0;
155     d->engine = ctxt?ctxt->engine():0;
156     d->initDefault(obj);
157 }
158
159 /*!
160     Creates a QQmlProperty for the default property of \a obj
161     using the environment for instantiating QML components that is
162     provided by \a engine.  If there is no default property, an
163     invalid QQmlProperty will be created.
164  */
165 QQmlProperty::QQmlProperty(QObject *obj, QQmlEngine *engine)
166   : d(new QQmlPropertyPrivate)
167 {
168     d->context = 0;
169     d->engine = engine;
170     d->initDefault(obj);
171 }
172
173 /*!
174     Initialize from the default property of \a obj
175 */
176 void QQmlPropertyPrivate::initDefault(QObject *obj)
177 {
178     if (!obj)
179         return;
180
181     QMetaProperty p = QQmlMetaType::defaultProperty(obj);
182     core.load(p);
183     if (core.isValid())
184         object = obj;
185 }
186
187 /*!
188     Creates a QQmlProperty for the property \a name of \a obj.
189  */
190 QQmlProperty::QQmlProperty(QObject *obj, const QString &name)
191 : d(new QQmlPropertyPrivate)
192 {
193     d->initProperty(obj, name);
194     if (!isValid()) d->object = 0;
195 }
196
197 /*!
198     Creates a QQmlProperty for the property \a name of \a obj
199     using the \l{QQmlContext} {context} \a ctxt.
200
201     Creating a QQmlProperty without a context will render some
202     properties - like attached properties - inaccessible.
203 */
204 QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlContext *ctxt)
205 : d(new QQmlPropertyPrivate)
206 {
207     d->context = ctxt?QQmlContextData::get(ctxt):0;
208     d->engine = ctxt?ctxt->engine():0;
209     d->initProperty(obj, name);
210     if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
211 }
212
213 /*!
214     Creates a QQmlProperty for the property \a name of \a obj
215     using the environment for instantiating QML components that is
216     provided by \a engine.
217  */
218 QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlEngine *engine)
219 : d(new QQmlPropertyPrivate)
220 {
221     d->context = 0;
222     d->engine = engine;
223     d->initProperty(obj, name);
224     if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
225 }
226
227 Q_GLOBAL_STATIC(QQmlValueTypeFactory, qmlValueTypes);
228
229 QQmlPropertyPrivate::QQmlPropertyPrivate()
230 : context(0), engine(0), object(0), isNameCached(false)
231 {
232 }
233
234 QQmlContextData *QQmlPropertyPrivate::effectiveContext() const
235 {
236     if (context) return context;
237     else if (engine) return QQmlContextData::get(engine->rootContext());
238     else return 0;
239 }
240
241 void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
242 {
243     if (!obj) return;
244
245     QQmlTypeNameCache *typeNameCache = context?context->imports:0;
246
247     QStringList path = name.split(QLatin1Char('.'));
248     if (path.isEmpty()) return;
249
250     QObject *currentObject = obj;
251
252     // Everything up to the last property must be an "object type" property
253     for (int ii = 0; ii < path.count() - 1; ++ii) {
254         const QString &pathName = path.at(ii);
255
256         if (typeNameCache) {
257             QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
258             if (r.isValid()) {
259                 if (r.type) {
260                     QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
261                     if (!func) return; // Not an attachable type
262
263                     currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
264                     if (!currentObject) return; // Something is broken with the attachable type
265                 } else if (r.importNamespace) {
266                     if ((ii + 1) == path.count()) return; // No type following the namespace
267
268                     ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
269                     if (!r.type) return; // Invalid type in namespace
270
271                     QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
272                     if (!func) return; // Not an attachable type
273
274                     currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
275                     if (!currentObject) return; // Something is broken with the attachable type
276
277                 } else if (r.scriptIndex != -1) {
278                     return; // Not a type
279                 } else {
280                     Q_ASSERT(!"Unreachable");
281                 }
282                 continue;
283             }
284
285         }
286
287         QQmlPropertyData local;
288         QQmlPropertyData *property =
289             QQmlPropertyCache::property(engine, obj, pathName, local);
290
291         if (!property) return; // Not a property
292         if (property->isFunction())
293             return; // Not an object property
294
295         if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType)) {
296             // We're now at a value type property.  We can use a global valuetypes array as we
297             // never actually use the objects, just look up their properties.
298             QObject *typeObject = (*qmlValueTypes())[property->propType];
299             if (!typeObject) return; // Not a value type
300
301             int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
302             if (idx == -1) return; // Value type property does not exist
303
304             QMetaProperty vtProp = typeObject->metaObject()->property(idx);
305
306             typedef QQmlPropertyData PCD;
307
308             Q_ASSERT(PCD::flagsForProperty(vtProp) <= PCD::ValueTypeFlagMask);
309             Q_ASSERT(vtProp.userType() <= 0xFF);
310             Q_ASSERT(idx <= 0xFF);
311
312             object = currentObject;
313             core = *property;
314             core.setFlags(core.getFlags() | PCD::IsValueTypeVirtual);
315             core.valueTypeFlags = PCD::flagsForProperty(vtProp);
316             core.valueTypePropType = vtProp.userType();
317             core.valueTypeCoreIndex = idx;
318
319             return;
320         } else {
321             if (!property->isQObject())
322                 return; // Not an object property
323
324             void *args[] = { &currentObject, 0 };
325             QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
326             if (!currentObject) return; // No value
327
328         }
329
330     }
331
332     const QString &terminal = path.last();
333
334     if (terminal.count() >= 3 &&
335         terminal.at(0) == QLatin1Char('o') &&
336         terminal.at(1) == QLatin1Char('n') &&
337         terminal.at(2).isUpper()) {
338
339         QString signalName = terminal.mid(2);
340         signalName[0] = signalName.at(0).toLower();
341
342         // XXX - this code treats methods as signals
343
344         QQmlData *ddata = QQmlData::get(currentObject, false);
345         if (ddata && ddata->propertyCache) {
346
347             // Try method
348             QQmlPropertyData *d = ddata->propertyCache->property(signalName);
349             while (d && !d->isFunction())
350                 d = ddata->propertyCache->overrideData(d);
351
352             if (d) {
353                 object = currentObject;
354                 core = *d;
355                 return;
356             }
357
358             // Try property
359             if (signalName.endsWith(QLatin1String("Changed"))) {
360                 QString propName = signalName.mid(0, signalName.length() - 7);
361                 QQmlPropertyData *d = ddata->propertyCache->property(propName);
362                 while (d && d->isFunction())
363                     d = ddata->propertyCache->overrideData(d);
364
365                 if (d && d->notifyIndex != -1) {
366                     object = currentObject;
367                     core = *ddata->propertyCache->signal(d->notifyIndex);
368                     return;
369                 }
370             }
371
372         } else {
373             QMetaMethod method = findSignalByName(currentObject->metaObject(),
374                                                   signalName.toLatin1());
375             if (method.isValid()) {
376                 object = currentObject;
377                 core.load(method);
378                 return;
379             }
380         }
381     }
382
383     // Property
384     QQmlPropertyData local;
385     QQmlPropertyData *property =
386         QQmlPropertyCache::property(engine, currentObject, terminal, local);
387     if (property && !property->isFunction()) {
388         object = currentObject;
389         core = *property;
390         nameCache = terminal;
391         isNameCached = true;
392     }
393 }
394
395 /*! \internal
396     Returns the index of this property's signal, in the signal index range
397     (see QObjectPrivate::signalIndex()). This is different from
398     QMetaMethod::methodIndex().
399 */
400 int QQmlPropertyPrivate::signalIndex() const
401 {
402     Q_ASSERT(type() == QQmlProperty::SignalProperty);
403     QMetaMethod m = object->metaObject()->method(core.coreIndex);
404     return QMetaObjectPrivate::signalIndex(m);
405 }
406
407 /*!
408     Create a copy of \a other.
409 */
410 QQmlProperty::QQmlProperty(const QQmlProperty &other)
411 {
412     d = other.d;
413     if (d)
414         d->addref();
415 }
416
417 /*!
418   \enum QQmlProperty::PropertyTypeCategory
419
420   This enum specifies a category of QML property.
421
422   \value InvalidCategory The property is invalid, or is a signal property.
423   \value List The property is a QQmlListProperty list property
424   \value Object The property is a QObject derived type pointer
425   \value Normal The property is a normal value property.
426  */
427
428 /*!
429   \enum QQmlProperty::Type
430
431   This enum specifies a type of QML property.
432
433   \value Invalid The property is invalid.
434   \value Property The property is a regular Qt property.
435   \value SignalProperty The property is a signal property.
436 */
437
438 /*!
439     Returns the property category.
440 */
441 QQmlProperty::PropertyTypeCategory QQmlProperty::propertyTypeCategory() const
442 {
443     return d ? d->propertyTypeCategory() : InvalidCategory;
444 }
445
446 QQmlProperty::PropertyTypeCategory
447 QQmlPropertyPrivate::propertyTypeCategory() const
448 {
449     uint type = this->type();
450
451     if (isValueType()) {
452         return QQmlProperty::Normal;
453     } else if (type & QQmlProperty::Property) {
454         int type = propertyType();
455         if (type == QVariant::Invalid)
456             return QQmlProperty::InvalidCategory;
457         else if (QQmlValueTypeFactory::isValueType((uint)type))
458             return QQmlProperty::Normal;
459         else if (core.isQObject())
460             return QQmlProperty::Object;
461         else if (core.isQList())
462             return QQmlProperty::List;
463         else
464             return QQmlProperty::Normal;
465     } else {
466         return QQmlProperty::InvalidCategory;
467     }
468 }
469
470 /*!
471     Returns the type name of the property, or 0 if the property has no type
472     name.
473 */
474 const char *QQmlProperty::propertyTypeName() const
475 {
476     if (!d)
477         return 0;
478     if (d->isValueType()) {
479
480         QQmlEnginePrivate *ep = d->engine?QQmlEnginePrivate::get(d->engine):0;
481         QQmlValueType *valueType = 0;
482         if (ep) valueType = ep->valueTypes[d->core.propType];
483         else valueType = QQmlValueTypeFactory::valueType(d->core.propType);
484         Q_ASSERT(valueType);
485
486         const char *rv = valueType->metaObject()->property(d->core.valueTypeCoreIndex).typeName();
487
488         if (!ep) delete valueType;
489
490         return rv;
491     } else if (d->object && type() & Property && d->core.isValid()) {
492         return d->object->metaObject()->property(d->core.coreIndex).typeName();
493     } else {
494         return 0;
495     }
496 }
497
498 /*!
499     Returns true if \a other and this QQmlProperty represent the same
500     property.
501 */
502 bool QQmlProperty::operator==(const QQmlProperty &other) const
503 {
504     if (!d || !other.d)
505         return false;
506     // category is intentially omitted here as it is generated
507     // from the other members
508     return d->object == other.d->object &&
509            d->core.coreIndex == other.d->core.coreIndex &&
510            d->core.isValueTypeVirtual() == other.d->core.isValueTypeVirtual() &&
511            (!d->core.isValueTypeVirtual() ||
512             (d->core.valueTypeCoreIndex == other.d->core.valueTypeCoreIndex &&
513              d->core.valueTypePropType == other.d->core.valueTypePropType));
514 }
515
516 /*!
517     Returns the QVariant type of the property, or QVariant::Invalid if the
518     property has no QVariant type.
519 */
520 int QQmlProperty::propertyType() const
521 {
522     return d ? d->propertyType() : int(QVariant::Invalid);
523 }
524
525 bool QQmlPropertyPrivate::isValueType() const
526 {
527     return core.isValueTypeVirtual();
528 }
529
530 int QQmlPropertyPrivate::propertyType() const
531 {
532     uint type = this->type();
533     if (isValueType()) {
534         return core.valueTypePropType;
535     } else if (type & QQmlProperty::Property) {
536         return core.propType;
537     } else {
538         return QVariant::Invalid;
539     }
540 }
541
542 QQmlProperty::Type QQmlPropertyPrivate::type() const
543 {
544     if (core.isFunction())
545         return QQmlProperty::SignalProperty;
546     else if (core.isValid())
547         return QQmlProperty::Property;
548     else
549         return QQmlProperty::Invalid;
550 }
551
552 /*!
553     Returns the type of the property.
554 */
555 QQmlProperty::Type QQmlProperty::type() const
556 {
557     return d ? d->type() : Invalid;
558 }
559
560 /*!
561     Returns true if this QQmlProperty represents a regular Qt property.
562 */
563 bool QQmlProperty::isProperty() const
564 {
565     return type() & Property;
566 }
567
568 /*!
569     Returns true if this QQmlProperty represents a QML signal property.
570 */
571 bool QQmlProperty::isSignalProperty() const
572 {
573     return type() & SignalProperty;
574 }
575
576 /*!
577     Returns the QQmlProperty's QObject.
578 */
579 QObject *QQmlProperty::object() const
580 {
581     return d ? d->object : 0;
582 }
583
584 /*!
585     Assign \a other to this QQmlProperty.
586 */
587 QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other)
588 {
589     if (d)
590         d->release();
591     d = other.d;
592     if (d)
593         d->addref();
594
595     return *this;
596 }
597
598 /*!
599     Returns true if the property is writable, otherwise false.
600 */
601 bool QQmlProperty::isWritable() const
602 {
603     if (!d)
604         return false;
605     if (!d->object)
606         return false;
607     if (d->core.isQList())           //list
608         return true;
609     else if (d->core.isFunction())   //signal handler
610         return false;
611     else if (d->core.isValid())      //normal property
612         return d->core.isWritable();
613     else
614         return false;
615 }
616
617 /*!
618     Returns true if the property is designable, otherwise false.
619 */
620 bool QQmlProperty::isDesignable() const
621 {
622     if (!d)
623         return false;
624     if (type() & Property && d->core.isValid() && d->object)
625         return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
626     else
627         return false;
628 }
629
630 /*!
631     Returns true if the property is resettable, otherwise false.
632 */
633 bool QQmlProperty::isResettable() const
634 {
635     if (!d)
636         return false;
637     if (type() & Property && d->core.isValid() && d->object)
638         return d->core.isResettable();
639     else
640         return false;
641 }
642
643 /*!
644     Returns true if the QQmlProperty refers to a valid property, otherwise
645     false.
646 */
647 bool QQmlProperty::isValid() const
648 {
649     if (!d)
650         return false;
651     return type() != Invalid;
652 }
653
654 /*!
655     Return the name of this QML property.
656 */
657 QString QQmlProperty::name() const
658 {
659     if (!d)
660         return QString();
661     if (!d->isNameCached) {
662         // ###
663         if (!d->object) {
664         } else if (d->isValueType()) {
665             QString rv = d->core.name(d->object) + QLatin1Char('.');
666
667             QQmlEnginePrivate *ep = d->engine?QQmlEnginePrivate::get(d->engine):0;
668             QQmlValueType *valueType = 0;
669             if (ep) valueType = ep->valueTypes[d->core.propType];
670             else valueType = QQmlValueTypeFactory::valueType(d->core.propType);
671             Q_ASSERT(valueType);
672
673             const char *vtName = valueType->metaObject()->property(d->core.valueTypeCoreIndex).name();
674             rv += QString::fromUtf8(vtName);
675
676             if (!ep) delete valueType;
677
678             d->nameCache = rv;
679         } else if (type() & SignalProperty) {
680             QString name = QLatin1String("on") + d->core.name(d->object);
681             name[2] = name.at(2).toUpper();
682             d->nameCache = name;
683         } else {
684             d->nameCache = d->core.name(d->object);
685         }
686         d->isNameCached = true;
687     }
688
689     return d->nameCache;
690 }
691
692 /*!
693   Returns the \l{QMetaProperty} {Qt property} associated with
694   this QML property.
695  */
696 QMetaProperty QQmlProperty::property() const
697 {
698     if (!d)
699         return QMetaProperty();
700     if (type() & Property && d->core.isValid() && d->object)
701         return d->object->metaObject()->property(d->core.coreIndex);
702     else
703         return QMetaProperty();
704 }
705
706 /*!
707     Return the QMetaMethod for this property if it is a SignalProperty,
708     otherwise returns an invalid QMetaMethod.
709 */
710 QMetaMethod QQmlProperty::method() const
711 {
712     if (!d)
713         return QMetaMethod();
714     if (type() & SignalProperty && d->object)
715         return d->object->metaObject()->method(d->core.coreIndex);
716     else
717         return QMetaMethod();
718 }
719
720 /*!
721     Returns the binding associated with this property, or 0 if no binding
722     exists.
723 */
724 QQmlAbstractBinding *
725 QQmlPropertyPrivate::binding(const QQmlProperty &that)
726 {
727     if (!that.d || !that.isProperty() || !that.d->object)
728         return 0;
729
730     return binding(that.d->object, that.d->core.coreIndex,
731                    that.d->core.getValueTypeCoreIndex());
732 }
733
734 /*!
735     Set the binding associated with this property to \a newBinding.  Returns
736     the existing binding (if any), otherwise 0.
737
738     \a newBinding will be enabled, and the returned binding (if any) will be
739     disabled.
740
741     Ownership of \a newBinding transfers to QML.  Ownership of the return value
742     is assumed by the caller.
743
744     \a flags is passed through to the binding and is used for the initial update (when
745     the binding sets the initial value, it will use these flags for the write).
746 */
747 QQmlAbstractBinding *
748 QQmlPropertyPrivate::setBinding(const QQmlProperty &that,
749                                         QQmlAbstractBinding *newBinding,
750                                         WriteFlags flags)
751 {
752     if (!that.d || !that.isProperty() || !that.d->object) {
753         if (newBinding)
754             newBinding->destroy();
755         return 0;
756     }
757
758     if (newBinding) {
759         // In the case that the new binding is provided, we must target the property it
760         // is associated with.  If we don't do this, retargetBinding() can fail.
761         QObject *object = newBinding->object();
762         int pi = newBinding->propertyIndex();
763
764         int core = pi & 0xFFFFFF;
765         int vt = (pi & 0xFF000000)?(pi >> 24):-1;
766
767         return setBinding(object, core, vt, newBinding, flags);
768     } else {
769         return setBinding(that.d->object, that.d->core.coreIndex,
770                           that.d->core.getValueTypeCoreIndex(),
771                           newBinding, flags);
772     }
773 }
774
775 QQmlAbstractBinding *
776 QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
777 {
778     QQmlData *data = QQmlData::get(object);
779     if (!data)
780         return 0;
781
782     QQmlPropertyData *propertyData =
783         data->propertyCache?data->propertyCache->property(coreIndex):0;
784     if (propertyData && propertyData->isAlias()) {
785         QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
786
787         QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
788         if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
789             return 0;
790
791         // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
792         Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
793         aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
794         return binding(aObject, aCoreIndex, aValueTypeIndex);
795     }
796
797     if (!data->hasBindingBit(coreIndex))
798         return 0;
799
800     QQmlAbstractBinding *binding = data->bindings;
801     while (binding && binding->propertyIndex() != coreIndex)
802         binding = binding->nextBinding();
803
804     if (binding && valueTypeIndex != -1) {
805         if (binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) {
806             int index = coreIndex | (valueTypeIndex << 24);
807             binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
808         }
809     }
810
811     return binding;
812 }
813
814 void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
815                                                   QObject **targetObject, int *targetBindingIndex)
816 {
817     int coreIndex = bindingIndex & 0xFFFFFF;
818     int valueTypeIndex = bindingIndex >> 24;
819     if (valueTypeIndex == 0) valueTypeIndex = -1;
820
821     QQmlData *data = QQmlData::get(object, false);
822     if (data) {
823         QQmlPropertyData *propertyData =
824             data->propertyCache?data->propertyCache->property(coreIndex):0;
825         if (propertyData && propertyData->isAlias()) {
826             QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
827
828             QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
829             if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
830                 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
831                 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
832
833                 int aBindingIndex = aCoreIndex;
834                 if (aValueTypeIndex != -1)
835                     aBindingIndex |= aValueTypeIndex << 24;
836                 else if (valueTypeIndex != -1)
837                     aBindingIndex |= valueTypeIndex << 24;
838
839                 findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
840                 return;
841             }
842         }
843     }
844
845     *targetObject = object;
846     *targetBindingIndex = bindingIndex;
847 }
848
849 QQmlAbstractBinding *
850 QQmlPropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
851                                         QQmlAbstractBinding *newBinding, WriteFlags flags)
852 {
853     QQmlData *data = QQmlData::get(object, 0 != newBinding);
854     QQmlAbstractBinding *binding = 0;
855
856     if (data) {
857         QQmlPropertyData *propertyData =
858             data->propertyCache?data->propertyCache->property(coreIndex):0;
859         if (propertyData && propertyData->isAlias()) {
860             QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
861
862             QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
863             if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
864                 if (newBinding) newBinding->destroy();
865                 return 0;
866             }
867
868             // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
869             Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
870             aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
871             return setBinding(aObject, aCoreIndex, aValueTypeIndex, newBinding, flags);
872         }
873     }
874
875     if (data && data->hasBindingBit(coreIndex)) {
876         binding = data->bindings;
877
878         while (binding && binding->propertyIndex() != coreIndex)
879             binding = binding->nextBinding();
880     }
881
882     int index = coreIndex;
883     if (valueTypeIndex != -1)
884         index |= (valueTypeIndex << 24);
885
886     if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
887         binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
888
889     if (binding) {
890         binding->removeFromObject();
891         binding->setEnabled(false, 0);
892     }
893
894     if (newBinding) {
895         if (newBinding->propertyIndex() != index || newBinding->object() != object)
896             newBinding->retargetBinding(object, index);
897
898         Q_ASSERT(newBinding->propertyIndex() == index);
899         Q_ASSERT(newBinding->object() == object);
900
901         newBinding->addToObject();
902         newBinding->setEnabled(true, flags);
903     }
904
905     return binding;
906 }
907
908 QQmlAbstractBinding *
909 QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
910                                                 QQmlAbstractBinding *newBinding)
911 {
912     QQmlData *data = QQmlData::get(object, 0 != newBinding);
913     QQmlAbstractBinding *binding = 0;
914
915     if (data) {
916         QQmlPropertyData *propertyData =
917             data->propertyCache?data->propertyCache->property(coreIndex):0;
918         if (propertyData && propertyData->isAlias()) {
919             QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
920
921             QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
922             if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
923                 if (newBinding) newBinding->destroy();
924                 return 0;
925             }
926
927             // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
928             Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
929             aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
930             return setBindingNoEnable(aObject, aCoreIndex, aValueTypeIndex, newBinding);
931         }
932     }
933
934     if (data && data->hasBindingBit(coreIndex)) {
935         binding = data->bindings;
936
937         while (binding && binding->propertyIndex() != coreIndex)
938             binding = binding->nextBinding();
939     }
940
941     int index = coreIndex;
942     if (valueTypeIndex != -1)
943         index |= (valueTypeIndex << 24);
944
945     if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
946         binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
947
948     if (binding)
949         binding->removeFromObject();
950
951     if (newBinding) {
952         if (newBinding->propertyIndex() != index || newBinding->object() != object)
953             newBinding->retargetBinding(object, index);
954
955         Q_ASSERT(newBinding->propertyIndex() == index);
956         Q_ASSERT(newBinding->object() == object);
957
958         newBinding->addToObject();
959     }
960
961     return binding;
962 }
963
964 /*!
965     Activates a shared binding which was previously created but not added to the
966     object.  This is needed when an optimized binding is invalidated.
967 */
968 QQmlAbstractBinding *QQmlPropertyPrivate::activateSharedBinding(QQmlContextData *context,
969                                                                 int sharedIdx, WriteFlags flags)
970 {
971     QQmlAbstractBinding *newBinding = 0;
972     newBinding = context->v8bindings->binding(sharedIdx);
973
974     if (!newBinding)
975         return newBinding;
976
977     // This binding now references the bindings object
978     context->v8bindings->addref();
979
980     QObject *object = newBinding->object();
981     int pi = newBinding->propertyIndex();
982
983     int core = pi & 0xFFFFFF;
984     int vt = (pi & 0xFF000000)?(pi >> 24):-1;
985
986     return setBinding(object, core, vt, newBinding, flags);
987 }
988
989 /*!
990     Returns the expression associated with this signal property, or 0 if no
991     signal expression exists.
992 */
993 QQmlBoundSignalExpression *
994 QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
995 {
996     if (!(that.type() & QQmlProperty::SignalProperty))
997         return 0;
998
999     QQmlData *data = QQmlData::get(that.d->object);
1000     if (!data)
1001         return 0;
1002
1003     QQmlAbstractBoundSignal *signalHandler = data->signalHandlers;
1004
1005     while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex())
1006         signalHandler = signalHandler->m_nextSignal;
1007
1008     if (signalHandler)
1009         return signalHandler->expression();
1010
1011     return 0;
1012 }
1013
1014 /*!
1015     Set the signal expression associated with this signal property to \a expr.
1016     Returns the existing signal expression (if any), otherwise null.
1017
1018     A reference to \a expr will be added by QML.  Ownership of the return value
1019     reference is assumed by the caller.
1020 */
1021 QQmlBoundSignalExpressionPointer
1022 QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that,
1023                                          QQmlBoundSignalExpression *expr)
1024 {
1025     if (expr)
1026         expr->addref();
1027     return QQmlPropertyPrivate::takeSignalExpression(that, expr);
1028 }
1029
1030 /*!
1031     Set the signal expression associated with this signal property to \a expr.
1032     Returns the existing signal expression (if any), otherwise null.
1033
1034     Ownership of \a expr transfers to QML.  Ownership of the return value
1035     reference is assumed by the caller.
1036 */
1037 QQmlBoundSignalExpressionPointer
1038 QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that,
1039                                          QQmlBoundSignalExpression *expr)
1040 {
1041     if (!(that.type() & QQmlProperty::SignalProperty)) {
1042         if (expr)
1043             expr->release();
1044         return 0;
1045     }
1046
1047     QQmlData *data = QQmlData::get(that.d->object, 0 != expr);
1048     if (!data)
1049         return 0;
1050
1051     QQmlAbstractBoundSignal *signalHandler = data->signalHandlers;
1052
1053     while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex())
1054         signalHandler = signalHandler->m_nextSignal;
1055
1056     if (signalHandler)
1057         return signalHandler->takeExpression(expr);
1058
1059     if (expr) {
1060         int signalIndex = QQmlPropertyPrivate::get(that)->signalIndex();
1061         QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, signalIndex, that.d->object,
1062                                                       expr->context()->engine);
1063         signal->takeExpression(expr);
1064     }
1065     return 0;
1066 }
1067
1068 /*!
1069     Returns the property value.
1070 */
1071 QVariant QQmlProperty::read() const
1072 {
1073     if (!d)
1074         return QVariant();
1075     if (!d->object)
1076         return QVariant();
1077
1078     if (type() & SignalProperty) {
1079
1080         return QVariant();
1081
1082     } else if (type() & Property) {
1083
1084         return d->readValueProperty();
1085
1086     }
1087     return QVariant();
1088 }
1089
1090 /*!
1091 Return the \a name property value of \a object.  This method is equivalent to:
1092 \code
1093     QQmlProperty p(object, name);
1094     p.read();
1095 \endcode
1096 */
1097 QVariant QQmlProperty::read(QObject *object, const QString &name)
1098 {
1099     QQmlProperty p(object, name);
1100     return p.read();
1101 }
1102
1103 /*!
1104   Return the \a name property value of \a object using the
1105   \l{QQmlContext} {context} \a ctxt.  This method is
1106   equivalent to:
1107
1108   \code
1109     QQmlProperty p(object, name, context);
1110     p.read();
1111   \endcode
1112 */
1113 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlContext *ctxt)
1114 {
1115     QQmlProperty p(object, name, ctxt);
1116     return p.read();
1117 }
1118
1119 /*!
1120
1121   Return the \a name property value of \a object using the environment
1122   for instantiating QML components that is provided by \a engine. .
1123   This method is equivalent to:
1124
1125   \code
1126     QQmlProperty p(object, name, engine);
1127     p.read();
1128   \endcode
1129 */
1130 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlEngine *engine)
1131 {
1132     QQmlProperty p(object, name, engine);
1133     return p.read();
1134 }
1135
1136 QVariant QQmlPropertyPrivate::readValueProperty()
1137 {
1138     if (isValueType()) {
1139
1140         QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
1141         QQmlValueType *valueType = 0;
1142         if (ep) valueType = ep->valueTypes[core.propType];
1143         else valueType = QQmlValueTypeFactory::valueType(core.propType);
1144         Q_ASSERT(valueType);
1145
1146         valueType->read(object, core.coreIndex);
1147
1148         QVariant rv = valueType->metaObject()->property(core.valueTypeCoreIndex).read(valueType);
1149
1150         if (!ep) delete valueType;
1151         return rv;
1152
1153     } else if (core.isQList()) {
1154
1155         QQmlListProperty<QObject> prop;
1156         void *args[] = { &prop, 0 };
1157         QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1158         return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType, engine));
1159
1160     } else if (core.isQObject()) {
1161
1162         QObject *rv = 0;
1163         void *args[] = { &rv, 0 };
1164         QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1165         return QVariant::fromValue(rv);
1166
1167     } else {
1168
1169         if (!core.propType) // Unregistered type
1170             return object->metaObject()->property(core.coreIndex).read(object);
1171
1172         QVariant value;
1173         int status = -1;
1174         void *args[] = { 0, &value, &status };
1175         if (core.propType == QMetaType::QVariant) {
1176             args[0] = &value;
1177         } else {
1178             value = QVariant(core.propType, (void*)0);
1179             args[0] = value.data();
1180         }
1181         QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1182         if (core.propType != QMetaType::QVariant && args[0] != value.data())
1183             return QVariant((QVariant::Type)core.propType, args[0]);
1184
1185         return value;
1186     }
1187 }
1188
1189 // helper function to allow assignment / binding to QList<QUrl> properties.
1190 static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context)
1191 {
1192     QList<QUrl> urls;
1193     if (value.userType() == qMetaTypeId<QUrl>()) {
1194         urls.append(value.toUrl());
1195     } else if (value.userType() == qMetaTypeId<QString>()) {
1196         urls.append(QUrl(value.toString()));
1197     } else if (value.userType() == qMetaTypeId<QByteArray>()) {
1198         urls.append(QUrl(QString::fromUtf8(value.toByteArray())));
1199     } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
1200         urls = value.value<QList<QUrl> >();
1201     } else if (value.userType() == qMetaTypeId<QStringList>()) {
1202         QStringList urlStrings = value.value<QStringList>();
1203         for (int i = 0; i < urlStrings.size(); ++i)
1204             urls.append(QUrl(urlStrings.at(i)));
1205     } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
1206         QList<QString> urlStrings = value.value<QList<QString> >();
1207         for (int i = 0; i < urlStrings.size(); ++i)
1208             urls.append(QUrl(urlStrings.at(i)));
1209     } // note: QList<QByteArray> is not currently supported.
1210
1211     QList<QUrl> resolvedUrls;
1212     for (int i = 0; i < urls.size(); ++i) {
1213         QUrl u = urls.at(i);
1214         if (context && u.isRelative() && !u.isEmpty())
1215             u = context->resolvedUrl(u);
1216         resolvedUrls.append(u);
1217     }
1218
1219     return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
1220 }
1221
1222 //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1223 bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1224 {
1225     if (!object || !prop.isWritable())
1226         return false;
1227
1228     QVariant v = value;
1229     if (prop.isEnumType()) {
1230         QMetaEnum menum = prop.enumerator();
1231         if (v.userType() == QVariant::String
1232 #ifdef QT3_SUPPORT
1233             || v.userType() == QVariant::CString
1234 #endif
1235             ) {
1236             bool ok;
1237             if (prop.isFlagType())
1238                 v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
1239             else
1240                 v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
1241             if (!ok)
1242                 return false;
1243         } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
1244             int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
1245             if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData())
1246                 return false;
1247             v = QVariant(*reinterpret_cast<const int *>(v.constData()));
1248         }
1249         v.convert(QVariant::Int);
1250     }
1251
1252     // the status variable is changed by qt_metacall to indicate what it did
1253     // this feature is currently only used by QtDBus and should not be depended
1254     // upon. Don't change it without looking into QDBusAbstractInterface first
1255     // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1256     // changed: result stored directly in value, return the value of status
1257     int status = -1;
1258     void *argv[] = { v.data(), &v, &status, &flags };
1259     QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
1260     return status;
1261 }
1262
1263 bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
1264 {
1265     return writeValueProperty(object, engine, core, value, effectiveContext(), flags);
1266 }
1267
1268 bool
1269 QQmlPropertyPrivate::writeValueProperty(QObject *object, QQmlEngine *engine,
1270                                                 const QQmlPropertyData &core,
1271                                                 const QVariant &value,
1272                                                 QQmlContextData *context, WriteFlags flags)
1273 {
1274     // Remove any existing bindings on this property
1275     if (!(flags & DontRemoveBinding) && object) {
1276         QQmlAbstractBinding *binding = setBinding(object, core.coreIndex,
1277                                                           core.getValueTypeCoreIndex(),
1278                                                           0, flags);
1279         if (binding) binding->destroy();
1280     }
1281
1282     bool rv = false;
1283     if (core.isValueTypeVirtual()) {
1284         QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
1285
1286         QQmlValueType *writeBack = 0;
1287         if (ep) {
1288             writeBack = ep->valueTypes[core.propType];
1289         } else {
1290             writeBack = QQmlValueTypeFactory::valueType(core.propType);
1291         }
1292
1293         writeBack->read(object, core.coreIndex);
1294
1295         QQmlPropertyData data = core;
1296         data.setFlags(QQmlPropertyData::Flag(core.valueTypeFlags));
1297         data.coreIndex = core.valueTypeCoreIndex;
1298         data.propType = core.valueTypePropType;
1299
1300         rv = write(writeBack, data, value, context, flags);
1301
1302         writeBack->write(object, core.coreIndex, flags);
1303         if (!ep) delete writeBack;
1304
1305     } else {
1306
1307         rv = write(object, core, value, context, flags);
1308
1309     }
1310
1311     return rv;
1312 }
1313
1314 bool QQmlPropertyPrivate::write(QObject *object, 
1315                                         const QQmlPropertyData &property,
1316                                         const QVariant &value, QQmlContextData *context,
1317                                         WriteFlags flags)
1318 {
1319     int coreIdx = property.coreIndex;
1320     int status = -1;    //for dbus
1321
1322     if (property.isEnum()) {
1323         QMetaProperty prop = object->metaObject()->property(property.coreIndex);
1324         QVariant v = value;
1325         // Enum values come through the script engine as doubles
1326         if (value.userType() == QVariant::Double) {
1327             double integral;
1328             double fractional = modf(value.toDouble(), &integral);
1329             if (qFuzzyIsNull(fractional))
1330                 v.convert(QVariant::Int);
1331         }
1332         return writeEnumProperty(prop, coreIdx, object, v, flags);
1333     }
1334
1335     int propertyType = property.propType;
1336     int variantType = value.userType();
1337
1338     QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
1339
1340     if (propertyType == QVariant::Url) {
1341
1342         QUrl u;
1343         bool found = false;
1344         if (variantType == QVariant::Url) {
1345             u = value.toUrl();
1346             found = true;
1347         } else if (variantType == QVariant::ByteArray) {
1348             QString input(QString::fromUtf8(value.toByteArray()));
1349             // Encoded dir-separators defeat QUrl processing - decode them first
1350             input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
1351             u = QUrl(input);
1352             found = true;
1353         } else if (variantType == QVariant::String) {
1354             QString input(value.toString());
1355             // Encoded dir-separators defeat QUrl processing - decode them first
1356             input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
1357             u = QUrl(input);
1358             found = true;
1359         }
1360
1361         if (!found)
1362             return false;
1363
1364         if (context && u.isRelative() && !u.isEmpty())
1365             u = context->resolvedUrl(u);
1366         int status = -1;
1367         void *argv[] = { &u, 0, &status, &flags };
1368         QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1369
1370     } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
1371         QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
1372         int status = -1;
1373         void *argv[] = { &urlSeq, 0, &status, &flags };
1374         QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1375     } else if (variantType == propertyType) {
1376
1377         void *a[] = { (void *)value.constData(), 0, &status, &flags };
1378         QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1379
1380     } else if (qMetaTypeId<QVariant>() == propertyType) {
1381
1382         void *a[] = { (void *)&value, 0, &status, &flags };
1383         QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1384
1385     } else if (property.isQObject()) {
1386
1387         QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, value.userType());
1388
1389         if (valMo.isNull())
1390             return false;
1391
1392         QObject *o = *(QObject **)value.constData();
1393         QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
1394
1395         if (o) valMo = o;
1396
1397         if (QQmlMetaObject::canConvert(valMo, propMo)) {
1398             void *args[] = { &o, 0, &status, &flags };
1399             QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args);
1400         } else if (!o && QQmlMetaObject::canConvert(propMo, valMo)) {
1401             // In the case of a null QObject, we assign the null if there is
1402             // any change that the null variant type could be up or down cast to
1403             // the property type.
1404             void *args[] = { &o, 0, &status, &flags };
1405             QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args);
1406         } else {
1407             return false;
1408         }
1409
1410     } else if (property.isQList()) {
1411
1412         QQmlMetaObject listType;
1413
1414         if (enginePriv) {
1415             listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
1416         } else {
1417             QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType));
1418             if (!type) return false;
1419             listType = type->baseMetaObject();
1420         }
1421         if (listType.isNull()) return false;
1422
1423         QQmlListProperty<void> prop;
1424         void *args[] = { &prop, 0 };
1425         QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
1426
1427         if (!prop.clear) return false;
1428
1429         prop.clear(&prop);
1430
1431         if (value.userType() == qMetaTypeId<QQmlListReference>()) {
1432             QQmlListReference qdlr = value.value<QQmlListReference>();
1433
1434             for (int ii = 0; ii < qdlr.count(); ++ii) {
1435                 QObject *o = qdlr.at(ii);
1436                 if (o && !QQmlMetaObject::canConvert(o, listType))
1437                     o = 0;
1438                 prop.append(&prop, (void *)o);
1439             }
1440         } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
1441             const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1442
1443             for (int ii = 0; ii < list.count(); ++ii) {
1444                 QObject *o = list.at(ii);
1445                 if (o && !QQmlMetaObject::canConvert(o, listType))
1446                     o = 0;
1447                 prop.append(&prop, (void *)o);
1448             }
1449         } else {
1450             QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value);
1451             if (o && !QQmlMetaObject::canConvert(o, listType))
1452                 o = 0;
1453             prop.append(&prop, (void *)o);
1454         }
1455
1456     } else {
1457         Q_ASSERT(variantType != propertyType);
1458
1459         bool ok = false;
1460         QVariant v;
1461         if (variantType == QVariant::String)
1462             v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
1463         if (!ok) {
1464             v = value;
1465             if (v.convert(propertyType)) {
1466                 ok = true;
1467             } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
1468                 QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
1469                 if (con) {
1470                     v = con(value.toString());
1471                     if (v.userType() == propertyType)
1472                         ok = true;
1473                 }
1474             }
1475         }
1476         if (!ok) {
1477             // the only other option is that they are assigning a single value
1478             // to a sequence type property (eg, an int to a QList<int> property).
1479             // Note that we've already handled single-value assignment to QList<QUrl> properties.
1480             if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
1481                 QList<int> list;
1482                 list << value.toInt();
1483                 v = QVariant::fromValue<QList<int> >(list);
1484                 ok = true;
1485             } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
1486                 QList<qreal> list;
1487                 list << value.toReal();
1488                 v = QVariant::fromValue<QList<qreal> >(list);
1489                 ok = true;
1490             } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
1491                 QList<bool> list;
1492                 list << value.toBool();
1493                 v = QVariant::fromValue<QList<bool> >(list);
1494                 ok = true;
1495             } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
1496                 QList<QString> list;
1497                 list << value.toString();
1498                 v = QVariant::fromValue<QList<QString> >(list);
1499                 ok = true;
1500             } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
1501                 QStringList list;
1502                 list << value.toString();
1503                 v = QVariant::fromValue<QStringList>(list);
1504                 ok = true;
1505             }
1506         }
1507
1508         if (ok) {
1509             void *a[] = { (void *)v.constData(), 0, &status, &flags};
1510             QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1511         } else {
1512             return false;
1513         }
1514     }
1515
1516     return true;
1517 }
1518
1519 // Returns true if successful, false if an error description was set on expression
1520 bool QQmlPropertyPrivate::writeBinding(QObject *object,
1521                                                const QQmlPropertyData &core,
1522                                                QQmlContextData *context,
1523                                                QQmlJavaScriptExpression *expression,
1524                                                v8::Handle<v8::Value> result, bool isUndefined,
1525                                                WriteFlags flags)
1526 {
1527     Q_ASSERT(object);
1528     Q_ASSERT(core.coreIndex != -1);
1529
1530     QQmlEngine *engine = context->engine;
1531     QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
1532
1533 #define QUICK_STORE(cpptype, conversion) \
1534         { \
1535             cpptype o = (conversion); \
1536             int status = -1; \
1537             void *argv[] = { &o, 0, &status, &flags }; \
1538             QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \
1539             return true; \
1540         } \
1541
1542
1543     if (!isUndefined && !core.isValueTypeVirtual()) {
1544         switch (core.propType) {
1545         case QMetaType::Int:
1546             if (result->IsInt32())
1547                 QUICK_STORE(int, result->Int32Value())
1548             else if (result->IsNumber())
1549                 QUICK_STORE(int, qRound(result->NumberValue()))
1550             break;
1551         case QMetaType::Double:
1552             if (result->IsNumber())
1553                 QUICK_STORE(double, result->NumberValue())
1554             break;
1555         case QMetaType::Float:
1556             if (result->IsNumber())
1557                 QUICK_STORE(float, result->NumberValue())
1558             break;
1559         case QMetaType::QString:
1560             if (result->IsString())
1561                 QUICK_STORE(QString, v8engine->toString(result))
1562             break;
1563         default:
1564             break;
1565         }
1566     }
1567 #undef QUICK_STORE
1568
1569     int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType;
1570
1571     QQmlJavaScriptExpression::DeleteWatcher watcher(expression);
1572
1573     QVariant value;
1574     bool isVarProperty = core.isVarProperty();
1575
1576     if (isUndefined) {
1577     } else if (core.isQList()) {
1578         value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
1579     } else if (result->IsNull() && core.isQObject()) {
1580         value = QVariant::fromValue((QObject *)0);
1581     } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
1582         value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
1583     } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) {
1584         value = v8engine->toVariant(result, type);
1585     }
1586
1587     if (expression->hasError()) {
1588         return false;
1589     } else if (isVarProperty) {
1590         if (!result.IsEmpty() && result->IsFunction()
1591                 && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
1592             // we explicitly disallow this case to avoid confusion.  Users can still store one
1593             // in an array in a var property if they need to, but the common case is user error.
1594             expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1595             return false;
1596         }
1597
1598         typedef QQmlVMEMetaObject VMEMO;
1599         QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
1600         Q_ASSERT(vmemo);
1601         vmemo->setVMEProperty(core.coreIndex, result);
1602     } else if (isUndefined && core.isResettable()) {
1603         void *args[] = { 0 };
1604         QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
1605     } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
1606         writeValueProperty(object, engine, core, QVariant(), context, flags);
1607     } else if (type == qMetaTypeId<QJSValue>()) {
1608         if (!result.IsEmpty() && result->IsFunction()
1609                 && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
1610             expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1611             return false;
1612         }
1613         writeValueProperty(object, engine, core, QVariant::fromValue(v8engine->scriptValueFromInternal(result)), context, flags);
1614     } else if (isUndefined) {
1615         QString errorStr = QLatin1String("Unable to assign [undefined] to ");
1616         if (!QMetaType::typeName(type))
1617             errorStr += QLatin1String("[unknown property type]");
1618         else
1619             errorStr += QLatin1String(QMetaType::typeName(type));
1620         expression->delayedError()->setErrorDescription(errorStr);
1621         return false;
1622     } else if (result->IsFunction()) {
1623         if (!result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty())
1624             expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1625         else
1626             expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
1627         return false;
1628     } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
1629
1630         if (watcher.wasDeleted())
1631             return true;
1632
1633         const char *valueType = 0;
1634         const char *propertyType = 0;
1635
1636         if (value.userType() == QMetaType::QObjectStar) {
1637             if (QObject *o = *(QObject **)value.constData()) {
1638                 valueType = o->metaObject()->className();
1639
1640                 QQmlMetaObject propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type);
1641                 if (!propertyMetaObject.isNull())
1642                     propertyType = propertyMetaObject.className();
1643             }
1644         } else if (value.userType() != QVariant::Invalid) {
1645             valueType = QMetaType::typeName(value.userType());
1646         }
1647
1648         if (!valueType)
1649             valueType = "null";
1650         if (!propertyType)
1651             propertyType = QMetaType::typeName(type);
1652         if (!propertyType)
1653             propertyType = "[unknown property type]";
1654
1655         expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign ") +
1656                                                         QLatin1String(valueType) +
1657                                                         QLatin1String(" to ") +
1658                                                         QLatin1String(propertyType));
1659         return false;
1660     }
1661
1662     return true;
1663 }
1664
1665 QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
1666 {
1667     if (engine) {
1668         return engine->rawMetaObjectForType(userType);
1669     } else {
1670         QQmlType *type = QQmlMetaType::qmlType(userType);
1671         return QQmlMetaObject(type?type->baseMetaObject():0);
1672     }
1673 }
1674
1675 /*!
1676     Sets the property value to \a value and returns true.
1677     Returns false if the property can't be set because the
1678     \a value is the wrong type, for example.
1679  */
1680 bool QQmlProperty::write(const QVariant &value) const
1681 {
1682     return QQmlPropertyPrivate::write(*this, value, 0);
1683 }
1684
1685 /*!
1686   Writes \a value to the \a name property of \a object.  This method
1687   is equivalent to:
1688
1689   \code
1690     QQmlProperty p(object, name);
1691     p.write(value);
1692   \endcode
1693 */
1694 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
1695 {
1696     QQmlProperty p(object, name);
1697     return p.write(value);
1698 }
1699
1700 /*!
1701   Writes \a value to the \a name property of \a object using the
1702   \l{QQmlContext} {context} \a ctxt.  This method is
1703   equivalent to:
1704
1705   \code
1706     QQmlProperty p(object, name, ctxt);
1707     p.write(value);
1708   \endcode
1709 */
1710 bool QQmlProperty::write(QObject *object,
1711                                  const QString &name,
1712                                  const QVariant &value,
1713                                  QQmlContext *ctxt)
1714 {
1715     QQmlProperty p(object, name, ctxt);
1716     return p.write(value);
1717 }
1718
1719 /*!
1720
1721   Writes \a value to the \a name property of \a object using the
1722   environment for instantiating QML components that is provided by
1723   \a engine.  This method is equivalent to:
1724
1725   \code
1726     QQmlProperty p(object, name, engine);
1727     p.write(value);
1728   \endcode
1729 */
1730 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
1731                                  QQmlEngine *engine)
1732 {
1733     QQmlProperty p(object, name, engine);
1734     return p.write(value);
1735 }
1736
1737 /*!
1738     Resets the property and returns true if the property is
1739     resettable.  If the property is not resettable, nothing happens
1740     and false is returned.
1741 */
1742 bool QQmlProperty::reset() const
1743 {
1744     if (isResettable()) {
1745         void *args[] = { 0 };
1746         QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1747         return true;
1748     } else {
1749         return false;
1750     }
1751 }
1752
1753 bool QQmlPropertyPrivate::write(const QQmlProperty &that,
1754                                         const QVariant &value, WriteFlags flags)
1755 {
1756     if (!that.d)
1757         return false;
1758     if (that.d->object && that.type() & QQmlProperty::Property &&
1759         that.d->core.isValid() && that.isWritable())
1760         return that.d->writeValueProperty(value, flags);
1761     else
1762         return false;
1763 }
1764
1765 /*!
1766     Returns true if the property has a change notifier signal, otherwise false.
1767 */
1768 bool QQmlProperty::hasNotifySignal() const
1769 {
1770     if (type() & Property && d->object) {
1771         return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1772     }
1773     return false;
1774 }
1775
1776 /*!
1777     Returns true if the property needs a change notifier signal for bindings
1778     to remain upto date, false otherwise.
1779
1780     Some properties, such as attached properties or those whose value never
1781     changes, do not require a change notifier.
1782 */
1783 bool QQmlProperty::needsNotifySignal() const
1784 {
1785     return type() & Property && !property().isConstant();
1786 }
1787
1788 /*!
1789     Connects the property's change notifier signal to the
1790     specified \a method of the \a dest object and returns
1791     true. Returns false if this metaproperty does not
1792     represent a regular Qt property or if it has no
1793     change notifier signal, or if the \a dest object does
1794     not have the specified \a method.
1795 */
1796 bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
1797 {
1798     if (!(type() & Property) || !d->object)
1799         return false;
1800
1801     QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1802     if (prop.hasNotifySignal()) {
1803         return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1804     } else {
1805         return false;
1806     }
1807 }
1808
1809 /*!
1810     Connects the property's change notifier signal to the
1811     specified \a slot of the \a dest object and returns
1812     true. Returns false if this metaproperty does not
1813     represent a regular Qt property or if it has no
1814     change notifier signal, or if the \a dest object does
1815     not have the specified \a slot.
1816 */
1817 bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
1818 {
1819     if (!(type() & Property) || !d->object)
1820         return false;
1821
1822     QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1823     if (prop.hasNotifySignal()) {
1824         QByteArray signal('2' + prop.notifySignal().methodSignature());
1825         return QObject::connect(d->object, signal.constData(), dest, slot);
1826     } else  {
1827         return false;
1828     }
1829 }
1830
1831 /*!
1832     Return the Qt metaobject index of the property.
1833 */
1834 int QQmlProperty::index() const
1835 {
1836     return d ? d->core.coreIndex : -1;
1837 }
1838
1839 int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that)
1840 {
1841     return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
1842 }
1843
1844 /*!
1845     Returns the "property index" for use in bindings.  The top 8 bits are the value type
1846     offset, and 0 otherwise.  The bottom 24-bits are the regular property index.
1847 */
1848 int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that)
1849 {
1850     if (!that.d)
1851         return -1;
1852     return bindingIndex(that.d->core);
1853 }
1854
1855 int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that)
1856 {
1857     int rv = that.coreIndex;
1858     if (rv != -1 && that.isValueTypeVirtual())
1859         rv = rv | (that.valueTypeCoreIndex << 24);
1860     return rv;
1861 }
1862
1863 QQmlPropertyData
1864 QQmlPropertyPrivate::saveValueType(const QQmlPropertyData &base,
1865                                    const QMetaObject *subObject, int subIndex,
1866                                    QQmlEngine *)
1867 {
1868     QMetaProperty subProp = subObject->property(subIndex);
1869
1870     QQmlPropertyData core = base;
1871     core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
1872     core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp);
1873     core.valueTypeCoreIndex = subIndex;
1874     core.valueTypePropType = subProp.userType();
1875
1876     return core;
1877 }
1878
1879 QQmlProperty
1880 QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
1881                                      QQmlContextData *ctxt)
1882 {
1883     QQmlProperty prop;
1884
1885     prop.d = new QQmlPropertyPrivate;
1886     prop.d->object = object;
1887     prop.d->context = ctxt;
1888     prop.d->engine = ctxt?ctxt->engine:0;
1889
1890     prop.d->core = data;
1891
1892     return prop;
1893 }
1894
1895 /*!
1896     Return the signal corresponding to \a name
1897 */
1898 QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1899 {
1900     Q_ASSERT(mo);
1901     int methods = mo->methodCount();
1902     for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1903         QMetaMethod method = mo->method(ii);
1904
1905         if (method.name() == name && (method.methodType() & QMetaMethod::Signal))
1906             return method;
1907     }
1908
1909     // If no signal is found, but the signal is of the form "onBlahChanged",
1910     // return the notify signal for the property "Blah"
1911     if (name.endsWith("Changed")) {
1912         QByteArray propName = name.mid(0, name.length() - 7);
1913         int propIdx = mo->indexOfProperty(propName.constData());
1914         if (propIdx >= 0) {
1915             QMetaProperty prop = mo->property(propIdx);
1916             if (prop.hasNotifySignal())
1917                 return prop.notifySignal();
1918         }
1919     }
1920
1921     return QMetaMethod();
1922 }
1923
1924 /*! \internal
1925     If \a indexInSignalRange is true, \a index is treated as a signal index
1926     (see QObjectPrivate::signalIndex()), otherwise it is treated as a
1927     method index (QMetaMethod::methodIndex()).
1928 */
1929 static inline void flush_vme_signal(const QObject *object, int index, bool indexInSignalRange)
1930 {
1931     QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1932     if (data && data->propertyCache) {
1933         QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
1934                                                         : data->propertyCache->method(index);
1935
1936         if (property && property->isVMESignal()) {
1937             QQmlVMEMetaObject *vme;
1938             if (indexInSignalRange)
1939                 vme = QQmlVMEMetaObject::getForSignal(const_cast<QObject *>(object), index);
1940             else
1941                 vme = QQmlVMEMetaObject::getForMethod(const_cast<QObject *>(object), index);
1942             vme->connectAliasSignal(index, indexInSignalRange);
1943         }
1944     }
1945 }
1946
1947 /*!
1948 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1949 \a type and \a types.  This behaves identically to QMetaObject::connect() except that
1950 it connects any lazy "proxy" signal connections set up by QML.
1951
1952 It is possible that this logic should be moved to QMetaObject::connect().
1953 */
1954 bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
1955                                           const QObject *receiver, int method_index,
1956                                           int type, int *types)
1957 {
1958     static const bool indexInSignalRange = false;
1959     flush_vme_signal(sender, signal_index, indexInSignalRange);
1960     flush_vme_signal(receiver, method_index, indexInSignalRange);
1961
1962     return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1963 }
1964
1965 /*! \internal
1966     \a signal_index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
1967     This is different from QMetaMethod::methodIndex().
1968 */
1969 void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
1970 {
1971     static const bool indexInSignalRange = true;
1972     flush_vme_signal(sender, signal_index, indexInSignalRange);
1973 }
1974
1975 QT_END_NAMESPACE