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.
923 QQmlBoundSignalExpression *
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.
951 QQmlBoundSignalExpression *
952 QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that,
953 QQmlBoundSignalExpression *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 QQmlAbstractBoundSignal *signal = 0;
974 if (that.method().parameterTypes().count())
975 signal = new QQmlBoundSignal(that.d->object, that.method(), that.d->object);
977 signal = new QQmlBoundSignalNoParams(that.d->object, that.method(), that.d->object);
978 QQmlBoundSignalExpression *oldExpr = signal->setExpression(expr);
979 signal->addToObject();
987 Returns the property value.
989 QVariant QQmlProperty::read() const
996 if (type() & SignalProperty) {
1000 } else if (type() & Property) {
1002 return d->readValueProperty();
1009 Return the \a name property value of \a object. This method is equivalent to:
1011 QQmlProperty p(object, name);
1015 QVariant QQmlProperty::read(QObject *object, const QString &name)
1017 QQmlProperty p(object, name);
1022 Return the \a name property value of \a object using the
1023 \l{QQmlContext} {context} \a ctxt. This method is
1027 QQmlProperty p(object, name, context);
1031 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlContext *ctxt)
1033 QQmlProperty p(object, name, ctxt);
1039 Return the \a name property value of \a object using the environment
1040 for instantiating QML components that is provided by \a engine. .
1041 This method is equivalent to:
1044 QQmlProperty p(object, name, engine);
1048 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlEngine *engine)
1050 QQmlProperty p(object, name, engine);
1054 QVariant QQmlPropertyPrivate::readValueProperty()
1056 if (isValueType()) {
1058 QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
1059 QQmlValueType *valueType = 0;
1060 if (ep) valueType = ep->valueTypes[core.propType];
1061 else valueType = QQmlValueTypeFactory::valueType(core.propType);
1062 Q_ASSERT(valueType);
1064 valueType->read(object, core.coreIndex);
1066 QVariant rv = valueType->metaObject()->property(core.valueTypeCoreIndex).read(valueType);
1068 if (!ep) delete valueType;
1071 } else if (core.isQList()) {
1073 QQmlListProperty<QObject> prop;
1074 void *args[] = { &prop, 0 };
1075 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1076 return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType, engine));
1078 } else if (core.isQObject()) {
1081 void *args[] = { &rv, 0 };
1082 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1083 return QVariant::fromValue(rv);
1087 return object->metaObject()->property(core.coreIndex).read(object.data());
1092 static QUrl urlFromUserString(const QByteArray &data)
1095 if (!data.isEmpty())
1097 // Preserve any valid percent-encoded octets supplied by the source
1098 u.setEncodedUrl(data, QUrl::TolerantMode);
1103 static QUrl urlFromUserString(const QString &data)
1105 return urlFromUserString(data.toUtf8());
1108 // helper function to allow assignment / binding to QList<QUrl> properties.
1109 static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context)
1112 if (value.userType() == qMetaTypeId<QUrl>()) {
1113 urls.append(value.toUrl());
1114 } else if (value.userType() == qMetaTypeId<QString>()) {
1115 urls.append(urlFromUserString(value.toString()));
1116 } else if (value.userType() == qMetaTypeId<QByteArray>()) {
1117 urls.append(urlFromUserString(value.toByteArray()));
1118 } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
1119 urls = value.value<QList<QUrl> >();
1120 } else if (value.userType() == qMetaTypeId<QStringList>()) {
1121 QStringList urlStrings = value.value<QStringList>();
1122 for (int i = 0; i < urlStrings.size(); ++i)
1123 urls.append(urlFromUserString(urlStrings.at(i)));
1124 } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
1125 QList<QString> urlStrings = value.value<QList<QString> >();
1126 for (int i = 0; i < urlStrings.size(); ++i)
1127 urls.append(urlFromUserString(urlStrings.at(i)));
1128 } // note: QList<QByteArray> is not currently supported.
1130 QList<QUrl> resolvedUrls;
1131 for (int i = 0; i < urls.size(); ++i) {
1132 QUrl u = urls.at(i);
1133 if (context && u.isRelative() && !u.isEmpty())
1134 u = context->resolvedUrl(u);
1135 resolvedUrls.append(u);
1138 return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
1141 //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1142 bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1144 if (!object || !prop.isWritable())
1148 if (prop.isEnumType()) {
1149 QMetaEnum menum = prop.enumerator();
1150 if (v.userType() == QVariant::String
1152 || v.userType() == QVariant::CString
1156 if (prop.isFlagType())
1157 v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
1159 v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
1162 } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
1163 int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
1164 if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData())
1166 v = QVariant(*reinterpret_cast<const int *>(v.constData()));
1168 v.convert(QVariant::Int);
1171 // the status variable is changed by qt_metacall to indicate what it did
1172 // this feature is currently only used by QtDBus and should not be depended
1173 // upon. Don't change it without looking into QDBusAbstractInterface first
1174 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1175 // changed: result stored directly in value, return the value of status
1177 void *argv[] = { v.data(), &v, &status, &flags };
1178 QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
1182 bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
1184 return writeValueProperty(object, engine, core, value, effectiveContext(), flags);
1188 QQmlPropertyPrivate::writeValueProperty(QObject *object, QQmlEngine *engine,
1189 const QQmlPropertyData &core,
1190 const QVariant &value,
1191 QQmlContextData *context, WriteFlags flags)
1193 // Remove any existing bindings on this property
1194 if (!(flags & DontRemoveBinding) && object) {
1195 QQmlAbstractBinding *binding = setBinding(object, core.coreIndex,
1196 core.getValueTypeCoreIndex(),
1198 if (binding) binding->destroy();
1202 if (core.isValueTypeVirtual()) {
1203 QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
1205 QQmlValueType *writeBack = 0;
1207 writeBack = ep->valueTypes[core.propType];
1209 writeBack = QQmlValueTypeFactory::valueType(core.propType);
1212 writeBack->read(object, core.coreIndex);
1214 QQmlPropertyData data = core;
1215 data.setFlags(QQmlPropertyData::Flag(core.valueTypeFlags));
1216 data.coreIndex = core.valueTypeCoreIndex;
1217 data.propType = core.valueTypePropType;
1219 rv = write(writeBack, data, value, context, flags);
1221 writeBack->write(object, core.coreIndex, flags);
1222 if (!ep) delete writeBack;
1226 rv = write(object, core, value, context, flags);
1233 bool QQmlPropertyPrivate::write(QObject *object,
1234 const QQmlPropertyData &property,
1235 const QVariant &value, QQmlContextData *context,
1238 int coreIdx = property.coreIndex;
1239 int status = -1; //for dbus
1241 if (property.isEnum()) {
1242 QMetaProperty prop = object->metaObject()->property(property.coreIndex);
1244 // Enum values come through the script engine as doubles
1245 if (value.userType() == QVariant::Double) {
1247 double fractional = modf(value.toDouble(), &integral);
1248 if (qFuzzyIsNull(fractional))
1249 v.convert(QVariant::Int);
1251 return writeEnumProperty(prop, coreIdx, object, v, flags);
1254 int propertyType = property.propType;
1255 int variantType = value.userType();
1257 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
1259 if (propertyType == QVariant::Url) {
1263 if (variantType == QVariant::Url) {
1266 } else if (variantType == QVariant::ByteArray) {
1267 u = urlFromUserString(value.toByteArray());
1269 } else if (variantType == QVariant::String) {
1270 u = urlFromUserString(value.toString());
1277 if (context && u.isRelative() && !u.isEmpty())
1278 u = context->resolvedUrl(u);
1280 void *argv[] = { &u, 0, &status, &flags };
1281 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1283 } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
1284 QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
1286 void *argv[] = { &urlSeq, 0, &status, &flags };
1287 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1288 } else if (variantType == propertyType) {
1290 void *a[] = { (void *)value.constData(), 0, &status, &flags };
1291 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1293 } else if (qMetaTypeId<QVariant>() == propertyType) {
1295 void *a[] = { (void *)&value, 0, &status, &flags };
1296 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1298 } else if (property.isQObject()) {
1300 const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType());
1305 QObject *o = *(QObject **)value.constData();
1306 const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType);
1308 if (o) valMo = o->metaObject();
1310 if (canConvert(valMo, propMo)) {
1311 void *args[] = { &o, 0, &status, &flags };
1312 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
1314 } else if (!o && canConvert(propMo, valMo)) {
1315 // In the case of a null QObject, we assign the null if there is
1316 // any change that the null variant type could be up or down cast to
1317 // the property type.
1318 void *args[] = { &o, 0, &status, &flags };
1319 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
1325 } else if (property.isQList()) {
1327 const QMetaObject *listType = 0;
1329 listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
1331 QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType));
1332 if (!type) return false;
1333 listType = type->baseMetaObject();
1335 if (!listType) return false;
1337 QQmlListProperty<void> prop;
1338 void *args[] = { &prop, 0 };
1339 QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
1341 if (!prop.clear) return false;
1345 if (value.userType() == qMetaTypeId<QQmlListReference>()) {
1346 QQmlListReference qdlr = value.value<QQmlListReference>();
1348 for (int ii = 0; ii < qdlr.count(); ++ii) {
1349 QObject *o = qdlr.at(ii);
1350 if (o && !canConvert(o->metaObject(), listType))
1352 prop.append(&prop, (void *)o);
1354 } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
1355 const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1357 for (int ii = 0; ii < list.count(); ++ii) {
1358 QObject *o = list.at(ii);
1359 if (o && !canConvert(o->metaObject(), listType))
1361 prop.append(&prop, (void *)o);
1364 QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value);
1365 if (o && !canConvert(o->metaObject(), listType))
1367 prop.append(&prop, (void *)o);
1371 Q_ASSERT(variantType != propertyType);
1375 if (variantType == QVariant::String)
1376 v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
1379 if (v.convert((QVariant::Type)propertyType)) {
1381 } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
1382 QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
1384 v = con(value.toString());
1385 if (v.userType() == propertyType)
1391 // the only other option is that they are assigning a single value
1392 // to a sequence type property (eg, an int to a QList<int> property).
1393 // Note that we've already handled single-value assignment to QList<QUrl> properties.
1394 if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
1396 list << value.toInt();
1397 v = QVariant::fromValue<QList<int> >(list);
1399 } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
1401 list << value.toReal();
1402 v = QVariant::fromValue<QList<qreal> >(list);
1404 } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
1406 list << value.toBool();
1407 v = QVariant::fromValue<QList<bool> >(list);
1409 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
1410 QList<QString> list;
1411 list << value.toString();
1412 v = QVariant::fromValue<QList<QString> >(list);
1414 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
1416 list << value.toString();
1417 v = QVariant::fromValue<QStringList>(list);
1423 void *a[] = { (void *)v.constData(), 0, &status, &flags};
1424 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1433 // Returns true if successful, false if an error description was set on expression
1434 bool QQmlPropertyPrivate::writeBinding(QObject *object,
1435 const QQmlPropertyData &core,
1436 QQmlContextData *context,
1437 QQmlJavaScriptExpression *expression,
1438 v8::Handle<v8::Value> result, bool isUndefined,
1442 Q_ASSERT(core.coreIndex != -1);
1444 QQmlEngine *engine = context->engine;
1445 QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
1447 #define QUICK_STORE(cpptype, conversion) \
1449 cpptype o = (conversion); \
1451 void *argv[] = { &o, 0, &status, &flags }; \
1452 QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \
1457 if (!isUndefined && !core.isValueTypeVirtual()) {
1458 switch (core.propType) {
1459 case QMetaType::Int:
1460 if (result->IsInt32())
1461 QUICK_STORE(int, result->Int32Value())
1462 else if (result->IsNumber())
1463 QUICK_STORE(int, qRound(result->NumberValue()))
1465 case QMetaType::Double:
1466 if (result->IsNumber())
1467 QUICK_STORE(double, result->NumberValue())
1469 case QMetaType::Float:
1470 if (result->IsNumber())
1471 QUICK_STORE(float, result->NumberValue())
1473 case QMetaType::QString:
1474 if (result->IsString())
1475 QUICK_STORE(QString, v8engine->toString(result))
1483 int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType;
1485 QQmlJavaScriptExpression::DeleteWatcher watcher(expression);
1488 bool isVmeProperty = core.isVMEProperty();
1491 } else if (core.isQList()) {
1492 value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
1493 } else if (result->IsNull() && core.isQObject()) {
1494 value = QVariant::fromValue((QObject *)0);
1495 } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
1496 value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
1497 } else if (!isVmeProperty) {
1498 value = v8engine->toVariant(result, type);
1501 if (expression->hasError()) {
1503 } else if (isUndefined && core.isResettable()) {
1504 void *args[] = { 0 };
1505 QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
1506 } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
1507 writeValueProperty(object, engine, core, QVariant(), context, flags);
1508 } else if (isUndefined) {
1509 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(type)));
1511 } else if (result->IsFunction()) {
1512 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign a function to a property."));
1514 } else if (isVmeProperty) {
1515 typedef QQmlVMEMetaObject VMEMO;
1516 VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject()));
1517 vmemo->setVMEProperty(core.coreIndex, result);
1518 } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
1520 if (watcher.wasDeleted())
1523 const char *valueType = 0;
1524 const char *propertyType = 0;
1526 if (value.userType() == QMetaType::QObjectStar) {
1527 if (QObject *o = *(QObject **)value.constData()) {
1528 valueType = o->metaObject()->className();
1530 const QMetaObject *propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type);
1531 propertyType = propertyMetaObject->className();
1533 } else if (value.userType() != QVariant::Invalid) {
1534 valueType = QMetaType::typeName(value.userType());
1540 propertyType = QMetaType::typeName(type);
1542 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign ") +
1543 QLatin1String(valueType) +
1544 QLatin1String(" to ") +
1545 QLatin1String(propertyType));
1552 const QMetaObject *QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
1555 return engine->rawMetaObjectForType(userType);
1557 QQmlType *type = QQmlMetaType::qmlType(userType);
1558 return type?type->baseMetaObject():0;
1563 Sets the property value to \a value and returns true.
1564 Returns false if the property can't be set because the
1565 \a value is the wrong type, for example.
1567 bool QQmlProperty::write(const QVariant &value) const
1569 return QQmlPropertyPrivate::write(*this, value, 0);
1573 Writes \a value to the \a name property of \a object. This method
1577 QQmlProperty p(object, name);
1581 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
1583 QQmlProperty p(object, name);
1584 return p.write(value);
1588 Writes \a value to the \a name property of \a object using the
1589 \l{QQmlContext} {context} \a ctxt. This method is
1593 QQmlProperty p(object, name, ctxt);
1597 bool QQmlProperty::write(QObject *object,
1598 const QString &name,
1599 const QVariant &value,
1602 QQmlProperty p(object, name, ctxt);
1603 return p.write(value);
1608 Writes \a value to the \a name property of \a object using the
1609 environment for instantiating QML components that is provided by
1610 \a engine. This method is equivalent to:
1613 QQmlProperty p(object, name, engine);
1617 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
1620 QQmlProperty p(object, name, engine);
1621 return p.write(value);
1625 Resets the property and returns true if the property is
1626 resettable. If the property is not resettable, nothing happens
1627 and false is returned.
1629 bool QQmlProperty::reset() const
1631 if (isResettable()) {
1632 void *args[] = { 0 };
1633 QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1640 bool QQmlPropertyPrivate::write(const QQmlProperty &that,
1641 const QVariant &value, WriteFlags flags)
1645 if (that.d->object && that.type() & QQmlProperty::Property &&
1646 that.d->core.isValid() && that.isWritable())
1647 return that.d->writeValueProperty(value, flags);
1653 Returns true if the property has a change notifier signal, otherwise false.
1655 bool QQmlProperty::hasNotifySignal() const
1657 if (type() & Property && d->object) {
1658 return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1664 Returns true if the property needs a change notifier signal for bindings
1665 to remain upto date, false otherwise.
1667 Some properties, such as attached properties or those whose value never
1668 changes, do not require a change notifier.
1670 bool QQmlProperty::needsNotifySignal() const
1672 return type() & Property && !property().isConstant();
1676 Connects the property's change notifier signal to the
1677 specified \a method of the \a dest object and returns
1678 true. Returns false if this metaproperty does not
1679 represent a regular Qt property or if it has no
1680 change notifier signal, or if the \a dest object does
1681 not have the specified \a method.
1683 bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
1685 if (!(type() & Property) || !d->object)
1688 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1689 if (prop.hasNotifySignal()) {
1690 return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1697 Connects the property's change notifier signal to the
1698 specified \a slot of the \a dest object and returns
1699 true. Returns false if this metaproperty does not
1700 represent a regular Qt property or if it has no
1701 change notifier signal, or if the \a dest object does
1702 not have the specified \a slot.
1704 bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
1706 if (!(type() & Property) || !d->object)
1709 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1710 if (prop.hasNotifySignal()) {
1711 QByteArray signal(QByteArray("2") + prop.notifySignal().signature());
1712 return QObject::connect(d->object, signal.constData(), dest, slot);
1719 Return the Qt metaobject index of the property.
1721 int QQmlProperty::index() const
1723 return d ? d->core.coreIndex : -1;
1726 int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that)
1728 return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
1732 Returns the "property index" for use in bindings. The top 8 bits are the value type
1733 offset, and 0 otherwise. The bottom 24-bits are the regular property index.
1735 int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that)
1739 return bindingIndex(that.d->core);
1742 int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that)
1744 int rv = that.coreIndex;
1745 if (rv != -1 && that.isValueTypeVirtual())
1746 rv = rv | (that.valueTypeCoreIndex << 24);
1751 QQmlPropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
1752 const QMetaObject *subObject, int subIndex,
1755 QMetaProperty subProp = subObject->property(subIndex);
1757 QQmlPropertyData core;
1758 core.load(metaObject->property(index));
1759 core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
1760 core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp);
1761 core.valueTypeCoreIndex = subIndex;
1762 core.valueTypePropType = subProp.userType();
1768 QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
1769 QQmlContextData *ctxt)
1773 prop.d = new QQmlPropertyPrivate;
1774 prop.d->object = object;
1775 prop.d->context = ctxt;
1776 prop.d->engine = ctxt?ctxt->engine:0;
1778 prop.d->core = data;
1784 Returns true if lhs and rhs refer to the same metaobject data
1786 bool QQmlPropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
1788 return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1792 Returns true if from inherits to.
1794 bool QQmlPropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
1796 if (from && to == &QObject::staticMetaObject)
1800 if (equal(from, to))
1802 from = from->superClass();
1809 Return the signal corresponding to \a name
1811 QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1814 int methods = mo->methodCount();
1815 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1816 QMetaMethod method = mo->method(ii);
1817 QByteArray methodName = method.signature();
1818 int idx = methodName.indexOf('(');
1819 methodName = methodName.left(idx);
1821 if (methodName == name)
1825 // If no signal is found, but the signal is of the form "onBlahChanged",
1826 // return the notify signal for the property "Blah"
1827 if (name.endsWith("Changed")) {
1828 QByteArray propName = name.mid(0, name.length() - 7);
1829 int propIdx = mo->indexOfProperty(propName.constData());
1831 QMetaProperty prop = mo->property(propIdx);
1832 if (prop.hasNotifySignal())
1833 return prop.notifySignal();
1837 return QMetaMethod();
1840 static inline int QMetaObject_methods(const QMetaObject *metaObject)
1846 int classInfoCount, classInfoData;
1847 int methodCount, methodData;
1848 int propertyCount, propertyData;
1851 return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
1854 static inline int QMetaObject_properties(const QMetaObject *metaObject)
1860 int classInfoCount, classInfoData;
1861 int methodCount, methodData;
1862 int propertyCount, propertyData;
1865 return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
1868 static inline void flush_vme_signal(const QObject *object, int index)
1870 QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1871 if (data && data->propertyCache) {
1872 QQmlPropertyData *property = data->propertyCache->method(index);
1874 if (property && property->isVMESignal()) {
1875 const QMetaObject *metaObject = object->metaObject();
1876 int methodOffset = metaObject->methodOffset();
1878 while (methodOffset > index) {
1879 metaObject = metaObject->d.superdata;
1880 methodOffset -= QMetaObject_methods(metaObject);
1883 QQmlVMEMetaObject *vme =
1884 static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
1886 vme->connectAliasSignal(index);
1892 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1893 \a type and \a types. This behaves identically to QMetaObject::connect() except that
1894 it connects any lazy "proxy" signal connections set up by QML.
1896 It is possible that this logic should be moved to QMetaObject::connect().
1898 bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
1899 const QObject *receiver, int method_index,
1900 int type, int *types)
1902 flush_vme_signal(sender, signal_index);
1903 flush_vme_signal(receiver, method_index);
1905 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1908 void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
1910 flush_vme_signal(sender, signal_index);
1914 Return \a metaObject's [super] meta object that provides data for \a property.
1916 const QMetaObject *QQmlPropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
1918 int propertyOffset = metaObject->propertyOffset();
1920 while (propertyOffset > property) {
1921 metaObject = metaObject->d.superdata;
1922 propertyOffset -= QMetaObject_properties(metaObject);