408b070cdbc801514a2a808dfd8073aabaae3b3b
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativeproperty.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativeproperty.h"
43 #include "qdeclarativeproperty_p.h"
44
45 #include "qdeclarative.h"
46 #include "qdeclarativebinding_p.h"
47 #include "qdeclarativecontext.h"
48 #include "qdeclarativecontext_p.h"
49 #include "qdeclarativeboundsignal_p.h"
50 #include "qdeclarativeengine.h"
51 #include "qdeclarativeengine_p.h"
52 #include "qdeclarativedata_p.h"
53 #include "qdeclarativestringconverters_p.h"
54 #include "qdeclarativelist_p.h"
55 #include "qdeclarativecompiler_p.h"
56 #include "qdeclarativevmemetaobject_p.h"
57 #include "qdeclarativeexpression_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 QDeclarativeProperty
74 \since 4.7
75 \brief The QDeclarativeProperty 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 QDeclarativeProperty class 
80 that simplifies some of their natural complexity.
81
82 Unlike QMetaProperty which represents a property on a class type, QDeclarativeProperty encapsulates 
83 a property on a specific object instance.  To read a property's value, programmers create a 
84 QDeclarativeProperty 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 1.0
92
93 Text { text: "A bit of text" }
94 \endqml
95
96 The \l Text object's properties could be accessed using QDeclarativeProperty, like this:
97
98 \code
99 #include <QDeclarativeProperty>
100 #include <QGraphicsObject>
101
102 ...
103
104 QDeclarativeView view(QUrl::fromLocalFile("MyItem.qml"));
105 QDeclarativeProperty 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 QDeclarativeProperty.
114 */
115 QDeclarativeProperty::QDeclarativeProperty()
116 : d(0)
117 {
118 }
119
120 /*!  \internal */
121 QDeclarativeProperty::~QDeclarativeProperty()
122 {
123     if (d)
124         d->release();
125     d = 0;
126 }
127
128 /*!
129     Creates a QDeclarativeProperty for the default property of \a obj. If there is no
130     default property, an invalid QDeclarativeProperty will be created.
131  */
132 QDeclarativeProperty::QDeclarativeProperty(QObject *obj)
133 : d(new QDeclarativePropertyPrivate)
134 {
135     d->initDefault(obj);
136 }
137
138 /*!
139     Creates a QDeclarativeProperty for the default property of \a obj
140     using the \l{QDeclarativeContext} {context} \a ctxt. If there is
141     no default property, an invalid QDeclarativeProperty will be
142     created.
143  */
144 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeContext *ctxt)
145 : d(new QDeclarativePropertyPrivate)
146 {
147     d->context = ctxt?QDeclarativeContextData::get(ctxt):0;
148     d->engine = ctxt?ctxt->engine():0;
149     d->initDefault(obj);
150 }
151
152 /*!
153     Creates a QDeclarativeProperty 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 QDeclarativeProperty will be created.
157  */
158 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeEngine *engine)
159   : d(new QDeclarativePropertyPrivate)
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 QDeclarativePropertyPrivate::initDefault(QObject *obj)
170 {
171     if (!obj)
172         return;
173
174     QMetaProperty p = QDeclarativeMetaType::defaultProperty(obj);
175     core.load(p);
176     if (core.isValid()) 
177         object = obj;
178 }
179
180 /*!
181     Creates a QDeclarativeProperty for the property \a name of \a obj.
182  */
183 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name)
184 : d(new QDeclarativePropertyPrivate)
185 {
186     d->initProperty(obj, name);
187     if (!isValid()) d->object = 0;
188 }
189
190 /*!
191     Creates a QDeclarativeProperty for the property \a name of \a obj
192     using the \l{QDeclarativeContext} {context} \a ctxt.
193
194     Creating a QDeclarativeProperty without a context will render some 
195     properties - like attached properties - inaccessible.
196 */
197 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeContext *ctxt)
198 : d(new QDeclarativePropertyPrivate)
199 {
200     d->context = ctxt?QDeclarativeContextData::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 QDeclarativeProperty 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 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeEngine *engine)
212 : d(new QDeclarativePropertyPrivate)
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(QDeclarativeValueTypeFactory, qmlValueTypes);
221
222 QDeclarativePropertyPrivate::QDeclarativePropertyPrivate()
223 : context(0), engine(0), object(0), isNameCached(false)
224 {
225 }
226
227 QDeclarativeContextData *QDeclarativePropertyPrivate::effectiveContext() const 
228 {
229     if (context) return context;
230     else if (engine) return QDeclarativeContextData::get(engine->rootContext());
231     else return 0;
232 }
233
234 void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name)
235 {
236     if (!obj) return;
237
238     QDeclarativeTypeNameCache *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             QDeclarativeTypeNameCache::Result r = typeNameCache->query(pathName);
251             if (r.isValid()) {
252                 if (r.type) {
253                     QDeclarativeAttachedPropertiesFunc 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                     QDeclarativeAttachedPropertiesFunc 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         QDeclarativePropertyData local;
281         QDeclarativePropertyData *property =
282             QDeclarativePropertyCache::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) && QDeclarativeValueTypeFactory::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 QDeclarativePropertyData 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     QDeclarativePropertyData local;
345     QDeclarativePropertyData *property =
346         QDeclarativePropertyCache::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 QDeclarativeProperty::QDeclarativeProperty(const QDeclarativeProperty &other)
359 {
360     d = other.d;
361     if (d)
362         d->addref();
363 }
364
365 /*!
366   \enum QDeclarativeProperty::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 QDeclarativeListProperty 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 QDeclarativeProperty::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 QDeclarativeProperty::PropertyTypeCategory QDeclarativeProperty::propertyTypeCategory() const
390 {
391     return d ? d->propertyTypeCategory() : InvalidCategory;
392 }
393
394 QDeclarativeProperty::PropertyTypeCategory 
395 QDeclarativePropertyPrivate::propertyTypeCategory() const
396 {
397     uint type = this->type();
398
399     if (isValueType()) {
400         return QDeclarativeProperty::Normal;
401     } else if (type & QDeclarativeProperty::Property) {
402         int type = propertyType();
403         if (type == QVariant::Invalid)
404             return QDeclarativeProperty::InvalidCategory;
405         else if (QDeclarativeValueTypeFactory::isValueType((uint)type))
406             return QDeclarativeProperty::Normal;
407         else if (core.isQObject())
408             return QDeclarativeProperty::Object;
409         else if (core.isQList())
410             return QDeclarativeProperty::List;
411         else 
412             return QDeclarativeProperty::Normal;
413     } else {
414         return QDeclarativeProperty::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 *QDeclarativeProperty::propertyTypeName() const
423 {
424     if (!d)
425         return 0;
426     if (d->isValueType()) {
427
428         QDeclarativeEnginePrivate *ep = d->engine?QDeclarativeEnginePrivate::get(d->engine):0;
429         QDeclarativeValueType *valueType = 0;
430         if (ep) valueType = ep->valueTypes[d->core.propType];
431         else valueType = QDeclarativeValueTypeFactory::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 QDeclarativeProperty represent the same 
448     property.
449 */
450 bool QDeclarativeProperty::operator==(const QDeclarativeProperty &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 QDeclarativeProperty::propertyType() const
469 {
470     return d ? d->propertyType() : int(QVariant::Invalid);
471 }
472
473 bool QDeclarativePropertyPrivate::isValueType() const
474 {
475     return core.isValueTypeVirtual();
476 }
477
478 int QDeclarativePropertyPrivate::propertyType() const
479 {
480     uint type = this->type();
481     if (isValueType()) {
482         return core.valueTypePropType;
483     } else if (type & QDeclarativeProperty::Property) {
484         return core.propType;
485     } else {
486         return QVariant::Invalid;
487     }
488 }
489
490 QDeclarativeProperty::Type QDeclarativePropertyPrivate::type() const
491 {
492     if (core.isFunction())
493         return QDeclarativeProperty::SignalProperty;
494     else if (core.isValid())
495         return QDeclarativeProperty::Property;
496     else
497         return QDeclarativeProperty::Invalid;
498 }
499
500 /*!
501     Returns the type of the property.
502 */
503 QDeclarativeProperty::Type QDeclarativeProperty::type() const
504 {
505     return d ? d->type() : Invalid;
506 }
507
508 /*!
509     Returns true if this QDeclarativeProperty represents a regular Qt property.
510 */
511 bool QDeclarativeProperty::isProperty() const
512 {
513     return type() & Property;
514 }
515
516 /*!
517     Returns true if this QDeclarativeProperty represents a QML signal property.
518 */
519 bool QDeclarativeProperty::isSignalProperty() const
520 {
521     return type() & SignalProperty;
522 }
523
524 /*!
525     Returns the QDeclarativeProperty's QObject.
526 */
527 QObject *QDeclarativeProperty::object() const
528 {
529     return d ? d->object : 0;
530 }
531
532 /*!
533     Assign \a other to this QDeclarativeProperty.
534 */
535 QDeclarativeProperty &QDeclarativeProperty::operator=(const QDeclarativeProperty &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 QDeclarativeProperty::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 QDeclarativeProperty::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 QDeclarativeProperty::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 QDeclarativeProperty refers to a valid property, otherwise
593     false.
594 */
595 bool QDeclarativeProperty::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 QDeclarativeProperty::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             QDeclarativeEnginePrivate *ep = d->engine?QDeclarativeEnginePrivate::get(d->engine):0;
616             QDeclarativeValueType *valueType = 0;
617             if (ep) valueType = ep->valueTypes[d->core.propType];
618             else valueType = QDeclarativeValueTypeFactory::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 QDeclarativeProperty::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 QDeclarativeProperty::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 QDeclarativeAbstractBinding *
673 QDeclarativePropertyPrivate::binding(const QDeclarativeProperty &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 QDeclarativeAbstractBinding *
696 QDeclarativePropertyPrivate::setBinding(const QDeclarativeProperty &that,
697                                             QDeclarativeAbstractBinding *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     return that.d->setBinding(that.d->object, that.d->core.coreIndex, 
707                               that.d->core.getValueTypeCoreIndex(),
708                               newBinding, flags);
709 }
710
711 QDeclarativeAbstractBinding *
712 QDeclarativePropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
713 {
714     QDeclarativeData *data = QDeclarativeData::get(object);
715     if (!data)
716         return 0;
717
718     QDeclarativePropertyData *propertyData =
719         data->propertyCache?data->propertyCache->property(coreIndex):0;
720     if (propertyData && propertyData->isAlias()) {
721         const QDeclarativeVMEMetaObject *vme = 
722             static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
723
724         QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
725         if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
726             return 0;
727
728         // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
729         Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
730         return binding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex);
731     }
732
733     if (!data->hasBindingBit(coreIndex))
734         return 0;
735
736     QDeclarativeAbstractBinding *binding = data->bindings;
737     while (binding && binding->propertyIndex() != coreIndex)
738         binding = binding->m_nextBinding;
739
740     if (binding && valueTypeIndex != -1) {
741         if (binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) {
742             int index = coreIndex | (valueTypeIndex << 24);
743             binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
744         }
745     }
746
747     return binding;
748 }
749
750 void QDeclarativePropertyPrivate::findAliasTarget(QObject *object, int bindingIndex, 
751                                                   QObject **targetObject, int *targetBindingIndex)
752 {
753     int coreIndex = bindingIndex & 0xFFFFFF;
754     int valueTypeIndex = bindingIndex >> 24;
755     if (valueTypeIndex == 0) valueTypeIndex = -1;
756
757     QDeclarativeData *data = QDeclarativeData::get(object, false);
758     if (data) {
759         QDeclarativePropertyData *propertyData =
760             data->propertyCache?data->propertyCache->property(coreIndex):0;
761         if (propertyData && propertyData->isAlias()) {
762             const QDeclarativeVMEMetaObject *vme = 
763                 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
764             QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
765             if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
766                 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
767                 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
768
769                 int aBindingIndex = aCoreIndex;
770                 if (aValueTypeIndex != -1) 
771                     aBindingIndex |= aValueTypeIndex << 24;
772                 else if (valueTypeIndex != -1)
773                     aBindingIndex |= valueTypeIndex << 24;
774
775                 findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
776                 return;
777             }
778         }
779     }
780
781     *targetObject = object; 
782     *targetBindingIndex = bindingIndex;
783 }
784
785 QDeclarativeAbstractBinding *
786 QDeclarativePropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
787                                         QDeclarativeAbstractBinding *newBinding, WriteFlags flags)
788 {
789     QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
790     QDeclarativeAbstractBinding *binding = 0;
791
792     if (data) {
793         QDeclarativePropertyData *propertyData =
794             data->propertyCache?data->propertyCache->property(coreIndex):0;
795         if (propertyData && propertyData->isAlias()) {
796             const QDeclarativeVMEMetaObject *vme = 
797                 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
798
799             QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
800             if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
801                 if (newBinding) newBinding->destroy();
802                 return 0;
803             }
804
805             // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
806             Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
807             return setBinding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex,
808                               newBinding, flags);
809         }
810     }
811
812     if (data && data->hasBindingBit(coreIndex)) {
813         binding = data->bindings;
814
815         while (binding && binding->propertyIndex() != coreIndex) 
816             binding = binding->m_nextBinding;
817     }
818
819     int index = coreIndex;
820     if (valueTypeIndex != -1)
821         index |= (valueTypeIndex << 24);
822
823     if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) 
824         binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
825
826     if (binding) {
827         binding->removeFromObject();
828         binding->setEnabled(false, 0);
829     }
830
831     if (newBinding) {
832         newBinding->addToObject(object, index);
833         newBinding->setEnabled(true, flags);
834     }
835
836     return binding;
837 }
838
839 QDeclarativeAbstractBinding *
840 QDeclarativePropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
841                                                 QDeclarativeAbstractBinding *newBinding)
842 {
843     QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
844     QDeclarativeAbstractBinding *binding = 0;
845
846     if (data) {
847         QDeclarativePropertyData *propertyData =
848             data->propertyCache?data->propertyCache->property(coreIndex):0;
849         if (propertyData && propertyData->isAlias()) {
850             const QDeclarativeVMEMetaObject *vme = 
851                 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
852
853             QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
854             if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
855                 if (newBinding) newBinding->destroy();
856                 return 0;
857             }
858
859             // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
860             Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
861             return setBindingNoEnable(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex,
862                                       newBinding);
863         }
864     }
865
866     if (data && data->hasBindingBit(coreIndex)) {
867         binding = data->bindings;
868
869         while (binding && binding->propertyIndex() != coreIndex) 
870             binding = binding->m_nextBinding;
871     }
872
873     int index = coreIndex;
874     if (valueTypeIndex != -1)
875         index |= (valueTypeIndex << 24);
876
877     if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) 
878         binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
879
880     if (binding) 
881         binding->removeFromObject();
882
883     if (newBinding) 
884         newBinding->addToObject(object, index);
885
886     return binding;
887 }
888
889 /*!
890     Returns the expression associated with this signal property, or 0 if no 
891     signal expression exists.
892 */
893 QDeclarativeExpression *
894 QDeclarativePropertyPrivate::signalExpression(const QDeclarativeProperty &that)
895 {
896     if (!(that.type() & QDeclarativeProperty::SignalProperty))
897         return 0;
898
899     const QObjectList &children = that.d->object->children();
900     
901     for (int ii = 0; ii < children.count(); ++ii) {
902         QObject *child = children.at(ii);
903
904         QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
905         if (signal && signal->index() == that.index()) 
906             return signal->expression();
907     }
908
909     return 0;
910 }
911
912 /*!
913     Set the signal expression associated with this signal property to \a expr.
914     Returns the existing signal expression (if any), otherwise 0.
915
916     Ownership of \a expr transfers to QML.  Ownership of the return value is
917     assumed by the caller.
918 */
919 QDeclarativeExpression *
920 QDeclarativePropertyPrivate::setSignalExpression(const QDeclarativeProperty &that,
921                                                      QDeclarativeExpression *expr) 
922 {
923     if (!(that.type() & QDeclarativeProperty::SignalProperty)) {
924         delete expr;
925         return 0;
926     }
927
928     const QObjectList &children = that.d->object->children();
929     
930     for (int ii = 0; ii < children.count(); ++ii) {
931         QObject *child = children.at(ii);
932
933         QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
934         if (signal && signal->index() == that.index()) 
935             return signal->setExpression(expr);
936     }
937
938     if (expr) {
939         QDeclarativeBoundSignal *signal = new QDeclarativeBoundSignal(that.d->object, that.method(), that.d->object);
940         return signal->setExpression(expr);
941     } else {
942         return 0;
943     }
944 }
945
946 /*!
947     Returns the property value.
948 */
949 QVariant QDeclarativeProperty::read() const
950 {
951     if (!d)
952         return QVariant();
953     if (!d->object)
954         return QVariant();
955
956     if (type() & SignalProperty) {
957
958         return QVariant();
959
960     } else if (type() & Property) {
961
962         return d->readValueProperty();
963
964     }
965     return QVariant();
966 }
967
968 /*!
969 Return the \a name property value of \a object.  This method is equivalent to:
970 \code
971     QDeclarativeProperty p(object, name);
972     p.read();
973 \endcode
974 */
975 QVariant QDeclarativeProperty::read(QObject *object, const QString &name)
976 {
977     QDeclarativeProperty p(object, name);
978     return p.read();
979 }
980
981 /*!
982   Return the \a name property value of \a object using the
983   \l{QDeclarativeContext} {context} \a ctxt.  This method is
984   equivalent to:
985
986   \code
987     QDeclarativeProperty p(object, name, context);
988     p.read();
989   \endcode
990 */
991 QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeContext *ctxt)
992 {
993     QDeclarativeProperty p(object, name, ctxt);
994     return p.read();
995 }
996
997 /*!
998   
999   Return the \a name property value of \a object using the environment
1000   for instantiating QML components that is provided by \a engine. .
1001   This method is equivalent to:
1002
1003   \code
1004     QDeclarativeProperty p(object, name, engine);
1005     p.read();
1006   \endcode
1007 */
1008 QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeEngine *engine)
1009 {
1010     QDeclarativeProperty p(object, name, engine);
1011     return p.read();
1012 }
1013
1014 QVariant QDeclarativePropertyPrivate::readValueProperty()
1015 {
1016     if (isValueType()) {
1017
1018         QDeclarativeEnginePrivate *ep = engine?QDeclarativeEnginePrivate::get(engine):0;
1019         QDeclarativeValueType *valueType = 0;
1020         if (ep) valueType = ep->valueTypes[core.propType];
1021         else valueType = QDeclarativeValueTypeFactory::valueType(core.propType);
1022         Q_ASSERT(valueType);
1023
1024         valueType->read(object, core.coreIndex);
1025
1026         QVariant rv = valueType->metaObject()->property(core.valueTypeCoreIndex).read(valueType);
1027
1028         if (!ep) delete valueType;
1029         return rv;
1030
1031     } else if (core.isQList()) {
1032
1033         QDeclarativeListProperty<QObject> prop;
1034         void *args[] = { &prop, 0 };
1035         QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1036         return QVariant::fromValue(QDeclarativeListReferencePrivate::init(prop, core.propType, engine)); 
1037
1038     } else if (core.isQObject()) {
1039
1040         QObject *rv = 0;
1041         void *args[] = { &rv, 0 };
1042         QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1043         return QVariant::fromValue(rv);
1044
1045     } else {
1046
1047         return object->metaObject()->property(core.coreIndex).read(object.data());
1048
1049     }
1050 }
1051
1052 static QUrl urlFromUserString(const QByteArray &data)
1053 {
1054     QUrl u;
1055     if (!data.isEmpty())
1056     {
1057         // Preserve any valid percent-encoded octets supplied by the source
1058         u.setEncodedUrl(data, QUrl::TolerantMode);
1059     }
1060     return u;
1061 }
1062
1063 static QUrl urlFromUserString(const QString &data)
1064 {
1065     return urlFromUserString(data.toUtf8());
1066 }
1067
1068 // helper function to allow assignment / binding to QList<QUrl> properties.
1069 static QVariant resolvedUrlSequence(const QVariant &value, QDeclarativeContextData *context)
1070 {
1071     QList<QUrl> urls;
1072     if (value.userType() == qMetaTypeId<QUrl>()) {
1073         urls.append(value.toUrl());
1074     } else if (value.userType() == qMetaTypeId<QString>()) {
1075         urls.append(urlFromUserString(value.toString()));
1076     } else if (value.userType() == qMetaTypeId<QByteArray>()) {
1077         urls.append(urlFromUserString(value.toByteArray()));
1078     } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
1079         urls = value.value<QList<QUrl> >();
1080     } else if (value.userType() == qMetaTypeId<QStringList>()) {
1081         QStringList urlStrings = value.value<QStringList>();
1082         for (int i = 0; i < urlStrings.size(); ++i)
1083             urls.append(urlFromUserString(urlStrings.at(i)));
1084     } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
1085         QList<QString> urlStrings = value.value<QList<QString> >();
1086         for (int i = 0; i < urlStrings.size(); ++i)
1087             urls.append(urlFromUserString(urlStrings.at(i)));
1088     } // note: QList<QByteArray> is not currently supported.
1089
1090     QList<QUrl> resolvedUrls;
1091     for (int i = 0; i < urls.size(); ++i) {
1092         QUrl u = urls.at(i);
1093         if (context && u.isRelative() && !u.isEmpty())
1094             u = context->resolvedUrl(u);
1095         resolvedUrls.append(u);
1096     }
1097
1098     return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
1099 }
1100
1101 //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1102 bool QDeclarativePropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1103 {
1104     if (!object || !prop.isWritable())
1105         return false;
1106
1107     QVariant v = value;
1108     if (prop.isEnumType()) {
1109         QMetaEnum menum = prop.enumerator();
1110         if (v.userType() == QVariant::String
1111 #ifdef QT3_SUPPORT
1112             || v.userType() == QVariant::CString
1113 #endif
1114             ) {
1115             bool ok;
1116             if (prop.isFlagType())
1117                 v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
1118             else
1119                 v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
1120             if (!ok)
1121                 return false;
1122         } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
1123             int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
1124             if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData())
1125                 return false;
1126             v = QVariant(*reinterpret_cast<const int *>(v.constData()));
1127         }
1128         v.convert(QVariant::Int);
1129     }
1130
1131     // the status variable is changed by qt_metacall to indicate what it did
1132     // this feature is currently only used by QtDBus and should not be depended
1133     // upon. Don't change it without looking into QDBusAbstractInterface first
1134     // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1135     // changed: result stored directly in value, return the value of status
1136     int status = -1;
1137     void *argv[] = { v.data(), &v, &status, &flags };
1138     QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
1139     return status;
1140 }
1141
1142 bool QDeclarativePropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
1143 {
1144     return writeValueProperty(object, engine, core, value, effectiveContext(), flags);
1145 }
1146
1147 bool 
1148 QDeclarativePropertyPrivate::writeValueProperty(QObject *object, QDeclarativeEngine *engine,
1149                                                 const QDeclarativePropertyData &core,
1150                                                 const QVariant &value, 
1151                                                 QDeclarativeContextData *context, WriteFlags flags)
1152 {
1153     // Remove any existing bindings on this property
1154     if (!(flags & DontRemoveBinding) && object) {
1155         QDeclarativeAbstractBinding *binding = setBinding(object, core.coreIndex,
1156                                                           core.getValueTypeCoreIndex(), 
1157                                                           0, flags);
1158         if (binding) binding->destroy();
1159     }
1160
1161     bool rv = false;
1162     if (core.isValueTypeVirtual()) {
1163         QDeclarativeEnginePrivate *ep = engine?QDeclarativeEnginePrivate::get(engine):0;
1164
1165         QDeclarativeValueType *writeBack = 0;
1166         if (ep) {
1167             writeBack = ep->valueTypes[core.propType];
1168         } else {
1169             writeBack = QDeclarativeValueTypeFactory::valueType(core.propType);
1170         }
1171
1172         writeBack->read(object, core.coreIndex);
1173
1174         QDeclarativePropertyData data = core;
1175         data.setFlags(QDeclarativePropertyData::Flag(core.valueTypeFlags));
1176         data.coreIndex = core.valueTypeCoreIndex;
1177         data.propType = core.valueTypePropType;
1178
1179         rv = write(writeBack, data, value, context, flags);
1180
1181         writeBack->write(object, core.coreIndex, flags);
1182         if (!ep) delete writeBack;
1183
1184     } else {
1185
1186         rv = write(object, core, value, context, flags);
1187
1188     }
1189
1190     return rv;
1191 }
1192
1193 bool QDeclarativePropertyPrivate::write(QObject *object, 
1194                                         const QDeclarativePropertyData &property,
1195                                         const QVariant &value, QDeclarativeContextData *context, 
1196                                         WriteFlags flags)
1197 {
1198     int coreIdx = property.coreIndex;
1199     int status = -1;    //for dbus
1200
1201     if (property.isEnum()) {
1202         QMetaProperty prop = object->metaObject()->property(property.coreIndex);
1203         QVariant v = value;
1204         // Enum values come through the script engine as doubles
1205         if (value.userType() == QVariant::Double) { 
1206             double integral;
1207             double fractional = modf(value.toDouble(), &integral);
1208             if (qFuzzyIsNull(fractional))
1209                 v.convert(QVariant::Int);
1210         }
1211         return writeEnumProperty(prop, coreIdx, object, v, flags);
1212     }
1213
1214     int propertyType = property.propType;
1215     int variantType = value.userType();
1216
1217     QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context);
1218
1219     if (propertyType == QVariant::Url) {
1220
1221         QUrl u;
1222         bool found = false;
1223         if (variantType == QVariant::Url) {
1224             u = value.toUrl();
1225             found = true;
1226         } else if (variantType == QVariant::ByteArray) {
1227             u = urlFromUserString(value.toByteArray());
1228             found = true;
1229         } else if (variantType == QVariant::String) {
1230             u = urlFromUserString(value.toString());
1231             found = true;
1232         }
1233
1234         if (!found)
1235             return false;
1236
1237         if (context && u.isRelative() && !u.isEmpty())
1238             u = context->resolvedUrl(u);
1239         int status = -1;
1240         void *argv[] = { &u, 0, &status, &flags };
1241         QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1242
1243     } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
1244         QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
1245         int status = -1;
1246         void *argv[] = { &urlSeq, 0, &status, &flags };
1247         QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1248     } else if (variantType == propertyType) {
1249
1250         void *a[] = { (void *)value.constData(), 0, &status, &flags };
1251         QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1252
1253     } else if (qMetaTypeId<QVariant>() == propertyType) {
1254
1255         void *a[] = { (void *)&value, 0, &status, &flags };
1256         QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1257
1258     } else if (property.isQObject()) {
1259
1260         const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType());
1261         
1262         if (!valMo)
1263             return false;
1264
1265         QObject *o = *(QObject **)value.constData();
1266         const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType);
1267
1268         if (o) valMo = o->metaObject();
1269
1270         if (canConvert(valMo, propMo)) {
1271             void *args[] = { &o, 0, &status, &flags };
1272             QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, 
1273                                   args);
1274         } else if (!o && canConvert(propMo, valMo)) {
1275             // In the case of a null QObject, we assign the null if there is 
1276             // any change that the null variant type could be up or down cast to 
1277             // the property type.
1278             void *args[] = { &o, 0, &status, &flags };
1279             QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, 
1280                                   args);
1281         } else {
1282             return false;
1283         }
1284
1285     } else if (property.isQList()) {
1286
1287         const QMetaObject *listType = 0;
1288         if (enginePriv) {
1289             listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
1290         } else {
1291             QDeclarativeType *type = QDeclarativeMetaType::qmlType(QDeclarativeMetaType::listType(property.propType));
1292             if (!type) return false;
1293             listType = type->baseMetaObject();
1294         }
1295         if (!listType) return false;
1296
1297         QDeclarativeListProperty<void> prop;
1298         void *args[] = { &prop, 0 };
1299         QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
1300
1301         if (!prop.clear) return false;
1302
1303         prop.clear(&prop);
1304
1305         if (value.userType() == qMetaTypeId<QDeclarativeListReference>()) {
1306             QDeclarativeListReference qdlr = value.value<QDeclarativeListReference>();
1307
1308             for (int ii = 0; ii < qdlr.count(); ++ii) {
1309                 QObject *o = qdlr.at(ii);
1310                 if (o && !canConvert(o->metaObject(), listType))
1311                     o = 0;
1312                 prop.append(&prop, (void *)o);
1313             }
1314         } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
1315             const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1316
1317             for (int ii = 0; ii < list.count(); ++ii) {
1318                 QObject *o = list.at(ii);
1319                 if (o && !canConvert(o->metaObject(), listType))
1320                     o = 0;
1321                 prop.append(&prop, (void *)o);
1322             }
1323         } else {
1324             QObject *o = enginePriv?enginePriv->toQObject(value):QDeclarativeMetaType::toQObject(value);
1325             if (o && !canConvert(o->metaObject(), listType))
1326                 o = 0;
1327             prop.append(&prop, (void *)o);
1328         }
1329
1330     } else {
1331         Q_ASSERT(variantType != propertyType);
1332
1333         bool ok = false;
1334         QVariant v;
1335         if (variantType == QVariant::String)
1336             v = QDeclarativeStringConverters::variantFromString(value.toString(), propertyType, &ok);
1337         if (!ok) {
1338             v = value;
1339             if (v.convert((QVariant::Type)propertyType)) {
1340                 ok = true;
1341             } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
1342                 QDeclarativeMetaType::StringConverter con = QDeclarativeMetaType::customStringConverter(propertyType);
1343                 if (con) {
1344                     v = con(value.toString());
1345                     if (v.userType() == propertyType)
1346                         ok = true;
1347                 }
1348             }
1349         }
1350         if (!ok) {
1351             // the only other option is that they are assigning a single value
1352             // to a sequence type property (eg, an int to a QList<int> property).
1353             // Note that we've already handled single-value assignment to QList<QUrl> properties.
1354             if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
1355                 QList<int> list;
1356                 list << value.toInt();
1357                 v = QVariant::fromValue<QList<int> >(list);
1358                 ok = true;
1359             } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
1360                 QList<qreal> list;
1361                 list << value.toReal();
1362                 v = QVariant::fromValue<QList<qreal> >(list);
1363                 ok = true;
1364             } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
1365                 QList<bool> list;
1366                 list << value.toBool();
1367                 v = QVariant::fromValue<QList<bool> >(list);
1368                 ok = true;
1369             } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
1370                 QList<QString> list;
1371                 list << value.toString();
1372                 v = QVariant::fromValue<QList<QString> >(list);
1373                 ok = true;
1374             } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
1375                 QStringList list;
1376                 list << value.toString();
1377                 v = QVariant::fromValue<QStringList>(list);
1378                 ok = true;
1379             }
1380         }
1381
1382         if (ok) {
1383             void *a[] = { (void *)v.constData(), 0, &status, &flags};
1384             QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1385         } else {
1386             return false;
1387         }
1388     }
1389
1390     return true;
1391 }
1392
1393 // Returns true if successful, false if an error description was set on expression
1394 bool QDeclarativePropertyPrivate::writeBinding(QObject *object, 
1395                                                const QDeclarativePropertyData &core,
1396                                                QDeclarativeJavaScriptExpression *expression, 
1397                                                v8::Handle<v8::Value> result, bool isUndefined,
1398                                                WriteFlags flags)
1399 {
1400     Q_ASSERT(object);
1401     Q_ASSERT(core.coreIndex != -1);
1402
1403     QDeclarativeContextData *context = expression->context();
1404     QDeclarativeEngine *engine = context->engine;
1405     QV8Engine *v8engine = QDeclarativeEnginePrivate::getV8Engine(engine);
1406
1407 #define QUICK_STORE(cpptype, conversion) \
1408         { \
1409             cpptype o = (conversion); \
1410             int status = -1; \
1411             void *argv[] = { &o, 0, &status, &flags }; \
1412             QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \
1413             return true; \
1414         } \
1415
1416
1417     if (!isUndefined && !core.isValueTypeVirtual()) {
1418         switch (core.propType) {
1419         case QMetaType::Int:
1420             if (result->IsInt32()) 
1421                 QUICK_STORE(int, result->Int32Value())
1422             else if (result->IsNumber())
1423                 QUICK_STORE(int, qRound(result->NumberValue()))
1424             break;
1425         case QMetaType::Double:
1426             if (result->IsNumber())
1427                 QUICK_STORE(double, result->NumberValue())
1428             break;
1429         case QMetaType::Float:
1430             if (result->IsNumber())
1431                 QUICK_STORE(float, result->NumberValue())
1432             break;
1433         case QMetaType::QString:
1434             if (result->IsString())
1435                 QUICK_STORE(QString, v8engine->toString(result))
1436             break;
1437         default:
1438             break;
1439         }
1440     }
1441 #undef QUICK_STORE
1442
1443     int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType;
1444
1445     QDeleteWatcher watcher(expression);
1446
1447     QVariant value;
1448     bool isVmeProperty = core.isVMEProperty();
1449
1450     if (isUndefined) {
1451     } else if (core.isQList()) {
1452         value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
1453     } else if (result->IsNull() && core.isQObject()) {
1454         value = QVariant::fromValue((QObject *)0);
1455     } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
1456         value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
1457     } else if (!isVmeProperty) {
1458         value = v8engine->toVariant(result, type);
1459     }
1460
1461     if (expression->error.isValid()) {
1462         return false;
1463     } else if (isUndefined && core.isResettable()) {
1464         void *args[] = { 0 };
1465         QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
1466     } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
1467         writeValueProperty(object, engine, core, QVariant(), context, flags);
1468     } else if (isUndefined) {
1469         expression->error.setDescription(QLatin1String("Unable to assign [undefined] to ") +
1470                                          QLatin1String(QMetaType::typeName(type))); 
1471         return false;
1472     } else if (result->IsFunction()) {
1473         expression->error.setDescription(QLatin1String("Unable to assign a function to a property."));
1474         return false;
1475     } else if (isVmeProperty) {
1476         typedef QDeclarativeVMEMetaObject VMEMO;
1477         VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject()));
1478         vmemo->setVMEProperty(core.coreIndex, result);
1479     } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
1480
1481         if (watcher.wasDeleted()) 
1482             return true;
1483
1484         const char *valueType = 0;
1485         if (value.userType() == QVariant::Invalid) valueType = "null";
1486         else valueType = QMetaType::typeName(value.userType());
1487
1488         expression->error.setDescription(QLatin1String("Unable to assign ") +
1489                                          QLatin1String(valueType) +
1490                                          QLatin1String(" to ") +
1491                                          QLatin1String(QMetaType::typeName(type)));
1492         return false;
1493     }
1494
1495     return true;
1496 }
1497
1498 bool QDeclarativePropertyPrivate::writeBinding(const QDeclarativeProperty &that, 
1499                                                QDeclarativeJavaScriptExpression *expression, 
1500                                                v8::Handle<v8::Value> result, bool isUndefined,
1501                                                WriteFlags flags)
1502 {
1503     QDeclarativePropertyPrivate *pp = that.d;
1504
1505     if (!pp)
1506         return true;
1507
1508     QObject *object = that.object();
1509     if (!object)
1510         return true;
1511
1512     return writeBinding(object, pp->core, expression, result, isUndefined, flags);
1513 }
1514
1515 const QMetaObject *QDeclarativePropertyPrivate::rawMetaObjectForType(QDeclarativeEnginePrivate *engine, int userType)
1516 {
1517     if (engine) {
1518         return engine->rawMetaObjectForType(userType);
1519     } else {
1520         QDeclarativeType *type = QDeclarativeMetaType::qmlType(userType);
1521         return type?type->baseMetaObject():0;
1522     }
1523 }
1524
1525 /*!
1526     Sets the property value to \a value and returns true.
1527     Returns false if the property can't be set because the
1528     \a value is the wrong type, for example.
1529  */
1530 bool QDeclarativeProperty::write(const QVariant &value) const
1531 {
1532     return QDeclarativePropertyPrivate::write(*this, value, 0);
1533 }
1534
1535 /*!
1536   Writes \a value to the \a name property of \a object.  This method
1537   is equivalent to:
1538
1539   \code
1540     QDeclarativeProperty p(object, name);
1541     p.write(value);
1542   \endcode
1543 */
1544 bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value)
1545 {
1546     QDeclarativeProperty p(object, name);
1547     return p.write(value);
1548 }
1549
1550 /*!
1551   Writes \a value to the \a name property of \a object using the
1552   \l{QDeclarativeContext} {context} \a ctxt.  This method is
1553   equivalent to:
1554
1555   \code
1556     QDeclarativeProperty p(object, name, ctxt);
1557     p.write(value);
1558   \endcode
1559 */
1560 bool QDeclarativeProperty::write(QObject *object,
1561                                  const QString &name,
1562                                  const QVariant &value, 
1563                                  QDeclarativeContext *ctxt)
1564 {
1565     QDeclarativeProperty p(object, name, ctxt);
1566     return p.write(value);
1567 }
1568
1569 /*!
1570   
1571   Writes \a value to the \a name property of \a object using the
1572   environment for instantiating QML components that is provided by
1573   \a engine.  This method is equivalent to:
1574
1575   \code
1576     QDeclarativeProperty p(object, name, engine);
1577     p.write(value);
1578   \endcode
1579 */
1580 bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value, 
1581                                  QDeclarativeEngine *engine)
1582 {
1583     QDeclarativeProperty p(object, name, engine);
1584     return p.write(value);
1585 }
1586
1587 /*!
1588     Resets the property and returns true if the property is
1589     resettable.  If the property is not resettable, nothing happens
1590     and false is returned.
1591 */
1592 bool QDeclarativeProperty::reset() const
1593 {
1594     if (isResettable()) {
1595         void *args[] = { 0 };
1596         QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1597         return true;
1598     } else {
1599         return false;
1600     }
1601 }
1602
1603 bool QDeclarativePropertyPrivate::write(const QDeclarativeProperty &that,
1604                                         const QVariant &value, WriteFlags flags) 
1605 {
1606     if (!that.d)
1607         return false;
1608     if (that.d->object && that.type() & QDeclarativeProperty::Property && 
1609         that.d->core.isValid() && that.isWritable()) 
1610         return that.d->writeValueProperty(value, flags);
1611     else 
1612         return false;
1613 }
1614
1615 /*!
1616     Returns true if the property has a change notifier signal, otherwise false.
1617 */
1618 bool QDeclarativeProperty::hasNotifySignal() const
1619 {
1620     if (type() & Property && d->object) {
1621         return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1622     }
1623     return false;
1624 }
1625
1626 /*!
1627     Returns true if the property needs a change notifier signal for bindings
1628     to remain upto date, false otherwise.
1629
1630     Some properties, such as attached properties or those whose value never 
1631     changes, do not require a change notifier.
1632 */
1633 bool QDeclarativeProperty::needsNotifySignal() const
1634 {
1635     return type() & Property && !property().isConstant();
1636 }
1637
1638 /*!
1639     Connects the property's change notifier signal to the
1640     specified \a method of the \a dest object and returns
1641     true. Returns false if this metaproperty does not
1642     represent a regular Qt property or if it has no
1643     change notifier signal, or if the \a dest object does
1644     not have the specified \a method.
1645 */
1646 bool QDeclarativeProperty::connectNotifySignal(QObject *dest, int method) const
1647 {
1648     if (!(type() & Property) || !d->object)
1649         return false;
1650
1651     QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1652     if (prop.hasNotifySignal()) {
1653         return QDeclarativePropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1654     } else {
1655         return false;
1656     }
1657 }
1658
1659 /*!
1660     Connects the property's change notifier signal to the
1661     specified \a slot of the \a dest object and returns
1662     true. Returns false if this metaproperty does not
1663     represent a regular Qt property or if it has no
1664     change notifier signal, or if the \a dest object does
1665     not have the specified \a slot.
1666 */
1667 bool QDeclarativeProperty::connectNotifySignal(QObject *dest, const char *slot) const
1668 {
1669     if (!(type() & Property) || !d->object)
1670         return false;
1671
1672     QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1673     if (prop.hasNotifySignal()) {
1674         QByteArray signal(QByteArray("2") + prop.notifySignal().signature());
1675         return QObject::connect(d->object, signal.constData(), dest, slot);
1676     } else  {
1677         return false;
1678     }
1679 }
1680
1681 /*!
1682     Return the Qt metaobject index of the property.
1683 */
1684 int QDeclarativeProperty::index() const
1685 {
1686     return d ? d->core.coreIndex : -1;
1687 }
1688
1689 int QDeclarativePropertyPrivate::valueTypeCoreIndex(const QDeclarativeProperty &that)
1690 {
1691     return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
1692 }
1693
1694 /*!
1695     Returns the "property index" for use in bindings.  The top 8 bits are the value type
1696     offset, and 0 otherwise.  The bottom 24-bits are the regular property index.
1697 */
1698 int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativeProperty &that)
1699 {
1700     if (!that.d)
1701         return -1;
1702     return bindingIndex(that.d->core);
1703 }
1704
1705 int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativePropertyData &that)
1706 {
1707     int rv = that.coreIndex;
1708     if (rv != -1 && that.isValueTypeVirtual())
1709         rv = rv | (that.valueTypeCoreIndex << 24);
1710     return rv;
1711 }
1712
1713 QDeclarativePropertyData
1714 QDeclarativePropertyPrivate::saveValueType(const QMetaObject *metaObject, int index, 
1715                                            const QMetaObject *subObject, int subIndex,
1716                                            QDeclarativeEngine *)
1717 {
1718     QMetaProperty subProp = subObject->property(subIndex);
1719
1720     QDeclarativePropertyData core;
1721     core.load(metaObject->property(index));
1722     core.setFlags(core.getFlags() | QDeclarativePropertyData::IsValueTypeVirtual);
1723     core.valueTypeFlags = QDeclarativePropertyData::flagsForProperty(subProp);
1724     core.valueTypeCoreIndex = subIndex;
1725     core.valueTypePropType = subProp.userType();
1726
1727     return core;
1728 }
1729
1730 QDeclarativeProperty
1731 QDeclarativePropertyPrivate::restore(QObject *object, const QDeclarativePropertyData &data,
1732                                      QDeclarativeContextData *ctxt)
1733 {
1734     QDeclarativeProperty prop;
1735
1736     prop.d = new QDeclarativePropertyPrivate;
1737     prop.d->object = object;
1738     prop.d->context = ctxt;
1739     prop.d->engine = ctxt?ctxt->engine:0;
1740
1741     prop.d->core = data;
1742
1743     return prop;
1744 }
1745
1746 /*!
1747     Returns true if lhs and rhs refer to the same metaobject data
1748 */
1749 bool QDeclarativePropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
1750 {
1751     return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1752 }
1753
1754 /*!
1755     Returns true if from inherits to.
1756 */
1757 bool QDeclarativePropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
1758 {
1759     if (from && to == &QObject::staticMetaObject)
1760         return true;
1761
1762     while (from) {
1763         if (equal(from, to))
1764             return true;
1765         from = from->superClass();
1766     }
1767     
1768     return false;
1769 }
1770
1771 /*!
1772     Return the signal corresponding to \a name
1773 */
1774 QMetaMethod QDeclarativePropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1775 {
1776     Q_ASSERT(mo);
1777     int methods = mo->methodCount();
1778     for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1779         QMetaMethod method = mo->method(ii);
1780         QByteArray methodName = method.signature();
1781         int idx = methodName.indexOf('(');
1782         methodName = methodName.left(idx);
1783
1784         if (methodName == name)
1785             return method;
1786     }
1787
1788     // If no signal is found, but the signal is of the form "onBlahChanged",
1789     // return the notify signal for the property "Blah"
1790     if (name.endsWith("Changed")) {
1791         QByteArray propName = name.mid(0, name.length() - 7);
1792         int propIdx = mo->indexOfProperty(propName.constData());
1793         if (propIdx >= 0) {
1794             QMetaProperty prop = mo->property(propIdx);
1795             if (prop.hasNotifySignal())
1796                 return prop.notifySignal();
1797         }
1798     }
1799
1800     return QMetaMethod();
1801 }
1802
1803 static inline int QMetaObject_methods(const QMetaObject *metaObject)
1804 {
1805     struct Private
1806     {
1807         int revision;
1808         int className;
1809         int classInfoCount, classInfoData;
1810         int methodCount, methodData;
1811         int propertyCount, propertyData;
1812     };
1813
1814     return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
1815 }
1816
1817 static inline int QMetaObject_properties(const QMetaObject *metaObject)
1818 {
1819     struct Private
1820     {
1821         int revision;
1822         int className;
1823         int classInfoCount, classInfoData;
1824         int methodCount, methodData;
1825         int propertyCount, propertyData;
1826     };
1827
1828     return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
1829 }
1830
1831 static inline void flush_vme_signal(const QObject *object, int index)
1832 {
1833     QDeclarativeData *data = static_cast<QDeclarativeData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1834     if (data && data->propertyCache) {
1835         QDeclarativePropertyData *property = data->propertyCache->method(index);
1836
1837         if (property && property->isVMESignal()) {
1838             const QMetaObject *metaObject = object->metaObject();
1839             int methodOffset = metaObject->methodOffset();
1840
1841             while (methodOffset > index) {
1842                 metaObject = metaObject->d.superdata;
1843                 methodOffset -= QMetaObject_methods(metaObject);
1844             }
1845
1846             QDeclarativeVMEMetaObject *vme = 
1847                 static_cast<QDeclarativeVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
1848
1849             vme->connectAliasSignal(index);
1850         }
1851     }
1852 }
1853
1854 /*!
1855 Connect \a sender \a signal_index to \a receiver \a method_index with the specified 
1856 \a type and \a types.  This behaves identically to QMetaObject::connect() except that
1857 it connects any lazy "proxy" signal connections set up by QML.
1858
1859 It is possible that this logic should be moved to QMetaObject::connect().
1860 */
1861 bool QDeclarativePropertyPrivate::connect(const QObject *sender, int signal_index,
1862                                           const QObject *receiver, int method_index,
1863                                           int type, int *types)
1864 {
1865     flush_vme_signal(sender, signal_index);
1866     flush_vme_signal(receiver, method_index);
1867
1868     return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1869 }
1870
1871 void QDeclarativePropertyPrivate::flushSignal(const QObject *sender, int signal_index)
1872 {
1873     flush_vme_signal(sender, signal_index);
1874 }
1875
1876 /*!
1877 Return \a metaObject's [super] meta object that provides data for \a property.
1878 */
1879 const QMetaObject *QDeclarativePropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
1880 {
1881     int propertyOffset = metaObject->propertyOffset();
1882
1883     while (propertyOffset > property) {
1884         metaObject = metaObject->d.superdata;
1885         propertyOffset -= QMetaObject_properties(metaObject);
1886     }
1887
1888     return metaObject;
1889 }
1890
1891 QT_END_NAMESPACE