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"
59 #include <private/qv8bindings_p.h>
61 #include <QStringList>
62 #include <private/qmetaobject_p.h>
63 #include <QtCore/qdebug.h>
67 Q_DECLARE_METATYPE(QJSValue)
68 Q_DECLARE_METATYPE(QList<int>)
69 Q_DECLARE_METATYPE(QList<qreal>)
70 Q_DECLARE_METATYPE(QList<bool>)
71 Q_DECLARE_METATYPE(QList<QString>)
72 Q_DECLARE_METATYPE(QList<QUrl>)
80 \brief The QQmlProperty class abstracts accessing properties on objects created from QML.
82 As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect
83 and interact with objects created by QML. However, some of the new features provided by QML - such
84 as type safety and attached properties - are most easily used through the QQmlProperty class
85 that simplifies some of their natural complexity.
87 Unlike QMetaProperty which represents a property on a class type, QQmlProperty encapsulates
88 a property on a specific object instance. To read a property's value, programmers create a
89 QQmlProperty instance and call the read() method. Likewise to write a property value the
90 write() method is used.
92 For example, for the following QML code:
98 Text { text: "A bit of text" }
101 The \l Text object's properties could be accessed using QQmlProperty, like this:
104 #include <QQmlProperty>
105 #include <QGraphicsObject>
109 QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
110 QQmlProperty property(view.rootObject(), "font.pixelSize");
111 qWarning() << "Current pixel size:" << property.read().toInt();
113 qWarning() << "Pixel size should now be 24:" << property.read().toInt();
116 The QtQuick 1 version of this class was named QDeclarativeProperty.
120 Create an invalid QQmlProperty.
122 QQmlProperty::QQmlProperty()
128 QQmlProperty::~QQmlProperty()
136 Creates a QQmlProperty for the default property of \a obj. If there is no
137 default property, an invalid QQmlProperty will be created.
139 QQmlProperty::QQmlProperty(QObject *obj)
140 : d(new QQmlPropertyPrivate)
146 Creates a QQmlProperty for the default property of \a obj
147 using the \l{QQmlContext} {context} \a ctxt. If there is
148 no default property, an invalid QQmlProperty will be
151 QQmlProperty::QQmlProperty(QObject *obj, QQmlContext *ctxt)
152 : d(new QQmlPropertyPrivate)
154 d->context = ctxt?QQmlContextData::get(ctxt):0;
155 d->engine = ctxt?ctxt->engine():0;
160 Creates a QQmlProperty for the default property of \a obj
161 using the environment for instantiating QML components that is
162 provided by \a engine. If there is no default property, an
163 invalid QQmlProperty will be created.
165 QQmlProperty::QQmlProperty(QObject *obj, QQmlEngine *engine)
166 : d(new QQmlPropertyPrivate)
174 Initialize from the default property of \a obj
176 void QQmlPropertyPrivate::initDefault(QObject *obj)
181 QMetaProperty p = QQmlMetaType::defaultProperty(obj);
188 Creates a QQmlProperty for the property \a name of \a obj.
190 QQmlProperty::QQmlProperty(QObject *obj, const QString &name)
191 : d(new QQmlPropertyPrivate)
193 d->initProperty(obj, name);
194 if (!isValid()) d->object = 0;
198 Creates a QQmlProperty for the property \a name of \a obj
199 using the \l{QQmlContext} {context} \a ctxt.
201 Creating a QQmlProperty without a context will render some
202 properties - like attached properties - inaccessible.
204 QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlContext *ctxt)
205 : d(new QQmlPropertyPrivate)
207 d->context = ctxt?QQmlContextData::get(ctxt):0;
208 d->engine = ctxt?ctxt->engine():0;
209 d->initProperty(obj, name);
210 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
214 Creates a QQmlProperty for the property \a name of \a obj
215 using the environment for instantiating QML components that is
216 provided by \a engine.
218 QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlEngine *engine)
219 : d(new QQmlPropertyPrivate)
223 d->initProperty(obj, name);
224 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
227 QQmlPropertyPrivate::QQmlPropertyPrivate()
228 : context(0), engine(0), object(0), isNameCached(false)
232 QQmlContextData *QQmlPropertyPrivate::effectiveContext() const
234 if (context) return context;
235 else if (engine) return QQmlContextData::get(engine->rootContext());
239 void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
243 QQmlTypeNameCache *typeNameCache = context?context->imports:0;
245 QStringList path = name.split(QLatin1Char('.'));
246 if (path.isEmpty()) return;
248 QObject *currentObject = obj;
250 // Everything up to the last property must be an "object type" property
251 for (int ii = 0; ii < path.count() - 1; ++ii) {
252 const QString &pathName = path.at(ii);
255 QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
258 QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
259 if (!func) return; // Not an attachable type
261 currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
262 if (!currentObject) return; // Something is broken with the attachable type
263 } else if (r.importNamespace) {
264 if ((ii + 1) == path.count()) return; // No type following the namespace
266 ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
267 if (!r.type) return; // Invalid type in namespace
269 QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
270 if (!func) return; // Not an attachable type
272 currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
273 if (!currentObject) return; // Something is broken with the attachable type
275 } else if (r.scriptIndex != -1) {
276 return; // Not a type
278 Q_ASSERT(!"Unreachable");
285 QQmlPropertyData local;
286 QQmlPropertyData *property =
287 QQmlPropertyCache::property(engine, obj, pathName, local);
289 if (!property) return; // Not a property
290 if (property->isFunction())
291 return; // Not an object property
293 if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType)) {
294 // We're now at a value type property
295 QObject *typeObject = QQmlValueTypeFactory::valueType(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 Q_ASSERT(QQmlPropertyData::flagsForProperty(vtProp) <= QQmlPropertyData::ValueTypeFlagMask);
304 Q_ASSERT(vtProp.userType() <= 0x0000FFFF);
305 Q_ASSERT(idx <= 0x0000FFFF);
307 object = currentObject;
309 core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
310 core.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp);
311 core.valueTypePropType = vtProp.userType();
312 core.valueTypeCoreIndex = idx;
316 if (!property->isQObject())
317 return; // Not an object property
319 void *args[] = { ¤tObject, 0 };
320 QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
321 if (!currentObject) return; // No value
327 const QString &terminal = path.last();
329 if (terminal.count() >= 3 &&
330 terminal.at(0) == QLatin1Char('o') &&
331 terminal.at(1) == QLatin1Char('n') &&
332 terminal.at(2).isUpper()) {
334 QString signalName = terminal.mid(2);
335 signalName[0] = signalName.at(0).toLower();
337 // XXX - this code treats methods as signals
339 QQmlData *ddata = QQmlData::get(currentObject, false);
340 if (ddata && ddata->propertyCache) {
343 QQmlPropertyData *d = ddata->propertyCache->property(signalName);
344 while (d && !d->isFunction())
345 d = ddata->propertyCache->overrideData(d);
348 object = currentObject;
354 if (signalName.endsWith(QLatin1String("Changed"))) {
355 QString propName = signalName.mid(0, signalName.length() - 7);
356 QQmlPropertyData *d = ddata->propertyCache->property(propName);
357 while (d && d->isFunction())
358 d = ddata->propertyCache->overrideData(d);
360 if (d && d->notifyIndex != -1) {
361 object = currentObject;
362 core = *ddata->propertyCache->signal(d->notifyIndex);
368 QMetaMethod method = findSignalByName(currentObject->metaObject(),
369 signalName.toLatin1());
370 if (method.isValid()) {
371 object = currentObject;
379 QQmlPropertyData local;
380 QQmlPropertyData *property =
381 QQmlPropertyCache::property(engine, currentObject, terminal, local);
382 if (property && !property->isFunction()) {
383 object = currentObject;
385 nameCache = terminal;
391 Returns the index of this property's signal, in the signal index range
392 (see QObjectPrivate::signalIndex()). This is different from
393 QMetaMethod::methodIndex().
395 int QQmlPropertyPrivate::signalIndex() const
397 Q_ASSERT(type() == QQmlProperty::SignalProperty);
398 QMetaMethod m = object->metaObject()->method(core.coreIndex);
399 return QMetaObjectPrivate::signalIndex(m);
403 Create a copy of \a other.
405 QQmlProperty::QQmlProperty(const QQmlProperty &other)
413 \enum QQmlProperty::PropertyTypeCategory
415 This enum specifies a category of QML property.
417 \value InvalidCategory The property is invalid, or is a signal property.
418 \value List The property is a QQmlListProperty list property
419 \value Object The property is a QObject derived type pointer
420 \value Normal The property is a normal value property.
424 \enum QQmlProperty::Type
426 This enum specifies a type of QML property.
428 \value Invalid The property is invalid.
429 \value Property The property is a regular Qt property.
430 \value SignalProperty The property is a signal property.
434 Returns the property category.
436 QQmlProperty::PropertyTypeCategory QQmlProperty::propertyTypeCategory() const
438 return d ? d->propertyTypeCategory() : InvalidCategory;
441 QQmlProperty::PropertyTypeCategory
442 QQmlPropertyPrivate::propertyTypeCategory() const
444 uint type = this->type();
447 return QQmlProperty::Normal;
448 } else if (type & QQmlProperty::Property) {
449 int type = propertyType();
450 if (type == QVariant::Invalid)
451 return QQmlProperty::InvalidCategory;
452 else if (QQmlValueTypeFactory::isValueType((uint)type))
453 return QQmlProperty::Normal;
454 else if (core.isQObject())
455 return QQmlProperty::Object;
456 else if (core.isQList())
457 return QQmlProperty::List;
459 return QQmlProperty::Normal;
462 return QQmlProperty::InvalidCategory;
466 Returns the type name of the property, or 0 if the property has no type
469 const char *QQmlProperty::propertyTypeName() const
473 if (d->isValueType()) {
474 QQmlValueType *valueType = QQmlValueTypeFactory::valueType(d->core.propType);
476 return valueType->metaObject()->property(d->core.valueTypeCoreIndex).typeName();
477 } else if (d->object && type() & Property && d->core.isValid()) {
478 return d->object->metaObject()->property(d->core.coreIndex).typeName();
485 Returns true if \a other and this QQmlProperty represent the same
488 bool QQmlProperty::operator==(const QQmlProperty &other) const
492 // category is intentially omitted here as it is generated
493 // from the other members
494 return d->object == other.d->object &&
495 d->core.coreIndex == other.d->core.coreIndex &&
496 d->core.isValueTypeVirtual() == other.d->core.isValueTypeVirtual() &&
497 (!d->core.isValueTypeVirtual() ||
498 (d->core.valueTypeCoreIndex == other.d->core.valueTypeCoreIndex &&
499 d->core.valueTypePropType == other.d->core.valueTypePropType));
503 Returns the QVariant type of the property, or QVariant::Invalid if the
504 property has no QVariant type.
506 int QQmlProperty::propertyType() const
508 return d ? d->propertyType() : int(QVariant::Invalid);
511 bool QQmlPropertyPrivate::isValueType() const
513 return core.isValueTypeVirtual();
516 int QQmlPropertyPrivate::propertyType() const
518 uint type = this->type();
520 return core.valueTypePropType;
521 } else if (type & QQmlProperty::Property) {
522 return core.propType;
524 return QVariant::Invalid;
528 QQmlProperty::Type QQmlPropertyPrivate::type() const
530 if (core.isFunction())
531 return QQmlProperty::SignalProperty;
532 else if (core.isValid())
533 return QQmlProperty::Property;
535 return QQmlProperty::Invalid;
539 Returns the type of the property.
541 QQmlProperty::Type QQmlProperty::type() const
543 return d ? d->type() : Invalid;
547 Returns true if this QQmlProperty represents a regular Qt property.
549 bool QQmlProperty::isProperty() const
551 return type() & Property;
555 Returns true if this QQmlProperty represents a QML signal property.
557 bool QQmlProperty::isSignalProperty() const
559 return type() & SignalProperty;
563 Returns the QQmlProperty's QObject.
565 QObject *QQmlProperty::object() const
567 return d ? d->object : 0;
571 Assign \a other to this QQmlProperty.
573 QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other)
585 Returns true if the property is writable, otherwise false.
587 bool QQmlProperty::isWritable() const
593 if (d->core.isQList()) //list
595 else if (d->core.isFunction()) //signal handler
597 else if (d->core.isValid()) //normal property
598 return d->core.isWritable();
604 Returns true if the property is designable, otherwise false.
606 bool QQmlProperty::isDesignable() const
610 if (type() & Property && d->core.isValid() && d->object)
611 return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
617 Returns true if the property is resettable, otherwise false.
619 bool QQmlProperty::isResettable() const
623 if (type() & Property && d->core.isValid() && d->object)
624 return d->core.isResettable();
630 Returns true if the QQmlProperty refers to a valid property, otherwise
633 bool QQmlProperty::isValid() const
637 return type() != Invalid;
641 Return the name of this QML property.
643 QString QQmlProperty::name() const
647 if (!d->isNameCached) {
650 } else if (d->isValueType()) {
651 QString rv = d->core.name(d->object) + QLatin1Char('.');
653 QQmlValueType *valueType = QQmlValueTypeFactory::valueType(d->core.propType);
656 const char *vtName = valueType->metaObject()->property(d->core.valueTypeCoreIndex).name();
657 rv += QString::fromUtf8(vtName);
660 } else if (type() & SignalProperty) {
661 QString name = QLatin1String("on") + d->core.name(d->object);
662 name[2] = name.at(2).toUpper();
665 d->nameCache = d->core.name(d->object);
667 d->isNameCached = true;
674 Returns the \l{QMetaProperty} {Qt property} associated with
677 QMetaProperty QQmlProperty::property() const
680 return QMetaProperty();
681 if (type() & Property && d->core.isValid() && d->object)
682 return d->object->metaObject()->property(d->core.coreIndex);
684 return QMetaProperty();
688 Return the QMetaMethod for this property if it is a SignalProperty,
689 otherwise returns an invalid QMetaMethod.
691 QMetaMethod QQmlProperty::method() const
694 return QMetaMethod();
695 if (type() & SignalProperty && d->object)
696 return d->object->metaObject()->method(d->core.coreIndex);
698 return QMetaMethod();
702 Returns the binding associated with this property, or 0 if no binding
705 QQmlAbstractBinding *
706 QQmlPropertyPrivate::binding(const QQmlProperty &that)
708 if (!that.d || !that.isProperty() || !that.d->object)
711 return binding(that.d->object, that.d->core.coreIndex,
712 that.d->core.getValueTypeCoreIndex());
716 Set the binding associated with this property to \a newBinding. Returns
717 the existing binding (if any), otherwise 0.
719 \a newBinding will be enabled, and the returned binding (if any) will be
722 Ownership of \a newBinding transfers to QML. Ownership of the return value
723 is assumed by the caller.
725 \a flags is passed through to the binding and is used for the initial update (when
726 the binding sets the initial value, it will use these flags for the write).
728 QQmlAbstractBinding *
729 QQmlPropertyPrivate::setBinding(const QQmlProperty &that,
730 QQmlAbstractBinding *newBinding,
733 if (!that.d || !that.isProperty() || !that.d->object) {
735 newBinding->destroy();
740 // In the case that the new binding is provided, we must target the property it
741 // is associated with. If we don't do this, retargetBinding() can fail.
742 QObject *object = newBinding->object();
743 int pi = newBinding->propertyIndex();
745 int core = pi & 0x0000FFFF;
746 int vt = (pi & 0xFFFF0000)?(pi >> 16):-1;
748 return setBinding(object, core, vt, newBinding, flags);
750 return setBinding(that.d->object, that.d->core.coreIndex,
751 that.d->core.getValueTypeCoreIndex(),
756 QQmlAbstractBinding *
757 QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
759 QQmlData *data = QQmlData::get(object);
763 QQmlPropertyData *propertyData =
764 data->propertyCache?data->propertyCache->property(coreIndex):0;
765 if (propertyData && propertyData->isAlias()) {
766 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
768 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
769 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
772 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
773 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
774 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
775 return binding(aObject, aCoreIndex, aValueTypeIndex);
778 if (!data->hasBindingBit(coreIndex))
781 QQmlAbstractBinding *binding = data->bindings;
782 while (binding && binding->propertyIndex() != coreIndex)
783 binding = binding->nextBinding();
785 if (binding && valueTypeIndex != -1) {
786 if (binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) {
787 int index = coreIndex | (valueTypeIndex << 16);
788 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
795 void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
796 QObject **targetObject, int *targetBindingIndex)
798 int coreIndex = bindingIndex & 0x0000FFFF;
799 int valueTypeIndex = (bindingIndex & 0xFFFF0000)?(bindingIndex >> 16):-1;
801 QQmlData *data = QQmlData::get(object, false);
803 QQmlPropertyData *propertyData =
804 data->propertyCache?data->propertyCache->property(coreIndex):0;
805 if (propertyData && propertyData->isAlias()) {
806 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
808 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
809 if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
810 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
811 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
813 int aBindingIndex = aCoreIndex;
814 if (aValueTypeIndex != -1)
815 aBindingIndex |= aValueTypeIndex << 16;
816 else if (valueTypeIndex != -1)
817 aBindingIndex |= valueTypeIndex << 16;
819 findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
825 *targetObject = object;
826 *targetBindingIndex = bindingIndex;
829 QQmlAbstractBinding *
830 QQmlPropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
831 QQmlAbstractBinding *newBinding, WriteFlags flags)
833 QQmlData *data = QQmlData::get(object, 0 != newBinding);
834 QQmlAbstractBinding *binding = 0;
837 QQmlPropertyData *propertyData =
838 data->propertyCache?data->propertyCache->property(coreIndex):0;
839 if (propertyData && propertyData->isAlias()) {
840 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
842 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
843 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
844 if (newBinding) newBinding->destroy();
848 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
849 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
850 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
851 return setBinding(aObject, aCoreIndex, aValueTypeIndex, newBinding, flags);
855 if (data && data->hasBindingBit(coreIndex)) {
856 binding = data->bindings;
858 while (binding && binding->propertyIndex() != coreIndex)
859 binding = binding->nextBinding();
862 int index = coreIndex;
863 if (valueTypeIndex != -1)
864 index |= (valueTypeIndex << 16);
866 if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
867 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
870 binding->removeFromObject();
871 binding->setEnabled(false, 0);
875 if (newBinding->propertyIndex() != index || newBinding->object() != object)
876 newBinding->retargetBinding(object, index);
878 Q_ASSERT(newBinding->propertyIndex() == index);
879 Q_ASSERT(newBinding->object() == object);
881 newBinding->addToObject();
882 newBinding->setEnabled(true, flags);
888 QQmlAbstractBinding *
889 QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
890 QQmlAbstractBinding *newBinding)
892 QQmlData *data = QQmlData::get(object, 0 != newBinding);
893 QQmlAbstractBinding *binding = 0;
896 QQmlPropertyData *propertyData =
897 data->propertyCache?data->propertyCache->property(coreIndex):0;
898 if (propertyData && propertyData->isAlias()) {
899 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
901 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
902 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
903 if (newBinding) newBinding->destroy();
907 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
908 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
909 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
910 return setBindingNoEnable(aObject, aCoreIndex, aValueTypeIndex, newBinding);
914 if (data && data->hasBindingBit(coreIndex)) {
915 binding = data->bindings;
917 while (binding && binding->propertyIndex() != coreIndex)
918 binding = binding->nextBinding();
921 int index = coreIndex;
922 if (valueTypeIndex != -1)
923 index |= (valueTypeIndex << 16);
925 if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
926 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
929 binding->removeFromObject();
932 if (newBinding->propertyIndex() != index || newBinding->object() != object)
933 newBinding->retargetBinding(object, index);
935 Q_ASSERT(newBinding->propertyIndex() == index);
936 Q_ASSERT(newBinding->object() == object);
938 newBinding->addToObject();
945 Activates a shared binding which was previously created but not added to the
946 object. This is needed when an optimized binding is invalidated.
948 QQmlAbstractBinding *QQmlPropertyPrivate::activateSharedBinding(QQmlContextData *context,
949 int sharedIdx, WriteFlags flags)
951 QQmlAbstractBinding *newBinding = 0;
952 newBinding = context->v8bindings->binding(sharedIdx);
957 // This binding now references the bindings object
958 context->v8bindings->addref();
960 QObject *object = newBinding->object();
961 int pi = newBinding->propertyIndex();
963 int core = pi & 0x0000FFFF;
964 int vt = (pi & 0xFFFF0000)?(pi >> 16):-1;
966 return setBinding(object, core, vt, newBinding, flags);
970 Returns the expression associated with this signal property, or 0 if no
971 signal expression exists.
973 QQmlBoundSignalExpression *
974 QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
976 if (!(that.type() & QQmlProperty::SignalProperty))
979 QQmlData *data = QQmlData::get(that.d->object);
983 QQmlAbstractBoundSignal *signalHandler = data->signalHandlers;
985 while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex())
986 signalHandler = signalHandler->m_nextSignal;
989 return signalHandler->expression();
995 Set the signal expression associated with this signal property to \a expr.
996 Returns the existing signal expression (if any), otherwise null.
998 A reference to \a expr will be added by QML. Ownership of the return value
999 reference is assumed by the caller.
1001 QQmlBoundSignalExpressionPointer
1002 QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that,
1003 QQmlBoundSignalExpression *expr)
1007 return QQmlPropertyPrivate::takeSignalExpression(that, expr);
1011 Set the signal expression associated with this signal property to \a expr.
1012 Returns the existing signal expression (if any), otherwise null.
1014 Ownership of \a expr transfers to QML. Ownership of the return value
1015 reference is assumed by the caller.
1017 QQmlBoundSignalExpressionPointer
1018 QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that,
1019 QQmlBoundSignalExpression *expr)
1021 if (!(that.type() & QQmlProperty::SignalProperty)) {
1027 QQmlData *data = QQmlData::get(that.d->object, 0 != expr);
1031 QQmlAbstractBoundSignal *signalHandler = data->signalHandlers;
1033 while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex())
1034 signalHandler = signalHandler->m_nextSignal;
1037 return signalHandler->takeExpression(expr);
1040 int signalIndex = QQmlPropertyPrivate::get(that)->signalIndex();
1041 QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, signalIndex, that.d->object,
1042 expr->context()->engine);
1043 signal->takeExpression(expr);
1049 Returns the property value.
1051 QVariant QQmlProperty::read() const
1058 if (type() & SignalProperty) {
1062 } else if (type() & Property) {
1064 return d->readValueProperty();
1071 Return the \a name property value of \a object. This method is equivalent to:
1073 QQmlProperty p(object, name);
1077 QVariant QQmlProperty::read(QObject *object, const QString &name)
1079 QQmlProperty p(object, name);
1084 Return the \a name property value of \a object using the
1085 \l{QQmlContext} {context} \a ctxt. This method is
1089 QQmlProperty p(object, name, context);
1093 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlContext *ctxt)
1095 QQmlProperty p(object, name, ctxt);
1101 Return the \a name property value of \a object using the environment
1102 for instantiating QML components that is provided by \a engine. .
1103 This method is equivalent to:
1106 QQmlProperty p(object, name, engine);
1110 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlEngine *engine)
1112 QQmlProperty p(object, name, engine);
1116 QVariant QQmlPropertyPrivate::readValueProperty()
1118 if (isValueType()) {
1120 QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType);
1121 Q_ASSERT(valueType);
1122 valueType->read(object, core.coreIndex);
1123 return valueType->metaObject()->property(core.valueTypeCoreIndex).read(valueType);
1125 } else if (core.isQList()) {
1127 QQmlListProperty<QObject> prop;
1128 void *args[] = { &prop, 0 };
1129 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1130 return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType, engine));
1132 } else if (core.isQObject()) {
1135 void *args[] = { &rv, 0 };
1136 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1137 return QVariant::fromValue(rv);
1141 if (!core.propType) // Unregistered type
1142 return object->metaObject()->property(core.coreIndex).read(object);
1146 void *args[] = { 0, &value, &status };
1147 if (core.propType == QMetaType::QVariant) {
1150 value = QVariant(core.propType, (void*)0);
1151 args[0] = value.data();
1153 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1154 if (core.propType != QMetaType::QVariant && args[0] != value.data())
1155 return QVariant((QVariant::Type)core.propType, args[0]);
1161 // helper function to allow assignment / binding to QList<QUrl> properties.
1162 static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context)
1165 if (value.userType() == qMetaTypeId<QUrl>()) {
1166 urls.append(value.toUrl());
1167 } else if (value.userType() == qMetaTypeId<QString>()) {
1168 urls.append(QUrl(value.toString()));
1169 } else if (value.userType() == qMetaTypeId<QByteArray>()) {
1170 urls.append(QUrl(QString::fromUtf8(value.toByteArray())));
1171 } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
1172 urls = value.value<QList<QUrl> >();
1173 } else if (value.userType() == qMetaTypeId<QStringList>()) {
1174 QStringList urlStrings = value.value<QStringList>();
1175 for (int i = 0; i < urlStrings.size(); ++i)
1176 urls.append(QUrl(urlStrings.at(i)));
1177 } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
1178 QList<QString> urlStrings = value.value<QList<QString> >();
1179 for (int i = 0; i < urlStrings.size(); ++i)
1180 urls.append(QUrl(urlStrings.at(i)));
1181 } // note: QList<QByteArray> is not currently supported.
1183 QList<QUrl> resolvedUrls;
1184 for (int i = 0; i < urls.size(); ++i) {
1185 QUrl u = urls.at(i);
1186 if (context && u.isRelative() && !u.isEmpty())
1187 u = context->resolvedUrl(u);
1188 resolvedUrls.append(u);
1191 return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
1194 //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1195 bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1197 if (!object || !prop.isWritable())
1201 if (prop.isEnumType()) {
1202 QMetaEnum menum = prop.enumerator();
1203 if (v.userType() == QVariant::String
1205 || v.userType() == QVariant::CString
1209 if (prop.isFlagType())
1210 v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
1212 v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
1215 } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
1216 int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
1217 if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData())
1219 v = QVariant(*reinterpret_cast<const int *>(v.constData()));
1221 v.convert(QVariant::Int);
1224 // the status variable is changed by qt_metacall to indicate what it did
1225 // this feature is currently only used by QtDBus and should not be depended
1226 // upon. Don't change it without looking into QDBusAbstractInterface first
1227 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1228 // changed: result stored directly in value, return the value of status
1230 void *argv[] = { v.data(), &v, &status, &flags };
1231 QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
1235 bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
1237 return writeValueProperty(object, core, value, effectiveContext(), flags);
1241 QQmlPropertyPrivate::writeValueProperty(QObject *object,
1242 const QQmlPropertyData &core,
1243 const QVariant &value,
1244 QQmlContextData *context, WriteFlags flags)
1246 // Remove any existing bindings on this property
1247 if (!(flags & DontRemoveBinding) && object) {
1248 QQmlAbstractBinding *binding = setBinding(object, core.coreIndex,
1249 core.getValueTypeCoreIndex(),
1251 if (binding) binding->destroy();
1255 if (core.isValueTypeVirtual()) {
1257 QQmlValueType *writeBack = QQmlValueTypeFactory::valueType(core.propType);
1258 writeBack->read(object, core.coreIndex);
1260 QQmlPropertyData data = core;
1261 data.setFlags(QQmlPropertyData::Flag(core.valueTypeFlags));
1262 data.coreIndex = core.valueTypeCoreIndex;
1263 data.propType = core.valueTypePropType;
1265 rv = write(writeBack, data, value, context, flags);
1267 writeBack->write(object, core.coreIndex, flags);
1271 rv = write(object, core, value, context, flags);
1278 bool QQmlPropertyPrivate::write(QObject *object,
1279 const QQmlPropertyData &property,
1280 const QVariant &value, QQmlContextData *context,
1283 int coreIdx = property.coreIndex;
1284 int status = -1; //for dbus
1286 if (property.isEnum()) {
1287 QMetaProperty prop = object->metaObject()->property(property.coreIndex);
1289 // Enum values come through the script engine as doubles
1290 if (value.userType() == QVariant::Double) {
1292 double fractional = modf(value.toDouble(), &integral);
1293 if (qFuzzyIsNull(fractional))
1294 v.convert(QVariant::Int);
1296 return writeEnumProperty(prop, coreIdx, object, v, flags);
1299 int propertyType = property.propType;
1300 int variantType = value.userType();
1302 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
1304 if (propertyType == QVariant::Url) {
1308 if (variantType == QVariant::Url) {
1311 } else if (variantType == QVariant::ByteArray) {
1312 QString input(QString::fromUtf8(value.toByteArray()));
1313 // Encoded dir-separators defeat QUrl processing - decode them first
1314 input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
1317 } else if (variantType == QVariant::String) {
1318 QString input(value.toString());
1319 // Encoded dir-separators defeat QUrl processing - decode them first
1320 input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
1328 if (context && u.isRelative() && !u.isEmpty())
1329 u = context->resolvedUrl(u);
1331 void *argv[] = { &u, 0, &status, &flags };
1332 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1334 } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
1335 QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
1337 void *argv[] = { &urlSeq, 0, &status, &flags };
1338 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1339 } else if (variantType == propertyType) {
1341 void *a[] = { (void *)value.constData(), 0, &status, &flags };
1342 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1344 } else if (qMetaTypeId<QVariant>() == propertyType) {
1346 void *a[] = { (void *)&value, 0, &status, &flags };
1347 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1349 } else if (property.isQObject()) {
1351 QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, value.userType());
1356 QObject *o = *(QObject **)value.constData();
1357 QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
1361 if (QQmlMetaObject::canConvert(valMo, propMo)) {
1362 void *args[] = { &o, 0, &status, &flags };
1363 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args);
1364 } else if (!o && QQmlMetaObject::canConvert(propMo, valMo)) {
1365 // In the case of a null QObject, we assign the null if there is
1366 // any change that the null variant type could be up or down cast to
1367 // the property type.
1368 void *args[] = { &o, 0, &status, &flags };
1369 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args);
1374 } else if (property.isQList()) {
1376 QQmlMetaObject listType;
1379 listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
1381 QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType));
1382 if (!type) return false;
1383 listType = type->baseMetaObject();
1385 if (listType.isNull()) return false;
1387 QQmlListProperty<void> prop;
1388 void *args[] = { &prop, 0 };
1389 QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
1391 if (!prop.clear) return false;
1395 if (value.userType() == qMetaTypeId<QQmlListReference>()) {
1396 QQmlListReference qdlr = value.value<QQmlListReference>();
1398 for (int ii = 0; ii < qdlr.count(); ++ii) {
1399 QObject *o = qdlr.at(ii);
1400 if (o && !QQmlMetaObject::canConvert(o, listType))
1402 prop.append(&prop, (void *)o);
1404 } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
1405 const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1407 for (int ii = 0; ii < list.count(); ++ii) {
1408 QObject *o = list.at(ii);
1409 if (o && !QQmlMetaObject::canConvert(o, listType))
1411 prop.append(&prop, (void *)o);
1414 QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value);
1415 if (o && !QQmlMetaObject::canConvert(o, listType))
1417 prop.append(&prop, (void *)o);
1421 Q_ASSERT(variantType != propertyType);
1425 if (variantType == QVariant::String)
1426 v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
1429 if (v.convert(propertyType)) {
1431 } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
1432 QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
1434 v = con(value.toString());
1435 if (v.userType() == propertyType)
1441 // the only other option is that they are assigning a single value
1442 // to a sequence type property (eg, an int to a QList<int> property).
1443 // Note that we've already handled single-value assignment to QList<QUrl> properties.
1444 if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
1446 list << value.toInt();
1447 v = QVariant::fromValue<QList<int> >(list);
1449 } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
1451 list << value.toReal();
1452 v = QVariant::fromValue<QList<qreal> >(list);
1454 } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
1456 list << value.toBool();
1457 v = QVariant::fromValue<QList<bool> >(list);
1459 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
1460 QList<QString> list;
1461 list << value.toString();
1462 v = QVariant::fromValue<QList<QString> >(list);
1464 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
1466 list << value.toString();
1467 v = QVariant::fromValue<QStringList>(list);
1473 void *a[] = { (void *)v.constData(), 0, &status, &flags};
1474 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1483 // Returns true if successful, false if an error description was set on expression
1484 bool QQmlPropertyPrivate::writeBinding(QObject *object,
1485 const QQmlPropertyData &core,
1486 QQmlContextData *context,
1487 QQmlJavaScriptExpression *expression,
1488 v8::Handle<v8::Value> result, bool isUndefined,
1492 Q_ASSERT(core.coreIndex != -1);
1494 QQmlEngine *engine = context->engine;
1495 QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
1497 #define QUICK_STORE(cpptype, conversion) \
1499 cpptype o = (conversion); \
1501 void *argv[] = { &o, 0, &status, &flags }; \
1502 QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \
1507 if (!isUndefined && !core.isValueTypeVirtual()) {
1508 switch (core.propType) {
1509 case QMetaType::Int:
1510 if (result->IsInt32())
1511 QUICK_STORE(int, result->Int32Value())
1512 else if (result->IsNumber())
1513 QUICK_STORE(int, qRound(result->NumberValue()))
1515 case QMetaType::Double:
1516 if (result->IsNumber())
1517 QUICK_STORE(double, result->NumberValue())
1519 case QMetaType::Float:
1520 if (result->IsNumber())
1521 QUICK_STORE(float, result->NumberValue())
1523 case QMetaType::QString:
1524 if (result->IsString())
1525 QUICK_STORE(QString, v8engine->toString(result))
1533 int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType;
1535 QQmlJavaScriptExpression::DeleteWatcher watcher(expression);
1538 bool isVarProperty = core.isVarProperty();
1541 } else if (core.isQList()) {
1542 value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
1543 } else if (result->IsNull() && core.isQObject()) {
1544 value = QVariant::fromValue((QObject *)0);
1545 } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
1546 value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
1547 } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) {
1548 value = v8engine->toVariant(result, type);
1551 if (expression->hasError()) {
1553 } else if (isVarProperty) {
1554 if (!result.IsEmpty() && result->IsFunction()
1555 && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
1556 // we explicitly disallow this case to avoid confusion. Users can still store one
1557 // in an array in a var property if they need to, but the common case is user error.
1558 expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1562 typedef QQmlVMEMetaObject VMEMO;
1563 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
1565 vmemo->setVMEProperty(core.coreIndex, result);
1566 } else if (isUndefined && core.isResettable()) {
1567 void *args[] = { 0 };
1568 QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
1569 } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
1570 writeValueProperty(object, core, QVariant(), context, flags);
1571 } else if (type == qMetaTypeId<QJSValue>()) {
1572 if (!result.IsEmpty() && result->IsFunction()
1573 && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
1574 expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1577 writeValueProperty(object, core, QVariant::fromValue(v8engine->scriptValueFromInternal(result)), context, flags);
1578 } else if (isUndefined) {
1579 QString errorStr = QLatin1String("Unable to assign [undefined] to ");
1580 if (!QMetaType::typeName(type))
1581 errorStr += QLatin1String("[unknown property type]");
1583 errorStr += QLatin1String(QMetaType::typeName(type));
1584 expression->delayedError()->setErrorDescription(errorStr);
1586 } else if (result->IsFunction()) {
1587 if (!result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty())
1588 expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1590 expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
1592 } else if (!writeValueProperty(object, core, value, context, flags)) {
1594 if (watcher.wasDeleted())
1597 const char *valueType = 0;
1598 const char *propertyType = 0;
1600 if (value.userType() == QMetaType::QObjectStar) {
1601 if (QObject *o = *(QObject **)value.constData()) {
1602 valueType = o->metaObject()->className();
1604 QQmlMetaObject propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type);
1605 if (!propertyMetaObject.isNull())
1606 propertyType = propertyMetaObject.className();
1608 } else if (value.userType() != QVariant::Invalid) {
1609 valueType = QMetaType::typeName(value.userType());
1615 propertyType = QMetaType::typeName(type);
1617 propertyType = "[unknown property type]";
1619 expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign ") +
1620 QLatin1String(valueType) +
1621 QLatin1String(" to ") +
1622 QLatin1String(propertyType));
1629 QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
1632 return engine->rawMetaObjectForType(userType);
1634 QQmlType *type = QQmlMetaType::qmlType(userType);
1635 return QQmlMetaObject(type?type->baseMetaObject():0);
1640 Sets the property value to \a value and returns true.
1641 Returns false if the property can't be set because the
1642 \a value is the wrong type, for example.
1644 bool QQmlProperty::write(const QVariant &value) const
1646 return QQmlPropertyPrivate::write(*this, value, 0);
1650 Writes \a value to the \a name property of \a object. This method
1654 QQmlProperty p(object, name);
1658 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
1660 QQmlProperty p(object, name);
1661 return p.write(value);
1665 Writes \a value to the \a name property of \a object using the
1666 \l{QQmlContext} {context} \a ctxt. This method is
1670 QQmlProperty p(object, name, ctxt);
1674 bool QQmlProperty::write(QObject *object,
1675 const QString &name,
1676 const QVariant &value,
1679 QQmlProperty p(object, name, ctxt);
1680 return p.write(value);
1685 Writes \a value to the \a name property of \a object using the
1686 environment for instantiating QML components that is provided by
1687 \a engine. This method is equivalent to:
1690 QQmlProperty p(object, name, engine);
1694 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
1697 QQmlProperty p(object, name, engine);
1698 return p.write(value);
1702 Resets the property and returns true if the property is
1703 resettable. If the property is not resettable, nothing happens
1704 and false is returned.
1706 bool QQmlProperty::reset() const
1708 if (isResettable()) {
1709 void *args[] = { 0 };
1710 QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1717 bool QQmlPropertyPrivate::write(const QQmlProperty &that,
1718 const QVariant &value, WriteFlags flags)
1722 if (that.d->object && that.type() & QQmlProperty::Property &&
1723 that.d->core.isValid() && that.isWritable())
1724 return that.d->writeValueProperty(value, flags);
1730 Returns true if the property has a change notifier signal, otherwise false.
1732 bool QQmlProperty::hasNotifySignal() const
1734 if (type() & Property && d->object) {
1735 return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1741 Returns true if the property needs a change notifier signal for bindings
1742 to remain upto date, false otherwise.
1744 Some properties, such as attached properties or those whose value never
1745 changes, do not require a change notifier.
1747 bool QQmlProperty::needsNotifySignal() const
1749 return type() & Property && !property().isConstant();
1753 Connects the property's change notifier signal to the
1754 specified \a method of the \a dest object and returns
1755 true. Returns false if this metaproperty does not
1756 represent a regular Qt property or if it has no
1757 change notifier signal, or if the \a dest object does
1758 not have the specified \a method.
1760 bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
1762 if (!(type() & Property) || !d->object)
1765 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1766 if (prop.hasNotifySignal()) {
1767 return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1774 Connects the property's change notifier signal to the
1775 specified \a slot of the \a dest object and returns
1776 true. Returns false if this metaproperty does not
1777 represent a regular Qt property or if it has no
1778 change notifier signal, or if the \a dest object does
1779 not have the specified \a slot.
1781 bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
1783 if (!(type() & Property) || !d->object)
1786 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1787 if (prop.hasNotifySignal()) {
1788 QByteArray signal('2' + prop.notifySignal().methodSignature());
1789 return QObject::connect(d->object, signal.constData(), dest, slot);
1796 Return the Qt metaobject index of the property.
1798 int QQmlProperty::index() const
1800 return d ? d->core.coreIndex : -1;
1803 int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that)
1805 return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
1809 Returns the "property index" for use in bindings. The top 16 bits are the value type
1810 offset, and 0 otherwise. The bottom 16 bits are the regular property index.
1812 int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that)
1816 return bindingIndex(that.d->core);
1819 int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that)
1821 int rv = that.coreIndex;
1822 if (rv != -1 && that.isValueTypeVirtual())
1823 rv = rv | (that.valueTypeCoreIndex << 16);
1828 QQmlPropertyPrivate::saveValueType(const QQmlPropertyData &base,
1829 const QMetaObject *subObject, int subIndex,
1832 QMetaProperty subProp = subObject->property(subIndex);
1834 QQmlPropertyData core = base;
1835 core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
1836 core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp);
1837 core.valueTypeCoreIndex = subIndex;
1838 core.valueTypePropType = subProp.userType();
1844 QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
1845 QQmlContextData *ctxt)
1849 prop.d = new QQmlPropertyPrivate;
1850 prop.d->object = object;
1851 prop.d->context = ctxt;
1852 prop.d->engine = ctxt?ctxt->engine:0;
1854 prop.d->core = data;
1860 Return the signal corresponding to \a name
1862 QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1865 int methods = mo->methodCount();
1866 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1867 QMetaMethod method = mo->method(ii);
1869 if (method.name() == name && (method.methodType() & QMetaMethod::Signal))
1873 // If no signal is found, but the signal is of the form "onBlahChanged",
1874 // return the notify signal for the property "Blah"
1875 if (name.endsWith("Changed")) {
1876 QByteArray propName = name.mid(0, name.length() - 7);
1877 int propIdx = mo->indexOfProperty(propName.constData());
1879 QMetaProperty prop = mo->property(propIdx);
1880 if (prop.hasNotifySignal())
1881 return prop.notifySignal();
1885 return QMetaMethod();
1889 If \a indexInSignalRange is true, \a index is treated as a signal index
1890 (see QObjectPrivate::signalIndex()), otherwise it is treated as a
1891 method index (QMetaMethod::methodIndex()).
1893 static inline void flush_vme_signal(const QObject *object, int index, bool indexInSignalRange)
1895 QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1896 if (data && data->propertyCache) {
1897 QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
1898 : data->propertyCache->method(index);
1900 if (property && property->isVMESignal()) {
1901 QQmlVMEMetaObject *vme;
1902 if (indexInSignalRange)
1903 vme = QQmlVMEMetaObject::getForSignal(const_cast<QObject *>(object), index);
1905 vme = QQmlVMEMetaObject::getForMethod(const_cast<QObject *>(object), index);
1906 vme->connectAliasSignal(index, indexInSignalRange);
1912 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1913 \a type and \a types. This behaves identically to QMetaObject::connect() except that
1914 it connects any lazy "proxy" signal connections set up by QML.
1916 It is possible that this logic should be moved to QMetaObject::connect().
1918 bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
1919 const QObject *receiver, int method_index,
1920 int type, int *types)
1922 static const bool indexInSignalRange = false;
1923 flush_vme_signal(sender, signal_index, indexInSignalRange);
1924 flush_vme_signal(receiver, method_index, indexInSignalRange);
1926 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1930 \a signal_index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
1931 This is different from QMetaMethod::methodIndex().
1933 void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
1935 static const bool indexInSignalRange = true;
1936 flush_vme_signal(sender, signal_index, indexInSignalRange);