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