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 Q_GLOBAL_STATIC(QQmlValueTypeFactory, qmlValueTypes);
229 QQmlPropertyPrivate::QQmlPropertyPrivate()
230 : context(0), engine(0), object(0), isNameCached(false)
234 QQmlContextData *QQmlPropertyPrivate::effectiveContext() const
236 if (context) return context;
237 else if (engine) return QQmlContextData::get(engine->rootContext());
241 void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
245 QQmlTypeNameCache *typeNameCache = context?context->imports:0;
247 QStringList path = name.split(QLatin1Char('.'));
248 if (path.isEmpty()) return;
250 QObject *currentObject = obj;
252 // Everything up to the last property must be an "object type" property
253 for (int ii = 0; ii < path.count() - 1; ++ii) {
254 const QString &pathName = path.at(ii);
257 QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
260 QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
261 if (!func) return; // Not an attachable type
263 currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
264 if (!currentObject) return; // Something is broken with the attachable type
265 } else if (r.importNamespace) {
266 if ((ii + 1) == path.count()) return; // No type following the namespace
268 ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
269 if (!r.type) return; // Invalid type in namespace
271 QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
272 if (!func) return; // Not an attachable type
274 currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
275 if (!currentObject) return; // Something is broken with the attachable type
277 } else if (r.scriptIndex != -1) {
278 return; // Not a type
280 Q_ASSERT(!"Unreachable");
287 QQmlPropertyData local;
288 QQmlPropertyData *property =
289 QQmlPropertyCache::property(engine, obj, pathName, local);
291 if (!property) return; // Not a property
292 if (property->isFunction())
293 return; // Not an object property
295 if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType)) {
296 // We're now at a value type property. We can use a global valuetypes array as we
297 // never actually use the objects, just look up their properties.
298 QObject *typeObject = (*qmlValueTypes())[property->propType];
299 if (!typeObject) return; // Not a value type
301 int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
302 if (idx == -1) return; // Value type property does not exist
304 QMetaProperty vtProp = typeObject->metaObject()->property(idx);
306 typedef QQmlPropertyData PCD;
308 Q_ASSERT(PCD::flagsForProperty(vtProp) <= PCD::ValueTypeFlagMask);
309 Q_ASSERT(vtProp.userType() <= 0xFF);
310 Q_ASSERT(idx <= 0xFF);
312 object = currentObject;
314 core.setFlags(core.getFlags() | PCD::IsValueTypeVirtual);
315 core.valueTypeFlags = PCD::flagsForProperty(vtProp);
316 core.valueTypePropType = vtProp.userType();
317 core.valueTypeCoreIndex = idx;
321 if (!property->isQObject())
322 return; // Not an object property
324 void *args[] = { ¤tObject, 0 };
325 QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
326 if (!currentObject) return; // No value
332 const QString &terminal = path.last();
334 if (terminal.count() >= 3 &&
335 terminal.at(0) == QLatin1Char('o') &&
336 terminal.at(1) == QLatin1Char('n') &&
337 terminal.at(2).isUpper()) {
339 QString signalName = terminal.mid(2);
340 signalName[0] = signalName.at(0).toLower();
342 // XXX - this code treats methods as signals
344 QQmlData *ddata = QQmlData::get(currentObject, false);
345 if (ddata && ddata->propertyCache) {
348 QQmlPropertyData *d = ddata->propertyCache->property(signalName);
349 while (d && !d->isFunction())
350 d = ddata->propertyCache->overrideData(d);
353 object = currentObject;
359 if (signalName.endsWith(QLatin1String("Changed"))) {
360 QString propName = signalName.mid(0, signalName.length() - 7);
361 QQmlPropertyData *d = ddata->propertyCache->property(propName);
362 while (d && d->isFunction())
363 d = ddata->propertyCache->overrideData(d);
365 if (d && d->notifyIndex != -1) {
366 object = currentObject;
367 core = *ddata->propertyCache->signal(d->notifyIndex);
373 QMetaMethod method = findSignalByName(currentObject->metaObject(),
374 signalName.toLatin1());
375 if (method.isValid()) {
376 object = currentObject;
384 QQmlPropertyData local;
385 QQmlPropertyData *property =
386 QQmlPropertyCache::property(engine, currentObject, terminal, local);
387 if (property && !property->isFunction()) {
388 object = currentObject;
390 nameCache = terminal;
396 Returns the index of this property's signal, in the signal index range
397 (see QObjectPrivate::signalIndex()). This is different from
398 QMetaMethod::methodIndex().
400 int QQmlPropertyPrivate::signalIndex() const
402 Q_ASSERT(type() == QQmlProperty::SignalProperty);
403 QMetaMethod m = object->metaObject()->method(core.coreIndex);
404 return QMetaObjectPrivate::signalIndex(m);
408 Create a copy of \a other.
410 QQmlProperty::QQmlProperty(const QQmlProperty &other)
418 \enum QQmlProperty::PropertyTypeCategory
420 This enum specifies a category of QML property.
422 \value InvalidCategory The property is invalid, or is a signal property.
423 \value List The property is a QQmlListProperty list property
424 \value Object The property is a QObject derived type pointer
425 \value Normal The property is a normal value property.
429 \enum QQmlProperty::Type
431 This enum specifies a type of QML property.
433 \value Invalid The property is invalid.
434 \value Property The property is a regular Qt property.
435 \value SignalProperty The property is a signal property.
439 Returns the property category.
441 QQmlProperty::PropertyTypeCategory QQmlProperty::propertyTypeCategory() const
443 return d ? d->propertyTypeCategory() : InvalidCategory;
446 QQmlProperty::PropertyTypeCategory
447 QQmlPropertyPrivate::propertyTypeCategory() const
449 uint type = this->type();
452 return QQmlProperty::Normal;
453 } else if (type & QQmlProperty::Property) {
454 int type = propertyType();
455 if (type == QVariant::Invalid)
456 return QQmlProperty::InvalidCategory;
457 else if (QQmlValueTypeFactory::isValueType((uint)type))
458 return QQmlProperty::Normal;
459 else if (core.isQObject())
460 return QQmlProperty::Object;
461 else if (core.isQList())
462 return QQmlProperty::List;
464 return QQmlProperty::Normal;
466 return QQmlProperty::InvalidCategory;
471 Returns the type name of the property, or 0 if the property has no type
474 const char *QQmlProperty::propertyTypeName() const
478 if (d->isValueType()) {
480 QQmlEnginePrivate *ep = d->engine?QQmlEnginePrivate::get(d->engine):0;
481 QQmlValueType *valueType = 0;
482 if (ep) valueType = ep->valueTypes[d->core.propType];
483 else valueType = QQmlValueTypeFactory::valueType(d->core.propType);
486 const char *rv = valueType->metaObject()->property(d->core.valueTypeCoreIndex).typeName();
488 if (!ep) delete valueType;
491 } else if (d->object && type() & Property && d->core.isValid()) {
492 return d->object->metaObject()->property(d->core.coreIndex).typeName();
499 Returns true if \a other and this QQmlProperty represent the same
502 bool QQmlProperty::operator==(const QQmlProperty &other) const
506 // category is intentially omitted here as it is generated
507 // from the other members
508 return d->object == other.d->object &&
509 d->core.coreIndex == other.d->core.coreIndex &&
510 d->core.isValueTypeVirtual() == other.d->core.isValueTypeVirtual() &&
511 (!d->core.isValueTypeVirtual() ||
512 (d->core.valueTypeCoreIndex == other.d->core.valueTypeCoreIndex &&
513 d->core.valueTypePropType == other.d->core.valueTypePropType));
517 Returns the QVariant type of the property, or QVariant::Invalid if the
518 property has no QVariant type.
520 int QQmlProperty::propertyType() const
522 return d ? d->propertyType() : int(QVariant::Invalid);
525 bool QQmlPropertyPrivate::isValueType() const
527 return core.isValueTypeVirtual();
530 int QQmlPropertyPrivate::propertyType() const
532 uint type = this->type();
534 return core.valueTypePropType;
535 } else if (type & QQmlProperty::Property) {
536 return core.propType;
538 return QVariant::Invalid;
542 QQmlProperty::Type QQmlPropertyPrivate::type() const
544 if (core.isFunction())
545 return QQmlProperty::SignalProperty;
546 else if (core.isValid())
547 return QQmlProperty::Property;
549 return QQmlProperty::Invalid;
553 Returns the type of the property.
555 QQmlProperty::Type QQmlProperty::type() const
557 return d ? d->type() : Invalid;
561 Returns true if this QQmlProperty represents a regular Qt property.
563 bool QQmlProperty::isProperty() const
565 return type() & Property;
569 Returns true if this QQmlProperty represents a QML signal property.
571 bool QQmlProperty::isSignalProperty() const
573 return type() & SignalProperty;
577 Returns the QQmlProperty's QObject.
579 QObject *QQmlProperty::object() const
581 return d ? d->object : 0;
585 Assign \a other to this QQmlProperty.
587 QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other)
599 Returns true if the property is writable, otherwise false.
601 bool QQmlProperty::isWritable() const
607 if (d->core.isQList()) //list
609 else if (d->core.isFunction()) //signal handler
611 else if (d->core.isValid()) //normal property
612 return d->core.isWritable();
618 Returns true if the property is designable, otherwise false.
620 bool QQmlProperty::isDesignable() const
624 if (type() & Property && d->core.isValid() && d->object)
625 return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
631 Returns true if the property is resettable, otherwise false.
633 bool QQmlProperty::isResettable() const
637 if (type() & Property && d->core.isValid() && d->object)
638 return d->core.isResettable();
644 Returns true if the QQmlProperty refers to a valid property, otherwise
647 bool QQmlProperty::isValid() const
651 return type() != Invalid;
655 Return the name of this QML property.
657 QString QQmlProperty::name() const
661 if (!d->isNameCached) {
664 } else if (d->isValueType()) {
665 QString rv = d->core.name(d->object) + QLatin1Char('.');
667 QQmlEnginePrivate *ep = d->engine?QQmlEnginePrivate::get(d->engine):0;
668 QQmlValueType *valueType = 0;
669 if (ep) valueType = ep->valueTypes[d->core.propType];
670 else valueType = QQmlValueTypeFactory::valueType(d->core.propType);
673 const char *vtName = valueType->metaObject()->property(d->core.valueTypeCoreIndex).name();
674 rv += QString::fromUtf8(vtName);
676 if (!ep) delete valueType;
679 } else if (type() & SignalProperty) {
680 QString name = QLatin1String("on") + d->core.name(d->object);
681 name[2] = name.at(2).toUpper();
684 d->nameCache = d->core.name(d->object);
686 d->isNameCached = true;
693 Returns the \l{QMetaProperty} {Qt property} associated with
696 QMetaProperty QQmlProperty::property() const
699 return QMetaProperty();
700 if (type() & Property && d->core.isValid() && d->object)
701 return d->object->metaObject()->property(d->core.coreIndex);
703 return QMetaProperty();
707 Return the QMetaMethod for this property if it is a SignalProperty,
708 otherwise returns an invalid QMetaMethod.
710 QMetaMethod QQmlProperty::method() const
713 return QMetaMethod();
714 if (type() & SignalProperty && d->object)
715 return d->object->metaObject()->method(d->core.coreIndex);
717 return QMetaMethod();
721 Returns the binding associated with this property, or 0 if no binding
724 QQmlAbstractBinding *
725 QQmlPropertyPrivate::binding(const QQmlProperty &that)
727 if (!that.d || !that.isProperty() || !that.d->object)
730 return binding(that.d->object, that.d->core.coreIndex,
731 that.d->core.getValueTypeCoreIndex());
735 Set the binding associated with this property to \a newBinding. Returns
736 the existing binding (if any), otherwise 0.
738 \a newBinding will be enabled, and the returned binding (if any) will be
741 Ownership of \a newBinding transfers to QML. Ownership of the return value
742 is assumed by the caller.
744 \a flags is passed through to the binding and is used for the initial update (when
745 the binding sets the initial value, it will use these flags for the write).
747 QQmlAbstractBinding *
748 QQmlPropertyPrivate::setBinding(const QQmlProperty &that,
749 QQmlAbstractBinding *newBinding,
752 if (!that.d || !that.isProperty() || !that.d->object) {
754 newBinding->destroy();
759 // In the case that the new binding is provided, we must target the property it
760 // is associated with. If we don't do this, retargetBinding() can fail.
761 QObject *object = newBinding->object();
762 int pi = newBinding->propertyIndex();
764 int core = pi & 0xFFFFFF;
765 int vt = (pi & 0xFF000000)?(pi >> 24):-1;
767 return setBinding(object, core, vt, newBinding, flags);
769 return setBinding(that.d->object, that.d->core.coreIndex,
770 that.d->core.getValueTypeCoreIndex(),
775 QQmlAbstractBinding *
776 QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
778 QQmlData *data = QQmlData::get(object);
782 QQmlPropertyData *propertyData =
783 data->propertyCache?data->propertyCache->property(coreIndex):0;
784 if (propertyData && propertyData->isAlias()) {
785 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
787 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
788 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
791 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
792 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
793 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
794 return binding(aObject, aCoreIndex, aValueTypeIndex);
797 if (!data->hasBindingBit(coreIndex))
800 QQmlAbstractBinding *binding = data->bindings;
801 while (binding && binding->propertyIndex() != coreIndex)
802 binding = binding->nextBinding();
804 if (binding && valueTypeIndex != -1) {
805 if (binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) {
806 int index = coreIndex | (valueTypeIndex << 24);
807 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
814 void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
815 QObject **targetObject, int *targetBindingIndex)
817 int coreIndex = bindingIndex & 0xFFFFFF;
818 int valueTypeIndex = bindingIndex >> 24;
819 if (valueTypeIndex == 0) valueTypeIndex = -1;
821 QQmlData *data = QQmlData::get(object, false);
823 QQmlPropertyData *propertyData =
824 data->propertyCache?data->propertyCache->property(coreIndex):0;
825 if (propertyData && propertyData->isAlias()) {
826 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
828 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
829 if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
830 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
831 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
833 int aBindingIndex = aCoreIndex;
834 if (aValueTypeIndex != -1)
835 aBindingIndex |= aValueTypeIndex << 24;
836 else if (valueTypeIndex != -1)
837 aBindingIndex |= valueTypeIndex << 24;
839 findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
845 *targetObject = object;
846 *targetBindingIndex = bindingIndex;
849 QQmlAbstractBinding *
850 QQmlPropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
851 QQmlAbstractBinding *newBinding, WriteFlags flags)
853 QQmlData *data = QQmlData::get(object, 0 != newBinding);
854 QQmlAbstractBinding *binding = 0;
857 QQmlPropertyData *propertyData =
858 data->propertyCache?data->propertyCache->property(coreIndex):0;
859 if (propertyData && propertyData->isAlias()) {
860 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
862 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
863 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
864 if (newBinding) newBinding->destroy();
868 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
869 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
870 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
871 return setBinding(aObject, aCoreIndex, aValueTypeIndex, newBinding, flags);
875 if (data && data->hasBindingBit(coreIndex)) {
876 binding = data->bindings;
878 while (binding && binding->propertyIndex() != coreIndex)
879 binding = binding->nextBinding();
882 int index = coreIndex;
883 if (valueTypeIndex != -1)
884 index |= (valueTypeIndex << 24);
886 if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
887 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
890 binding->removeFromObject();
891 binding->setEnabled(false, 0);
895 if (newBinding->propertyIndex() != index || newBinding->object() != object)
896 newBinding->retargetBinding(object, index);
898 Q_ASSERT(newBinding->propertyIndex() == index);
899 Q_ASSERT(newBinding->object() == object);
901 newBinding->addToObject();
902 newBinding->setEnabled(true, flags);
908 QQmlAbstractBinding *
909 QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
910 QQmlAbstractBinding *newBinding)
912 QQmlData *data = QQmlData::get(object, 0 != newBinding);
913 QQmlAbstractBinding *binding = 0;
916 QQmlPropertyData *propertyData =
917 data->propertyCache?data->propertyCache->property(coreIndex):0;
918 if (propertyData && propertyData->isAlias()) {
919 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
921 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
922 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
923 if (newBinding) newBinding->destroy();
927 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
928 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
929 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
930 return setBindingNoEnable(aObject, aCoreIndex, aValueTypeIndex, newBinding);
934 if (data && data->hasBindingBit(coreIndex)) {
935 binding = data->bindings;
937 while (binding && binding->propertyIndex() != coreIndex)
938 binding = binding->nextBinding();
941 int index = coreIndex;
942 if (valueTypeIndex != -1)
943 index |= (valueTypeIndex << 24);
945 if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
946 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
949 binding->removeFromObject();
952 if (newBinding->propertyIndex() != index || newBinding->object() != object)
953 newBinding->retargetBinding(object, index);
955 Q_ASSERT(newBinding->propertyIndex() == index);
956 Q_ASSERT(newBinding->object() == object);
958 newBinding->addToObject();
965 Activates a shared binding which was previously created but not added to the
966 object. This is needed when an optimized binding is invalidated.
968 QQmlAbstractBinding *QQmlPropertyPrivate::activateSharedBinding(QQmlContextData *context,
969 int sharedIdx, WriteFlags flags)
971 QQmlAbstractBinding *newBinding = 0;
972 newBinding = context->v8bindings->binding(sharedIdx);
977 // This binding now references the bindings object
978 context->v8bindings->addref();
980 QObject *object = newBinding->object();
981 int pi = newBinding->propertyIndex();
983 int core = pi & 0xFFFFFF;
984 int vt = (pi & 0xFF000000)?(pi >> 24):-1;
986 return setBinding(object, core, vt, newBinding, flags);
990 Returns the expression associated with this signal property, or 0 if no
991 signal expression exists.
993 QQmlBoundSignalExpression *
994 QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
996 if (!(that.type() & QQmlProperty::SignalProperty))
999 QQmlData *data = QQmlData::get(that.d->object);
1003 QQmlAbstractBoundSignal *signalHandler = data->signalHandlers;
1005 while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex())
1006 signalHandler = signalHandler->m_nextSignal;
1009 return signalHandler->expression();
1015 Set the signal expression associated with this signal property to \a expr.
1016 Returns the existing signal expression (if any), otherwise null.
1018 A reference to \a expr will be added by QML. Ownership of the return value
1019 reference is assumed by the caller.
1021 QQmlBoundSignalExpressionPointer
1022 QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that,
1023 QQmlBoundSignalExpression *expr)
1027 return QQmlPropertyPrivate::takeSignalExpression(that, expr);
1031 Set the signal expression associated with this signal property to \a expr.
1032 Returns the existing signal expression (if any), otherwise null.
1034 Ownership of \a expr transfers to QML. Ownership of the return value
1035 reference is assumed by the caller.
1037 QQmlBoundSignalExpressionPointer
1038 QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that,
1039 QQmlBoundSignalExpression *expr)
1041 if (!(that.type() & QQmlProperty::SignalProperty)) {
1047 QQmlData *data = QQmlData::get(that.d->object, 0 != expr);
1051 QQmlAbstractBoundSignal *signalHandler = data->signalHandlers;
1053 while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex())
1054 signalHandler = signalHandler->m_nextSignal;
1057 return signalHandler->takeExpression(expr);
1060 int signalIndex = QQmlPropertyPrivate::get(that)->signalIndex();
1061 QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, signalIndex, that.d->object,
1062 expr->context()->engine);
1063 signal->takeExpression(expr);
1069 Returns the property value.
1071 QVariant QQmlProperty::read() const
1078 if (type() & SignalProperty) {
1082 } else if (type() & Property) {
1084 return d->readValueProperty();
1091 Return the \a name property value of \a object. This method is equivalent to:
1093 QQmlProperty p(object, name);
1097 QVariant QQmlProperty::read(QObject *object, const QString &name)
1099 QQmlProperty p(object, name);
1104 Return the \a name property value of \a object using the
1105 \l{QQmlContext} {context} \a ctxt. This method is
1109 QQmlProperty p(object, name, context);
1113 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlContext *ctxt)
1115 QQmlProperty p(object, name, ctxt);
1121 Return the \a name property value of \a object using the environment
1122 for instantiating QML components that is provided by \a engine. .
1123 This method is equivalent to:
1126 QQmlProperty p(object, name, engine);
1130 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlEngine *engine)
1132 QQmlProperty p(object, name, engine);
1136 QVariant QQmlPropertyPrivate::readValueProperty()
1138 if (isValueType()) {
1140 QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
1141 QQmlValueType *valueType = 0;
1142 if (ep) valueType = ep->valueTypes[core.propType];
1143 else valueType = QQmlValueTypeFactory::valueType(core.propType);
1144 Q_ASSERT(valueType);
1146 valueType->read(object, core.coreIndex);
1148 QVariant rv = valueType->metaObject()->property(core.valueTypeCoreIndex).read(valueType);
1150 if (!ep) delete valueType;
1153 } else if (core.isQList()) {
1155 QQmlListProperty<QObject> prop;
1156 void *args[] = { &prop, 0 };
1157 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1158 return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType, engine));
1160 } else if (core.isQObject()) {
1163 void *args[] = { &rv, 0 };
1164 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1165 return QVariant::fromValue(rv);
1169 if (!core.propType) // Unregistered type
1170 return object->metaObject()->property(core.coreIndex).read(object);
1174 void *args[] = { 0, &value, &status };
1175 if (core.propType == QMetaType::QVariant) {
1178 value = QVariant(core.propType, (void*)0);
1179 args[0] = value.data();
1181 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1182 if (core.propType != QMetaType::QVariant && args[0] != value.data())
1183 return QVariant((QVariant::Type)core.propType, args[0]);
1189 // helper function to allow assignment / binding to QList<QUrl> properties.
1190 static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context)
1193 if (value.userType() == qMetaTypeId<QUrl>()) {
1194 urls.append(value.toUrl());
1195 } else if (value.userType() == qMetaTypeId<QString>()) {
1196 urls.append(QUrl(value.toString()));
1197 } else if (value.userType() == qMetaTypeId<QByteArray>()) {
1198 urls.append(QUrl(QString::fromUtf8(value.toByteArray())));
1199 } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
1200 urls = value.value<QList<QUrl> >();
1201 } else if (value.userType() == qMetaTypeId<QStringList>()) {
1202 QStringList urlStrings = value.value<QStringList>();
1203 for (int i = 0; i < urlStrings.size(); ++i)
1204 urls.append(QUrl(urlStrings.at(i)));
1205 } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
1206 QList<QString> urlStrings = value.value<QList<QString> >();
1207 for (int i = 0; i < urlStrings.size(); ++i)
1208 urls.append(QUrl(urlStrings.at(i)));
1209 } // note: QList<QByteArray> is not currently supported.
1211 QList<QUrl> resolvedUrls;
1212 for (int i = 0; i < urls.size(); ++i) {
1213 QUrl u = urls.at(i);
1214 if (context && u.isRelative() && !u.isEmpty())
1215 u = context->resolvedUrl(u);
1216 resolvedUrls.append(u);
1219 return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
1222 //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1223 bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1225 if (!object || !prop.isWritable())
1229 if (prop.isEnumType()) {
1230 QMetaEnum menum = prop.enumerator();
1231 if (v.userType() == QVariant::String
1233 || v.userType() == QVariant::CString
1237 if (prop.isFlagType())
1238 v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
1240 v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
1243 } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
1244 int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
1245 if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData())
1247 v = QVariant(*reinterpret_cast<const int *>(v.constData()));
1249 v.convert(QVariant::Int);
1252 // the status variable is changed by qt_metacall to indicate what it did
1253 // this feature is currently only used by QtDBus and should not be depended
1254 // upon. Don't change it without looking into QDBusAbstractInterface first
1255 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1256 // changed: result stored directly in value, return the value of status
1258 void *argv[] = { v.data(), &v, &status, &flags };
1259 QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
1263 bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
1265 return writeValueProperty(object, engine, core, value, effectiveContext(), flags);
1269 QQmlPropertyPrivate::writeValueProperty(QObject *object, QQmlEngine *engine,
1270 const QQmlPropertyData &core,
1271 const QVariant &value,
1272 QQmlContextData *context, WriteFlags flags)
1274 // Remove any existing bindings on this property
1275 if (!(flags & DontRemoveBinding) && object) {
1276 QQmlAbstractBinding *binding = setBinding(object, core.coreIndex,
1277 core.getValueTypeCoreIndex(),
1279 if (binding) binding->destroy();
1283 if (core.isValueTypeVirtual()) {
1284 QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
1286 QQmlValueType *writeBack = 0;
1288 writeBack = ep->valueTypes[core.propType];
1290 writeBack = QQmlValueTypeFactory::valueType(core.propType);
1293 writeBack->read(object, core.coreIndex);
1295 QQmlPropertyData data = core;
1296 data.setFlags(QQmlPropertyData::Flag(core.valueTypeFlags));
1297 data.coreIndex = core.valueTypeCoreIndex;
1298 data.propType = core.valueTypePropType;
1300 rv = write(writeBack, data, value, context, flags);
1302 writeBack->write(object, core.coreIndex, flags);
1303 if (!ep) delete writeBack;
1307 rv = write(object, core, value, context, flags);
1314 bool QQmlPropertyPrivate::write(QObject *object,
1315 const QQmlPropertyData &property,
1316 const QVariant &value, QQmlContextData *context,
1319 int coreIdx = property.coreIndex;
1320 int status = -1; //for dbus
1322 if (property.isEnum()) {
1323 QMetaProperty prop = object->metaObject()->property(property.coreIndex);
1325 // Enum values come through the script engine as doubles
1326 if (value.userType() == QVariant::Double) {
1328 double fractional = modf(value.toDouble(), &integral);
1329 if (qFuzzyIsNull(fractional))
1330 v.convert(QVariant::Int);
1332 return writeEnumProperty(prop, coreIdx, object, v, flags);
1335 int propertyType = property.propType;
1336 int variantType = value.userType();
1338 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
1340 if (propertyType == QVariant::Url) {
1344 if (variantType == QVariant::Url) {
1347 } else if (variantType == QVariant::ByteArray) {
1348 QString input(QString::fromUtf8(value.toByteArray()));
1349 // Encoded dir-separators defeat QUrl processing - decode them first
1350 input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
1353 } else if (variantType == QVariant::String) {
1354 QString input(value.toString());
1355 // Encoded dir-separators defeat QUrl processing - decode them first
1356 input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
1364 if (context && u.isRelative() && !u.isEmpty())
1365 u = context->resolvedUrl(u);
1367 void *argv[] = { &u, 0, &status, &flags };
1368 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1370 } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
1371 QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
1373 void *argv[] = { &urlSeq, 0, &status, &flags };
1374 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1375 } else if (variantType == propertyType) {
1377 void *a[] = { (void *)value.constData(), 0, &status, &flags };
1378 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1380 } else if (qMetaTypeId<QVariant>() == propertyType) {
1382 void *a[] = { (void *)&value, 0, &status, &flags };
1383 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1385 } else if (property.isQObject()) {
1387 QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, value.userType());
1392 QObject *o = *(QObject **)value.constData();
1393 QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
1397 if (QQmlMetaObject::canConvert(valMo, propMo)) {
1398 void *args[] = { &o, 0, &status, &flags };
1399 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args);
1400 } else if (!o && QQmlMetaObject::canConvert(propMo, valMo)) {
1401 // In the case of a null QObject, we assign the null if there is
1402 // any change that the null variant type could be up or down cast to
1403 // the property type.
1404 void *args[] = { &o, 0, &status, &flags };
1405 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args);
1410 } else if (property.isQList()) {
1412 QQmlMetaObject listType;
1415 listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
1417 QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType));
1418 if (!type) return false;
1419 listType = type->baseMetaObject();
1421 if (listType.isNull()) return false;
1423 QQmlListProperty<void> prop;
1424 void *args[] = { &prop, 0 };
1425 QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
1427 if (!prop.clear) return false;
1431 if (value.userType() == qMetaTypeId<QQmlListReference>()) {
1432 QQmlListReference qdlr = value.value<QQmlListReference>();
1434 for (int ii = 0; ii < qdlr.count(); ++ii) {
1435 QObject *o = qdlr.at(ii);
1436 if (o && !QQmlMetaObject::canConvert(o, listType))
1438 prop.append(&prop, (void *)o);
1440 } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
1441 const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1443 for (int ii = 0; ii < list.count(); ++ii) {
1444 QObject *o = list.at(ii);
1445 if (o && !QQmlMetaObject::canConvert(o, listType))
1447 prop.append(&prop, (void *)o);
1450 QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value);
1451 if (o && !QQmlMetaObject::canConvert(o, listType))
1453 prop.append(&prop, (void *)o);
1457 Q_ASSERT(variantType != propertyType);
1461 if (variantType == QVariant::String)
1462 v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
1465 if (v.convert(propertyType)) {
1467 } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
1468 QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
1470 v = con(value.toString());
1471 if (v.userType() == propertyType)
1477 // the only other option is that they are assigning a single value
1478 // to a sequence type property (eg, an int to a QList<int> property).
1479 // Note that we've already handled single-value assignment to QList<QUrl> properties.
1480 if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
1482 list << value.toInt();
1483 v = QVariant::fromValue<QList<int> >(list);
1485 } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
1487 list << value.toReal();
1488 v = QVariant::fromValue<QList<qreal> >(list);
1490 } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
1492 list << value.toBool();
1493 v = QVariant::fromValue<QList<bool> >(list);
1495 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
1496 QList<QString> list;
1497 list << value.toString();
1498 v = QVariant::fromValue<QList<QString> >(list);
1500 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
1502 list << value.toString();
1503 v = QVariant::fromValue<QStringList>(list);
1509 void *a[] = { (void *)v.constData(), 0, &status, &flags};
1510 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1519 // Returns true if successful, false if an error description was set on expression
1520 bool QQmlPropertyPrivate::writeBinding(QObject *object,
1521 const QQmlPropertyData &core,
1522 QQmlContextData *context,
1523 QQmlJavaScriptExpression *expression,
1524 v8::Handle<v8::Value> result, bool isUndefined,
1528 Q_ASSERT(core.coreIndex != -1);
1530 QQmlEngine *engine = context->engine;
1531 QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
1533 #define QUICK_STORE(cpptype, conversion) \
1535 cpptype o = (conversion); \
1537 void *argv[] = { &o, 0, &status, &flags }; \
1538 QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \
1543 if (!isUndefined && !core.isValueTypeVirtual()) {
1544 switch (core.propType) {
1545 case QMetaType::Int:
1546 if (result->IsInt32())
1547 QUICK_STORE(int, result->Int32Value())
1548 else if (result->IsNumber())
1549 QUICK_STORE(int, qRound(result->NumberValue()))
1551 case QMetaType::Double:
1552 if (result->IsNumber())
1553 QUICK_STORE(double, result->NumberValue())
1555 case QMetaType::Float:
1556 if (result->IsNumber())
1557 QUICK_STORE(float, result->NumberValue())
1559 case QMetaType::QString:
1560 if (result->IsString())
1561 QUICK_STORE(QString, v8engine->toString(result))
1569 int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType;
1571 QQmlJavaScriptExpression::DeleteWatcher watcher(expression);
1574 bool isVarProperty = core.isVarProperty();
1577 } else if (core.isQList()) {
1578 value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
1579 } else if (result->IsNull() && core.isQObject()) {
1580 value = QVariant::fromValue((QObject *)0);
1581 } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
1582 value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
1583 } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) {
1584 value = v8engine->toVariant(result, type);
1587 if (expression->hasError()) {
1589 } else if (isVarProperty) {
1590 if (!result.IsEmpty() && result->IsFunction()
1591 && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
1592 // we explicitly disallow this case to avoid confusion. Users can still store one
1593 // in an array in a var property if they need to, but the common case is user error.
1594 expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1598 typedef QQmlVMEMetaObject VMEMO;
1599 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
1601 vmemo->setVMEProperty(core.coreIndex, result);
1602 } else if (isUndefined && core.isResettable()) {
1603 void *args[] = { 0 };
1604 QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
1605 } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
1606 writeValueProperty(object, engine, core, QVariant(), context, flags);
1607 } else if (type == qMetaTypeId<QJSValue>()) {
1608 if (!result.IsEmpty() && result->IsFunction()
1609 && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
1610 expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1613 writeValueProperty(object, engine, core, QVariant::fromValue(v8engine->scriptValueFromInternal(result)), context, flags);
1614 } else if (isUndefined) {
1615 QString errorStr = QLatin1String("Unable to assign [undefined] to ");
1616 if (!QMetaType::typeName(type))
1617 errorStr += QLatin1String("[unknown property type]");
1619 errorStr += QLatin1String(QMetaType::typeName(type));
1620 expression->delayedError()->setErrorDescription(errorStr);
1622 } else if (result->IsFunction()) {
1623 if (!result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty())
1624 expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1626 expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
1628 } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
1630 if (watcher.wasDeleted())
1633 const char *valueType = 0;
1634 const char *propertyType = 0;
1636 if (value.userType() == QMetaType::QObjectStar) {
1637 if (QObject *o = *(QObject **)value.constData()) {
1638 valueType = o->metaObject()->className();
1640 QQmlMetaObject propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type);
1641 if (!propertyMetaObject.isNull())
1642 propertyType = propertyMetaObject.className();
1644 } else if (value.userType() != QVariant::Invalid) {
1645 valueType = QMetaType::typeName(value.userType());
1651 propertyType = QMetaType::typeName(type);
1653 propertyType = "[unknown property type]";
1655 expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign ") +
1656 QLatin1String(valueType) +
1657 QLatin1String(" to ") +
1658 QLatin1String(propertyType));
1665 QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
1668 return engine->rawMetaObjectForType(userType);
1670 QQmlType *type = QQmlMetaType::qmlType(userType);
1671 return QQmlMetaObject(type?type->baseMetaObject():0);
1676 Sets the property value to \a value and returns true.
1677 Returns false if the property can't be set because the
1678 \a value is the wrong type, for example.
1680 bool QQmlProperty::write(const QVariant &value) const
1682 return QQmlPropertyPrivate::write(*this, value, 0);
1686 Writes \a value to the \a name property of \a object. This method
1690 QQmlProperty p(object, name);
1694 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
1696 QQmlProperty p(object, name);
1697 return p.write(value);
1701 Writes \a value to the \a name property of \a object using the
1702 \l{QQmlContext} {context} \a ctxt. This method is
1706 QQmlProperty p(object, name, ctxt);
1710 bool QQmlProperty::write(QObject *object,
1711 const QString &name,
1712 const QVariant &value,
1715 QQmlProperty p(object, name, ctxt);
1716 return p.write(value);
1721 Writes \a value to the \a name property of \a object using the
1722 environment for instantiating QML components that is provided by
1723 \a engine. This method is equivalent to:
1726 QQmlProperty p(object, name, engine);
1730 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
1733 QQmlProperty p(object, name, engine);
1734 return p.write(value);
1738 Resets the property and returns true if the property is
1739 resettable. If the property is not resettable, nothing happens
1740 and false is returned.
1742 bool QQmlProperty::reset() const
1744 if (isResettable()) {
1745 void *args[] = { 0 };
1746 QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1753 bool QQmlPropertyPrivate::write(const QQmlProperty &that,
1754 const QVariant &value, WriteFlags flags)
1758 if (that.d->object && that.type() & QQmlProperty::Property &&
1759 that.d->core.isValid() && that.isWritable())
1760 return that.d->writeValueProperty(value, flags);
1766 Returns true if the property has a change notifier signal, otherwise false.
1768 bool QQmlProperty::hasNotifySignal() const
1770 if (type() & Property && d->object) {
1771 return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1777 Returns true if the property needs a change notifier signal for bindings
1778 to remain upto date, false otherwise.
1780 Some properties, such as attached properties or those whose value never
1781 changes, do not require a change notifier.
1783 bool QQmlProperty::needsNotifySignal() const
1785 return type() & Property && !property().isConstant();
1789 Connects the property's change notifier signal to the
1790 specified \a method of the \a dest object and returns
1791 true. Returns false if this metaproperty does not
1792 represent a regular Qt property or if it has no
1793 change notifier signal, or if the \a dest object does
1794 not have the specified \a method.
1796 bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
1798 if (!(type() & Property) || !d->object)
1801 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1802 if (prop.hasNotifySignal()) {
1803 return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1810 Connects the property's change notifier signal to the
1811 specified \a slot of the \a dest object and returns
1812 true. Returns false if this metaproperty does not
1813 represent a regular Qt property or if it has no
1814 change notifier signal, or if the \a dest object does
1815 not have the specified \a slot.
1817 bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
1819 if (!(type() & Property) || !d->object)
1822 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1823 if (prop.hasNotifySignal()) {
1824 QByteArray signal('2' + prop.notifySignal().methodSignature());
1825 return QObject::connect(d->object, signal.constData(), dest, slot);
1832 Return the Qt metaobject index of the property.
1834 int QQmlProperty::index() const
1836 return d ? d->core.coreIndex : -1;
1839 int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that)
1841 return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
1845 Returns the "property index" for use in bindings. The top 8 bits are the value type
1846 offset, and 0 otherwise. The bottom 24-bits are the regular property index.
1848 int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that)
1852 return bindingIndex(that.d->core);
1855 int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that)
1857 int rv = that.coreIndex;
1858 if (rv != -1 && that.isValueTypeVirtual())
1859 rv = rv | (that.valueTypeCoreIndex << 24);
1864 QQmlPropertyPrivate::saveValueType(const QQmlPropertyData &base,
1865 const QMetaObject *subObject, int subIndex,
1868 QMetaProperty subProp = subObject->property(subIndex);
1870 QQmlPropertyData core = base;
1871 core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
1872 core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp);
1873 core.valueTypeCoreIndex = subIndex;
1874 core.valueTypePropType = subProp.userType();
1880 QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
1881 QQmlContextData *ctxt)
1885 prop.d = new QQmlPropertyPrivate;
1886 prop.d->object = object;
1887 prop.d->context = ctxt;
1888 prop.d->engine = ctxt?ctxt->engine:0;
1890 prop.d->core = data;
1896 Return the signal corresponding to \a name
1898 QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1901 int methods = mo->methodCount();
1902 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1903 QMetaMethod method = mo->method(ii);
1905 if (method.name() == name && (method.methodType() & QMetaMethod::Signal))
1909 // If no signal is found, but the signal is of the form "onBlahChanged",
1910 // return the notify signal for the property "Blah"
1911 if (name.endsWith("Changed")) {
1912 QByteArray propName = name.mid(0, name.length() - 7);
1913 int propIdx = mo->indexOfProperty(propName.constData());
1915 QMetaProperty prop = mo->property(propIdx);
1916 if (prop.hasNotifySignal())
1917 return prop.notifySignal();
1921 return QMetaMethod();
1925 If \a indexInSignalRange is true, \a index is treated as a signal index
1926 (see QObjectPrivate::signalIndex()), otherwise it is treated as a
1927 method index (QMetaMethod::methodIndex()).
1929 static inline void flush_vme_signal(const QObject *object, int index, bool indexInSignalRange)
1931 QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1932 if (data && data->propertyCache) {
1933 QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
1934 : data->propertyCache->method(index);
1936 if (property && property->isVMESignal()) {
1937 QQmlVMEMetaObject *vme;
1938 if (indexInSignalRange)
1939 vme = QQmlVMEMetaObject::getForSignal(const_cast<QObject *>(object), index);
1941 vme = QQmlVMEMetaObject::getForMethod(const_cast<QObject *>(object), index);
1942 vme->connectAliasSignal(index, indexInSignalRange);
1948 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1949 \a type and \a types. This behaves identically to QMetaObject::connect() except that
1950 it connects any lazy "proxy" signal connections set up by QML.
1952 It is possible that this logic should be moved to QMetaObject::connect().
1954 bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
1955 const QObject *receiver, int method_index,
1956 int type, int *types)
1958 static const bool indexInSignalRange = false;
1959 flush_vme_signal(sender, signal_index, indexInSignalRange);
1960 flush_vme_signal(receiver, method_index, indexInSignalRange);
1962 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1966 \a signal_index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
1967 This is different from QMetaMethod::methodIndex().
1969 void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
1971 static const bool indexInSignalRange = true;
1972 flush_vme_signal(sender, signal_index, indexInSignalRange);