1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 */
QDeclarativeProperty()108 QDeclarativeProperty::QDeclarativeProperty()
109 : d(0)
110 {
111 }
112 
113 /*!  \internal */
~QDeclarativeProperty()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  */
QDeclarativeProperty(QObject * obj)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  */
QDeclarativeProperty(QObject * obj,QDeclarativeContext * ctxt)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  */
QDeclarativeProperty(QObject * obj,QDeclarativeEngine * engine)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 */
initDefault(QObject * obj)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  */
QDeclarativeProperty(QObject * obj,const QString & name)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 */
QDeclarativeProperty(QObject * obj,const QString & name,QDeclarativeContext * ctxt)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  */
QDeclarativeProperty(QObject * obj,const QString & name,QDeclarativeEngine * engine)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 
initProperty(QObject * obj,const QString & name)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 */
QDeclarativeProperty(const QDeclarativeProperty & other)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 */
propertyTypeCategory() const355 QDeclarativeProperty::PropertyTypeCategory QDeclarativeProperty::propertyTypeCategory() const
356 {
357     return d ? d->propertyTypeCategory() : InvalidCategory;
358 }
359 
360 QDeclarativeProperty::PropertyTypeCategory
propertyTypeCategory() const361 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 */
propertyTypeName() const388 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 */
operator ==(const QDeclarativeProperty & other) const416 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 */
propertyType() const431 int QDeclarativeProperty::propertyType() const
432 {
433     return d ? d->propertyType() : int(QVariant::Invalid);
434 }
435 
isValueType() const436 bool QDeclarativePropertyPrivate::isValueType() const
437 {
438     return valueType.valueTypeCoreIdx != -1;
439 }
440 
propertyType() const441 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 
type() const456 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 */
type() const469 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 */
isProperty() const477 bool QDeclarativeProperty::isProperty() const
478 {
479     return type() & Property;
480 }
481 
482 /*!
483     Returns true if this QDeclarativeProperty represents a QML signal property.
484 */
isSignalProperty() const485 bool QDeclarativeProperty::isSignalProperty() const
486 {
487     return type() & SignalProperty;
488 }
489 
490 /*!
491     Returns the QDeclarativeProperty's QObject.
492 */
object() const493 QObject *QDeclarativeProperty::object() const
494 {
495     return d ? d->object : 0;
496 }
497 
498 /*!
499     Assign \a other to this QDeclarativeProperty.
500 */
operator =(const QDeclarativeProperty & other)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 */
isWritable() const515 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 */
isDesignable() const534 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 */
isResettable() const547 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 */
isValid() const561 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 */
name() const571 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  */
property() const609 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 */
method() const623 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 *
binding(const QDeclarativeProperty & that)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 *
setBinding(const QDeclarativeProperty & that,QDeclarativeAbstractBinding * newBinding,WriteFlags flags)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 *
binding(QObject * object,int coreIndex,int valueTypeIndex)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 
findAliasTarget(QObject * object,int bindingIndex,QObject ** targetObject,int * targetBindingIndex)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 *
setBinding(QObject * object,int coreIndex,int valueTypeIndex,QDeclarativeAbstractBinding * newBinding,WriteFlags flags)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 *
setBindingNoEnable(QObject * object,int coreIndex,int valueTypeIndex,QDeclarativeAbstractBinding * newBinding)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 *
signalExpression(const QDeclarativeProperty & that)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 *
setSignalExpression(const QDeclarativeProperty & that,QDeclarativeExpression * expr)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 */
read() const912 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 */
read(QObject * object,const QString & name)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 */
read(QObject * object,const QString & name,QDeclarativeContext * ctxt)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 */
read(QObject * object,const QString & name,QDeclarativeEngine * engine)971 QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeEngine *engine)
972 {
973     QDeclarativeProperty p(object, name, engine);
974     return p.read();
975 }
976 
readValueProperty()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!
writeEnumProperty(const QMetaProperty & prop,int idx,QObject * object,const QVariant & value,int flags)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 
writeValueProperty(const QVariant & value,WriteFlags flags)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 
write(QObject * object,const QDeclarativePropertyCache::Data & property,const QVariant & value,QDeclarativeContextData * context,WriteFlags flags)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 
rawMetaObjectForType(QDeclarativeEnginePrivate * engine,int userType)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  */
write(const QVariant & value) const1263 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 */
write(QObject * object,const QString & name,const QVariant & value)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 */
write(QObject * object,const QString & name,const QVariant & value,QDeclarativeContext * ctxt)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 */
write(QObject * object,const QString & name,const QVariant & value,QDeclarativeEngine * engine)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 */
reset() const1325 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 
write(const QDeclarativeProperty & that,const QVariant & value,WriteFlags flags)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 */
hasNotifySignal() const1351 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 */
needsNotifySignal() const1366 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 */
connectNotifySignal(QObject * dest,int method) const1379 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 */
connectNotifySignal(QObject * dest,const char * slot) const1400 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 */
index() const1417 int QDeclarativeProperty::index() const
1418 {
1419     return d ? d->core.coreIndex : -1;
1420 }
1421 
valueTypeCoreIndex(const QDeclarativeProperty & that)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 */
bindingIndex(const QDeclarativeProperty & that)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 
saveValueType(const QMetaObject * metaObject,int index,const QMetaObject * subObject,int subIndex)1450 QByteArray QDeclarativePropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
1451                                                  const QMetaObject *subObject, int subIndex)
1452 {
1453     QMetaProperty subProp = subObject->property(subIndex);
1454 
1455     ValueTypeSerializedData sd;
1456     memset(&sd, 0, sizeof(sd));
1457     sd.isValueType = true;
1458     sd.core.load(metaObject->property(index));
1459     sd.valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(subProp);
1460     sd.valueType.valueTypeCoreIdx = subIndex;
1461     sd.valueType.valueTypePropType = subProp.userType();
1462 
1463     QByteArray rv((const char *)&sd, sizeof(sd));
1464 
1465     return rv;
1466 }
1467 
saveProperty(const QMetaObject * metaObject,int index)1468 QByteArray QDeclarativePropertyPrivate::saveProperty(const QMetaObject *metaObject, int index)
1469 {
1470     SerializedData sd;
1471     memset(&sd, 0, sizeof(sd));
1472     sd.isValueType = false;
1473     sd.core.load(metaObject->property(index));
1474 
1475     QByteArray rv((const char *)&sd, sizeof(sd));
1476     return rv;
1477 }
1478 
1479 QDeclarativeProperty
restore(const QByteArray & data,QObject * object,QDeclarativeContextData * ctxt)1480 QDeclarativePropertyPrivate::restore(const QByteArray &data, QObject *object, QDeclarativeContextData *ctxt)
1481 {
1482     QDeclarativeProperty prop;
1483 
1484     if (data.isEmpty())
1485         return prop;
1486 
1487     const SerializedData *sd = (const SerializedData *)data.constData();
1488     if (sd->isValueType) {
1489         const ValueTypeSerializedData *vt = (const ValueTypeSerializedData *)sd;
1490         return restore(vt->core, vt->valueType, object, ctxt);
1491     } else {
1492         QDeclarativePropertyCache::ValueTypeData data;
1493         return restore(sd->core, data, object, ctxt);
1494     }
1495 }
1496 
1497 QDeclarativeProperty
restore(const QDeclarativePropertyCache::Data & data,const QDeclarativePropertyCache::ValueTypeData & valueType,QObject * object,QDeclarativeContextData * ctxt)1498 QDeclarativePropertyPrivate::restore(const QDeclarativePropertyCache::Data &data, const QDeclarativePropertyCache::ValueTypeData &valueType, QObject *object, QDeclarativeContextData *ctxt)
1499 {
1500     QDeclarativeProperty prop;
1501 
1502     prop.d = new QDeclarativePropertyPrivate;
1503     prop.d->object = object;
1504     prop.d->context = ctxt;
1505     prop.d->engine = ctxt->engine;
1506 
1507     prop.d->core = data;
1508     prop.d->valueType = valueType;
1509 
1510     return prop;
1511 }
1512 
1513 /*!
1514     Returns true if lhs and rhs refer to the same metaobject data
1515 */
equal(const QMetaObject * lhs,const QMetaObject * rhs)1516 bool QDeclarativePropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
1517 {
1518     return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1519 }
1520 
1521 /*!
1522     Returns true if from inherits to.
1523 */
canConvert(const QMetaObject * from,const QMetaObject * to)1524 bool QDeclarativePropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
1525 {
1526     if (from && to == &QObject::staticMetaObject)
1527         return true;
1528 
1529     while (from) {
1530         if (equal(from, to))
1531             return true;
1532         from = from->superClass();
1533     }
1534 
1535     return false;
1536 }
1537 
1538 /*!
1539     Return the signal corresponding to \a name
1540 */
findSignalByName(const QMetaObject * mo,const QByteArray & name)1541 QMetaMethod QDeclarativePropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1542 {
1543     Q_ASSERT(mo);
1544     int methods = mo->methodCount();
1545     for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1546         QMetaMethod method = mo->method(ii);
1547         QByteArray methodName = method.signature();
1548         int idx = methodName.indexOf('(');
1549         methodName = methodName.left(idx);
1550 
1551         if (methodName == name)
1552             return method;
1553     }
1554 
1555     // If no signal is found, but the signal is of the form "onBlahChanged",
1556     // return the notify signal for the property "Blah"
1557     if (name.endsWith("Changed")) {
1558         QByteArray propName = name.mid(0, name.length() - 7);
1559         int propIdx = mo->indexOfProperty(propName.constData());
1560         if (propIdx >= 0) {
1561             QMetaProperty prop = mo->property(propIdx);
1562             if (prop.hasNotifySignal())
1563                 return prop.notifySignal();
1564         }
1565     }
1566 
1567     return QMetaMethod();
1568 }
1569 
QMetaObject_methods(const QMetaObject * metaObject)1570 static inline int QMetaObject_methods(const QMetaObject *metaObject)
1571 {
1572     struct Private
1573     {
1574         int revision;
1575         int className;
1576         int classInfoCount, classInfoData;
1577         int methodCount, methodData;
1578         int propertyCount, propertyData;
1579     };
1580 
1581     return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
1582 }
1583 
QMetaObject_properties(const QMetaObject * metaObject)1584 static inline int QMetaObject_properties(const QMetaObject *metaObject)
1585 {
1586     struct Private
1587     {
1588         int revision;
1589         int className;
1590         int classInfoCount, classInfoData;
1591         int methodCount, methodData;
1592         int propertyCount, propertyData;
1593     };
1594 
1595     return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
1596 }
1597 
flush_vme_signal(const QObject * object,int index)1598 static inline void flush_vme_signal(const QObject *object, int index)
1599 {
1600     QDeclarativeData *data = static_cast<QDeclarativeData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1601     if (data && data->propertyCache) {
1602         QDeclarativePropertyCache::Data *property = data->propertyCache->method(index);
1603 
1604         if (property && property->flags & QDeclarativePropertyCache::Data::IsVMESignal) {
1605             const QMetaObject *metaObject = object->metaObject();
1606             int methodOffset = metaObject->methodOffset();
1607 
1608             while (methodOffset > index) {
1609                 metaObject = metaObject->d.superdata;
1610                 methodOffset -= QMetaObject_methods(metaObject);
1611             }
1612 
1613             QDeclarativeVMEMetaObject *vme =
1614                 static_cast<QDeclarativeVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
1615 
1616             vme->connectAliasSignal(index);
1617         }
1618     }
1619 }
1620 
1621 /*!
1622 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1623 \a type and \a types.  This behaves identically to QMetaObject::connect() except that
1624 it connects any lazy "proxy" signal connections set up by QML.
1625 
1626 It is possible that this logic should be moved to QMetaObject::connect().
1627 */
connect(QObject * sender,int signal_index,const QObject * receiver,int method_index,int type,int * types)1628 bool QDeclarativePropertyPrivate::connect(QObject *sender, int signal_index,
1629                                           const QObject *receiver, int method_index,
1630                                           int type, int *types)
1631 {
1632     flush_vme_signal(sender, signal_index);
1633     flush_vme_signal(receiver, method_index);
1634 
1635     const bool result =
1636             QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1637 
1638     // connectNotify() needs to be called after the actual connect, as otherwise QObject::receivers()
1639     // would return the wrong result inside connectNotify().
1640     const QMetaMethod signal = sender->metaObject()->method(signal_index);
1641     QObjectPrivate * const senderPriv = QObjectPrivate::get(sender);
1642     QVarLengthArray<char> signalSignature;
1643     QObjectPrivate::signalSignature(signal, &signalSignature);
1644     senderPriv->connectNotify(signalSignature.constData());
1645 
1646     return result;
1647 }
1648 
1649 /*!
1650 Return \a metaObject's [super] meta object that provides data for \a property.
1651 */
metaObjectForProperty(const QMetaObject * metaObject,int property)1652 const QMetaObject *QDeclarativePropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
1653 {
1654     int propertyOffset = metaObject->propertyOffset();
1655 
1656     while (propertyOffset > property) {
1657         metaObject = metaObject->d.superdata;
1658         propertyOffset -= QMetaObject_properties(metaObject);
1659     }
1660 
1661     return metaObject;
1662 }
1663 
1664 QT_END_NAMESPACE
1665