1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qqmlproperty.h"
43 #include "qqmlproperty_p.h"
46 #include "qqmlbinding_p.h"
47 #include "qqmlcontext.h"
48 #include "qqmlcontext_p.h"
49 #include "qqmlboundsignal_p.h"
50 #include "qqmlengine.h"
51 #include "qqmlengine_p.h"
52 #include "qqmldata_p.h"
53 #include "qqmlstringconverters_p.h"
54 #include "qqmllist_p.h"
55 #include "qqmlcompiler_p.h"
56 #include "qqmlvmemetaobject_p.h"
57 #include "qqmlexpression_p.h"
58 #include "qqmlvaluetypeproxybinding_p.h"
60 #include <QStringList>
61 #include <QtCore/qdebug.h>
65 Q_DECLARE_METATYPE(QList<int>)
66 Q_DECLARE_METATYPE(QList<qreal>)
67 Q_DECLARE_METATYPE(QList<bool>)
68 Q_DECLARE_METATYPE(QList<QString>)
69 Q_DECLARE_METATYPE(QList<QUrl>)
77 \brief The QQmlProperty class abstracts accessing properties on objects created from QML.
79 As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect
80 and interact with objects created by QML. However, some of the new features provided by QML - such
81 as type safety and attached properties - are most easily used through the QQmlProperty class
82 that simplifies some of their natural complexity.
84 Unlike QMetaProperty which represents a property on a class type, QQmlProperty encapsulates
85 a property on a specific object instance. To read a property's value, programmers create a
86 QQmlProperty instance and call the read() method. Likewise to write a property value the
87 write() method is used.
89 For example, for the following QML code:
95 Text { text: "A bit of text" }
98 The \l Text object's properties could be accessed using QQmlProperty, like this:
101 #include <QQmlProperty>
102 #include <QGraphicsObject>
106 QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
107 QQmlProperty property(view.rootObject(), "font.pixelSize");
108 qWarning() << "Current pixel size:" << property.read().toInt();
110 qWarning() << "Pixel size should now be 24:" << property.read().toInt();
113 The QtQuick 1 version of this class was named QDeclarativeProperty.
117 Create an invalid QQmlProperty.
119 QQmlProperty::QQmlProperty()
125 QQmlProperty::~QQmlProperty()
133 Creates a QQmlProperty for the default property of \a obj. If there is no
134 default property, an invalid QQmlProperty will be created.
136 QQmlProperty::QQmlProperty(QObject *obj)
137 : d(new QQmlPropertyPrivate)
143 Creates a QQmlProperty for the default property of \a obj
144 using the \l{QQmlContext} {context} \a ctxt. If there is
145 no default property, an invalid QQmlProperty will be
148 QQmlProperty::QQmlProperty(QObject *obj, QQmlContext *ctxt)
149 : d(new QQmlPropertyPrivate)
151 d->context = ctxt?QQmlContextData::get(ctxt):0;
152 d->engine = ctxt?ctxt->engine():0;
157 Creates a QQmlProperty for the default property of \a obj
158 using the environment for instantiating QML components that is
159 provided by \a engine. If there is no default property, an
160 invalid QQmlProperty will be created.
162 QQmlProperty::QQmlProperty(QObject *obj, QQmlEngine *engine)
163 : d(new QQmlPropertyPrivate)
171 Initialize from the default property of \a obj
173 void QQmlPropertyPrivate::initDefault(QObject *obj)
178 QMetaProperty p = QQmlMetaType::defaultProperty(obj);
185 Creates a QQmlProperty for the property \a name of \a obj.
187 QQmlProperty::QQmlProperty(QObject *obj, const QString &name)
188 : d(new QQmlPropertyPrivate)
190 d->initProperty(obj, name);
191 if (!isValid()) d->object = 0;
195 Creates a QQmlProperty for the property \a name of \a obj
196 using the \l{QQmlContext} {context} \a ctxt.
198 Creating a QQmlProperty without a context will render some
199 properties - like attached properties - inaccessible.
201 QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlContext *ctxt)
202 : d(new QQmlPropertyPrivate)
204 d->context = ctxt?QQmlContextData::get(ctxt):0;
205 d->engine = ctxt?ctxt->engine():0;
206 d->initProperty(obj, name);
207 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
211 Creates a QQmlProperty for the property \a name of \a obj
212 using the environment for instantiating QML components that is
213 provided by \a engine.
215 QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlEngine *engine)
216 : d(new QQmlPropertyPrivate)
220 d->initProperty(obj, name);
221 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
224 Q_GLOBAL_STATIC(QQmlValueTypeFactory, qmlValueTypes);
226 QQmlPropertyPrivate::QQmlPropertyPrivate()
227 : context(0), engine(0), object(0), isNameCached(false)
231 QQmlContextData *QQmlPropertyPrivate::effectiveContext() const
233 if (context) return context;
234 else if (engine) return QQmlContextData::get(engine->rootContext());
238 void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
242 QQmlTypeNameCache *typeNameCache = context?context->imports:0;
244 QStringList path = name.split(QLatin1Char('.'));
245 if (path.isEmpty()) return;
247 QObject *currentObject = obj;
249 // Everything up to the last property must be an "object type" property
250 for (int ii = 0; ii < path.count() - 1; ++ii) {
251 const QString &pathName = path.at(ii);
254 QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
257 QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
258 if (!func) return; // Not an attachable type
260 currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
261 if (!currentObject) return; // Something is broken with the attachable type
262 } else if (r.importNamespace) {
263 if ((ii + 1) == path.count()) return; // No type following the namespace
265 ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
266 if (!r.type) return; // Invalid type in namespace
268 QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
269 if (!func) return; // Not an attachable type
271 currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
272 if (!currentObject) return; // Something is broken with the attachable type
274 } else if (r.scriptIndex != -1) {
275 return; // Not a type
277 Q_ASSERT(!"Unreachable");
284 QQmlPropertyData local;
285 QQmlPropertyData *property =
286 QQmlPropertyCache::property(engine, obj, pathName, local);
288 if (!property) return; // Not a property
289 if (property->isFunction())
290 return; // Not an object property
292 if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType)) {
293 // We're now at a value type property. We can use a global valuetypes array as we
294 // never actually use the objects, just look up their properties.
295 QObject *typeObject = (*qmlValueTypes())[property->propType];
296 if (!typeObject) return; // Not a value type
298 int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
299 if (idx == -1) return; // Value type property does not exist
301 QMetaProperty vtProp = typeObject->metaObject()->property(idx);
303 typedef QQmlPropertyData PCD;
305 Q_ASSERT(PCD::flagsForProperty(vtProp) <= PCD::ValueTypeFlagMask);
306 Q_ASSERT(vtProp.userType() <= 0xFF);
307 Q_ASSERT(idx <= 0xFF);
309 object = currentObject;
311 core.setFlags(core.getFlags() | PCD::IsValueTypeVirtual);
312 core.valueTypeFlags = PCD::flagsForProperty(vtProp);
313 core.valueTypePropType = vtProp.userType();
314 core.valueTypeCoreIndex = idx;
318 if (!property->isQObject())
319 return; // Not an object property
321 void *args[] = { ¤tObject, 0 };
322 QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
323 if (!currentObject) return; // No value
329 const QString &terminal = path.last();
331 if (terminal.count() >= 3 &&
332 terminal.at(0) == QLatin1Char('o') &&
333 terminal.at(1) == QLatin1Char('n') &&
334 terminal.at(2).isUpper()) {
336 QString signalName = terminal.mid(2);
337 signalName[0] = signalName.at(0).toLower();
339 QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName.toLatin1().constData());
340 if (method.signature()) {
341 object = currentObject;
348 QQmlPropertyData local;
349 QQmlPropertyData *property =
350 QQmlPropertyCache::property(engine, currentObject, terminal, local);
351 if (property && !property->isFunction()) {
352 object = currentObject;
354 nameCache = terminal;
360 Create a copy of \a other.
362 QQmlProperty::QQmlProperty(const QQmlProperty &other)
370 \enum QQmlProperty::PropertyTypeCategory
372 This enum specifies a category of QML property.
374 \value InvalidCategory The property is invalid, or is a signal property.
375 \value List The property is a QQmlListProperty list property
376 \value Object The property is a QObject derived type pointer
377 \value Normal The property is a normal value property.
381 \enum QQmlProperty::Type
383 This enum specifies a type of QML property.
385 \value Invalid The property is invalid.
386 \value Property The property is a regular Qt property.
387 \value SignalProperty The property is a signal property.
391 Returns the property category.
393 QQmlProperty::PropertyTypeCategory QQmlProperty::propertyTypeCategory() const
395 return d ? d->propertyTypeCategory() : InvalidCategory;
398 QQmlProperty::PropertyTypeCategory
399 QQmlPropertyPrivate::propertyTypeCategory() const
401 uint type = this->type();
404 return QQmlProperty::Normal;
405 } else if (type & QQmlProperty::Property) {
406 int type = propertyType();
407 if (type == QVariant::Invalid)
408 return QQmlProperty::InvalidCategory;
409 else if (QQmlValueTypeFactory::isValueType((uint)type))
410 return QQmlProperty::Normal;
411 else if (core.isQObject())
412 return QQmlProperty::Object;
413 else if (core.isQList())
414 return QQmlProperty::List;
416 return QQmlProperty::Normal;
418 return QQmlProperty::InvalidCategory;
423 Returns the type name of the property, or 0 if the property has no type
426 const char *QQmlProperty::propertyTypeName() const
430 if (d->isValueType()) {
432 QQmlEnginePrivate *ep = d->engine?QQmlEnginePrivate::get(d->engine):0;
433 QQmlValueType *valueType = 0;
434 if (ep) valueType = ep->valueTypes[d->core.propType];
435 else valueType = QQmlValueTypeFactory::valueType(d->core.propType);
438 const char *rv = valueType->metaObject()->property(d->core.valueTypeCoreIndex).typeName();
440 if (!ep) delete valueType;
443 } else if (d->object && type() & Property && d->core.isValid()) {
444 return d->object->metaObject()->property(d->core.coreIndex).typeName();
451 Returns true if \a other and this QQmlProperty represent the same
454 bool QQmlProperty::operator==(const QQmlProperty &other) const
458 // category is intentially omitted here as it is generated
459 // from the other members
460 return d->object == other.d->object &&
461 d->core.coreIndex == other.d->core.coreIndex &&
462 d->core.isValueTypeVirtual() == other.d->core.isValueTypeVirtual() &&
463 (!d->core.isValueTypeVirtual() ||
464 (d->core.valueTypeCoreIndex == other.d->core.valueTypeCoreIndex &&
465 d->core.valueTypePropType == other.d->core.valueTypePropType));
469 Returns the QVariant type of the property, or QVariant::Invalid if the
470 property has no QVariant type.
472 int QQmlProperty::propertyType() const
474 return d ? d->propertyType() : int(QVariant::Invalid);
477 bool QQmlPropertyPrivate::isValueType() const
479 return core.isValueTypeVirtual();
482 int QQmlPropertyPrivate::propertyType() const
484 uint type = this->type();
486 return core.valueTypePropType;
487 } else if (type & QQmlProperty::Property) {
488 return core.propType;
490 return QVariant::Invalid;
494 QQmlProperty::Type QQmlPropertyPrivate::type() const
496 if (core.isFunction())
497 return QQmlProperty::SignalProperty;
498 else if (core.isValid())
499 return QQmlProperty::Property;
501 return QQmlProperty::Invalid;
505 Returns the type of the property.
507 QQmlProperty::Type QQmlProperty::type() const
509 return d ? d->type() : Invalid;
513 Returns true if this QQmlProperty represents a regular Qt property.
515 bool QQmlProperty::isProperty() const
517 return type() & Property;
521 Returns true if this QQmlProperty represents a QML signal property.
523 bool QQmlProperty::isSignalProperty() const
525 return type() & SignalProperty;
529 Returns the QQmlProperty's QObject.
531 QObject *QQmlProperty::object() const
533 return d ? d->object : 0;
537 Assign \a other to this QQmlProperty.
539 QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other)
551 Returns true if the property is writable, otherwise false.
553 bool QQmlProperty::isWritable() const
559 if (d->core.isQList()) //list
561 else if (d->core.isFunction()) //signal handler
563 else if (d->core.isValid()) //normal property
564 return d->core.isWritable();
570 Returns true if the property is designable, otherwise false.
572 bool QQmlProperty::isDesignable() const
576 if (type() & Property && d->core.isValid() && d->object)
577 return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
583 Returns true if the property is resettable, otherwise false.
585 bool QQmlProperty::isResettable() const
589 if (type() & Property && d->core.isValid() && d->object)
590 return d->core.isResettable();
596 Returns true if the QQmlProperty refers to a valid property, otherwise
599 bool QQmlProperty::isValid() const
603 return type() != Invalid;
607 Return the name of this QML property.
609 QString QQmlProperty::name() const
613 if (!d->isNameCached) {
616 } else if (d->isValueType()) {
617 QString rv = d->core.name(d->object) + QLatin1Char('.');
619 QQmlEnginePrivate *ep = d->engine?QQmlEnginePrivate::get(d->engine):0;
620 QQmlValueType *valueType = 0;
621 if (ep) valueType = ep->valueTypes[d->core.propType];
622 else valueType = QQmlValueTypeFactory::valueType(d->core.propType);
625 const char *vtName = valueType->metaObject()->property(d->core.valueTypeCoreIndex).name();
626 rv += QString::fromUtf8(vtName);
628 if (!ep) delete valueType;
631 } else if (type() & SignalProperty) {
632 QString name = QLatin1String("on") + d->core.name(d->object);
633 name[2] = name.at(2).toUpper();
636 d->nameCache = d->core.name(d->object);
638 d->isNameCached = true;
645 Returns the \l{QMetaProperty} {Qt property} associated with
648 QMetaProperty QQmlProperty::property() const
651 return QMetaProperty();
652 if (type() & Property && d->core.isValid() && d->object)
653 return d->object->metaObject()->property(d->core.coreIndex);
655 return QMetaProperty();
659 Return the QMetaMethod for this property if it is a SignalProperty,
660 otherwise returns an invalid QMetaMethod.
662 QMetaMethod QQmlProperty::method() const
665 return QMetaMethod();
666 if (type() & SignalProperty && d->object)
667 return d->object->metaObject()->method(d->core.coreIndex);
669 return QMetaMethod();
673 Returns the binding associated with this property, or 0 if no binding
676 QQmlAbstractBinding *
677 QQmlPropertyPrivate::binding(const QQmlProperty &that)
679 if (!that.d || !that.isProperty() || !that.d->object)
682 return binding(that.d->object, that.d->core.coreIndex,
683 that.d->core.getValueTypeCoreIndex());
687 Set the binding associated with this property to \a newBinding. Returns
688 the existing binding (if any), otherwise 0.
690 \a newBinding will be enabled, and the returned binding (if any) will be
693 Ownership of \a newBinding transfers to QML. Ownership of the return value
694 is assumed by the caller.
696 \a flags is passed through to the binding and is used for the initial update (when
697 the binding sets the initial value, it will use these flags for the write).
699 QQmlAbstractBinding *
700 QQmlPropertyPrivate::setBinding(const QQmlProperty &that,
701 QQmlAbstractBinding *newBinding,
704 if (!that.d || !that.isProperty() || !that.d->object) {
706 newBinding->destroy();
711 // In the case that the new binding is provided, we must target the property it
712 // is associated with. If we don't do this, retargetBinding() can fail.
713 QObject *object = newBinding->object();
714 int pi = newBinding->propertyIndex();
716 int core = pi & 0xFFFFFF;
717 int vt = (pi & 0xFF000000)?(pi >> 24):-1;
719 return setBinding(object, core, vt, newBinding, flags);
721 return setBinding(that.d->object, that.d->core.coreIndex,
722 that.d->core.getValueTypeCoreIndex(),
727 QQmlAbstractBinding *
728 QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
730 QQmlData *data = QQmlData::get(object);
734 QQmlPropertyData *propertyData =
735 data->propertyCache?data->propertyCache->property(coreIndex):0;
736 if (propertyData && propertyData->isAlias()) {
737 const QQmlVMEMetaObject *vme =
738 static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
740 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
741 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
744 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
745 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
746 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
747 return binding(aObject, aCoreIndex, aValueTypeIndex);
750 if (!data->hasBindingBit(coreIndex))
753 QQmlAbstractBinding *binding = data->bindings;
754 while (binding && binding->propertyIndex() != coreIndex)
755 binding = binding->m_nextBinding;
757 if (binding && valueTypeIndex != -1) {
758 if (binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) {
759 int index = coreIndex | (valueTypeIndex << 24);
760 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
767 void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
768 QObject **targetObject, int *targetBindingIndex)
770 int coreIndex = bindingIndex & 0xFFFFFF;
771 int valueTypeIndex = bindingIndex >> 24;
772 if (valueTypeIndex == 0) valueTypeIndex = -1;
774 QQmlData *data = QQmlData::get(object, false);
776 QQmlPropertyData *propertyData =
777 data->propertyCache?data->propertyCache->property(coreIndex):0;
778 if (propertyData && propertyData->isAlias()) {
779 const QQmlVMEMetaObject *vme =
780 static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
781 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
782 if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
783 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
784 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
786 int aBindingIndex = aCoreIndex;
787 if (aValueTypeIndex != -1)
788 aBindingIndex |= aValueTypeIndex << 24;
789 else if (valueTypeIndex != -1)
790 aBindingIndex |= valueTypeIndex << 24;
792 findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
798 *targetObject = object;
799 *targetBindingIndex = bindingIndex;
802 QQmlAbstractBinding *
803 QQmlPropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
804 QQmlAbstractBinding *newBinding, WriteFlags flags)
806 QQmlData *data = QQmlData::get(object, 0 != newBinding);
807 QQmlAbstractBinding *binding = 0;
810 QQmlPropertyData *propertyData =
811 data->propertyCache?data->propertyCache->property(coreIndex):0;
812 if (propertyData && propertyData->isAlias()) {
813 const QQmlVMEMetaObject *vme =
814 static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
816 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
817 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
818 if (newBinding) newBinding->destroy();
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 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
825 return setBinding(aObject, aCoreIndex, aValueTypeIndex, newBinding, flags);
829 if (data && data->hasBindingBit(coreIndex)) {
830 binding = data->bindings;
832 while (binding && binding->propertyIndex() != coreIndex)
833 binding = binding->m_nextBinding;
836 int index = coreIndex;
837 if (valueTypeIndex != -1)
838 index |= (valueTypeIndex << 24);
840 if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
841 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
844 binding->removeFromObject();
845 binding->setEnabled(false, 0);
849 if (newBinding->propertyIndex() != index || newBinding->object() != object)
850 newBinding->retargetBinding(object, index);
852 Q_ASSERT(newBinding->propertyIndex() == index);
853 Q_ASSERT(newBinding->object() == object);
855 newBinding->addToObject();
856 newBinding->setEnabled(true, flags);
862 QQmlAbstractBinding *
863 QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
864 QQmlAbstractBinding *newBinding)
866 QQmlData *data = QQmlData::get(object, 0 != newBinding);
867 QQmlAbstractBinding *binding = 0;
870 QQmlPropertyData *propertyData =
871 data->propertyCache?data->propertyCache->property(coreIndex):0;
872 if (propertyData && propertyData->isAlias()) {
873 const QQmlVMEMetaObject *vme =
874 static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
876 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
877 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
878 if (newBinding) newBinding->destroy();
882 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
883 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
884 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
885 return setBindingNoEnable(aObject, aCoreIndex, aValueTypeIndex, newBinding);
889 if (data && data->hasBindingBit(coreIndex)) {
890 binding = data->bindings;
892 while (binding && binding->propertyIndex() != coreIndex)
893 binding = binding->m_nextBinding;
896 int index = coreIndex;
897 if (valueTypeIndex != -1)
898 index |= (valueTypeIndex << 24);
900 if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
901 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
904 binding->removeFromObject();
907 if (newBinding->propertyIndex() != index || newBinding->object() != object)
908 newBinding->retargetBinding(object, index);
910 Q_ASSERT(newBinding->propertyIndex() == index);
911 Q_ASSERT(newBinding->object() == object);
913 newBinding->addToObject();
920 Returns the expression associated with this signal property, or 0 if no
921 signal expression exists.
924 QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
926 if (!(that.type() & QQmlProperty::SignalProperty))
929 QQmlData *data = QQmlData::get(that.d->object);
933 QQmlAbstractBoundSignal *signalHandler = data->signalHandlers;
935 while (signalHandler && signalHandler->index() != that.index())
936 signalHandler = signalHandler->m_nextSignal;
939 return signalHandler->expression();
945 Set the signal expression associated with this signal property to \a expr.
946 Returns the existing signal expression (if any), otherwise 0.
948 Ownership of \a expr transfers to QML. Ownership of the return value is
949 assumed by the caller.
952 QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that,
953 QQmlExpression *expr)
955 if (!(that.type() & QQmlProperty::SignalProperty)) {
960 QQmlData *data = QQmlData::get(that.d->object, 0 != expr);
964 QQmlAbstractBoundSignal *signalHandler = data->signalHandlers;
966 while (signalHandler && signalHandler->index() != that.index())
967 signalHandler = signalHandler->m_nextSignal;
970 return signalHandler->setExpression(expr);
973 QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, that.method(), that.d->object);
974 QQmlExpression *oldExpr = signal->setExpression(expr);
975 signal->addToObject();
983 Returns the property value.
985 QVariant QQmlProperty::read() const
992 if (type() & SignalProperty) {
996 } else if (type() & Property) {
998 return d->readValueProperty();
1005 Return the \a name property value of \a object. This method is equivalent to:
1007 QQmlProperty p(object, name);
1011 QVariant QQmlProperty::read(QObject *object, const QString &name)
1013 QQmlProperty p(object, name);
1018 Return the \a name property value of \a object using the
1019 \l{QQmlContext} {context} \a ctxt. This method is
1023 QQmlProperty p(object, name, context);
1027 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlContext *ctxt)
1029 QQmlProperty p(object, name, ctxt);
1035 Return the \a name property value of \a object using the environment
1036 for instantiating QML components that is provided by \a engine. .
1037 This method is equivalent to:
1040 QQmlProperty p(object, name, engine);
1044 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlEngine *engine)
1046 QQmlProperty p(object, name, engine);
1050 QVariant QQmlPropertyPrivate::readValueProperty()
1052 if (isValueType()) {
1054 QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
1055 QQmlValueType *valueType = 0;
1056 if (ep) valueType = ep->valueTypes[core.propType];
1057 else valueType = QQmlValueTypeFactory::valueType(core.propType);
1058 Q_ASSERT(valueType);
1060 valueType->read(object, core.coreIndex);
1062 QVariant rv = valueType->metaObject()->property(core.valueTypeCoreIndex).read(valueType);
1064 if (!ep) delete valueType;
1067 } else if (core.isQList()) {
1069 QQmlListProperty<QObject> prop;
1070 void *args[] = { &prop, 0 };
1071 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1072 return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType, engine));
1074 } else if (core.isQObject()) {
1077 void *args[] = { &rv, 0 };
1078 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1079 return QVariant::fromValue(rv);
1083 return object->metaObject()->property(core.coreIndex).read(object.data());
1088 static QUrl urlFromUserString(const QByteArray &data)
1091 if (!data.isEmpty())
1093 // Preserve any valid percent-encoded octets supplied by the source
1094 u.setEncodedUrl(data, QUrl::TolerantMode);
1099 static QUrl urlFromUserString(const QString &data)
1101 return urlFromUserString(data.toUtf8());
1104 // helper function to allow assignment / binding to QList<QUrl> properties.
1105 static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context)
1108 if (value.userType() == qMetaTypeId<QUrl>()) {
1109 urls.append(value.toUrl());
1110 } else if (value.userType() == qMetaTypeId<QString>()) {
1111 urls.append(urlFromUserString(value.toString()));
1112 } else if (value.userType() == qMetaTypeId<QByteArray>()) {
1113 urls.append(urlFromUserString(value.toByteArray()));
1114 } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
1115 urls = value.value<QList<QUrl> >();
1116 } else if (value.userType() == qMetaTypeId<QStringList>()) {
1117 QStringList urlStrings = value.value<QStringList>();
1118 for (int i = 0; i < urlStrings.size(); ++i)
1119 urls.append(urlFromUserString(urlStrings.at(i)));
1120 } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
1121 QList<QString> urlStrings = value.value<QList<QString> >();
1122 for (int i = 0; i < urlStrings.size(); ++i)
1123 urls.append(urlFromUserString(urlStrings.at(i)));
1124 } // note: QList<QByteArray> is not currently supported.
1126 QList<QUrl> resolvedUrls;
1127 for (int i = 0; i < urls.size(); ++i) {
1128 QUrl u = urls.at(i);
1129 if (context && u.isRelative() && !u.isEmpty())
1130 u = context->resolvedUrl(u);
1131 resolvedUrls.append(u);
1134 return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
1137 //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1138 bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1140 if (!object || !prop.isWritable())
1144 if (prop.isEnumType()) {
1145 QMetaEnum menum = prop.enumerator();
1146 if (v.userType() == QVariant::String
1148 || v.userType() == QVariant::CString
1152 if (prop.isFlagType())
1153 v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
1155 v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
1158 } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
1159 int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
1160 if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData())
1162 v = QVariant(*reinterpret_cast<const int *>(v.constData()));
1164 v.convert(QVariant::Int);
1167 // the status variable is changed by qt_metacall to indicate what it did
1168 // this feature is currently only used by QtDBus and should not be depended
1169 // upon. Don't change it without looking into QDBusAbstractInterface first
1170 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1171 // changed: result stored directly in value, return the value of status
1173 void *argv[] = { v.data(), &v, &status, &flags };
1174 QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
1178 bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
1180 return writeValueProperty(object, engine, core, value, effectiveContext(), flags);
1184 QQmlPropertyPrivate::writeValueProperty(QObject *object, QQmlEngine *engine,
1185 const QQmlPropertyData &core,
1186 const QVariant &value,
1187 QQmlContextData *context, WriteFlags flags)
1189 // Remove any existing bindings on this property
1190 if (!(flags & DontRemoveBinding) && object) {
1191 QQmlAbstractBinding *binding = setBinding(object, core.coreIndex,
1192 core.getValueTypeCoreIndex(),
1194 if (binding) binding->destroy();
1198 if (core.isValueTypeVirtual()) {
1199 QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
1201 QQmlValueType *writeBack = 0;
1203 writeBack = ep->valueTypes[core.propType];
1205 writeBack = QQmlValueTypeFactory::valueType(core.propType);
1208 writeBack->read(object, core.coreIndex);
1210 QQmlPropertyData data = core;
1211 data.setFlags(QQmlPropertyData::Flag(core.valueTypeFlags));
1212 data.coreIndex = core.valueTypeCoreIndex;
1213 data.propType = core.valueTypePropType;
1215 rv = write(writeBack, data, value, context, flags);
1217 writeBack->write(object, core.coreIndex, flags);
1218 if (!ep) delete writeBack;
1222 rv = write(object, core, value, context, flags);
1229 bool QQmlPropertyPrivate::write(QObject *object,
1230 const QQmlPropertyData &property,
1231 const QVariant &value, QQmlContextData *context,
1234 int coreIdx = property.coreIndex;
1235 int status = -1; //for dbus
1237 if (property.isEnum()) {
1238 QMetaProperty prop = object->metaObject()->property(property.coreIndex);
1240 // Enum values come through the script engine as doubles
1241 if (value.userType() == QVariant::Double) {
1243 double fractional = modf(value.toDouble(), &integral);
1244 if (qFuzzyIsNull(fractional))
1245 v.convert(QVariant::Int);
1247 return writeEnumProperty(prop, coreIdx, object, v, flags);
1250 int propertyType = property.propType;
1251 int variantType = value.userType();
1253 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
1255 if (propertyType == QVariant::Url) {
1259 if (variantType == QVariant::Url) {
1262 } else if (variantType == QVariant::ByteArray) {
1263 u = urlFromUserString(value.toByteArray());
1265 } else if (variantType == QVariant::String) {
1266 u = urlFromUserString(value.toString());
1273 if (context && u.isRelative() && !u.isEmpty())
1274 u = context->resolvedUrl(u);
1276 void *argv[] = { &u, 0, &status, &flags };
1277 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1279 } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
1280 QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
1282 void *argv[] = { &urlSeq, 0, &status, &flags };
1283 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1284 } else if (variantType == propertyType) {
1286 void *a[] = { (void *)value.constData(), 0, &status, &flags };
1287 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1289 } else if (qMetaTypeId<QVariant>() == propertyType) {
1291 void *a[] = { (void *)&value, 0, &status, &flags };
1292 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1294 } else if (property.isQObject()) {
1296 const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType());
1301 QObject *o = *(QObject **)value.constData();
1302 const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType);
1304 if (o) valMo = o->metaObject();
1306 if (canConvert(valMo, propMo)) {
1307 void *args[] = { &o, 0, &status, &flags };
1308 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
1310 } else if (!o && canConvert(propMo, valMo)) {
1311 // In the case of a null QObject, we assign the null if there is
1312 // any change that the null variant type could be up or down cast to
1313 // the property type.
1314 void *args[] = { &o, 0, &status, &flags };
1315 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
1321 } else if (property.isQList()) {
1323 const QMetaObject *listType = 0;
1325 listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
1327 QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType));
1328 if (!type) return false;
1329 listType = type->baseMetaObject();
1331 if (!listType) return false;
1333 QQmlListProperty<void> prop;
1334 void *args[] = { &prop, 0 };
1335 QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
1337 if (!prop.clear) return false;
1341 if (value.userType() == qMetaTypeId<QQmlListReference>()) {
1342 QQmlListReference qdlr = value.value<QQmlListReference>();
1344 for (int ii = 0; ii < qdlr.count(); ++ii) {
1345 QObject *o = qdlr.at(ii);
1346 if (o && !canConvert(o->metaObject(), listType))
1348 prop.append(&prop, (void *)o);
1350 } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
1351 const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1353 for (int ii = 0; ii < list.count(); ++ii) {
1354 QObject *o = list.at(ii);
1355 if (o && !canConvert(o->metaObject(), listType))
1357 prop.append(&prop, (void *)o);
1360 QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value);
1361 if (o && !canConvert(o->metaObject(), listType))
1363 prop.append(&prop, (void *)o);
1367 Q_ASSERT(variantType != propertyType);
1371 if (variantType == QVariant::String)
1372 v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
1375 if (v.convert((QVariant::Type)propertyType)) {
1377 } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
1378 QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
1380 v = con(value.toString());
1381 if (v.userType() == propertyType)
1387 // the only other option is that they are assigning a single value
1388 // to a sequence type property (eg, an int to a QList<int> property).
1389 // Note that we've already handled single-value assignment to QList<QUrl> properties.
1390 if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
1392 list << value.toInt();
1393 v = QVariant::fromValue<QList<int> >(list);
1395 } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
1397 list << value.toReal();
1398 v = QVariant::fromValue<QList<qreal> >(list);
1400 } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
1402 list << value.toBool();
1403 v = QVariant::fromValue<QList<bool> >(list);
1405 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
1406 QList<QString> list;
1407 list << value.toString();
1408 v = QVariant::fromValue<QList<QString> >(list);
1410 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
1412 list << value.toString();
1413 v = QVariant::fromValue<QStringList>(list);
1419 void *a[] = { (void *)v.constData(), 0, &status, &flags};
1420 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1429 // Returns true if successful, false if an error description was set on expression
1430 bool QQmlPropertyPrivate::writeBinding(QObject *object,
1431 const QQmlPropertyData &core,
1432 QQmlContextData *context,
1433 QQmlJavaScriptExpression *expression,
1434 v8::Handle<v8::Value> result, bool isUndefined,
1438 Q_ASSERT(core.coreIndex != -1);
1440 QQmlEngine *engine = context->engine;
1441 QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
1443 #define QUICK_STORE(cpptype, conversion) \
1445 cpptype o = (conversion); \
1447 void *argv[] = { &o, 0, &status, &flags }; \
1448 QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \
1453 if (!isUndefined && !core.isValueTypeVirtual()) {
1454 switch (core.propType) {
1455 case QMetaType::Int:
1456 if (result->IsInt32())
1457 QUICK_STORE(int, result->Int32Value())
1458 else if (result->IsNumber())
1459 QUICK_STORE(int, qRound(result->NumberValue()))
1461 case QMetaType::Double:
1462 if (result->IsNumber())
1463 QUICK_STORE(double, result->NumberValue())
1465 case QMetaType::Float:
1466 if (result->IsNumber())
1467 QUICK_STORE(float, result->NumberValue())
1469 case QMetaType::QString:
1470 if (result->IsString())
1471 QUICK_STORE(QString, v8engine->toString(result))
1479 int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType;
1481 QQmlJavaScriptExpression::DeleteWatcher watcher(expression);
1484 bool isVmeProperty = core.isVMEProperty();
1487 } else if (core.isQList()) {
1488 value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
1489 } else if (result->IsNull() && core.isQObject()) {
1490 value = QVariant::fromValue((QObject *)0);
1491 } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
1492 value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
1493 } else if (!isVmeProperty) {
1494 value = v8engine->toVariant(result, type);
1497 if (expression->hasError()) {
1499 } else if (isUndefined && core.isResettable()) {
1500 void *args[] = { 0 };
1501 QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
1502 } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
1503 writeValueProperty(object, engine, core, QVariant(), context, flags);
1504 } else if (isUndefined) {
1505 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(type)));
1507 } else if (result->IsFunction()) {
1508 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign a function to a property."));
1510 } else if (isVmeProperty) {
1511 typedef QQmlVMEMetaObject VMEMO;
1512 VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject()));
1513 vmemo->setVMEProperty(core.coreIndex, result);
1514 } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
1516 if (watcher.wasDeleted())
1519 const char *valueType = 0;
1520 if (value.userType() == QVariant::Invalid) valueType = "null";
1521 else valueType = QMetaType::typeName(value.userType());
1523 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign ") +
1524 QLatin1String(valueType) +
1525 QLatin1String(" to ") +
1526 QLatin1String(QMetaType::typeName(type)));
1533 const QMetaObject *QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
1536 return engine->rawMetaObjectForType(userType);
1538 QQmlType *type = QQmlMetaType::qmlType(userType);
1539 return type?type->baseMetaObject():0;
1544 Sets the property value to \a value and returns true.
1545 Returns false if the property can't be set because the
1546 \a value is the wrong type, for example.
1548 bool QQmlProperty::write(const QVariant &value) const
1550 return QQmlPropertyPrivate::write(*this, value, 0);
1554 Writes \a value to the \a name property of \a object. This method
1558 QQmlProperty p(object, name);
1562 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
1564 QQmlProperty p(object, name);
1565 return p.write(value);
1569 Writes \a value to the \a name property of \a object using the
1570 \l{QQmlContext} {context} \a ctxt. This method is
1574 QQmlProperty p(object, name, ctxt);
1578 bool QQmlProperty::write(QObject *object,
1579 const QString &name,
1580 const QVariant &value,
1583 QQmlProperty p(object, name, ctxt);
1584 return p.write(value);
1589 Writes \a value to the \a name property of \a object using the
1590 environment for instantiating QML components that is provided by
1591 \a engine. This method is equivalent to:
1594 QQmlProperty p(object, name, engine);
1598 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
1601 QQmlProperty p(object, name, engine);
1602 return p.write(value);
1606 Resets the property and returns true if the property is
1607 resettable. If the property is not resettable, nothing happens
1608 and false is returned.
1610 bool QQmlProperty::reset() const
1612 if (isResettable()) {
1613 void *args[] = { 0 };
1614 QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1621 bool QQmlPropertyPrivate::write(const QQmlProperty &that,
1622 const QVariant &value, WriteFlags flags)
1626 if (that.d->object && that.type() & QQmlProperty::Property &&
1627 that.d->core.isValid() && that.isWritable())
1628 return that.d->writeValueProperty(value, flags);
1634 Returns true if the property has a change notifier signal, otherwise false.
1636 bool QQmlProperty::hasNotifySignal() const
1638 if (type() & Property && d->object) {
1639 return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1645 Returns true if the property needs a change notifier signal for bindings
1646 to remain upto date, false otherwise.
1648 Some properties, such as attached properties or those whose value never
1649 changes, do not require a change notifier.
1651 bool QQmlProperty::needsNotifySignal() const
1653 return type() & Property && !property().isConstant();
1657 Connects the property's change notifier signal to the
1658 specified \a method of the \a dest object and returns
1659 true. Returns false if this metaproperty does not
1660 represent a regular Qt property or if it has no
1661 change notifier signal, or if the \a dest object does
1662 not have the specified \a method.
1664 bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
1666 if (!(type() & Property) || !d->object)
1669 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1670 if (prop.hasNotifySignal()) {
1671 return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1678 Connects the property's change notifier signal to the
1679 specified \a slot of the \a dest object and returns
1680 true. Returns false if this metaproperty does not
1681 represent a regular Qt property or if it has no
1682 change notifier signal, or if the \a dest object does
1683 not have the specified \a slot.
1685 bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
1687 if (!(type() & Property) || !d->object)
1690 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1691 if (prop.hasNotifySignal()) {
1692 QByteArray signal(QByteArray("2") + prop.notifySignal().signature());
1693 return QObject::connect(d->object, signal.constData(), dest, slot);
1700 Return the Qt metaobject index of the property.
1702 int QQmlProperty::index() const
1704 return d ? d->core.coreIndex : -1;
1707 int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that)
1709 return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
1713 Returns the "property index" for use in bindings. The top 8 bits are the value type
1714 offset, and 0 otherwise. The bottom 24-bits are the regular property index.
1716 int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that)
1720 return bindingIndex(that.d->core);
1723 int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that)
1725 int rv = that.coreIndex;
1726 if (rv != -1 && that.isValueTypeVirtual())
1727 rv = rv | (that.valueTypeCoreIndex << 24);
1732 QQmlPropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
1733 const QMetaObject *subObject, int subIndex,
1736 QMetaProperty subProp = subObject->property(subIndex);
1738 QQmlPropertyData core;
1739 core.load(metaObject->property(index));
1740 core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
1741 core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp);
1742 core.valueTypeCoreIndex = subIndex;
1743 core.valueTypePropType = subProp.userType();
1749 QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
1750 QQmlContextData *ctxt)
1754 prop.d = new QQmlPropertyPrivate;
1755 prop.d->object = object;
1756 prop.d->context = ctxt;
1757 prop.d->engine = ctxt?ctxt->engine:0;
1759 prop.d->core = data;
1765 Returns true if lhs and rhs refer to the same metaobject data
1767 bool QQmlPropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
1769 return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1773 Returns true if from inherits to.
1775 bool QQmlPropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
1777 if (from && to == &QObject::staticMetaObject)
1781 if (equal(from, to))
1783 from = from->superClass();
1790 Return the signal corresponding to \a name
1792 QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1795 int methods = mo->methodCount();
1796 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1797 QMetaMethod method = mo->method(ii);
1798 QByteArray methodName = method.signature();
1799 int idx = methodName.indexOf('(');
1800 methodName = methodName.left(idx);
1802 if (methodName == name)
1806 // If no signal is found, but the signal is of the form "onBlahChanged",
1807 // return the notify signal for the property "Blah"
1808 if (name.endsWith("Changed")) {
1809 QByteArray propName = name.mid(0, name.length() - 7);
1810 int propIdx = mo->indexOfProperty(propName.constData());
1812 QMetaProperty prop = mo->property(propIdx);
1813 if (prop.hasNotifySignal())
1814 return prop.notifySignal();
1818 return QMetaMethod();
1821 static inline int QMetaObject_methods(const QMetaObject *metaObject)
1827 int classInfoCount, classInfoData;
1828 int methodCount, methodData;
1829 int propertyCount, propertyData;
1832 return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
1835 static inline int QMetaObject_properties(const QMetaObject *metaObject)
1841 int classInfoCount, classInfoData;
1842 int methodCount, methodData;
1843 int propertyCount, propertyData;
1846 return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
1849 static inline void flush_vme_signal(const QObject *object, int index)
1851 QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1852 if (data && data->propertyCache) {
1853 QQmlPropertyData *property = data->propertyCache->method(index);
1855 if (property && property->isVMESignal()) {
1856 const QMetaObject *metaObject = object->metaObject();
1857 int methodOffset = metaObject->methodOffset();
1859 while (methodOffset > index) {
1860 metaObject = metaObject->d.superdata;
1861 methodOffset -= QMetaObject_methods(metaObject);
1864 QQmlVMEMetaObject *vme =
1865 static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
1867 vme->connectAliasSignal(index);
1873 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1874 \a type and \a types. This behaves identically to QMetaObject::connect() except that
1875 it connects any lazy "proxy" signal connections set up by QML.
1877 It is possible that this logic should be moved to QMetaObject::connect().
1879 bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
1880 const QObject *receiver, int method_index,
1881 int type, int *types)
1883 flush_vme_signal(sender, signal_index);
1884 flush_vme_signal(receiver, method_index);
1886 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1889 void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
1891 flush_vme_signal(sender, signal_index);
1895 Return \a metaObject's [super] meta object that provides data for \a property.
1897 const QMetaObject *QQmlPropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
1899 int propertyOffset = metaObject->propertyOffset();
1901 while (propertyOffset > property) {
1902 metaObject = metaObject->d.superdata;
1903 propertyOffset -= QMetaObject_properties(metaObject);