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