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