f68c345f3ad2e70b8b06a56beb51e34f27b6e1d7
[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.isValid()) {
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 QQmlExpression *
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 QQmlExpression *
952 QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that,
953                                                      QQmlExpression *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         QQmlExpression *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 == QMetaType::UnknownType) || (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 (isVmeProperty) {
1504         typedef QQmlVMEMetaObject VMEMO;
1505         if (!result.IsEmpty() && result->IsFunction()
1506                 && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
1507             // we explicitly disallow this case to avoid confusion.  Users can still store one
1508             // in an array in a var property if they need to, but the common case is user error.
1509             expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1510             return false;
1511         }
1512         VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject()));
1513         vmemo->setVMEProperty(core.coreIndex, result);
1514     } else if (isUndefined && core.isResettable()) {
1515         void *args[] = { 0 };
1516         QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
1517     } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
1518         writeValueProperty(object, engine, core, QVariant(), context, flags);
1519     } else if (isUndefined) {
1520         expression->delayedError()->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(type)));
1521         return false;
1522     } else if (result->IsFunction()) {
1523         if (!result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty())
1524             expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1525         else
1526             expression->delayedError()->error.setDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
1527         return false;
1528     } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
1529
1530         if (watcher.wasDeleted()) 
1531             return true;
1532
1533         const char *valueType = 0;
1534         if (value.userType() == QVariant::Invalid) valueType = "null";
1535         else valueType = QMetaType::typeName(value.userType());
1536
1537         expression->delayedError()->error.setDescription(QLatin1String("Unable to assign ") +
1538                                                          QLatin1String(valueType) +
1539                                                          QLatin1String(" to ") +
1540                                                          QLatin1String(QMetaType::typeName(type)));
1541         return false;
1542     }
1543
1544     return true;
1545 }
1546
1547 const QMetaObject *QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
1548 {
1549     if (engine) {
1550         return engine->rawMetaObjectForType(userType);
1551     } else {
1552         QQmlType *type = QQmlMetaType::qmlType(userType);
1553         return type?type->baseMetaObject():0;
1554     }
1555 }
1556
1557 /*!
1558     Sets the property value to \a value and returns true.
1559     Returns false if the property can't be set because the
1560     \a value is the wrong type, for example.
1561  */
1562 bool QQmlProperty::write(const QVariant &value) const
1563 {
1564     return QQmlPropertyPrivate::write(*this, value, 0);
1565 }
1566
1567 /*!
1568   Writes \a value to the \a name property of \a object.  This method
1569   is equivalent to:
1570
1571   \code
1572     QQmlProperty p(object, name);
1573     p.write(value);
1574   \endcode
1575 */
1576 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
1577 {
1578     QQmlProperty p(object, name);
1579     return p.write(value);
1580 }
1581
1582 /*!
1583   Writes \a value to the \a name property of \a object using the
1584   \l{QQmlContext} {context} \a ctxt.  This method is
1585   equivalent to:
1586
1587   \code
1588     QQmlProperty p(object, name, ctxt);
1589     p.write(value);
1590   \endcode
1591 */
1592 bool QQmlProperty::write(QObject *object,
1593                                  const QString &name,
1594                                  const QVariant &value, 
1595                                  QQmlContext *ctxt)
1596 {
1597     QQmlProperty p(object, name, ctxt);
1598     return p.write(value);
1599 }
1600
1601 /*!
1602   
1603   Writes \a value to the \a name property of \a object using the
1604   environment for instantiating QML components that is provided by
1605   \a engine.  This method is equivalent to:
1606
1607   \code
1608     QQmlProperty p(object, name, engine);
1609     p.write(value);
1610   \endcode
1611 */
1612 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value, 
1613                                  QQmlEngine *engine)
1614 {
1615     QQmlProperty p(object, name, engine);
1616     return p.write(value);
1617 }
1618
1619 /*!
1620     Resets the property and returns true if the property is
1621     resettable.  If the property is not resettable, nothing happens
1622     and false is returned.
1623 */
1624 bool QQmlProperty::reset() const
1625 {
1626     if (isResettable()) {
1627         void *args[] = { 0 };
1628         QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1629         return true;
1630     } else {
1631         return false;
1632     }
1633 }
1634
1635 bool QQmlPropertyPrivate::write(const QQmlProperty &that,
1636                                         const QVariant &value, WriteFlags flags) 
1637 {
1638     if (!that.d)
1639         return false;
1640     if (that.d->object && that.type() & QQmlProperty::Property && 
1641         that.d->core.isValid() && that.isWritable()) 
1642         return that.d->writeValueProperty(value, flags);
1643     else 
1644         return false;
1645 }
1646
1647 /*!
1648     Returns true if the property has a change notifier signal, otherwise false.
1649 */
1650 bool QQmlProperty::hasNotifySignal() const
1651 {
1652     if (type() & Property && d->object) {
1653         return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1654     }
1655     return false;
1656 }
1657
1658 /*!
1659     Returns true if the property needs a change notifier signal for bindings
1660     to remain upto date, false otherwise.
1661
1662     Some properties, such as attached properties or those whose value never 
1663     changes, do not require a change notifier.
1664 */
1665 bool QQmlProperty::needsNotifySignal() const
1666 {
1667     return type() & Property && !property().isConstant();
1668 }
1669
1670 /*!
1671     Connects the property's change notifier signal to the
1672     specified \a method of the \a dest object and returns
1673     true. Returns false if this metaproperty does not
1674     represent a regular Qt property or if it has no
1675     change notifier signal, or if the \a dest object does
1676     not have the specified \a method.
1677 */
1678 bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
1679 {
1680     if (!(type() & Property) || !d->object)
1681         return false;
1682
1683     QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1684     if (prop.hasNotifySignal()) {
1685         return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1686     } else {
1687         return false;
1688     }
1689 }
1690
1691 /*!
1692     Connects the property's change notifier signal to the
1693     specified \a slot of the \a dest object and returns
1694     true. Returns false if this metaproperty does not
1695     represent a regular Qt property or if it has no
1696     change notifier signal, or if the \a dest object does
1697     not have the specified \a slot.
1698 */
1699 bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
1700 {
1701     if (!(type() & Property) || !d->object)
1702         return false;
1703
1704     QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1705     if (prop.hasNotifySignal()) {
1706         QByteArray signal(QByteArray("2") + prop.notifySignal().methodSignature());
1707         return QObject::connect(d->object, signal.constData(), dest, slot);
1708     } else  {
1709         return false;
1710     }
1711 }
1712
1713 /*!
1714     Return the Qt metaobject index of the property.
1715 */
1716 int QQmlProperty::index() const
1717 {
1718     return d ? d->core.coreIndex : -1;
1719 }
1720
1721 int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that)
1722 {
1723     return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
1724 }
1725
1726 /*!
1727     Returns the "property index" for use in bindings.  The top 8 bits are the value type
1728     offset, and 0 otherwise.  The bottom 24-bits are the regular property index.
1729 */
1730 int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that)
1731 {
1732     if (!that.d)
1733         return -1;
1734     return bindingIndex(that.d->core);
1735 }
1736
1737 int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that)
1738 {
1739     int rv = that.coreIndex;
1740     if (rv != -1 && that.isValueTypeVirtual())
1741         rv = rv | (that.valueTypeCoreIndex << 24);
1742     return rv;
1743 }
1744
1745 QQmlPropertyData
1746 QQmlPropertyPrivate::saveValueType(const QMetaObject *metaObject, int index, 
1747                                            const QMetaObject *subObject, int subIndex,
1748                                            QQmlEngine *)
1749 {
1750     QMetaProperty subProp = subObject->property(subIndex);
1751
1752     QQmlPropertyData core;
1753     core.load(metaObject->property(index));
1754     core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
1755     core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp);
1756     core.valueTypeCoreIndex = subIndex;
1757     core.valueTypePropType = subProp.userType();
1758
1759     return core;
1760 }
1761
1762 QQmlProperty
1763 QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
1764                                      QQmlContextData *ctxt)
1765 {
1766     QQmlProperty prop;
1767
1768     prop.d = new QQmlPropertyPrivate;
1769     prop.d->object = object;
1770     prop.d->context = ctxt;
1771     prop.d->engine = ctxt?ctxt->engine:0;
1772
1773     prop.d->core = data;
1774
1775     return prop;
1776 }
1777
1778 /*!
1779     Returns true if lhs and rhs refer to the same metaobject data
1780 */
1781 bool QQmlPropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
1782 {
1783     return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1784 }
1785
1786 /*!
1787     Returns true if from inherits to.
1788 */
1789 bool QQmlPropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
1790 {
1791     if (from && to == &QObject::staticMetaObject)
1792         return true;
1793
1794     while (from) {
1795         if (equal(from, to))
1796             return true;
1797         from = from->superClass();
1798     }
1799     
1800     return false;
1801 }
1802
1803 /*!
1804     Return the signal corresponding to \a name
1805 */
1806 QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1807 {
1808     Q_ASSERT(mo);
1809     int methods = mo->methodCount();
1810     for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1811         QMetaMethod method = mo->method(ii);
1812
1813         if (method.name() == name)
1814             return method;
1815     }
1816
1817     // If no signal is found, but the signal is of the form "onBlahChanged",
1818     // return the notify signal for the property "Blah"
1819     if (name.endsWith("Changed")) {
1820         QByteArray propName = name.mid(0, name.length() - 7);
1821         int propIdx = mo->indexOfProperty(propName.constData());
1822         if (propIdx >= 0) {
1823             QMetaProperty prop = mo->property(propIdx);
1824             if (prop.hasNotifySignal())
1825                 return prop.notifySignal();
1826         }
1827     }
1828
1829     return QMetaMethod();
1830 }
1831
1832 static inline int QMetaObject_methods(const QMetaObject *metaObject)
1833 {
1834     struct Private
1835     {
1836         int revision;
1837         int className;
1838         int classInfoCount, classInfoData;
1839         int methodCount, methodData;
1840         int propertyCount, propertyData;
1841     };
1842
1843     return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
1844 }
1845
1846 static inline int QMetaObject_properties(const QMetaObject *metaObject)
1847 {
1848     struct Private
1849     {
1850         int revision;
1851         int className;
1852         int classInfoCount, classInfoData;
1853         int methodCount, methodData;
1854         int propertyCount, propertyData;
1855     };
1856
1857     return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
1858 }
1859
1860 static inline void flush_vme_signal(const QObject *object, int index)
1861 {
1862     QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1863     if (data && data->propertyCache) {
1864         QQmlPropertyData *property = data->propertyCache->method(index);
1865
1866         if (property && property->isVMESignal()) {
1867             const QMetaObject *metaObject = object->metaObject();
1868             int methodOffset = metaObject->methodOffset();
1869
1870             while (methodOffset > index) {
1871                 metaObject = metaObject->d.superdata;
1872                 methodOffset -= QMetaObject_methods(metaObject);
1873             }
1874
1875             QQmlVMEMetaObject *vme = 
1876                 static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
1877
1878             vme->connectAliasSignal(index);
1879         }
1880     }
1881 }
1882
1883 /*!
1884 Connect \a sender \a signal_index to \a receiver \a method_index with the specified 
1885 \a type and \a types.  This behaves identically to QMetaObject::connect() except that
1886 it connects any lazy "proxy" signal connections set up by QML.
1887
1888 It is possible that this logic should be moved to QMetaObject::connect().
1889 */
1890 bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
1891                                           const QObject *receiver, int method_index,
1892                                           int type, int *types)
1893 {
1894     flush_vme_signal(sender, signal_index);
1895     flush_vme_signal(receiver, method_index);
1896
1897     return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1898 }
1899
1900 void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
1901 {
1902     flush_vme_signal(sender, signal_index);
1903 }
1904
1905 /*!
1906 Return \a metaObject's [super] meta object that provides data for \a property.
1907 */
1908 const QMetaObject *QQmlPropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
1909 {
1910     int propertyOffset = metaObject->propertyOffset();
1911
1912     while (propertyOffset > property) {
1913         metaObject = metaObject->d.superdata;
1914         propertyOffset -= QMetaObject_properties(metaObject);
1915     }
1916
1917     return metaObject;
1918 }
1919
1920 QT_END_NAMESPACE