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.signature()) {
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 (isUndefined && core.isResettable()) {
1490 void *args[] = { 0 };
1491 QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
1492 } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
1493 writeValueProperty(object, engine, core, QVariant(), context, flags);
1494 } else if (isUndefined) {
1495 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(type)));
1497 } else if (result->IsFunction()) {
1498 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign a function to a property."));
1500 } else if (isVmeProperty) {
1501 typedef QQmlVMEMetaObject VMEMO;
1502 VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject()));
1503 vmemo->setVMEProperty(core.coreIndex, result);
1504 } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
1506 if (watcher.wasDeleted())
1509 const char *valueType = 0;
1510 if (value.userType() == QVariant::Invalid) valueType = "null";
1511 else valueType = QMetaType::typeName(value.userType());
1513 expression->delayedError()->error.setDescription(QLatin1String("Unable to assign ") +
1514 QLatin1String(valueType) +
1515 QLatin1String(" to ") +
1516 QLatin1String(QMetaType::typeName(type)));
1523 bool QQmlPropertyPrivate::writeBinding(const QQmlProperty &that,
1524 QQmlContextData *context,
1525 QQmlJavaScriptExpression *expression,
1526 v8::Handle<v8::Value> result, bool isUndefined,
1529 QQmlPropertyPrivate *pp = that.d;
1534 QObject *object = that.object();
1538 return writeBinding(object, pp->core, context, expression, result, isUndefined, flags);
1541 const QMetaObject *QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
1544 return engine->rawMetaObjectForType(userType);
1546 QQmlType *type = QQmlMetaType::qmlType(userType);
1547 return type?type->baseMetaObject():0;
1552 Sets the property value to \a value and returns true.
1553 Returns false if the property can't be set because the
1554 \a value is the wrong type, for example.
1556 bool QQmlProperty::write(const QVariant &value) const
1558 return QQmlPropertyPrivate::write(*this, value, 0);
1562 Writes \a value to the \a name property of \a object. This method
1566 QQmlProperty p(object, name);
1570 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
1572 QQmlProperty p(object, name);
1573 return p.write(value);
1577 Writes \a value to the \a name property of \a object using the
1578 \l{QQmlContext} {context} \a ctxt. This method is
1582 QQmlProperty p(object, name, ctxt);
1586 bool QQmlProperty::write(QObject *object,
1587 const QString &name,
1588 const QVariant &value,
1591 QQmlProperty p(object, name, ctxt);
1592 return p.write(value);
1597 Writes \a value to the \a name property of \a object using the
1598 environment for instantiating QML components that is provided by
1599 \a engine. This method is equivalent to:
1602 QQmlProperty p(object, name, engine);
1606 bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
1609 QQmlProperty p(object, name, engine);
1610 return p.write(value);
1614 Resets the property and returns true if the property is
1615 resettable. If the property is not resettable, nothing happens
1616 and false is returned.
1618 bool QQmlProperty::reset() const
1620 if (isResettable()) {
1621 void *args[] = { 0 };
1622 QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1629 bool QQmlPropertyPrivate::write(const QQmlProperty &that,
1630 const QVariant &value, WriteFlags flags)
1634 if (that.d->object && that.type() & QQmlProperty::Property &&
1635 that.d->core.isValid() && that.isWritable())
1636 return that.d->writeValueProperty(value, flags);
1642 Returns true if the property has a change notifier signal, otherwise false.
1644 bool QQmlProperty::hasNotifySignal() const
1646 if (type() & Property && d->object) {
1647 return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1653 Returns true if the property needs a change notifier signal for bindings
1654 to remain upto date, false otherwise.
1656 Some properties, such as attached properties or those whose value never
1657 changes, do not require a change notifier.
1659 bool QQmlProperty::needsNotifySignal() const
1661 return type() & Property && !property().isConstant();
1665 Connects the property's change notifier signal to the
1666 specified \a method of the \a dest object and returns
1667 true. Returns false if this metaproperty does not
1668 represent a regular Qt property or if it has no
1669 change notifier signal, or if the \a dest object does
1670 not have the specified \a method.
1672 bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
1674 if (!(type() & Property) || !d->object)
1677 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1678 if (prop.hasNotifySignal()) {
1679 return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1686 Connects the property's change notifier signal to the
1687 specified \a slot of the \a dest object and returns
1688 true. Returns false if this metaproperty does not
1689 represent a regular Qt property or if it has no
1690 change notifier signal, or if the \a dest object does
1691 not have the specified \a slot.
1693 bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
1695 if (!(type() & Property) || !d->object)
1698 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1699 if (prop.hasNotifySignal()) {
1700 QByteArray signal(QByteArray("2") + prop.notifySignal().signature());
1701 return QObject::connect(d->object, signal.constData(), dest, slot);
1708 Return the Qt metaobject index of the property.
1710 int QQmlProperty::index() const
1712 return d ? d->core.coreIndex : -1;
1715 int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that)
1717 return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
1721 Returns the "property index" for use in bindings. The top 8 bits are the value type
1722 offset, and 0 otherwise. The bottom 24-bits are the regular property index.
1724 int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that)
1728 return bindingIndex(that.d->core);
1731 int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that)
1733 int rv = that.coreIndex;
1734 if (rv != -1 && that.isValueTypeVirtual())
1735 rv = rv | (that.valueTypeCoreIndex << 24);
1740 QQmlPropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
1741 const QMetaObject *subObject, int subIndex,
1744 QMetaProperty subProp = subObject->property(subIndex);
1746 QQmlPropertyData core;
1747 core.load(metaObject->property(index));
1748 core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
1749 core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp);
1750 core.valueTypeCoreIndex = subIndex;
1751 core.valueTypePropType = subProp.userType();
1757 QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
1758 QQmlContextData *ctxt)
1762 prop.d = new QQmlPropertyPrivate;
1763 prop.d->object = object;
1764 prop.d->context = ctxt;
1765 prop.d->engine = ctxt?ctxt->engine:0;
1767 prop.d->core = data;
1773 Returns true if lhs and rhs refer to the same metaobject data
1775 bool QQmlPropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
1777 return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1781 Returns true if from inherits to.
1783 bool QQmlPropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
1785 if (from && to == &QObject::staticMetaObject)
1789 if (equal(from, to))
1791 from = from->superClass();
1798 Return the signal corresponding to \a name
1800 QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1803 int methods = mo->methodCount();
1804 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1805 QMetaMethod method = mo->method(ii);
1806 QByteArray methodName = method.signature();
1807 int idx = methodName.indexOf('(');
1808 methodName = methodName.left(idx);
1810 if (methodName == name)
1814 // If no signal is found, but the signal is of the form "onBlahChanged",
1815 // return the notify signal for the property "Blah"
1816 if (name.endsWith("Changed")) {
1817 QByteArray propName = name.mid(0, name.length() - 7);
1818 int propIdx = mo->indexOfProperty(propName.constData());
1820 QMetaProperty prop = mo->property(propIdx);
1821 if (prop.hasNotifySignal())
1822 return prop.notifySignal();
1826 return QMetaMethod();
1829 static inline int QMetaObject_methods(const QMetaObject *metaObject)
1835 int classInfoCount, classInfoData;
1836 int methodCount, methodData;
1837 int propertyCount, propertyData;
1840 return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
1843 static inline int QMetaObject_properties(const QMetaObject *metaObject)
1849 int classInfoCount, classInfoData;
1850 int methodCount, methodData;
1851 int propertyCount, propertyData;
1854 return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
1857 static inline void flush_vme_signal(const QObject *object, int index)
1859 QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1860 if (data && data->propertyCache) {
1861 QQmlPropertyData *property = data->propertyCache->method(index);
1863 if (property && property->isVMESignal()) {
1864 const QMetaObject *metaObject = object->metaObject();
1865 int methodOffset = metaObject->methodOffset();
1867 while (methodOffset > index) {
1868 metaObject = metaObject->d.superdata;
1869 methodOffset -= QMetaObject_methods(metaObject);
1872 QQmlVMEMetaObject *vme =
1873 static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
1875 vme->connectAliasSignal(index);
1881 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1882 \a type and \a types. This behaves identically to QMetaObject::connect() except that
1883 it connects any lazy "proxy" signal connections set up by QML.
1885 It is possible that this logic should be moved to QMetaObject::connect().
1887 bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
1888 const QObject *receiver, int method_index,
1889 int type, int *types)
1891 flush_vme_signal(sender, signal_index);
1892 flush_vme_signal(receiver, method_index);
1894 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1897 void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
1899 flush_vme_signal(sender, signal_index);
1903 Return \a metaObject's [super] meta object that provides data for \a property.
1905 const QMetaObject *QQmlPropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
1907 int propertyOffset = metaObject->propertyOffset();
1909 while (propertyOffset > property) {
1910 metaObject = metaObject->d.superdata;
1911 propertyOffset -= QMetaObject_properties(metaObject);