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