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