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"
59 #include <QStringList>
60 #include <QtCore/qdebug.h>
64 Q_DECLARE_METATYPE(QList<int>)
65 Q_DECLARE_METATYPE(QList<qreal>)
66 Q_DECLARE_METATYPE(QList<bool>)
67 Q_DECLARE_METATYPE(QList<QString>)
68 Q_DECLARE_METATYPE(QList<QUrl>)
75 \brief The QQmlProperty class abstracts accessing properties on objects created from QML.
77 As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect
78 and interact with objects created by QML. However, some of the new features provided by QML - such
79 as type safety and attached properties - are most easily used through the QQmlProperty class
80 that simplifies some of their natural complexity.
82 Unlike QMetaProperty which represents a property on a class type, QQmlProperty encapsulates
83 a property on a specific object instance. To read a property's value, programmers create a
84 QQmlProperty instance and call the read() method. Likewise to write a property value the
85 write() method is used.
87 For example, for the following QML code:
93 Text { text: "A bit of text" }
96 The \l Text object's properties could be accessed using QQmlProperty, like this:
99 #include <QQmlProperty>
100 #include <QGraphicsObject>
104 QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
105 QQmlProperty property(view.rootObject(), "font.pixelSize");
106 qWarning() << "Current pixel size:" << property.read().toInt();
108 qWarning() << "Pixel size should now be 24:" << property.read().toInt();
113 Create an invalid QQmlProperty.
115 QQmlProperty::QQmlProperty()
121 QQmlProperty::~QQmlProperty()
129 Creates a QQmlProperty for the default property of \a obj. If there is no
130 default property, an invalid QQmlProperty will be created.
132 QQmlProperty::QQmlProperty(QObject *obj)
133 : d(new QQmlPropertyPrivate)
139 Creates a QQmlProperty for the default property of \a obj
140 using the \l{QQmlContext} {context} \a ctxt. If there is
141 no default property, an invalid QQmlProperty will be
144 QQmlProperty::QQmlProperty(QObject *obj, QQmlContext *ctxt)
145 : d(new QQmlPropertyPrivate)
147 d->context = ctxt?QQmlContextData::get(ctxt):0;
148 d->engine = ctxt?ctxt->engine():0;
153 Creates a QQmlProperty for the default property of \a obj
154 using the environment for instantiating QML components that is
155 provided by \a engine. If there is no default property, an
156 invalid QQmlProperty will be created.
158 QQmlProperty::QQmlProperty(QObject *obj, QQmlEngine *engine)
159 : d(new QQmlPropertyPrivate)
167 Initialize from the default property of \a obj
169 void QQmlPropertyPrivate::initDefault(QObject *obj)
174 QMetaProperty p = QQmlMetaType::defaultProperty(obj);
181 Creates a QQmlProperty for the property \a name of \a obj.
183 QQmlProperty::QQmlProperty(QObject *obj, const QString &name)
184 : d(new QQmlPropertyPrivate)
186 d->initProperty(obj, name);
187 if (!isValid()) d->object = 0;
191 Creates a QQmlProperty for the property \a name of \a obj
192 using the \l{QQmlContext} {context} \a ctxt.
194 Creating a QQmlProperty without a context will render some
195 properties - like attached properties - inaccessible.
197 QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlContext *ctxt)
198 : d(new QQmlPropertyPrivate)
200 d->context = ctxt?QQmlContextData::get(ctxt):0;
201 d->engine = ctxt?ctxt->engine():0;
202 d->initProperty(obj, name);
203 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
207 Creates a QQmlProperty for the property \a name of \a obj
208 using the environment for instantiating QML components that is
209 provided by \a engine.
211 QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlEngine *engine)
212 : d(new QQmlPropertyPrivate)
216 d->initProperty(obj, name);
217 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
220 Q_GLOBAL_STATIC(QQmlValueTypeFactory, qmlValueTypes);
222 QQmlPropertyPrivate::QQmlPropertyPrivate()
223 : context(0), engine(0), object(0), isNameCached(false)
227 QQmlContextData *QQmlPropertyPrivate::effectiveContext() const
229 if (context) return context;
230 else if (engine) return QQmlContextData::get(engine->rootContext());
234 void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
238 QQmlTypeNameCache *typeNameCache = context?context->imports:0;
240 QStringList path = name.split(QLatin1Char('.'));
241 if (path.isEmpty()) return;
243 QObject *currentObject = obj;
245 // Everything up to the last property must be an "object type" property
246 for (int ii = 0; ii < path.count() - 1; ++ii) {
247 const QString &pathName = path.at(ii);
250 QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
253 QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
254 if (!func) return; // Not an attachable type
256 currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
257 if (!currentObject) return; // Something is broken with the attachable type
258 } else if (r.importNamespace) {
259 if ((ii + 1) == path.count()) return; // No type following the namespace
261 ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
262 if (!r.type) return; // Invalid type in namespace
264 QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
265 if (!func) return; // Not an attachable type
267 currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
268 if (!currentObject) return; // Something is broken with the attachable type
270 } else if (r.scriptIndex != -1) {
271 return; // Not a type
273 Q_ASSERT(!"Unreachable");
280 QQmlPropertyData local;
281 QQmlPropertyData *property =
282 QQmlPropertyCache::property(engine, obj, pathName, local);
284 if (!property) return; // Not a property
285 if (property->isFunction())
286 return; // Not an object property
288 if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType)) {
289 // We're now at a value type property. We can use a global valuetypes array as we
290 // never actually use the objects, just look up their properties.
291 QObject *typeObject = (*qmlValueTypes())[property->propType];
292 if (!typeObject) return; // Not a value type
294 int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
295 if (idx == -1) return; // Value type property does not exist
297 QMetaProperty vtProp = typeObject->metaObject()->property(idx);
299 typedef QQmlPropertyData PCD;
301 Q_ASSERT(PCD::flagsForProperty(vtProp) <= PCD::ValueTypeFlagMask);
302 Q_ASSERT(vtProp.userType() <= 0xFF);
303 Q_ASSERT(idx <= 0xFF);
305 object = currentObject;
307 core.setFlags(core.getFlags() | PCD::IsValueTypeVirtual);
308 core.valueTypeFlags = PCD::flagsForProperty(vtProp);
309 core.valueTypePropType = vtProp.userType();
310 core.valueTypeCoreIndex = idx;
314 if (!property->isQObject())
315 return; // Not an object property
317 void *args[] = { ¤tObject, 0 };
318 QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
319 if (!currentObject) return; // No value
325 const QString &terminal = path.last();
327 if (terminal.count() >= 3 &&
328 terminal.at(0) == QLatin1Char('o') &&
329 terminal.at(1) == QLatin1Char('n') &&
330 terminal.at(2).isUpper()) {
332 QString signalName = terminal.mid(2);
333 signalName[0] = signalName.at(0).toLower();
335 QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName.toLatin1().constData());
336 if (method.isValid()) {
337 object = currentObject;
344 QQmlPropertyData local;
345 QQmlPropertyData *property =
346 QQmlPropertyCache::property(engine, currentObject, terminal, local);
347 if (property && !property->isFunction()) {
348 object = currentObject;
350 nameCache = terminal;
356 Create a copy of \a other.
358 QQmlProperty::QQmlProperty(const QQmlProperty &other)
366 \enum QQmlProperty::PropertyTypeCategory
368 This enum specifies a category of QML property.
370 \value InvalidCategory The property is invalid, or is a signal property.
371 \value List The property is a QQmlListProperty list property
372 \value Object The property is a QObject derived type pointer
373 \value Normal The property is a normal value property.
377 \enum QQmlProperty::Type
379 This enum specifies a type of QML property.
381 \value Invalid The property is invalid.
382 \value Property The property is a regular Qt property.
383 \value SignalProperty The property is a signal property.
387 Returns the property category.
389 QQmlProperty::PropertyTypeCategory QQmlProperty::propertyTypeCategory() const
391 return d ? d->propertyTypeCategory() : InvalidCategory;
394 QQmlProperty::PropertyTypeCategory
395 QQmlPropertyPrivate::propertyTypeCategory() const
397 uint type = this->type();
400 return QQmlProperty::Normal;
401 } else if (type & QQmlProperty::Property) {
402 int type = propertyType();
403 if (type == QVariant::Invalid)
404 return QQmlProperty::InvalidCategory;
405 else if (QQmlValueTypeFactory::isValueType((uint)type))
406 return QQmlProperty::Normal;
407 else if (core.isQObject())
408 return QQmlProperty::Object;
409 else if (core.isQList())
410 return QQmlProperty::List;
412 return QQmlProperty::Normal;
414 return QQmlProperty::InvalidCategory;
419 Returns the type name of the property, or 0 if the property has no type
422 const char *QQmlProperty::propertyTypeName() const
426 if (d->isValueType()) {
428 QQmlEnginePrivate *ep = d->engine?QQmlEnginePrivate::get(d->engine):0;
429 QQmlValueType *valueType = 0;
430 if (ep) valueType = ep->valueTypes[d->core.propType];
431 else valueType = QQmlValueTypeFactory::valueType(d->core.propType);
434 const char *rv = valueType->metaObject()->property(d->core.valueTypeCoreIndex).typeName();
436 if (!ep) delete valueType;
439 } else if (d->object && type() & Property && d->core.isValid()) {
440 return d->object->metaObject()->property(d->core.coreIndex).typeName();
447 Returns true if \a other and this QQmlProperty represent the same
450 bool QQmlProperty::operator==(const QQmlProperty &other) const
454 // category is intentially omitted here as it is generated
455 // from the other members
456 return d->object == other.d->object &&
457 d->core.coreIndex == other.d->core.coreIndex &&
458 d->core.isValueTypeVirtual() == other.d->core.isValueTypeVirtual() &&
459 (!d->core.isValueTypeVirtual() ||
460 (d->core.valueTypeCoreIndex == other.d->core.valueTypeCoreIndex &&
461 d->core.valueTypePropType == other.d->core.valueTypePropType));
465 Returns the QVariant type of the property, or QVariant::Invalid if the
466 property has no QVariant type.
468 int QQmlProperty::propertyType() const
470 return d ? d->propertyType() : int(QVariant::Invalid);
473 bool QQmlPropertyPrivate::isValueType() const
475 return core.isValueTypeVirtual();
478 int QQmlPropertyPrivate::propertyType() const
480 uint type = this->type();
482 return core.valueTypePropType;
483 } else if (type & QQmlProperty::Property) {
484 return core.propType;
486 return QVariant::Invalid;
490 QQmlProperty::Type QQmlPropertyPrivate::type() const
492 if (core.isFunction())
493 return QQmlProperty::SignalProperty;
494 else if (core.isValid())
495 return QQmlProperty::Property;
497 return QQmlProperty::Invalid;
501 Returns the type of the property.
503 QQmlProperty::Type QQmlProperty::type() const
505 return d ? d->type() : Invalid;
509 Returns true if this QQmlProperty represents a regular Qt property.
511 bool QQmlProperty::isProperty() const
513 return type() & Property;
517 Returns true if this QQmlProperty represents a QML signal property.
519 bool QQmlProperty::isSignalProperty() const
521 return type() & SignalProperty;
525 Returns the QQmlProperty's QObject.
527 QObject *QQmlProperty::object() const
529 return d ? d->object : 0;
533 Assign \a other to this QQmlProperty.
535 QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other)
547 Returns true if the property is writable, otherwise false.
549 bool QQmlProperty::isWritable() const
555 if (d->core.isQList()) //list
557 else if (d->core.isFunction()) //signal handler
559 else if (d->core.isValid()) //normal property
560 return d->core.isWritable();
566 Returns true if the property is designable, otherwise false.
568 bool QQmlProperty::isDesignable() const
572 if (type() & Property && d->core.isValid() && d->object)
573 return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
579 Returns true if the property is resettable, otherwise false.
581 bool QQmlProperty::isResettable() const
585 if (type() & Property && d->core.isValid() && d->object)
586 return d->core.isResettable();
592 Returns true if the QQmlProperty refers to a valid property, otherwise
595 bool QQmlProperty::isValid() const
599 return type() != Invalid;
603 Return the name of this QML property.
605 QString QQmlProperty::name() const
609 if (!d->isNameCached) {
612 } else if (d->isValueType()) {
613 QString rv = d->core.name(d->object) + QLatin1Char('.');
615 QQmlEnginePrivate *ep = d->engine?QQmlEnginePrivate::get(d->engine):0;
616 QQmlValueType *valueType = 0;
617 if (ep) valueType = ep->valueTypes[d->core.propType];
618 else valueType = QQmlValueTypeFactory::valueType(d->core.propType);
621 const char *vtName = valueType->metaObject()->property(d->core.valueTypeCoreIndex).name();
622 rv += QString::fromUtf8(vtName);
624 if (!ep) delete valueType;
627 } else if (type() & SignalProperty) {
628 QString name = QLatin1String("on") + d->core.name(d->object);
629 name[2] = name.at(2).toUpper();
632 d->nameCache = d->core.name(d->object);
634 d->isNameCached = true;
641 Returns the \l{QMetaProperty} {Qt property} associated with
644 QMetaProperty QQmlProperty::property() const
647 return QMetaProperty();
648 if (type() & Property && d->core.isValid() && d->object)
649 return d->object->metaObject()->property(d->core.coreIndex);
651 return QMetaProperty();
655 Return the QMetaMethod for this property if it is a SignalProperty,
656 otherwise returns an invalid QMetaMethod.
658 QMetaMethod QQmlProperty::method() const
661 return QMetaMethod();
662 if (type() & SignalProperty && d->object)
663 return d->object->metaObject()->method(d->core.coreIndex);
665 return QMetaMethod();
669 Returns the binding associated with this property, or 0 if no binding
672 QQmlAbstractBinding *
673 QQmlPropertyPrivate::binding(const QQmlProperty &that)
675 if (!that.d || !that.isProperty() || !that.d->object)
678 return binding(that.d->object, that.d->core.coreIndex,
679 that.d->core.getValueTypeCoreIndex());
683 Set the binding associated with this property to \a newBinding. Returns
684 the existing binding (if any), otherwise 0.
686 \a newBinding will be enabled, and the returned binding (if any) will be
689 Ownership of \a newBinding transfers to QML. Ownership of the return value
690 is assumed by the caller.
692 \a flags is passed through to the binding and is used for the initial update (when
693 the binding sets the initial value, it will use these flags for the write).
695 QQmlAbstractBinding *
696 QQmlPropertyPrivate::setBinding(const QQmlProperty &that,
697 QQmlAbstractBinding *newBinding,
700 if (!that.d || !that.isProperty() || !that.d->object) {
702 newBinding->destroy();
707 // In the case that the new binding is provided, we must target the property it
708 // is associated with. If we don't do this, retargetBinding() can fail.
709 QObject *object = newBinding->object();
710 int pi = newBinding->propertyIndex();
712 int core = pi & 0xFFFFFF;
713 int vt = (pi & 0xFF000000)?(pi >> 24):-1;
715 return setBinding(object, core, vt, newBinding, flags);
717 return setBinding(that.d->object, that.d->core.coreIndex,
718 that.d->core.getValueTypeCoreIndex(),
723 QQmlAbstractBinding *
724 QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
726 QQmlData *data = QQmlData::get(object);
730 QQmlPropertyData *propertyData =
731 data->propertyCache?data->propertyCache->property(coreIndex):0;
732 if (propertyData && propertyData->isAlias()) {
733 const QQmlVMEMetaObject *vme =
734 static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
736 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
737 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
740 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
741 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
742 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
743 return binding(aObject, aCoreIndex, aValueTypeIndex);
746 if (!data->hasBindingBit(coreIndex))
749 QQmlAbstractBinding *binding = data->bindings;
750 while (binding && binding->propertyIndex() != coreIndex)
751 binding = binding->m_nextBinding;
753 if (binding && valueTypeIndex != -1) {
754 if (binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) {
755 int index = coreIndex | (valueTypeIndex << 24);
756 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
763 void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
764 QObject **targetObject, int *targetBindingIndex)
766 int coreIndex = bindingIndex & 0xFFFFFF;
767 int valueTypeIndex = bindingIndex >> 24;
768 if (valueTypeIndex == 0) valueTypeIndex = -1;
770 QQmlData *data = QQmlData::get(object, false);
772 QQmlPropertyData *propertyData =
773 data->propertyCache?data->propertyCache->property(coreIndex):0;
774 if (propertyData && propertyData->isAlias()) {
775 const QQmlVMEMetaObject *vme =
776 static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
777 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
778 if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
779 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
780 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
782 int aBindingIndex = aCoreIndex;
783 if (aValueTypeIndex != -1)
784 aBindingIndex |= aValueTypeIndex << 24;
785 else if (valueTypeIndex != -1)
786 aBindingIndex |= valueTypeIndex << 24;
788 findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
794 *targetObject = object;
795 *targetBindingIndex = bindingIndex;
798 QQmlAbstractBinding *
799 QQmlPropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
800 QQmlAbstractBinding *newBinding, WriteFlags flags)
802 QQmlData *data = QQmlData::get(object, 0 != newBinding);
803 QQmlAbstractBinding *binding = 0;
806 QQmlPropertyData *propertyData =
807 data->propertyCache?data->propertyCache->property(coreIndex):0;
808 if (propertyData && propertyData->isAlias()) {
809 const QQmlVMEMetaObject *vme =
810 static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
812 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
813 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
814 if (newBinding) newBinding->destroy();
818 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
819 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
820 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
821 return setBinding(aObject, aCoreIndex, aValueTypeIndex, newBinding, flags);
825 if (data && data->hasBindingBit(coreIndex)) {
826 binding = data->bindings;
828 while (binding && binding->propertyIndex() != coreIndex)
829 binding = binding->m_nextBinding;
832 int index = coreIndex;
833 if (valueTypeIndex != -1)
834 index |= (valueTypeIndex << 24);
836 if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
837 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
840 binding->removeFromObject();
841 binding->setEnabled(false, 0);
845 if (newBinding->propertyIndex() != index || newBinding->object() != object)
846 newBinding->retargetBinding(object, index);
848 Q_ASSERT(newBinding->propertyIndex() == index);
849 Q_ASSERT(newBinding->object() == object);
851 newBinding->addToObject();
852 newBinding->setEnabled(true, flags);
858 QQmlAbstractBinding *
859 QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
860 QQmlAbstractBinding *newBinding)
862 QQmlData *data = QQmlData::get(object, 0 != newBinding);
863 QQmlAbstractBinding *binding = 0;
866 QQmlPropertyData *propertyData =
867 data->propertyCache?data->propertyCache->property(coreIndex):0;
868 if (propertyData && propertyData->isAlias()) {
869 const QQmlVMEMetaObject *vme =
870 static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
872 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
873 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
874 if (newBinding) newBinding->destroy();
878 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
879 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
880 aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
881 return setBindingNoEnable(aObject, aCoreIndex, aValueTypeIndex, newBinding);
885 if (data && data->hasBindingBit(coreIndex)) {
886 binding = data->bindings;
888 while (binding && binding->propertyIndex() != coreIndex)
889 binding = binding->m_nextBinding;
892 int index = coreIndex;
893 if (valueTypeIndex != -1)
894 index |= (valueTypeIndex << 24);
896 if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
897 binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
900 binding->removeFromObject();
903 if (newBinding->propertyIndex() != index || newBinding->object() != object)
904 newBinding->retargetBinding(object, index);
906 Q_ASSERT(newBinding->propertyIndex() == index);
907 Q_ASSERT(newBinding->object() == object);
909 newBinding->addToObject();
916 Returns the expression associated with this signal property, or 0 if no
917 signal expression exists.
920 QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
922 if (!(that.type() & QQmlProperty::SignalProperty))
925 const QObjectList &children = that.d->object->children();
927 for (int ii = 0; ii < children.count(); ++ii) {
928 QObject *child = children.at(ii);
930 QQmlBoundSignal *signal = QQmlBoundSignal::cast(child);
931 if (signal && signal->index() == that.index())
932 return signal->expression();
939 Set the signal expression associated with this signal property to \a expr.
940 Returns the existing signal expression (if any), otherwise 0.
942 Ownership of \a expr transfers to QML. Ownership of the return value is
943 assumed by the caller.
946 QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that,
947 QQmlExpression *expr)
949 if (!(that.type() & QQmlProperty::SignalProperty)) {
954 const QObjectList &children = that.d->object->children();
956 for (int ii = 0; ii < children.count(); ++ii) {
957 QObject *child = children.at(ii);
959 QQmlBoundSignal *signal = QQmlBoundSignal::cast(child);
960 if (signal && signal->index() == that.index())
961 return signal->setExpression(expr);
965 QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, that.method(), that.d->object);
966 return signal->setExpression(expr);
973 Returns the property value.
975 QVariant QQmlProperty::read() const
982 if (type() & SignalProperty) {
986 } else if (type() & Property) {
988 return d->readValueProperty();
995 Return the \a name property value of \a object. This method is equivalent to:
997 QQmlProperty p(object, name);
1001 QVariant QQmlProperty::read(QObject *object, const QString &name)
1003 QQmlProperty p(object, name);
1008 Return the \a name property value of \a object using the
1009 \l{QQmlContext} {context} \a ctxt. This method is
1013 QQmlProperty p(object, name, context);
1017 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlContext *ctxt)
1019 QQmlProperty p(object, name, ctxt);
1025 Return the \a name property value of \a object using the environment
1026 for instantiating QML components that is provided by \a engine. .
1027 This method is equivalent to:
1030 QQmlProperty p(object, name, engine);
1034 QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlEngine *engine)
1036 QQmlProperty p(object, name, engine);
1040 QVariant QQmlPropertyPrivate::readValueProperty()
1042 if (isValueType()) {
1044 QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
1045 QQmlValueType *valueType = 0;
1046 if (ep) valueType = ep->valueTypes[core.propType];
1047 else valueType = QQmlValueTypeFactory::valueType(core.propType);
1048 Q_ASSERT(valueType);
1050 valueType->read(object, core.coreIndex);
1052 QVariant rv = valueType->metaObject()->property(core.valueTypeCoreIndex).read(valueType);
1054 if (!ep) delete valueType;
1057 } else if (core.isQList()) {
1059 QQmlListProperty<QObject> prop;
1060 void *args[] = { &prop, 0 };
1061 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1062 return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType, engine));
1064 } else if (core.isQObject()) {
1067 void *args[] = { &rv, 0 };
1068 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1069 return QVariant::fromValue(rv);
1073 return object->metaObject()->property(core.coreIndex).read(object.data());
1078 static QUrl urlFromUserString(const QByteArray &data)
1081 if (!data.isEmpty())
1083 // Preserve any valid percent-encoded octets supplied by the source
1084 u.setEncodedUrl(data, QUrl::TolerantMode);
1089 static QUrl urlFromUserString(const QString &data)
1091 return urlFromUserString(data.toUtf8());
1094 // helper function to allow assignment / binding to QList<QUrl> properties.
1095 static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context)
1098 if (value.userType() == qMetaTypeId<QUrl>()) {
1099 urls.append(value.toUrl());
1100 } else if (value.userType() == qMetaTypeId<QString>()) {
1101 urls.append(urlFromUserString(value.toString()));
1102 } else if (value.userType() == qMetaTypeId<QByteArray>()) {
1103 urls.append(urlFromUserString(value.toByteArray()));
1104 } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
1105 urls = value.value<QList<QUrl> >();
1106 } else if (value.userType() == qMetaTypeId<QStringList>()) {
1107 QStringList urlStrings = value.value<QStringList>();
1108 for (int i = 0; i < urlStrings.size(); ++i)
1109 urls.append(urlFromUserString(urlStrings.at(i)));
1110 } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
1111 QList<QString> urlStrings = value.value<QList<QString> >();
1112 for (int i = 0; i < urlStrings.size(); ++i)
1113 urls.append(urlFromUserString(urlStrings.at(i)));
1114 } // note: QList<QByteArray> is not currently supported.
1116 QList<QUrl> resolvedUrls;
1117 for (int i = 0; i < urls.size(); ++i) {
1118 QUrl u = urls.at(i);
1119 if (context && u.isRelative() && !u.isEmpty())
1120 u = context->resolvedUrl(u);
1121 resolvedUrls.append(u);
1124 return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
1127 //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1128 bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1130 if (!object || !prop.isWritable())
1134 if (prop.isEnumType()) {
1135 QMetaEnum menum = prop.enumerator();
1136 if (v.userType() == QVariant::String
1138 || v.userType() == QVariant::CString
1142 if (prop.isFlagType())
1143 v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
1145 v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
1148 } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
1149 int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
1150 if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData())
1152 v = QVariant(*reinterpret_cast<const int *>(v.constData()));
1154 v.convert(QVariant::Int);
1157 // the status variable is changed by qt_metacall to indicate what it did
1158 // this feature is currently only used by QtDBus and should not be depended
1159 // upon. Don't change it without looking into QDBusAbstractInterface first
1160 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1161 // changed: result stored directly in value, return the value of status
1163 void *argv[] = { v.data(), &v, &status, &flags };
1164 QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
1168 bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
1170 return writeValueProperty(object, engine, core, value, effectiveContext(), flags);
1174 QQmlPropertyPrivate::writeValueProperty(QObject *object, QQmlEngine *engine,
1175 const QQmlPropertyData &core,
1176 const QVariant &value,
1177 QQmlContextData *context, WriteFlags flags)
1179 // Remove any existing bindings on this property
1180 if (!(flags & DontRemoveBinding) && object) {
1181 QQmlAbstractBinding *binding = setBinding(object, core.coreIndex,
1182 core.getValueTypeCoreIndex(),
1184 if (binding) binding->destroy();
1188 if (core.isValueTypeVirtual()) {
1189 QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
1191 QQmlValueType *writeBack = 0;
1193 writeBack = ep->valueTypes[core.propType];
1195 writeBack = QQmlValueTypeFactory::valueType(core.propType);
1198 writeBack->read(object, core.coreIndex);
1200 QQmlPropertyData data = core;
1201 data.setFlags(QQmlPropertyData::Flag(core.valueTypeFlags));
1202 data.coreIndex = core.valueTypeCoreIndex;
1203 data.propType = core.valueTypePropType;
1205 rv = write(writeBack, data, value, context, flags);
1207 writeBack->write(object, core.coreIndex, flags);
1208 if (!ep) delete writeBack;
1212 rv = write(object, core, value, context, flags);
1219 bool QQmlPropertyPrivate::write(QObject *object,
1220 const QQmlPropertyData &property,
1221 const QVariant &value, QQmlContextData *context,
1224 int coreIdx = property.coreIndex;
1225 int status = -1; //for dbus
1227 if (property.isEnum()) {
1228 QMetaProperty prop = object->metaObject()->property(property.coreIndex);
1230 // Enum values come through the script engine as doubles
1231 if (value.userType() == QVariant::Double) {
1233 double fractional = modf(value.toDouble(), &integral);
1234 if (qFuzzyIsNull(fractional))
1235 v.convert(QVariant::Int);
1237 return writeEnumProperty(prop, coreIdx, object, v, flags);
1240 int propertyType = property.propType;
1241 int variantType = value.userType();
1243 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
1245 if (propertyType == QVariant::Url) {
1249 if (variantType == QVariant::Url) {
1252 } else if (variantType == QVariant::ByteArray) {
1253 u = urlFromUserString(value.toByteArray());
1255 } else if (variantType == QVariant::String) {
1256 u = urlFromUserString(value.toString());
1263 if (context && u.isRelative() && !u.isEmpty())
1264 u = context->resolvedUrl(u);
1266 void *argv[] = { &u, 0, &status, &flags };
1267 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1269 } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
1270 QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
1272 void *argv[] = { &urlSeq, 0, &status, &flags };
1273 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1274 } else if (variantType == propertyType) {
1276 void *a[] = { (void *)value.constData(), 0, &status, &flags };
1277 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1279 } else if (qMetaTypeId<QVariant>() == propertyType) {
1281 void *a[] = { (void *)&value, 0, &status, &flags };
1282 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1284 } else if (property.isQObject()) {
1286 const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType());
1291 QObject *o = *(QObject **)value.constData();
1292 const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType);
1294 if (o) valMo = o->metaObject();
1296 if (canConvert(valMo, propMo)) {
1297 void *args[] = { &o, 0, &status, &flags };
1298 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
1300 } else if (!o && canConvert(propMo, valMo)) {
1301 // In the case of a null QObject, we assign the null if there is
1302 // any change that the null variant type could be up or down cast to
1303 // the property type.
1304 void *args[] = { &o, 0, &status, &flags };
1305 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
1311 } else if (property.isQList()) {
1313 const QMetaObject *listType = 0;
1315 listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
1317 QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType));
1318 if (!type) return false;
1319 listType = type->baseMetaObject();
1321 if (!listType) return false;
1323 QQmlListProperty<void> prop;
1324 void *args[] = { &prop, 0 };
1325 QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
1327 if (!prop.clear) return false;
1331 if (value.userType() == qMetaTypeId<QQmlListReference>()) {
1332 QQmlListReference qdlr = value.value<QQmlListReference>();
1334 for (int ii = 0; ii < qdlr.count(); ++ii) {
1335 QObject *o = qdlr.at(ii);
1336 if (o && !canConvert(o->metaObject(), listType))
1338 prop.append(&prop, (void *)o);
1340 } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
1341 const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1343 for (int ii = 0; ii < list.count(); ++ii) {
1344 QObject *o = list.at(ii);
1345 if (o && !canConvert(o->metaObject(), listType))
1347 prop.append(&prop, (void *)o);
1350 QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value);
1351 if (o && !canConvert(o->metaObject(), listType))
1353 prop.append(&prop, (void *)o);
1357 Q_ASSERT(variantType != propertyType);
1361 if (variantType == QVariant::String)
1362 v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
1365 if (v.convert((QVariant::Type)propertyType)) {
1367 } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
1368 QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
1370 v = con(value.toString());
1371 if (v.userType() == propertyType)
1377 // the only other option is that they are assigning a single value
1378 // to a sequence type property (eg, an int to a QList<int> property).
1379 // Note that we've already handled single-value assignment to QList<QUrl> properties.
1380 if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
1382 list << value.toInt();
1383 v = QVariant::fromValue<QList<int> >(list);
1385 } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
1387 list << value.toReal();
1388 v = QVariant::fromValue<QList<qreal> >(list);
1390 } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
1392 list << value.toBool();
1393 v = QVariant::fromValue<QList<bool> >(list);
1395 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
1396 QList<QString> list;
1397 list << value.toString();
1398 v = QVariant::fromValue<QList<QString> >(list);
1400 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
1402 list << value.toString();
1403 v = QVariant::fromValue<QStringList>(list);
1409 void *a[] = { (void *)v.constData(), 0, &status, &flags};
1410 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1419 // Returns true if successful, false if an error description was set on expression
1420 bool QQmlPropertyPrivate::writeBinding(QObject *object,
1421 const QQmlPropertyData &core,
1422 QQmlContextData *context,
1423 QQmlJavaScriptExpression *expression,
1424 v8::Handle<v8::Value> result, bool isUndefined,
1428 Q_ASSERT(core.coreIndex != -1);
1430 QQmlEngine *engine = context->engine;
1431 QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
1433 #define QUICK_STORE(cpptype, conversion) \
1435 cpptype o = (conversion); \
1437 void *argv[] = { &o, 0, &status, &flags }; \
1438 QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \
1443 if (!isUndefined && !core.isValueTypeVirtual()) {
1444 switch (core.propType) {
1445 case QMetaType::Int:
1446 if (result->IsInt32())
1447 QUICK_STORE(int, result->Int32Value())
1448 else if (result->IsNumber())
1449 QUICK_STORE(int, qRound(result->NumberValue()))
1451 case QMetaType::Double:
1452 if (result->IsNumber())
1453 QUICK_STORE(double, result->NumberValue())
1455 case QMetaType::Float:
1456 if (result->IsNumber())
1457 QUICK_STORE(float, result->NumberValue())
1459 case QMetaType::QString:
1460 if (result->IsString())
1461 QUICK_STORE(QString, v8engine->toString(result))
1469 int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType;
1471 QQmlJavaScriptExpression::DeleteWatcher watcher(expression);
1474 bool isVmeProperty = core.isVMEProperty();
1477 } else if (core.isQList()) {
1478 value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
1479 } else if (result->IsNull() && core.isQObject()) {
1480 value = QVariant::fromValue((QObject *)0);
1481 } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
1482 value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
1483 } else if (!isVmeProperty) {
1484 value = v8engine->toVariant(result, type);
1487 if (expression->hasError()) {
1489 } else if (isVmeProperty) {
1490 typedef QQmlVMEMetaObject VMEMO;
1491 if (!result.IsEmpty() && result->IsFunction()
1492 && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
1493 // we explicitly disallow this case to avoid confusion. Users can still store one
1494 // in an array in a var property if they need to, but the common case is user error.
1495 expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1498 VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject()));
1499 vmemo->setVMEProperty(core.coreIndex, result);
1500 } else if (isUndefined && core.isResettable()) {
1501 void *args[] = { 0 };
1502 QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
1503 } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
1504 writeValueProperty(object, engine, core, QVariant(), context, flags);
1505 } else if (isUndefined) {
1506 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(type)));
1508 } else if (result->IsFunction()) {
1509 if (!result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty())
1510 expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
1512 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
1514 } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
1516 if (watcher.wasDeleted())
1519 const char *valueType = 0;
1520 if (value.userType() == QVariant::Invalid) valueType = "null";
1521 else valueType = QMetaType::typeName(value.userType());
1523 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign ") +
1524 QLatin1String(valueType) +
1525 QLatin1String(" to ") +
1526 QLatin1String(QMetaType::typeName(type)));
1533 bool QQmlPropertyPrivate::writeBinding(const QQmlProperty &that,
1534 QQmlContextData *context,
1535 QQmlJavaScriptExpression *expression,
1536 v8::Handle<v8::Value> result, bool isUndefined,
1539 QQmlPropertyPrivate *pp = that.d;
1544 QObject *object = that.object();
1548 return writeBinding(object, pp->core, context, expression, result, isUndefined, flags);
1551 const QMetaObject *QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
1554 return engine->rawMetaObjectForType(userType);
1556 QQmlType *type = QQmlMetaType::qmlType(userType);
1557 return type?type->baseMetaObject():0;
1562 Sets the property value to \a value and returns true.
1563 Returns false if the property can't be set because the
1564 \a value is the wrong type, for example.
1566 bool QQmlProperty::write(const QVariant &value) const
1568 return QQmlPropertyPrivate::write(*this, value, 0);
1572 Writes \a value to the \a name property of \a object. This method
1576 QQmlProperty p(object, name);
1580 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
1582 QQmlProperty p(object, name);
1583 return p.write(value);
1587 Writes \a value to the \a name property of \a object using the
1588 \l{QQmlContext} {context} \a ctxt. This method is
1592 QQmlProperty p(object, name, ctxt);
1596 bool QQmlProperty::write(QObject *object,
1597 const QString &name,
1598 const QVariant &value,
1601 QQmlProperty p(object, name, ctxt);
1602 return p.write(value);
1607 Writes \a value to the \a name property of \a object using the
1608 environment for instantiating QML components that is provided by
1609 \a engine. This method is equivalent to:
1612 QQmlProperty p(object, name, engine);
1616 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
1619 QQmlProperty p(object, name, engine);
1620 return p.write(value);
1624 Resets the property and returns true if the property is
1625 resettable. If the property is not resettable, nothing happens
1626 and false is returned.
1628 bool QQmlProperty::reset() const
1630 if (isResettable()) {
1631 void *args[] = { 0 };
1632 QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1639 bool QQmlPropertyPrivate::write(const QQmlProperty &that,
1640 const QVariant &value, WriteFlags flags)
1644 if (that.d->object && that.type() & QQmlProperty::Property &&
1645 that.d->core.isValid() && that.isWritable())
1646 return that.d->writeValueProperty(value, flags);
1652 Returns true if the property has a change notifier signal, otherwise false.
1654 bool QQmlProperty::hasNotifySignal() const
1656 if (type() & Property && d->object) {
1657 return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1663 Returns true if the property needs a change notifier signal for bindings
1664 to remain upto date, false otherwise.
1666 Some properties, such as attached properties or those whose value never
1667 changes, do not require a change notifier.
1669 bool QQmlProperty::needsNotifySignal() const
1671 return type() & Property && !property().isConstant();
1675 Connects the property's change notifier signal to the
1676 specified \a method of the \a dest object and returns
1677 true. Returns false if this metaproperty does not
1678 represent a regular Qt property or if it has no
1679 change notifier signal, or if the \a dest object does
1680 not have the specified \a method.
1682 bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
1684 if (!(type() & Property) || !d->object)
1687 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1688 if (prop.hasNotifySignal()) {
1689 return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1696 Connects the property's change notifier signal to the
1697 specified \a slot of the \a dest object and returns
1698 true. Returns false if this metaproperty does not
1699 represent a regular Qt property or if it has no
1700 change notifier signal, or if the \a dest object does
1701 not have the specified \a slot.
1703 bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
1705 if (!(type() & Property) || !d->object)
1708 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1709 if (prop.hasNotifySignal()) {
1710 QByteArray signal(QByteArray("2") + prop.notifySignal().methodSignature());
1711 return QObject::connect(d->object, signal.constData(), dest, slot);
1718 Return the Qt metaobject index of the property.
1720 int QQmlProperty::index() const
1722 return d ? d->core.coreIndex : -1;
1725 int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that)
1727 return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
1731 Returns the "property index" for use in bindings. The top 8 bits are the value type
1732 offset, and 0 otherwise. The bottom 24-bits are the regular property index.
1734 int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that)
1738 return bindingIndex(that.d->core);
1741 int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that)
1743 int rv = that.coreIndex;
1744 if (rv != -1 && that.isValueTypeVirtual())
1745 rv = rv | (that.valueTypeCoreIndex << 24);
1750 QQmlPropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
1751 const QMetaObject *subObject, int subIndex,
1754 QMetaProperty subProp = subObject->property(subIndex);
1756 QQmlPropertyData core;
1757 core.load(metaObject->property(index));
1758 core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
1759 core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp);
1760 core.valueTypeCoreIndex = subIndex;
1761 core.valueTypePropType = subProp.userType();
1767 QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
1768 QQmlContextData *ctxt)
1772 prop.d = new QQmlPropertyPrivate;
1773 prop.d->object = object;
1774 prop.d->context = ctxt;
1775 prop.d->engine = ctxt?ctxt->engine:0;
1777 prop.d->core = data;
1783 Returns true if lhs and rhs refer to the same metaobject data
1785 bool QQmlPropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
1787 return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1791 Returns true if from inherits to.
1793 bool QQmlPropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
1795 if (from && to == &QObject::staticMetaObject)
1799 if (equal(from, to))
1801 from = from->superClass();
1808 Return the signal corresponding to \a name
1810 QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1813 int methods = mo->methodCount();
1814 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1815 QMetaMethod method = mo->method(ii);
1817 if (method.name() == name)
1821 // If no signal is found, but the signal is of the form "onBlahChanged",
1822 // return the notify signal for the property "Blah"
1823 if (name.endsWith("Changed")) {
1824 QByteArray propName = name.mid(0, name.length() - 7);
1825 int propIdx = mo->indexOfProperty(propName.constData());
1827 QMetaProperty prop = mo->property(propIdx);
1828 if (prop.hasNotifySignal())
1829 return prop.notifySignal();
1833 return QMetaMethod();
1836 static inline int QMetaObject_methods(const QMetaObject *metaObject)
1842 int classInfoCount, classInfoData;
1843 int methodCount, methodData;
1844 int propertyCount, propertyData;
1847 return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
1850 static inline int QMetaObject_properties(const QMetaObject *metaObject)
1856 int classInfoCount, classInfoData;
1857 int methodCount, methodData;
1858 int propertyCount, propertyData;
1861 return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
1864 static inline void flush_vme_signal(const QObject *object, int index)
1866 QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1867 if (data && data->propertyCache) {
1868 QQmlPropertyData *property = data->propertyCache->method(index);
1870 if (property && property->isVMESignal()) {
1871 const QMetaObject *metaObject = object->metaObject();
1872 int methodOffset = metaObject->methodOffset();
1874 while (methodOffset > index) {
1875 metaObject = metaObject->d.superdata;
1876 methodOffset -= QMetaObject_methods(metaObject);
1879 QQmlVMEMetaObject *vme =
1880 static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
1882 vme->connectAliasSignal(index);
1888 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1889 \a type and \a types. This behaves identically to QMetaObject::connect() except that
1890 it connects any lazy "proxy" signal connections set up by QML.
1892 It is possible that this logic should be moved to QMetaObject::connect().
1894 bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
1895 const QObject *receiver, int method_index,
1896 int type, int *types)
1898 flush_vme_signal(sender, signal_index);
1899 flush_vme_signal(receiver, method_index);
1901 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1904 void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
1906 flush_vme_signal(sender, signal_index);
1910 Return \a metaObject's [super] meta object that provides data for \a property.
1912 const QMetaObject *QQmlPropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
1914 int propertyOffset = metaObject->propertyOffset();
1916 while (propertyOffset > property) {
1917 metaObject = metaObject->d.superdata;
1918 propertyOffset -= QMetaObject_properties(metaObject);