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