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 <private/qmetaobject_p.h>
62 #include <QtCore/qdebug.h>
66 Q_DECLARE_METATYPE(QJSValue)
67 Q_DECLARE_METATYPE(QList<int>)
68 Q_DECLARE_METATYPE(QList<qreal>)
69 Q_DECLARE_METATYPE(QList<bool>)
70 Q_DECLARE_METATYPE(QList<QString>)
71 Q_DECLARE_METATYPE(QList<QUrl>)
79 \brief The QQmlProperty class abstracts accessing properties on objects created from QML.
81 As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect
82 and interact with objects created by QML. However, some of the new features provided by QML - such
83 as type safety and attached properties - are most easily used through the QQmlProperty class
84 that simplifies some of their natural complexity.
86 Unlike QMetaProperty which represents a property on a class type, QQmlProperty encapsulates
87 a property on a specific object instance. To read a property's value, programmers create a
88 QQmlProperty instance and call the read() method. Likewise to write a property value the
89 write() method is used.
91 For example, for the following QML code:
97 Text { text: "A bit of text" }
100 The \l Text object's properties could be accessed using QQmlProperty, like this:
103 #include <QQmlProperty>
104 #include <QGraphicsObject>
108 QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
109 QQmlProperty property(view.rootObject(), "font.pixelSize");
110 qWarning() << "Current pixel size:" << property.read().toInt();
112 qWarning() << "Pixel size should now be 24:" << property.read().toInt();
115 The QtQuick 1 version of this class was named QDeclarativeProperty.
119 Create an invalid QQmlProperty.
121 QQmlProperty::QQmlProperty()
127 QQmlProperty::~QQmlProperty()
135 Creates a QQmlProperty for the default property of \a obj. If there is no
136 default property, an invalid QQmlProperty will be created.
138 QQmlProperty::QQmlProperty(QObject *obj)
139 : d(new QQmlPropertyPrivate)
145 Creates a QQmlProperty for the default property of \a obj
146 using the \l{QQmlContext} {context} \a ctxt. If there is
147 no default property, an invalid QQmlProperty will be
150 QQmlProperty::QQmlProperty(QObject *obj, QQmlContext *ctxt)
151 : d(new QQmlPropertyPrivate)
153 d->context = ctxt?QQmlContextData::get(ctxt):0;
154 d->engine = ctxt?ctxt->engine():0;
159 Creates a QQmlProperty for the default property of \a obj
160 using the environment for instantiating QML components that is
161 provided by \a engine. If there is no default property, an
162 invalid QQmlProperty will be created.
164 QQmlProperty::QQmlProperty(QObject *obj, QQmlEngine *engine)
165 : d(new QQmlPropertyPrivate)
173 Initialize from the default property of \a obj
175 void QQmlPropertyPrivate::initDefault(QObject *obj)
180 QMetaProperty p = QQmlMetaType::defaultProperty(obj);
187 Creates a QQmlProperty for the property \a name of \a obj.
189 QQmlProperty::QQmlProperty(QObject *obj, const QString &name)
190 : d(new QQmlPropertyPrivate)
192 d->initProperty(obj, name);
193 if (!isValid()) d->object = 0;
197 Creates a QQmlProperty for the property \a name of \a obj
198 using the \l{QQmlContext} {context} \a ctxt.
200 Creating a QQmlProperty without a context will render some
201 properties - like attached properties - inaccessible.
203 QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlContext *ctxt)
204 : d(new QQmlPropertyPrivate)
206 d->context = ctxt?QQmlContextData::get(ctxt):0;
207 d->engine = ctxt?ctxt->engine():0;
208 d->initProperty(obj, name);
209 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
213 Creates a QQmlProperty for the property \a name of \a obj
214 using the environment for instantiating QML components that is
215 provided by \a engine.
217 QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlEngine *engine)
218 : d(new QQmlPropertyPrivate)
222 d->initProperty(obj, name);
223 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
226 Q_GLOBAL_STATIC(QQmlValueTypeFactory, qmlValueTypes);
228 QQmlPropertyPrivate::QQmlPropertyPrivate()
229 : context(0), engine(0), object(0), isNameCached(false)
233 QQmlContextData *QQmlPropertyPrivate::effectiveContext() const
235 if (context) return context;
236 else if (engine) return QQmlContextData::get(engine->rootContext());
240 void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
244 QQmlTypeNameCache *typeNameCache = context?context->imports:0;
246 QStringList path = name.split(QLatin1Char('.'));
247 if (path.isEmpty()) return;
249 QObject *currentObject = obj;
251 // Everything up to the last property must be an "object type" property
252 for (int ii = 0; ii < path.count() - 1; ++ii) {
253 const QString &pathName = path.at(ii);
256 QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
259 QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
260 if (!func) return; // Not an attachable type
262 currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
263 if (!currentObject) return; // Something is broken with the attachable type
264 } else if (r.importNamespace) {
265 if ((ii + 1) == path.count()) return; // No type following the namespace
267 ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
268 if (!r.type) return; // Invalid type in namespace
270 QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
271 if (!func) return; // Not an attachable type
273 currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
274 if (!currentObject) return; // Something is broken with the attachable type
276 } else if (r.scriptIndex != -1) {
277 return; // Not a type
279 Q_ASSERT(!"Unreachable");
286 QQmlPropertyData local;
287 QQmlPropertyData *property =
288 QQmlPropertyCache::property(engine, obj, pathName, local);
290 if (!property) return; // Not a property
291 if (property->isFunction())
292 return; // Not an object property
294 if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType)) {
295 // We're now at a value type property. We can use a global valuetypes array as we
296 // never actually use the objects, just look up their properties.
297 QObject *typeObject = (*qmlValueTypes())[property->propType];
298 if (!typeObject) return; // Not a value type
300 int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
301 if (idx == -1) return; // Value type property does not exist
303 QMetaProperty vtProp = typeObject->metaObject()->property(idx);
305 typedef QQmlPropertyData PCD;
307 Q_ASSERT(PCD::flagsForProperty(vtProp) <= PCD::ValueTypeFlagMask);
308 Q_ASSERT(vtProp.userType() <= 0xFF);
309 Q_ASSERT(idx <= 0xFF);
311 object = currentObject;
313 core.setFlags(core.getFlags() | PCD::IsValueTypeVirtual);
314 core.valueTypeFlags = PCD::flagsForProperty(vtProp);
315 core.valueTypePropType = vtProp.userType();
316 core.valueTypeCoreIndex = idx;
320 if (!property->isQObject())
321 return; // Not an object property
323 void *args[] = { ¤tObject, 0 };
324 QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
325 if (!currentObject) return; // No value
331 const QString &terminal = path.last();
333 if (terminal.count() >= 3 &&
334 terminal.at(0) == QLatin1Char('o') &&
335 terminal.at(1) == QLatin1Char('n') &&
336 terminal.at(2).isUpper()) {
338 QString signalName = terminal.mid(2);
339 signalName[0] = signalName.at(0).toLower();
341 // XXX - this code treats methods as signals
343 QQmlData *ddata = QQmlData::get(currentObject, false);
344 if (ddata && ddata->propertyCache) {
347 QQmlPropertyData *d = ddata->propertyCache->property(signalName);
348 while (d && !d->isFunction())
349 d = ddata->propertyCache->overrideData(d);
352 object = currentObject;
358 if (signalName.endsWith(QLatin1String("Changed"))) {
359 QString propName = signalName.mid(0, signalName.length() - 7);
360 QQmlPropertyData *d = ddata->propertyCache->property(propName);
361 while (d && d->isFunction())
362 d = ddata->propertyCache->overrideData(d);
364 if (d && d->notifyIndex != -1) {
365 object = currentObject;
366 core = *ddata->propertyCache->signal(d->notifyIndex);
372 QMetaMethod method = findSignalByName(currentObject->metaObject(),
373 signalName.toLatin1());
374 if (method.isValid()) {
375 object = currentObject;
383 QQmlPropertyData local;
384 QQmlPropertyData *property =
385 QQmlPropertyCache::property(engine, currentObject, terminal, local);
386 if (property && !property->isFunction()) {
387 object = currentObject;
389 nameCache = terminal;
395 Returns the index of this property's signal, in the signal index range
396 (see QObjectPrivate::signalIndex()). This is different from
397 QMetaMethod::methodIndex().
399 int QQmlPropertyPrivate::signalIndex() const
401 Q_ASSERT(type() == QQmlProperty::SignalProperty);
402 QMetaMethod m = object->metaObject()->method(core.coreIndex);
403 return QMetaObjectPrivate::signalIndex(m);
407 Create a copy of \a other.
409 QQmlProperty::QQmlProperty(const QQmlProperty &other)
417 \enum QQmlProperty::PropertyTypeCategory
419 This enum specifies a category of QML property.
421 \value InvalidCategory The property is invalid, or is a signal property.
422 \value List The property is a QQmlListProperty list property
423 \value Object The property is a QObject derived type pointer
424 \value Normal The property is a normal value property.
428 \enum QQmlProperty::Type
430 This enum specifies a type of QML property.
432 \value Invalid The property is invalid.
433 \value Property The property is a regular Qt property.
434 \value SignalProperty The property is a signal property.
438 Returns the property category.
440 QQmlProperty::PropertyTypeCategory QQmlProperty::propertyTypeCategory() const
442 return d ? d->propertyTypeCategory() : InvalidCategory;
445 QQmlProperty::PropertyTypeCategory
446 QQmlPropertyPrivate::propertyTypeCategory() const
448 uint type = this->type();
451 return QQmlProperty::Normal;
452 } else if (type & QQmlProperty::Property) {
453 int type = propertyType();
454 if (type == QVariant::Invalid)
455 return QQmlProperty::InvalidCategory;
456 else if (QQmlValueTypeFactory::isValueType((uint)type))
457 return QQmlProperty::Normal;
458 else if (core.isQObject())
459 return QQmlProperty::Object;
460 else if (core.isQList())
461 return QQmlProperty::List;
463 return QQmlProperty::Normal;
465 return QQmlProperty::InvalidCategory;
470 Returns the type name of the property, or 0 if the property has no type
473 const char *QQmlProperty::propertyTypeName() const
477 if (d->isValueType()) {
479 QQmlEnginePrivate *ep = d->engine?QQmlEnginePrivate::get(d->engine):0;
480 QQmlValueType *valueType = 0;
481 if (ep) valueType = ep->valueTypes[d->core.propType];
482 else valueType = QQmlValueTypeFactory::valueType(d->core.propType);
485 const char *rv = valueType->metaObject()->property(d->core.valueTypeCoreIndex).typeName();
487 if (!ep) delete valueType;
490 } else if (d->object && type() & Property && d->core.isValid()) {
491 return d->object->metaObject()->property(d->core.coreIndex).typeName();
498 Returns true if \a other and this QQmlProperty represent the same
501 bool QQmlProperty::operator==(const QQmlProperty &other) const
505 // category is intentially omitted here as it is generated
506 // from the other members
507 return d->object == other.d->object &&
508 d->core.coreIndex == other.d->core.coreIndex &&
509 d->core.isValueTypeVirtual() == other.d->core.isValueTypeVirtual() &&
510 (!d->core.isValueTypeVirtual() ||
511 (d->core.valueTypeCoreIndex == other.d->core.valueTypeCoreIndex &&
512 d->core.valueTypePropType == other.d->core.valueTypePropType));
516 Returns the QVariant type of the property, or QVariant::Invalid if the
517 property has no QVariant type.
519 int QQmlProperty::propertyType() const
521 return d ? d->propertyType() : int(QVariant::Invalid);
524 bool QQmlPropertyPrivate::isValueType() const
526 return core.isValueTypeVirtual();
529 int QQmlPropertyPrivate::propertyType() const
531 uint type = this->type();
533 return core.valueTypePropType;
534 } else if (type & QQmlProperty::Property) {
535 return core.propType;
537 return QVariant::Invalid;
541 QQmlProperty::Type QQmlPropertyPrivate::type() const
543 if (core.isFunction())
544 return QQmlProperty::SignalProperty;
545 else if (core.isValid())
546 return QQmlProperty::Property;
548 return QQmlProperty::Invalid;
552 Returns the type of the property.
554 QQmlProperty::Type QQmlProperty::type() const
556 return d ? d->type() : Invalid;
560 Returns true if this QQmlProperty represents a regular Qt property.
562 bool QQmlProperty::isProperty() const
564 return type() & Property;
568 Returns true if this QQmlProperty represents a QML signal property.
570 bool QQmlProperty::isSignalProperty() const
572 return type() & SignalProperty;
576 Returns the QQmlProperty's QObject.
578 QObject *QQmlProperty::object() const
580 return d ? d->object : 0;
584 Assign \a other to this QQmlProperty.
586 QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other)
598 Returns true if the property is writable, otherwise false.
600 bool QQmlProperty::isWritable() const
606 if (d->core.isQList()) //list
608 else if (d->core.isFunction()) //signal handler
610 else if (d->core.isValid()) //normal property
611 return d->core.isWritable();
617 Returns true if the property is designable, otherwise false.
619 bool QQmlProperty::isDesignable() const
623 if (type() & Property && d->core.isValid() && d->object)
624 return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
630 Returns true if the property is resettable, otherwise false.
632 bool QQmlProperty::isResettable() const
636 if (type() & Property && d->core.isValid() && d->object)
637 return d->core.isResettable();
643 Returns true if the QQmlProperty refers to a valid property, otherwise
646 bool QQmlProperty::isValid() const
650 return type() != Invalid;
654 Return the name of this QML property.
656 QString QQmlProperty::name() const
660 if (!d->isNameCached) {
663 } else if (d->isValueType()) {
664 QString rv = d->core.name(d->object) + QLatin1Char('.');
666 QQmlEnginePrivate *ep = d->engine?QQmlEnginePrivate::get(d->engine):0;
667 QQmlValueType *valueType = 0;
668 if (ep) valueType = ep->valueTypes[d->core.propType];
669 else valueType = QQmlValueTypeFactory::valueType(d->core.propType);
672 const char *vtName = valueType->metaObject()->property(d->core.valueTypeCoreIndex).name();
673 rv += QString::fromUtf8(vtName);
675 if (!ep) delete valueType;
678 } else if (type() & SignalProperty) {
679 QString name = QLatin1String("on") + d->core.name(d->object);
680 name[2] = name.at(2).toUpper();
683 d->nameCache = d->core.name(d->object);
685 d->isNameCached = true;
692 Returns the \l{QMetaProperty} {Qt property} associated with
695 QMetaProperty QQmlProperty::property() const
698 return QMetaProperty();
699 if (type() & Property && d->core.isValid() && d->object)
700 return d->object->metaObject()->property(d->core.coreIndex);
702 return QMetaProperty();
706 Return the QMetaMethod for this property if it is a SignalProperty,
707 otherwise returns an invalid QMetaMethod.
709 QMetaMethod QQmlProperty::method() const
712 return QMetaMethod();
713 if (type() & SignalProperty && d->object)
714 return d->object->metaObject()->method(d->core.coreIndex);
716 return QMetaMethod();
720 Returns the binding associated with this property, or 0 if no binding
723 QQmlAbstractBinding *
724 QQmlPropertyPrivate::binding(const QQmlProperty &that)
726 if (!that.d || !that.isProperty() || !that.d->object)
729 return binding(that.d->object, that.d->core.coreIndex,
730 that.d->core.getValueTypeCoreIndex());
734 Set the binding associated with this property to \a newBinding. Returns
735 the existing binding (if any), otherwise 0.
737 \a newBinding will be enabled, and the returned binding (if any) will be
740 Ownership of \a newBinding transfers to QML. Ownership of the return value
741 is assumed by the caller.
743 \a flags is passed through to the binding and is used for the initial update (when
744 the binding sets the initial value, it will use these flags for the write).
746 QQmlAbstractBinding *
747 QQmlPropertyPrivate::setBinding(const QQmlProperty &that,
748 QQmlAbstractBinding *newBinding,
751 if (!that.d || !that.isProperty() || !that.d->object) {
753 newBinding->destroy();
758 // In the case that the new binding is provided, we must target the property it
759 // is associated with. If we don't do this, retargetBinding() can fail.
760 QObject *object = newBinding->object();
761 int pi = newBinding->propertyIndex();
763 int core = pi & 0xFFFFFF;
764 int vt = (pi & 0xFF000000)?(pi >> 24):-1;
766 return setBinding(object, core, vt, newBinding, flags);
768 return setBinding(that.d->object, that.d->core.coreIndex,
769 that.d->core.getValueTypeCoreIndex(),
774 QQmlAbstractBinding *
775 QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
777 QQmlData *data = QQmlData::get(object);
781 QQmlPropertyData *propertyData =
782 data->propertyCache?data->propertyCache->property(coreIndex):0;
783 if (propertyData && propertyData->isAlias()) {
784 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
786 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
787 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
790 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
791 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
792 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
793 return binding(aObject, aCoreIndex, aValueTypeIndex);
796 if (!data->hasBindingBit(coreIndex))
799 QQmlAbstractBinding *binding = data->bindings;
800 while (binding && binding->propertyIndex() != coreIndex)
801 binding = binding->nextBinding();
803 if (binding && valueTypeIndex != -1) {
804 if (binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) {
805 int index = coreIndex | (valueTypeIndex << 24);
806 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
813 void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
814 QObject **targetObject, int *targetBindingIndex)
816 int coreIndex = bindingIndex & 0xFFFFFF;
817 int valueTypeIndex = bindingIndex >> 24;
818 if (valueTypeIndex == 0) valueTypeIndex = -1;
820 QQmlData *data = QQmlData::get(object, false);
822 QQmlPropertyData *propertyData =
823 data->propertyCache?data->propertyCache->property(coreIndex):0;
824 if (propertyData && propertyData->isAlias()) {
825 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
827 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
828 if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
829 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
830 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
832 int aBindingIndex = aCoreIndex;
833 if (aValueTypeIndex != -1)
834 aBindingIndex |= aValueTypeIndex << 24;
835 else if (valueTypeIndex != -1)
836 aBindingIndex |= valueTypeIndex << 24;
838 findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
844 *targetObject = object;
845 *targetBindingIndex = bindingIndex;
848 QQmlAbstractBinding *
849 QQmlPropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
850 QQmlAbstractBinding *newBinding, WriteFlags flags)
852 QQmlData *data = QQmlData::get(object, 0 != newBinding);
853 QQmlAbstractBinding *binding = 0;
856 QQmlPropertyData *propertyData =
857 data->propertyCache?data->propertyCache->property(coreIndex):0;
858 if (propertyData && propertyData->isAlias()) {
859 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
861 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
862 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
863 if (newBinding) newBinding->destroy();
867 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
868 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
869 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
870 return setBinding(aObject, aCoreIndex, aValueTypeIndex, newBinding, flags);
874 if (data && data->hasBindingBit(coreIndex)) {
875 binding = data->bindings;
877 while (binding && binding->propertyIndex() != coreIndex)
878 binding = binding->nextBinding();
881 int index = coreIndex;
882 if (valueTypeIndex != -1)
883 index |= (valueTypeIndex << 24);
885 if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
886 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
889 binding->removeFromObject();
890 binding->setEnabled(false, 0);
894 if (newBinding->propertyIndex() != index || newBinding->object() != object)
895 newBinding->retargetBinding(object, index);
897 Q_ASSERT(newBinding->propertyIndex() == index);
898 Q_ASSERT(newBinding->object() == object);
900 newBinding->addToObject();
901 newBinding->setEnabled(true, flags);
907 QQmlAbstractBinding *
908 QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
909 QQmlAbstractBinding *newBinding)
911 QQmlData *data = QQmlData::get(object, 0 != newBinding);
912 QQmlAbstractBinding *binding = 0;
915 QQmlPropertyData *propertyData =
916 data->propertyCache?data->propertyCache->property(coreIndex):0;
917 if (propertyData && propertyData->isAlias()) {
918 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
920 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
921 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
922 if (newBinding) newBinding->destroy();
926 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
927 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
928 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
929 return setBindingNoEnable(aObject, aCoreIndex, aValueTypeIndex, newBinding);
933 if (data && data->hasBindingBit(coreIndex)) {
934 binding = data->bindings;
936 while (binding && binding->propertyIndex() != coreIndex)
937 binding = binding->nextBinding();
940 int index = coreIndex;
941 if (valueTypeIndex != -1)
942 index |= (valueTypeIndex << 24);
944 if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
945 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
948 binding->removeFromObject();
951 if (newBinding->propertyIndex() != index || newBinding->object() != object)
952 newBinding->retargetBinding(object, index);
954 Q_ASSERT(newBinding->propertyIndex() == index);
955 Q_ASSERT(newBinding->object() == object);
957 newBinding->addToObject();
964 Returns the expression associated with this signal property, or 0 if no
965 signal expression exists.
967 QQmlBoundSignalExpression *
968 QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
970 if (!(that.type() & QQmlProperty::SignalProperty))
973 QQmlData *data = QQmlData::get(that.d->object);
977 QQmlAbstractBoundSignal *signalHandler = data->signalHandlers;
979 while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex())
980 signalHandler = signalHandler->m_nextSignal;
983 return signalHandler->expression();
989 Set the signal expression associated with this signal property to \a expr.
990 Returns the existing signal expression (if any), otherwise null.
992 A reference to \a expr will be added by QML. Ownership of the return value
993 reference is assumed by the caller.
995 QQmlBoundSignalExpressionPointer
996 QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that,
997 QQmlBoundSignalExpression *expr)
1001 return QQmlPropertyPrivate::takeSignalExpression(that, expr);
1005 Set the signal expression associated with this signal property to \a expr.
1006 Returns the existing signal expression (if any), otherwise null.
1008 Ownership of \a expr transfers to QML. Ownership of the return value
1009 reference is assumed by the caller.
1011 QQmlBoundSignalExpressionPointer
1012 QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that,
1013 QQmlBoundSignalExpression *expr)
1015 if (!(that.type() & QQmlProperty::SignalProperty)) {
1021 QQmlData *data = QQmlData::get(that.d->object, 0 != expr);
1025 QQmlAbstractBoundSignal *signalHandler = data->signalHandlers;
1027 while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex())
1028 signalHandler = signalHandler->m_nextSignal;
1031 return signalHandler->takeExpression(expr);
1034 int signalIndex = QQmlPropertyPrivate::get(that)->signalIndex();
1035 QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, signalIndex, that.d->object,
1036 expr->context()->engine);
1037 signal->takeExpression(expr);
1043 Returns the property value.
1045 QVariant QQmlProperty::read() const
1052 if (type() & SignalProperty) {
1056 } else if (type() & Property) {
1058 return d->readValueProperty();
1065 Return the \a name property value of \a object. This method is equivalent to:
1067 QQmlProperty p(object, name);
1071 QVariant QQmlProperty::read(QObject *object, const QString &name)
1073 QQmlProperty p(object, name);
1078 Return the \a name property value of \a object using the
1079 \l{QQmlContext} {context} \a ctxt. This method is
1083 QQmlProperty p(object, name, context);
1087 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlContext *ctxt)
1089 QQmlProperty p(object, name, ctxt);
1095 Return the \a name property value of \a object using the environment
1096 for instantiating QML components that is provided by \a engine. .
1097 This method is equivalent to:
1100 QQmlProperty p(object, name, engine);
1104 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlEngine *engine)
1106 QQmlProperty p(object, name, engine);
1110 QVariant QQmlPropertyPrivate::readValueProperty()
1112 if (isValueType()) {
1114 QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
1115 QQmlValueType *valueType = 0;
1116 if (ep) valueType = ep->valueTypes[core.propType];
1117 else valueType = QQmlValueTypeFactory::valueType(core.propType);
1118 Q_ASSERT(valueType);
1120 valueType->read(object, core.coreIndex);
1122 QVariant rv = valueType->metaObject()->property(core.valueTypeCoreIndex).read(valueType);
1124 if (!ep) delete valueType;
1127 } else if (core.isQList()) {
1129 QQmlListProperty<QObject> prop;
1130 void *args[] = { &prop, 0 };
1131 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1132 return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType, engine));
1134 } else if (core.isQObject()) {
1137 void *args[] = { &rv, 0 };
1138 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1139 return QVariant::fromValue(rv);
1143 if (!core.propType) // Unregistered type
1144 return object->metaObject()->property(core.coreIndex).read(object);
1148 void *args[] = { 0, &value, &status };
1149 if (core.propType == QMetaType::QVariant) {
1152 value = QVariant(core.propType, (void*)0);
1153 args[0] = value.data();
1155 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1156 if (core.propType != QMetaType::QVariant && args[0] != value.data())
1157 return QVariant((QVariant::Type)core.propType, args[0]);
1163 // helper function to allow assignment / binding to QList<QUrl> properties.
1164 static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context)
1167 if (value.userType() == qMetaTypeId<QUrl>()) {
1168 urls.append(value.toUrl());
1169 } else if (value.userType() == qMetaTypeId<QString>()) {
1170 urls.append(QUrl(value.toString()));
1171 } else if (value.userType() == qMetaTypeId<QByteArray>()) {
1172 urls.append(QUrl(QString::fromUtf8(value.toByteArray())));
1173 } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
1174 urls = value.value<QList<QUrl> >();
1175 } else if (value.userType() == qMetaTypeId<QStringList>()) {
1176 QStringList urlStrings = value.value<QStringList>();
1177 for (int i = 0; i < urlStrings.size(); ++i)
1178 urls.append(QUrl(urlStrings.at(i)));
1179 } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
1180 QList<QString> urlStrings = value.value<QList<QString> >();
1181 for (int i = 0; i < urlStrings.size(); ++i)
1182 urls.append(QUrl(urlStrings.at(i)));
1183 } // note: QList<QByteArray> is not currently supported.
1185 QList<QUrl> resolvedUrls;
1186 for (int i = 0; i < urls.size(); ++i) {
1187 QUrl u = urls.at(i);
1188 if (context && u.isRelative() && !u.isEmpty())
1189 u = context->resolvedUrl(u);
1190 resolvedUrls.append(u);
1193 return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
1196 //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1197 bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1199 if (!object || !prop.isWritable())
1203 if (prop.isEnumType()) {
1204 QMetaEnum menum = prop.enumerator();
1205 if (v.userType() == QVariant::String
1207 || v.userType() == QVariant::CString
1211 if (prop.isFlagType())
1212 v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
1214 v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
1217 } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
1218 int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
1219 if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData())
1221 v = QVariant(*reinterpret_cast<const int *>(v.constData()));
1223 v.convert(QVariant::Int);
1226 // the status variable is changed by qt_metacall to indicate what it did
1227 // this feature is currently only used by QtDBus and should not be depended
1228 // upon. Don't change it without looking into QDBusAbstractInterface first
1229 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1230 // changed: result stored directly in value, return the value of status
1232 void *argv[] = { v.data(), &v, &status, &flags };
1233 QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
1237 bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
1239 return writeValueProperty(object, engine, core, value, effectiveContext(), flags);
1243 QQmlPropertyPrivate::writeValueProperty(QObject *object, QQmlEngine *engine,
1244 const QQmlPropertyData &core,
1245 const QVariant &value,
1246 QQmlContextData *context, WriteFlags flags)
1248 // Remove any existing bindings on this property
1249 if (!(flags & DontRemoveBinding) && object) {
1250 QQmlAbstractBinding *binding = setBinding(object, core.coreIndex,
1251 core.getValueTypeCoreIndex(),
1253 if (binding) binding->destroy();
1257 if (core.isValueTypeVirtual()) {
1258 QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
1260 QQmlValueType *writeBack = 0;
1262 writeBack = ep->valueTypes[core.propType];
1264 writeBack = QQmlValueTypeFactory::valueType(core.propType);
1267 writeBack->read(object, core.coreIndex);
1269 QQmlPropertyData data = core;
1270 data.setFlags(QQmlPropertyData::Flag(core.valueTypeFlags));
1271 data.coreIndex = core.valueTypeCoreIndex;
1272 data.propType = core.valueTypePropType;
1274 rv = write(writeBack, data, value, context, flags);
1276 writeBack->write(object, core.coreIndex, flags);
1277 if (!ep) delete writeBack;
1281 rv = write(object, core, value, context, flags);
1288 bool QQmlPropertyPrivate::write(QObject *object,
1289 const QQmlPropertyData &property,
1290 const QVariant &value, QQmlContextData *context,
1293 int coreIdx = property.coreIndex;
1294 int status = -1; //for dbus
1296 if (property.isEnum()) {
1297 QMetaProperty prop = object->metaObject()->property(property.coreIndex);
1299 // Enum values come through the script engine as doubles
1300 if (value.userType() == QVariant::Double) {
1302 double fractional = modf(value.toDouble(), &integral);
1303 if (qFuzzyIsNull(fractional))
1304 v.convert(QVariant::Int);
1306 return writeEnumProperty(prop, coreIdx, object, v, flags);
1309 int propertyType = property.propType;
1310 int variantType = value.userType();
1312 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
1314 if (propertyType == QVariant::Url) {
1318 if (variantType == QVariant::Url) {
1321 } else if (variantType == QVariant::ByteArray) {
1322 u = QUrl(QString::fromUtf8(value.toByteArray()));
1324 } else if (variantType == QVariant::String) {
1325 u = QUrl(value.toString());
1332 if (context && u.isRelative() && !u.isEmpty())
1333 u = context->resolvedUrl(u);
1335 void *argv[] = { &u, 0, &status, &flags };
1336 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1338 } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
1339 QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
1341 void *argv[] = { &urlSeq, 0, &status, &flags };
1342 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1343 } else if (variantType == propertyType) {
1345 void *a[] = { (void *)value.constData(), 0, &status, &flags };
1346 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1348 } else if (qMetaTypeId<QVariant>() == propertyType) {
1350 void *a[] = { (void *)&value, 0, &status, &flags };
1351 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1353 } else if (property.isQObject()) {
1355 QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, value.userType());
1360 QObject *o = *(QObject **)value.constData();
1361 QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
1365 if (QQmlMetaObject::canConvert(valMo, propMo)) {
1366 void *args[] = { &o, 0, &status, &flags };
1367 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args);
1368 } else if (!o && QQmlMetaObject::canConvert(propMo, valMo)) {
1369 // In the case of a null QObject, we assign the null if there is
1370 // any change that the null variant type could be up or down cast to
1371 // the property type.
1372 void *args[] = { &o, 0, &status, &flags };
1373 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args);
1378 } else if (property.isQList()) {
1380 QQmlMetaObject listType;
1383 listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
1385 QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType));
1386 if (!type) return false;
1387 listType = type->baseMetaObject();
1389 if (listType.isNull()) return false;
1391 QQmlListProperty<void> prop;
1392 void *args[] = { &prop, 0 };
1393 QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
1395 if (!prop.clear) return false;
1399 if (value.userType() == qMetaTypeId<QQmlListReference>()) {
1400 QQmlListReference qdlr = value.value<QQmlListReference>();
1402 for (int ii = 0; ii < qdlr.count(); ++ii) {
1403 QObject *o = qdlr.at(ii);
1404 if (o && !QQmlMetaObject::canConvert(o, listType))
1406 prop.append(&prop, (void *)o);
1408 } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
1409 const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1411 for (int ii = 0; ii < list.count(); ++ii) {
1412 QObject *o = list.at(ii);
1413 if (o && !QQmlMetaObject::canConvert(o, listType))
1415 prop.append(&prop, (void *)o);
1418 QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value);
1419 if (o && !QQmlMetaObject::canConvert(o, listType))
1421 prop.append(&prop, (void *)o);
1425 Q_ASSERT(variantType != propertyType);
1429 if (variantType == QVariant::String)
1430 v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
1433 if (v.convert(propertyType)) {
1435 } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
1436 QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
1438 v = con(value.toString());
1439 if (v.userType() == propertyType)
1445 // the only other option is that they are assigning a single value
1446 // to a sequence type property (eg, an int to a QList<int> property).
1447 // Note that we've already handled single-value assignment to QList<QUrl> properties.
1448 if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
1450 list << value.toInt();
1451 v = QVariant::fromValue<QList<int> >(list);
1453 } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
1455 list << value.toReal();
1456 v = QVariant::fromValue<QList<qreal> >(list);
1458 } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
1460 list << value.toBool();
1461 v = QVariant::fromValue<QList<bool> >(list);
1463 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
1464 QList<QString> list;
1465 list << value.toString();
1466 v = QVariant::fromValue<QList<QString> >(list);
1468 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
1470 list << value.toString();
1471 v = QVariant::fromValue<QStringList>(list);
1477 void *a[] = { (void *)v.constData(), 0, &status, &flags};
1478 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1487 // Returns true if successful, false if an error description was set on expression
1488 bool QQmlPropertyPrivate::writeBinding(QObject *object,
1489 const QQmlPropertyData &core,
1490 QQmlContextData *context,
1491 QQmlJavaScriptExpression *expression,
1492 v8::Handle<v8::Value> result, bool isUndefined,
1496 Q_ASSERT(core.coreIndex != -1);
1498 QQmlEngine *engine = context->engine;
1499 QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
1501 #define QUICK_STORE(cpptype, conversion) \
1503 cpptype o = (conversion); \
1505 void *argv[] = { &o, 0, &status, &flags }; \
1506 QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \
1511 if (!isUndefined && !core.isValueTypeVirtual()) {
1512 switch (core.propType) {
1513 case QMetaType::Int:
1514 if (result->IsInt32())
1515 QUICK_STORE(int, result->Int32Value())
1516 else if (result->IsNumber())
1517 QUICK_STORE(int, qRound(result->NumberValue()))
1519 case QMetaType::Double:
1520 if (result->IsNumber())
1521 QUICK_STORE(double, result->NumberValue())
1523 case QMetaType::Float:
1524 if (result->IsNumber())
1525 QUICK_STORE(float, result->NumberValue())
1527 case QMetaType::QString:
1528 if (result->IsString())
1529 QUICK_STORE(QString, v8engine->toString(result))
1537 int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType;
1539 QQmlJavaScriptExpression::DeleteWatcher watcher(expression);
1542 bool isVarProperty = core.isVarProperty();
1545 } else if (core.isQList()) {
1546 value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
1547 } else if (result->IsNull() && core.isQObject()) {
1548 value = QVariant::fromValue((QObject *)0);
1549 } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
1550 value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
1551 } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) {
1552 value = v8engine->toVariant(result, type);
1555 if (expression->hasError()) {
1557 } else if (isVarProperty) {
1558 if (!result.IsEmpty() && result->IsFunction()
1559 && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
1560 // we explicitly disallow this case to avoid confusion. Users can still store one
1561 // in an array in a var property if they need to, but the common case is user error.
1562 expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1566 typedef QQmlVMEMetaObject VMEMO;
1567 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
1569 vmemo->setVMEProperty(core.coreIndex, result);
1570 } else if (isUndefined && core.isResettable()) {
1571 void *args[] = { 0 };
1572 QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
1573 } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
1574 writeValueProperty(object, engine, core, QVariant(), context, flags);
1575 } else if (type == qMetaTypeId<QJSValue>()) {
1576 if (!result.IsEmpty() && result->IsFunction()
1577 && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
1578 expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1581 writeValueProperty(object, engine, core, QVariant::fromValue(v8engine->scriptValueFromInternal(result)), context, flags);
1582 } else if (isUndefined) {
1583 QString errorStr = QLatin1String("Unable to assign [undefined] to ");
1584 if (!QMetaType::typeName(type))
1585 errorStr += QLatin1String("[unknown property type]");
1587 errorStr += QLatin1String(QMetaType::typeName(type));
1588 expression->delayedError()->setErrorDescription(errorStr);
1590 } else if (result->IsFunction()) {
1591 if (!result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty())
1592 expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1594 expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
1596 } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
1598 if (watcher.wasDeleted())
1601 const char *valueType = 0;
1602 const char *propertyType = 0;
1604 if (value.userType() == QMetaType::QObjectStar) {
1605 if (QObject *o = *(QObject **)value.constData()) {
1606 valueType = o->metaObject()->className();
1608 QQmlMetaObject propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type);
1609 if (!propertyMetaObject.isNull())
1610 propertyType = propertyMetaObject.className();
1612 } else if (value.userType() != QVariant::Invalid) {
1613 valueType = QMetaType::typeName(value.userType());
1619 propertyType = QMetaType::typeName(type);
1621 propertyType = "[unknown property type]";
1623 expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign ") +
1624 QLatin1String(valueType) +
1625 QLatin1String(" to ") +
1626 QLatin1String(propertyType));
1633 QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
1636 return engine->rawMetaObjectForType(userType);
1638 QQmlType *type = QQmlMetaType::qmlType(userType);
1639 return QQmlMetaObject(type?type->baseMetaObject():0);
1644 Sets the property value to \a value and returns true.
1645 Returns false if the property can't be set because the
1646 \a value is the wrong type, for example.
1648 bool QQmlProperty::write(const QVariant &value) const
1650 return QQmlPropertyPrivate::write(*this, value, 0);
1654 Writes \a value to the \a name property of \a object. This method
1658 QQmlProperty p(object, name);
1662 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
1664 QQmlProperty p(object, name);
1665 return p.write(value);
1669 Writes \a value to the \a name property of \a object using the
1670 \l{QQmlContext} {context} \a ctxt. This method is
1674 QQmlProperty p(object, name, ctxt);
1678 bool QQmlProperty::write(QObject *object,
1679 const QString &name,
1680 const QVariant &value,
1683 QQmlProperty p(object, name, ctxt);
1684 return p.write(value);
1689 Writes \a value to the \a name property of \a object using the
1690 environment for instantiating QML components that is provided by
1691 \a engine. This method is equivalent to:
1694 QQmlProperty p(object, name, engine);
1698 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
1701 QQmlProperty p(object, name, engine);
1702 return p.write(value);
1706 Resets the property and returns true if the property is
1707 resettable. If the property is not resettable, nothing happens
1708 and false is returned.
1710 bool QQmlProperty::reset() const
1712 if (isResettable()) {
1713 void *args[] = { 0 };
1714 QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1721 bool QQmlPropertyPrivate::write(const QQmlProperty &that,
1722 const QVariant &value, WriteFlags flags)
1726 if (that.d->object && that.type() & QQmlProperty::Property &&
1727 that.d->core.isValid() && that.isWritable())
1728 return that.d->writeValueProperty(value, flags);
1734 Returns true if the property has a change notifier signal, otherwise false.
1736 bool QQmlProperty::hasNotifySignal() const
1738 if (type() & Property && d->object) {
1739 return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1745 Returns true if the property needs a change notifier signal for bindings
1746 to remain upto date, false otherwise.
1748 Some properties, such as attached properties or those whose value never
1749 changes, do not require a change notifier.
1751 bool QQmlProperty::needsNotifySignal() const
1753 return type() & Property && !property().isConstant();
1757 Connects the property's change notifier signal to the
1758 specified \a method of the \a dest object and returns
1759 true. Returns false if this metaproperty does not
1760 represent a regular Qt property or if it has no
1761 change notifier signal, or if the \a dest object does
1762 not have the specified \a method.
1764 bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
1766 if (!(type() & Property) || !d->object)
1769 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1770 if (prop.hasNotifySignal()) {
1771 return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1778 Connects the property's change notifier signal to the
1779 specified \a slot of the \a dest object and returns
1780 true. Returns false if this metaproperty does not
1781 represent a regular Qt property or if it has no
1782 change notifier signal, or if the \a dest object does
1783 not have the specified \a slot.
1785 bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
1787 if (!(type() & Property) || !d->object)
1790 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1791 if (prop.hasNotifySignal()) {
1792 QByteArray signal('2' + prop.notifySignal().methodSignature());
1793 return QObject::connect(d->object, signal.constData(), dest, slot);
1800 Return the Qt metaobject index of the property.
1802 int QQmlProperty::index() const
1804 return d ? d->core.coreIndex : -1;
1807 int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that)
1809 return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
1813 Returns the "property index" for use in bindings. The top 8 bits are the value type
1814 offset, and 0 otherwise. The bottom 24-bits are the regular property index.
1816 int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that)
1820 return bindingIndex(that.d->core);
1823 int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that)
1825 int rv = that.coreIndex;
1826 if (rv != -1 && that.isValueTypeVirtual())
1827 rv = rv | (that.valueTypeCoreIndex << 24);
1832 QQmlPropertyPrivate::saveValueType(const QQmlPropertyData &base,
1833 const QMetaObject *subObject, int subIndex,
1836 QMetaProperty subProp = subObject->property(subIndex);
1838 QQmlPropertyData core = base;
1839 core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
1840 core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp);
1841 core.valueTypeCoreIndex = subIndex;
1842 core.valueTypePropType = subProp.userType();
1848 QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
1849 QQmlContextData *ctxt)
1853 prop.d = new QQmlPropertyPrivate;
1854 prop.d->object = object;
1855 prop.d->context = ctxt;
1856 prop.d->engine = ctxt?ctxt->engine:0;
1858 prop.d->core = data;
1864 Return the signal corresponding to \a name
1866 QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1869 int methods = mo->methodCount();
1870 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1871 QMetaMethod method = mo->method(ii);
1873 if (method.name() == name && (method.methodType() & QMetaMethod::Signal))
1877 // If no signal is found, but the signal is of the form "onBlahChanged",
1878 // return the notify signal for the property "Blah"
1879 if (name.endsWith("Changed")) {
1880 QByteArray propName = name.mid(0, name.length() - 7);
1881 int propIdx = mo->indexOfProperty(propName.constData());
1883 QMetaProperty prop = mo->property(propIdx);
1884 if (prop.hasNotifySignal())
1885 return prop.notifySignal();
1889 return QMetaMethod();
1893 If \a indexInSignalRange is true, \a index is treated as a signal index
1894 (see QObjectPrivate::signalIndex()), otherwise it is treated as a
1895 method index (QMetaMethod::methodIndex()).
1897 static inline void flush_vme_signal(const QObject *object, int index, bool indexInSignalRange)
1899 QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1900 if (data && data->propertyCache) {
1901 QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
1902 : data->propertyCache->method(index);
1904 if (property && property->isVMESignal()) {
1905 QQmlVMEMetaObject *vme;
1906 if (indexInSignalRange)
1907 vme = QQmlVMEMetaObject::getForSignal(const_cast<QObject *>(object), index);
1909 vme = QQmlVMEMetaObject::getForMethod(const_cast<QObject *>(object), index);
1910 vme->connectAliasSignal(index, indexInSignalRange);
1916 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1917 \a type and \a types. This behaves identically to QMetaObject::connect() except that
1918 it connects any lazy "proxy" signal connections set up by QML.
1920 It is possible that this logic should be moved to QMetaObject::connect().
1922 bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
1923 const QObject *receiver, int method_index,
1924 int type, int *types)
1926 static const bool indexInSignalRange = false;
1927 flush_vme_signal(sender, signal_index, indexInSignalRange);
1928 flush_vme_signal(receiver, method_index, indexInSignalRange);
1930 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1934 \a signal_index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
1935 This is different from QMetaMethod::methodIndex().
1937 void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
1939 static const bool indexInSignalRange = true;
1940 flush_vme_signal(sender, signal_index, indexInSignalRange);