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.isValid()) {
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 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 QQmlExpression *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 == QMetaType::UnknownType) || (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 (isVmeProperty) {
1504 typedef QQmlVMEMetaObject VMEMO;
1505 if (!result.IsEmpty() && result->IsFunction()
1506 && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
1507 // we explicitly disallow this case to avoid confusion. Users can still store one
1508 // in an array in a var property if they need to, but the common case is user error.
1509 expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1512 VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject()));
1513 vmemo->setVMEProperty(core.coreIndex, result);
1514 } else if (isUndefined && core.isResettable()) {
1515 void *args[] = { 0 };
1516 QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
1517 } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
1518 writeValueProperty(object, engine, core, QVariant(), context, flags);
1519 } else if (isUndefined) {
1520 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(type)));
1522 } else if (result->IsFunction()) {
1523 if (!result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty())
1524 expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1526 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
1528 } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
1530 if (watcher.wasDeleted())
1533 const char *valueType = 0;
1534 if (value.userType() == QVariant::Invalid) valueType = "null";
1535 else valueType = QMetaType::typeName(value.userType());
1537 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign ") +
1538 QLatin1String(valueType) +
1539 QLatin1String(" to ") +
1540 QLatin1String(QMetaType::typeName(type)));
1547 const QMetaObject *QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
1550 return engine->rawMetaObjectForType(userType);
1552 QQmlType *type = QQmlMetaType::qmlType(userType);
1553 return type?type->baseMetaObject():0;
1558 Sets the property value to \a value and returns true.
1559 Returns false if the property can't be set because the
1560 \a value is the wrong type, for example.
1562 bool QQmlProperty::write(const QVariant &value) const
1564 return QQmlPropertyPrivate::write(*this, value, 0);
1568 Writes \a value to the \a name property of \a object. This method
1572 QQmlProperty p(object, name);
1576 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
1578 QQmlProperty p(object, name);
1579 return p.write(value);
1583 Writes \a value to the \a name property of \a object using the
1584 \l{QQmlContext} {context} \a ctxt. This method is
1588 QQmlProperty p(object, name, ctxt);
1592 bool QQmlProperty::write(QObject *object,
1593 const QString &name,
1594 const QVariant &value,
1597 QQmlProperty p(object, name, ctxt);
1598 return p.write(value);
1603 Writes \a value to the \a name property of \a object using the
1604 environment for instantiating QML components that is provided by
1605 \a engine. This method is equivalent to:
1608 QQmlProperty p(object, name, engine);
1612 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
1615 QQmlProperty p(object, name, engine);
1616 return p.write(value);
1620 Resets the property and returns true if the property is
1621 resettable. If the property is not resettable, nothing happens
1622 and false is returned.
1624 bool QQmlProperty::reset() const
1626 if (isResettable()) {
1627 void *args[] = { 0 };
1628 QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1635 bool QQmlPropertyPrivate::write(const QQmlProperty &that,
1636 const QVariant &value, WriteFlags flags)
1640 if (that.d->object && that.type() & QQmlProperty::Property &&
1641 that.d->core.isValid() && that.isWritable())
1642 return that.d->writeValueProperty(value, flags);
1648 Returns true if the property has a change notifier signal, otherwise false.
1650 bool QQmlProperty::hasNotifySignal() const
1652 if (type() & Property && d->object) {
1653 return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1659 Returns true if the property needs a change notifier signal for bindings
1660 to remain upto date, false otherwise.
1662 Some properties, such as attached properties or those whose value never
1663 changes, do not require a change notifier.
1665 bool QQmlProperty::needsNotifySignal() const
1667 return type() & Property && !property().isConstant();
1671 Connects the property's change notifier signal to the
1672 specified \a method of the \a dest object and returns
1673 true. Returns false if this metaproperty does not
1674 represent a regular Qt property or if it has no
1675 change notifier signal, or if the \a dest object does
1676 not have the specified \a method.
1678 bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
1680 if (!(type() & Property) || !d->object)
1683 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1684 if (prop.hasNotifySignal()) {
1685 return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1692 Connects the property's change notifier signal to the
1693 specified \a slot of the \a dest object and returns
1694 true. Returns false if this metaproperty does not
1695 represent a regular Qt property or if it has no
1696 change notifier signal, or if the \a dest object does
1697 not have the specified \a slot.
1699 bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
1701 if (!(type() & Property) || !d->object)
1704 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1705 if (prop.hasNotifySignal()) {
1706 QByteArray signal(QByteArray("2") + prop.notifySignal().methodSignature());
1707 return QObject::connect(d->object, signal.constData(), dest, slot);
1714 Return the Qt metaobject index of the property.
1716 int QQmlProperty::index() const
1718 return d ? d->core.coreIndex : -1;
1721 int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that)
1723 return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
1727 Returns the "property index" for use in bindings. The top 8 bits are the value type
1728 offset, and 0 otherwise. The bottom 24-bits are the regular property index.
1730 int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that)
1734 return bindingIndex(that.d->core);
1737 int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that)
1739 int rv = that.coreIndex;
1740 if (rv != -1 && that.isValueTypeVirtual())
1741 rv = rv | (that.valueTypeCoreIndex << 24);
1746 QQmlPropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
1747 const QMetaObject *subObject, int subIndex,
1750 QMetaProperty subProp = subObject->property(subIndex);
1752 QQmlPropertyData core;
1753 core.load(metaObject->property(index));
1754 core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
1755 core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp);
1756 core.valueTypeCoreIndex = subIndex;
1757 core.valueTypePropType = subProp.userType();
1763 QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
1764 QQmlContextData *ctxt)
1768 prop.d = new QQmlPropertyPrivate;
1769 prop.d->object = object;
1770 prop.d->context = ctxt;
1771 prop.d->engine = ctxt?ctxt->engine:0;
1773 prop.d->core = data;
1779 Returns true if lhs and rhs refer to the same metaobject data
1781 bool QQmlPropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
1783 return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1787 Returns true if from inherits to.
1789 bool QQmlPropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
1791 if (from && to == &QObject::staticMetaObject)
1795 if (equal(from, to))
1797 from = from->superClass();
1804 Return the signal corresponding to \a name
1806 QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1809 int methods = mo->methodCount();
1810 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1811 QMetaMethod method = mo->method(ii);
1813 if (method.name() == name)
1817 // If no signal is found, but the signal is of the form "onBlahChanged",
1818 // return the notify signal for the property "Blah"
1819 if (name.endsWith("Changed")) {
1820 QByteArray propName = name.mid(0, name.length() - 7);
1821 int propIdx = mo->indexOfProperty(propName.constData());
1823 QMetaProperty prop = mo->property(propIdx);
1824 if (prop.hasNotifySignal())
1825 return prop.notifySignal();
1829 return QMetaMethod();
1832 static inline int QMetaObject_methods(const QMetaObject *metaObject)
1838 int classInfoCount, classInfoData;
1839 int methodCount, methodData;
1840 int propertyCount, propertyData;
1843 return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
1846 static inline int QMetaObject_properties(const QMetaObject *metaObject)
1852 int classInfoCount, classInfoData;
1853 int methodCount, methodData;
1854 int propertyCount, propertyData;
1857 return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
1860 static inline void flush_vme_signal(const QObject *object, int index)
1862 QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1863 if (data && data->propertyCache) {
1864 QQmlPropertyData *property = data->propertyCache->method(index);
1866 if (property && property->isVMESignal()) {
1867 const QMetaObject *metaObject = object->metaObject();
1868 int methodOffset = metaObject->methodOffset();
1870 while (methodOffset > index) {
1871 metaObject = metaObject->d.superdata;
1872 methodOffset -= QMetaObject_methods(metaObject);
1875 QQmlVMEMetaObject *vme =
1876 static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
1878 vme->connectAliasSignal(index);
1884 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1885 \a type and \a types. This behaves identically to QMetaObject::connect() except that
1886 it connects any lazy "proxy" signal connections set up by QML.
1888 It is possible that this logic should be moved to QMetaObject::connect().
1890 bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
1891 const QObject *receiver, int method_index,
1892 int type, int *types)
1894 flush_vme_signal(sender, signal_index);
1895 flush_vme_signal(receiver, method_index);
1897 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1900 void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
1902 flush_vme_signal(sender, signal_index);
1906 Return \a metaObject's [super] meta object that provides data for \a property.
1908 const QMetaObject *QQmlPropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
1910 int propertyOffset = metaObject->propertyOffset();
1912 while (propertyOffset > property) {
1913 metaObject = metaObject->d.superdata;
1914 propertyOffset -= QMetaObject_properties(metaObject);