1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdeclarativeproperty.h"
43 #include "qdeclarativeproperty_p.h"
45 #include "qdeclarative.h"
46 #include "qdeclarativebinding_p.h"
47 #include "qdeclarativecontext.h"
48 #include "qdeclarativecontext_p.h"
49 #include "qdeclarativeboundsignal_p.h"
50 #include "qdeclarativeengine.h"
51 #include "qdeclarativeengine_p.h"
52 #include "qdeclarativedata_p.h"
53 #include "qdeclarativestringconverters_p.h"
54 #include "qdeclarativelist_p.h"
55 #include "qdeclarativecompiler_p.h"
56 #include "qdeclarativevmemetaobject_p.h"
57 #include "qdeclarativeexpression_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>)
73 \class QDeclarativeProperty
75 \brief The QDeclarativeProperty 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 QDeclarativeProperty class
80 that simplifies some of their natural complexity.
82 Unlike QMetaProperty which represents a property on a class type, QDeclarativeProperty encapsulates
83 a property on a specific object instance. To read a property's value, programmers create a
84 QDeclarativeProperty 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 QDeclarativeProperty, like this:
99 #include <QDeclarativeProperty>
100 #include <QGraphicsObject>
104 QDeclarativeView view(QUrl::fromLocalFile("MyItem.qml"));
105 QDeclarativeProperty 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 QDeclarativeProperty.
115 QDeclarativeProperty::QDeclarativeProperty()
121 QDeclarativeProperty::~QDeclarativeProperty()
129 Creates a QDeclarativeProperty for the default property of \a obj. If there is no
130 default property, an invalid QDeclarativeProperty will be created.
132 QDeclarativeProperty::QDeclarativeProperty(QObject *obj)
133 : d(new QDeclarativePropertyPrivate)
139 Creates a QDeclarativeProperty for the default property of \a obj
140 using the \l{QDeclarativeContext} {context} \a ctxt. If there is
141 no default property, an invalid QDeclarativeProperty will be
144 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeContext *ctxt)
145 : d(new QDeclarativePropertyPrivate)
147 d->context = ctxt?QDeclarativeContextData::get(ctxt):0;
148 d->engine = ctxt?ctxt->engine():0;
153 Creates a QDeclarativeProperty 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 QDeclarativeProperty will be created.
158 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeEngine *engine)
159 : d(new QDeclarativePropertyPrivate)
167 Initialize from the default property of \a obj
169 void QDeclarativePropertyPrivate::initDefault(QObject *obj)
174 QMetaProperty p = QDeclarativeMetaType::defaultProperty(obj);
181 Creates a QDeclarativeProperty for the property \a name of \a obj.
183 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name)
184 : d(new QDeclarativePropertyPrivate)
186 d->initProperty(obj, name);
187 if (!isValid()) d->object = 0;
191 Creates a QDeclarativeProperty for the property \a name of \a obj
192 using the \l{QDeclarativeContext} {context} \a ctxt.
194 Creating a QDeclarativeProperty without a context will render some
195 properties - like attached properties - inaccessible.
197 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeContext *ctxt)
198 : d(new QDeclarativePropertyPrivate)
200 d->context = ctxt?QDeclarativeContextData::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 QDeclarativeProperty for the property \a name of \a obj
208 using the environment for instantiating QML components that is
209 provided by \a engine.
211 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeEngine *engine)
212 : d(new QDeclarativePropertyPrivate)
216 d->initProperty(obj, name);
217 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
220 Q_GLOBAL_STATIC(QDeclarativeValueTypeFactory, qmlValueTypes);
222 QDeclarativePropertyPrivate::QDeclarativePropertyPrivate()
223 : context(0), engine(0), object(0), isNameCached(false)
227 QDeclarativeContextData *QDeclarativePropertyPrivate::effectiveContext() const
229 if (context) return context;
230 else if (engine) return QDeclarativeContextData::get(engine->rootContext());
234 void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name)
238 QDeclarativeTypeNameCache *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 QDeclarativeTypeNameCache::Result r = typeNameCache->query(pathName);
253 QDeclarativeAttachedPropertiesFunc 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 QDeclarativeAttachedPropertiesFunc 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 QDeclarativePropertyData local;
281 QDeclarativePropertyData *property =
282 QDeclarativePropertyCache::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) && QDeclarativeValueTypeFactory::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 QDeclarativePropertyData 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 QDeclarativePropertyData local;
345 QDeclarativePropertyData *property =
346 QDeclarativePropertyCache::property(engine, currentObject, terminal, local);
347 if (property && !property->isFunction()) {
348 object = currentObject;
350 nameCache = terminal;
356 Create a copy of \a other.
358 QDeclarativeProperty::QDeclarativeProperty(const QDeclarativeProperty &other)
366 \enum QDeclarativeProperty::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 QDeclarativeListProperty 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 QDeclarativeProperty::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 QDeclarativeProperty::PropertyTypeCategory QDeclarativeProperty::propertyTypeCategory() const
391 return d ? d->propertyTypeCategory() : InvalidCategory;
394 QDeclarativeProperty::PropertyTypeCategory
395 QDeclarativePropertyPrivate::propertyTypeCategory() const
397 uint type = this->type();
400 return QDeclarativeProperty::Normal;
401 } else if (type & QDeclarativeProperty::Property) {
402 int type = propertyType();
403 if (type == QVariant::Invalid)
404 return QDeclarativeProperty::InvalidCategory;
405 else if (QDeclarativeValueTypeFactory::isValueType((uint)type))
406 return QDeclarativeProperty::Normal;
407 else if (core.isQObject())
408 return QDeclarativeProperty::Object;
409 else if (core.isQList())
410 return QDeclarativeProperty::List;
412 return QDeclarativeProperty::Normal;
414 return QDeclarativeProperty::InvalidCategory;
419 Returns the type name of the property, or 0 if the property has no type
422 const char *QDeclarativeProperty::propertyTypeName() const
426 if (d->isValueType()) {
428 QDeclarativeEnginePrivate *ep = d->engine?QDeclarativeEnginePrivate::get(d->engine):0;
429 QDeclarativeValueType *valueType = 0;
430 if (ep) valueType = ep->valueTypes[d->core.propType];
431 else valueType = QDeclarativeValueTypeFactory::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 QDeclarativeProperty represent the same
450 bool QDeclarativeProperty::operator==(const QDeclarativeProperty &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 QDeclarativeProperty::propertyType() const
470 return d ? d->propertyType() : int(QVariant::Invalid);
473 bool QDeclarativePropertyPrivate::isValueType() const
475 return core.isValueTypeVirtual();
478 int QDeclarativePropertyPrivate::propertyType() const
480 uint type = this->type();
482 return core.valueTypePropType;
483 } else if (type & QDeclarativeProperty::Property) {
484 return core.propType;
486 return QVariant::Invalid;
490 QDeclarativeProperty::Type QDeclarativePropertyPrivate::type() const
492 if (core.isFunction())
493 return QDeclarativeProperty::SignalProperty;
494 else if (core.isValid())
495 return QDeclarativeProperty::Property;
497 return QDeclarativeProperty::Invalid;
501 Returns the type of the property.
503 QDeclarativeProperty::Type QDeclarativeProperty::type() const
505 return d ? d->type() : Invalid;
509 Returns true if this QDeclarativeProperty represents a regular Qt property.
511 bool QDeclarativeProperty::isProperty() const
513 return type() & Property;
517 Returns true if this QDeclarativeProperty represents a QML signal property.
519 bool QDeclarativeProperty::isSignalProperty() const
521 return type() & SignalProperty;
525 Returns the QDeclarativeProperty's QObject.
527 QObject *QDeclarativeProperty::object() const
529 return d ? d->object : 0;
533 Assign \a other to this QDeclarativeProperty.
535 QDeclarativeProperty &QDeclarativeProperty::operator=(const QDeclarativeProperty &other)
547 Returns true if the property is writable, otherwise false.
549 bool QDeclarativeProperty::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 QDeclarativeProperty::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 QDeclarativeProperty::isResettable() const
585 if (type() & Property && d->core.isValid() && d->object)
586 return d->core.isResettable();
592 Returns true if the QDeclarativeProperty refers to a valid property, otherwise
595 bool QDeclarativeProperty::isValid() const
599 return type() != Invalid;
603 Return the name of this QML property.
605 QString QDeclarativeProperty::name() const
609 if (!d->isNameCached) {
612 } else if (d->isValueType()) {
613 QString rv = d->core.name(d->object) + QLatin1Char('.');
615 QDeclarativeEnginePrivate *ep = d->engine?QDeclarativeEnginePrivate::get(d->engine):0;
616 QDeclarativeValueType *valueType = 0;
617 if (ep) valueType = ep->valueTypes[d->core.propType];
618 else valueType = QDeclarativeValueTypeFactory::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 QDeclarativeProperty::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 QDeclarativeProperty::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 QDeclarativeAbstractBinding *
673 QDeclarativePropertyPrivate::binding(const QDeclarativeProperty &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 QDeclarativeAbstractBinding *
696 QDeclarativePropertyPrivate::setBinding(const QDeclarativeProperty &that,
697 QDeclarativeAbstractBinding *newBinding,
700 if (!that.d || !that.isProperty() || !that.d->object) {
702 newBinding->destroy();
706 return that.d->setBinding(that.d->object, that.d->core.coreIndex,
707 that.d->core.getValueTypeCoreIndex(),
711 QDeclarativeAbstractBinding *
712 QDeclarativePropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
714 QDeclarativeData *data = QDeclarativeData::get(object);
718 QDeclarativePropertyData *propertyData =
719 data->propertyCache?data->propertyCache->property(coreIndex):0;
720 if (propertyData && propertyData->isAlias()) {
721 const QDeclarativeVMEMetaObject *vme =
722 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
724 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
725 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
728 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
729 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
730 return binding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex);
733 if (!data->hasBindingBit(coreIndex))
736 QDeclarativeAbstractBinding *binding = data->bindings;
737 while (binding && binding->propertyIndex() != coreIndex)
738 binding = binding->m_nextBinding;
740 if (binding && valueTypeIndex != -1) {
741 if (binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) {
742 int index = coreIndex | (valueTypeIndex << 24);
743 binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
750 void QDeclarativePropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
751 QObject **targetObject, int *targetBindingIndex)
753 int coreIndex = bindingIndex & 0xFFFFFF;
754 int valueTypeIndex = bindingIndex >> 24;
755 if (valueTypeIndex == 0) valueTypeIndex = -1;
757 QDeclarativeData *data = QDeclarativeData::get(object, false);
759 QDeclarativePropertyData *propertyData =
760 data->propertyCache?data->propertyCache->property(coreIndex):0;
761 if (propertyData && propertyData->isAlias()) {
762 const QDeclarativeVMEMetaObject *vme =
763 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
764 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
765 if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
766 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
767 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
769 int aBindingIndex = aCoreIndex;
770 if (aValueTypeIndex != -1)
771 aBindingIndex |= aValueTypeIndex << 24;
772 else if (valueTypeIndex != -1)
773 aBindingIndex |= valueTypeIndex << 24;
775 findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
781 *targetObject = object;
782 *targetBindingIndex = bindingIndex;
785 QDeclarativeAbstractBinding *
786 QDeclarativePropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
787 QDeclarativeAbstractBinding *newBinding, WriteFlags flags)
789 QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
790 QDeclarativeAbstractBinding *binding = 0;
793 QDeclarativePropertyData *propertyData =
794 data->propertyCache?data->propertyCache->property(coreIndex):0;
795 if (propertyData && propertyData->isAlias()) {
796 const QDeclarativeVMEMetaObject *vme =
797 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
799 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
800 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
801 if (newBinding) newBinding->destroy();
805 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
806 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
807 return setBinding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex,
812 if (data && data->hasBindingBit(coreIndex)) {
813 binding = data->bindings;
815 while (binding && binding->propertyIndex() != coreIndex)
816 binding = binding->m_nextBinding;
819 int index = coreIndex;
820 if (valueTypeIndex != -1)
821 index |= (valueTypeIndex << 24);
823 if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy)
824 binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
827 binding->removeFromObject();
828 binding->setEnabled(false, 0);
832 newBinding->addToObject(object, index);
833 newBinding->setEnabled(true, flags);
839 QDeclarativeAbstractBinding *
840 QDeclarativePropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
841 QDeclarativeAbstractBinding *newBinding)
843 QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
844 QDeclarativeAbstractBinding *binding = 0;
847 QDeclarativePropertyData *propertyData =
848 data->propertyCache?data->propertyCache->property(coreIndex):0;
849 if (propertyData && propertyData->isAlias()) {
850 const QDeclarativeVMEMetaObject *vme =
851 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
853 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
854 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
855 if (newBinding) newBinding->destroy();
859 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
860 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
861 return setBindingNoEnable(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex,
866 if (data && data->hasBindingBit(coreIndex)) {
867 binding = data->bindings;
869 while (binding && binding->propertyIndex() != coreIndex)
870 binding = binding->m_nextBinding;
873 int index = coreIndex;
874 if (valueTypeIndex != -1)
875 index |= (valueTypeIndex << 24);
877 if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy)
878 binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
881 binding->removeFromObject();
884 newBinding->addToObject(object, index);
890 Returns the expression associated with this signal property, or 0 if no
891 signal expression exists.
893 QDeclarativeExpression *
894 QDeclarativePropertyPrivate::signalExpression(const QDeclarativeProperty &that)
896 if (!(that.type() & QDeclarativeProperty::SignalProperty))
899 const QObjectList &children = that.d->object->children();
901 for (int ii = 0; ii < children.count(); ++ii) {
902 QObject *child = children.at(ii);
904 QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
905 if (signal && signal->index() == that.index())
906 return signal->expression();
913 Set the signal expression associated with this signal property to \a expr.
914 Returns the existing signal expression (if any), otherwise 0.
916 Ownership of \a expr transfers to QML. Ownership of the return value is
917 assumed by the caller.
919 QDeclarativeExpression *
920 QDeclarativePropertyPrivate::setSignalExpression(const QDeclarativeProperty &that,
921 QDeclarativeExpression *expr)
923 if (!(that.type() & QDeclarativeProperty::SignalProperty)) {
928 const QObjectList &children = that.d->object->children();
930 for (int ii = 0; ii < children.count(); ++ii) {
931 QObject *child = children.at(ii);
933 QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
934 if (signal && signal->index() == that.index())
935 return signal->setExpression(expr);
939 QDeclarativeBoundSignal *signal = new QDeclarativeBoundSignal(that.d->object, that.method(), that.d->object);
940 return signal->setExpression(expr);
947 Returns the property value.
949 QVariant QDeclarativeProperty::read() const
956 if (type() & SignalProperty) {
960 } else if (type() & Property) {
962 return d->readValueProperty();
969 Return the \a name property value of \a object. This method is equivalent to:
971 QDeclarativeProperty p(object, name);
975 QVariant QDeclarativeProperty::read(QObject *object, const QString &name)
977 QDeclarativeProperty p(object, name);
982 Return the \a name property value of \a object using the
983 \l{QDeclarativeContext} {context} \a ctxt. This method is
987 QDeclarativeProperty p(object, name, context);
991 QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeContext *ctxt)
993 QDeclarativeProperty p(object, name, ctxt);
999 Return the \a name property value of \a object using the environment
1000 for instantiating QML components that is provided by \a engine. .
1001 This method is equivalent to:
1004 QDeclarativeProperty p(object, name, engine);
1008 QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeEngine *engine)
1010 QDeclarativeProperty p(object, name, engine);
1014 QVariant QDeclarativePropertyPrivate::readValueProperty()
1016 if (isValueType()) {
1018 QDeclarativeEnginePrivate *ep = engine?QDeclarativeEnginePrivate::get(engine):0;
1019 QDeclarativeValueType *valueType = 0;
1020 if (ep) valueType = ep->valueTypes[core.propType];
1021 else valueType = QDeclarativeValueTypeFactory::valueType(core.propType);
1022 Q_ASSERT(valueType);
1024 valueType->read(object, core.coreIndex);
1026 QVariant rv = valueType->metaObject()->property(core.valueTypeCoreIndex).read(valueType);
1028 if (!ep) delete valueType;
1031 } else if (core.isQList()) {
1033 QDeclarativeListProperty<QObject> prop;
1034 void *args[] = { &prop, 0 };
1035 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1036 return QVariant::fromValue(QDeclarativeListReferencePrivate::init(prop, core.propType, engine));
1038 } else if (core.isQObject()) {
1041 void *args[] = { &rv, 0 };
1042 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1043 return QVariant::fromValue(rv);
1047 return object->metaObject()->property(core.coreIndex).read(object.data());
1052 static QUrl urlFromUserString(const QByteArray &data)
1055 if (!data.isEmpty())
1057 // Preserve any valid percent-encoded octets supplied by the source
1058 u.setEncodedUrl(data, QUrl::TolerantMode);
1063 static QUrl urlFromUserString(const QString &data)
1065 return urlFromUserString(data.toUtf8());
1068 // helper function to allow assignment / binding to QList<QUrl> properties.
1069 static QVariant resolvedUrlSequence(const QVariant &value, QDeclarativeContextData *context)
1072 if (value.userType() == qMetaTypeId<QUrl>()) {
1073 urls.append(value.toUrl());
1074 } else if (value.userType() == qMetaTypeId<QString>()) {
1075 urls.append(urlFromUserString(value.toString()));
1076 } else if (value.userType() == qMetaTypeId<QByteArray>()) {
1077 urls.append(urlFromUserString(value.toByteArray()));
1078 } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
1079 urls = value.value<QList<QUrl> >();
1080 } else if (value.userType() == qMetaTypeId<QStringList>()) {
1081 QStringList urlStrings = value.value<QStringList>();
1082 for (int i = 0; i < urlStrings.size(); ++i)
1083 urls.append(urlFromUserString(urlStrings.at(i)));
1084 } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
1085 QList<QString> urlStrings = value.value<QList<QString> >();
1086 for (int i = 0; i < urlStrings.size(); ++i)
1087 urls.append(urlFromUserString(urlStrings.at(i)));
1088 } // note: QList<QByteArray> is not currently supported.
1090 QList<QUrl> resolvedUrls;
1091 for (int i = 0; i < urls.size(); ++i) {
1092 QUrl u = urls.at(i);
1093 if (context && u.isRelative() && !u.isEmpty())
1094 u = context->resolvedUrl(u);
1095 resolvedUrls.append(u);
1098 return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
1101 //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1102 bool QDeclarativePropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1104 if (!object || !prop.isWritable())
1108 if (prop.isEnumType()) {
1109 QMetaEnum menum = prop.enumerator();
1110 if (v.userType() == QVariant::String
1112 || v.userType() == QVariant::CString
1116 if (prop.isFlagType())
1117 v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
1119 v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
1122 } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
1123 int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
1124 if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData())
1126 v = QVariant(*reinterpret_cast<const int *>(v.constData()));
1128 v.convert(QVariant::Int);
1131 // the status variable is changed by qt_metacall to indicate what it did
1132 // this feature is currently only used by QtDBus and should not be depended
1133 // upon. Don't change it without looking into QDBusAbstractInterface first
1134 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1135 // changed: result stored directly in value, return the value of status
1137 void *argv[] = { v.data(), &v, &status, &flags };
1138 QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
1142 bool QDeclarativePropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
1144 return writeValueProperty(object, engine, core, value, effectiveContext(), flags);
1148 QDeclarativePropertyPrivate::writeValueProperty(QObject *object, QDeclarativeEngine *engine,
1149 const QDeclarativePropertyData &core,
1150 const QVariant &value,
1151 QDeclarativeContextData *context, WriteFlags flags)
1153 // Remove any existing bindings on this property
1154 if (!(flags & DontRemoveBinding) && object) {
1155 QDeclarativeAbstractBinding *binding = setBinding(object, core.coreIndex,
1156 core.getValueTypeCoreIndex(),
1158 if (binding) binding->destroy();
1162 if (core.isValueTypeVirtual()) {
1163 QDeclarativeEnginePrivate *ep = engine?QDeclarativeEnginePrivate::get(engine):0;
1165 QDeclarativeValueType *writeBack = 0;
1167 writeBack = ep->valueTypes[core.propType];
1169 writeBack = QDeclarativeValueTypeFactory::valueType(core.propType);
1172 writeBack->read(object, core.coreIndex);
1174 QDeclarativePropertyData data = core;
1175 data.setFlags(QDeclarativePropertyData::Flag(core.valueTypeFlags));
1176 data.coreIndex = core.valueTypeCoreIndex;
1177 data.propType = core.valueTypePropType;
1179 rv = write(writeBack, data, value, context, flags);
1181 writeBack->write(object, core.coreIndex, flags);
1182 if (!ep) delete writeBack;
1186 rv = write(object, core, value, context, flags);
1193 bool QDeclarativePropertyPrivate::write(QObject *object,
1194 const QDeclarativePropertyData &property,
1195 const QVariant &value, QDeclarativeContextData *context,
1198 int coreIdx = property.coreIndex;
1199 int status = -1; //for dbus
1201 if (property.isEnum()) {
1202 QMetaProperty prop = object->metaObject()->property(property.coreIndex);
1204 // Enum values come through the script engine as doubles
1205 if (value.userType() == QVariant::Double) {
1207 double fractional = modf(value.toDouble(), &integral);
1208 if (qFuzzyIsNull(fractional))
1209 v.convert(QVariant::Int);
1211 return writeEnumProperty(prop, coreIdx, object, v, flags);
1214 int propertyType = property.propType;
1215 int variantType = value.userType();
1217 QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context);
1219 if (propertyType == QVariant::Url) {
1223 if (variantType == QVariant::Url) {
1226 } else if (variantType == QVariant::ByteArray) {
1227 u = urlFromUserString(value.toByteArray());
1229 } else if (variantType == QVariant::String) {
1230 u = urlFromUserString(value.toString());
1237 if (context && u.isRelative() && !u.isEmpty())
1238 u = context->resolvedUrl(u);
1240 void *argv[] = { &u, 0, &status, &flags };
1241 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1243 } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
1244 QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
1246 void *argv[] = { &urlSeq, 0, &status, &flags };
1247 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1248 } else if (variantType == propertyType) {
1250 void *a[] = { (void *)value.constData(), 0, &status, &flags };
1251 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1253 } else if (qMetaTypeId<QVariant>() == propertyType) {
1255 void *a[] = { (void *)&value, 0, &status, &flags };
1256 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1258 } else if (property.isQObject()) {
1260 const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType());
1265 QObject *o = *(QObject **)value.constData();
1266 const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType);
1268 if (o) valMo = o->metaObject();
1270 if (canConvert(valMo, propMo)) {
1271 void *args[] = { &o, 0, &status, &flags };
1272 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
1274 } else if (!o && canConvert(propMo, valMo)) {
1275 // In the case of a null QObject, we assign the null if there is
1276 // any change that the null variant type could be up or down cast to
1277 // the property type.
1278 void *args[] = { &o, 0, &status, &flags };
1279 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
1285 } else if (property.isQList()) {
1287 const QMetaObject *listType = 0;
1289 listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
1291 QDeclarativeType *type = QDeclarativeMetaType::qmlType(QDeclarativeMetaType::listType(property.propType));
1292 if (!type) return false;
1293 listType = type->baseMetaObject();
1295 if (!listType) return false;
1297 QDeclarativeListProperty<void> prop;
1298 void *args[] = { &prop, 0 };
1299 QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
1301 if (!prop.clear) return false;
1305 if (value.userType() == qMetaTypeId<QDeclarativeListReference>()) {
1306 QDeclarativeListReference qdlr = value.value<QDeclarativeListReference>();
1308 for (int ii = 0; ii < qdlr.count(); ++ii) {
1309 QObject *o = qdlr.at(ii);
1310 if (o && !canConvert(o->metaObject(), listType))
1312 prop.append(&prop, (void *)o);
1314 } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
1315 const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1317 for (int ii = 0; ii < list.count(); ++ii) {
1318 QObject *o = list.at(ii);
1319 if (o && !canConvert(o->metaObject(), listType))
1321 prop.append(&prop, (void *)o);
1324 QObject *o = enginePriv?enginePriv->toQObject(value):QDeclarativeMetaType::toQObject(value);
1325 if (o && !canConvert(o->metaObject(), listType))
1327 prop.append(&prop, (void *)o);
1331 Q_ASSERT(variantType != propertyType);
1335 if (variantType == QVariant::String)
1336 v = QDeclarativeStringConverters::variantFromString(value.toString(), propertyType, &ok);
1339 if (v.convert((QVariant::Type)propertyType)) {
1341 } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
1342 QDeclarativeMetaType::StringConverter con = QDeclarativeMetaType::customStringConverter(propertyType);
1344 v = con(value.toString());
1345 if (v.userType() == propertyType)
1351 // the only other option is that they are assigning a single value
1352 // to a sequence type property (eg, an int to a QList<int> property).
1353 // Note that we've already handled single-value assignment to QList<QUrl> properties.
1354 if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
1356 list << value.toInt();
1357 v = QVariant::fromValue<QList<int> >(list);
1359 } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
1361 list << value.toReal();
1362 v = QVariant::fromValue<QList<qreal> >(list);
1364 } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
1366 list << value.toBool();
1367 v = QVariant::fromValue<QList<bool> >(list);
1369 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
1370 QList<QString> list;
1371 list << value.toString();
1372 v = QVariant::fromValue<QList<QString> >(list);
1374 } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
1376 list << value.toString();
1377 v = QVariant::fromValue<QStringList>(list);
1383 void *a[] = { (void *)v.constData(), 0, &status, &flags};
1384 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1393 // Returns true if successful, false if an error description was set on expression
1394 bool QDeclarativePropertyPrivate::writeBinding(QObject *object,
1395 const QDeclarativePropertyData &core,
1396 QDeclarativeJavaScriptExpression *expression,
1397 v8::Handle<v8::Value> result, bool isUndefined,
1401 Q_ASSERT(core.coreIndex != -1);
1403 QDeclarativeContextData *context = expression->context();
1404 QDeclarativeEngine *engine = context->engine;
1405 QV8Engine *v8engine = QDeclarativeEnginePrivate::getV8Engine(engine);
1407 #define QUICK_STORE(cpptype, conversion) \
1409 cpptype o = (conversion); \
1411 void *argv[] = { &o, 0, &status, &flags }; \
1412 QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \
1417 if (!isUndefined && !core.isValueTypeVirtual()) {
1418 switch (core.propType) {
1419 case QMetaType::Int:
1420 if (result->IsInt32())
1421 QUICK_STORE(int, result->Int32Value())
1422 else if (result->IsNumber())
1423 QUICK_STORE(int, qRound(result->NumberValue()))
1425 case QMetaType::Double:
1426 if (result->IsNumber())
1427 QUICK_STORE(double, result->NumberValue())
1429 case QMetaType::Float:
1430 if (result->IsNumber())
1431 QUICK_STORE(float, result->NumberValue())
1433 case QMetaType::QString:
1434 if (result->IsString())
1435 QUICK_STORE(QString, v8engine->toString(result))
1443 int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType;
1445 QDeleteWatcher watcher(expression);
1448 bool isVmeProperty = core.isVMEProperty();
1451 } else if (core.isQList()) {
1452 value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
1453 } else if (result->IsNull() && core.isQObject()) {
1454 value = QVariant::fromValue((QObject *)0);
1455 } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
1456 value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
1457 } else if (!isVmeProperty) {
1458 value = v8engine->toVariant(result, type);
1461 if (expression->error.isValid()) {
1463 } else if (isUndefined && core.isResettable()) {
1464 void *args[] = { 0 };
1465 QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
1466 } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
1467 writeValueProperty(object, engine, core, QVariant(), context, flags);
1468 } else if (isUndefined) {
1469 expression->error.setDescription(QLatin1String("Unable to assign [undefined] to ") +
1470 QLatin1String(QMetaType::typeName(type)));
1472 } else if (result->IsFunction()) {
1473 expression->error.setDescription(QLatin1String("Unable to assign a function to a property."));
1475 } else if (isVmeProperty) {
1476 typedef QDeclarativeVMEMetaObject VMEMO;
1477 VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject()));
1478 vmemo->setVMEProperty(core.coreIndex, result);
1479 } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
1481 if (watcher.wasDeleted())
1484 const char *valueType = 0;
1485 if (value.userType() == QVariant::Invalid) valueType = "null";
1486 else valueType = QMetaType::typeName(value.userType());
1488 expression->error.setDescription(QLatin1String("Unable to assign ") +
1489 QLatin1String(valueType) +
1490 QLatin1String(" to ") +
1491 QLatin1String(QMetaType::typeName(type)));
1498 bool QDeclarativePropertyPrivate::writeBinding(const QDeclarativeProperty &that,
1499 QDeclarativeJavaScriptExpression *expression,
1500 v8::Handle<v8::Value> result, bool isUndefined,
1503 QDeclarativePropertyPrivate *pp = that.d;
1508 QObject *object = that.object();
1512 return writeBinding(object, pp->core, expression, result, isUndefined, flags);
1515 const QMetaObject *QDeclarativePropertyPrivate::rawMetaObjectForType(QDeclarativeEnginePrivate *engine, int userType)
1518 return engine->rawMetaObjectForType(userType);
1520 QDeclarativeType *type = QDeclarativeMetaType::qmlType(userType);
1521 return type?type->baseMetaObject():0;
1526 Sets the property value to \a value and returns true.
1527 Returns false if the property can't be set because the
1528 \a value is the wrong type, for example.
1530 bool QDeclarativeProperty::write(const QVariant &value) const
1532 return QDeclarativePropertyPrivate::write(*this, value, 0);
1536 Writes \a value to the \a name property of \a object. This method
1540 QDeclarativeProperty p(object, name);
1544 bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value)
1546 QDeclarativeProperty p(object, name);
1547 return p.write(value);
1551 Writes \a value to the \a name property of \a object using the
1552 \l{QDeclarativeContext} {context} \a ctxt. This method is
1556 QDeclarativeProperty p(object, name, ctxt);
1560 bool QDeclarativeProperty::write(QObject *object,
1561 const QString &name,
1562 const QVariant &value,
1563 QDeclarativeContext *ctxt)
1565 QDeclarativeProperty p(object, name, ctxt);
1566 return p.write(value);
1571 Writes \a value to the \a name property of \a object using the
1572 environment for instantiating QML components that is provided by
1573 \a engine. This method is equivalent to:
1576 QDeclarativeProperty p(object, name, engine);
1580 bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value,
1581 QDeclarativeEngine *engine)
1583 QDeclarativeProperty p(object, name, engine);
1584 return p.write(value);
1588 Resets the property and returns true if the property is
1589 resettable. If the property is not resettable, nothing happens
1590 and false is returned.
1592 bool QDeclarativeProperty::reset() const
1594 if (isResettable()) {
1595 void *args[] = { 0 };
1596 QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1603 bool QDeclarativePropertyPrivate::write(const QDeclarativeProperty &that,
1604 const QVariant &value, WriteFlags flags)
1608 if (that.d->object && that.type() & QDeclarativeProperty::Property &&
1609 that.d->core.isValid() && that.isWritable())
1610 return that.d->writeValueProperty(value, flags);
1616 Returns true if the property has a change notifier signal, otherwise false.
1618 bool QDeclarativeProperty::hasNotifySignal() const
1620 if (type() & Property && d->object) {
1621 return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1627 Returns true if the property needs a change notifier signal for bindings
1628 to remain upto date, false otherwise.
1630 Some properties, such as attached properties or those whose value never
1631 changes, do not require a change notifier.
1633 bool QDeclarativeProperty::needsNotifySignal() const
1635 return type() & Property && !property().isConstant();
1639 Connects the property's change notifier signal to the
1640 specified \a method of the \a dest object and returns
1641 true. Returns false if this metaproperty does not
1642 represent a regular Qt property or if it has no
1643 change notifier signal, or if the \a dest object does
1644 not have the specified \a method.
1646 bool QDeclarativeProperty::connectNotifySignal(QObject *dest, int method) const
1648 if (!(type() & Property) || !d->object)
1651 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1652 if (prop.hasNotifySignal()) {
1653 return QDeclarativePropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1660 Connects the property's change notifier signal to the
1661 specified \a slot of the \a dest object and returns
1662 true. Returns false if this metaproperty does not
1663 represent a regular Qt property or if it has no
1664 change notifier signal, or if the \a dest object does
1665 not have the specified \a slot.
1667 bool QDeclarativeProperty::connectNotifySignal(QObject *dest, const char *slot) const
1669 if (!(type() & Property) || !d->object)
1672 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1673 if (prop.hasNotifySignal()) {
1674 QByteArray signal(QByteArray("2") + prop.notifySignal().signature());
1675 return QObject::connect(d->object, signal.constData(), dest, slot);
1682 Return the Qt metaobject index of the property.
1684 int QDeclarativeProperty::index() const
1686 return d ? d->core.coreIndex : -1;
1689 int QDeclarativePropertyPrivate::valueTypeCoreIndex(const QDeclarativeProperty &that)
1691 return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
1695 Returns the "property index" for use in bindings. The top 8 bits are the value type
1696 offset, and 0 otherwise. The bottom 24-bits are the regular property index.
1698 int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativeProperty &that)
1702 return bindingIndex(that.d->core);
1705 int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativePropertyData &that)
1707 int rv = that.coreIndex;
1708 if (rv != -1 && that.isValueTypeVirtual())
1709 rv = rv | (that.valueTypeCoreIndex << 24);
1713 QDeclarativePropertyData
1714 QDeclarativePropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
1715 const QMetaObject *subObject, int subIndex,
1716 QDeclarativeEngine *)
1718 QMetaProperty subProp = subObject->property(subIndex);
1720 QDeclarativePropertyData core;
1721 core.load(metaObject->property(index));
1722 core.setFlags(core.getFlags() | QDeclarativePropertyData::IsValueTypeVirtual);
1723 core.valueTypeFlags = QDeclarativePropertyData::flagsForProperty(subProp);
1724 core.valueTypeCoreIndex = subIndex;
1725 core.valueTypePropType = subProp.userType();
1730 QDeclarativeProperty
1731 QDeclarativePropertyPrivate::restore(QObject *object, const QDeclarativePropertyData &data,
1732 QDeclarativeContextData *ctxt)
1734 QDeclarativeProperty prop;
1736 prop.d = new QDeclarativePropertyPrivate;
1737 prop.d->object = object;
1738 prop.d->context = ctxt;
1739 prop.d->engine = ctxt?ctxt->engine:0;
1741 prop.d->core = data;
1747 Returns true if lhs and rhs refer to the same metaobject data
1749 bool QDeclarativePropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
1751 return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1755 Returns true if from inherits to.
1757 bool QDeclarativePropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
1759 if (from && to == &QObject::staticMetaObject)
1763 if (equal(from, to))
1765 from = from->superClass();
1772 Return the signal corresponding to \a name
1774 QMetaMethod QDeclarativePropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1777 int methods = mo->methodCount();
1778 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1779 QMetaMethod method = mo->method(ii);
1780 QByteArray methodName = method.signature();
1781 int idx = methodName.indexOf('(');
1782 methodName = methodName.left(idx);
1784 if (methodName == name)
1788 // If no signal is found, but the signal is of the form "onBlahChanged",
1789 // return the notify signal for the property "Blah"
1790 if (name.endsWith("Changed")) {
1791 QByteArray propName = name.mid(0, name.length() - 7);
1792 int propIdx = mo->indexOfProperty(propName.constData());
1794 QMetaProperty prop = mo->property(propIdx);
1795 if (prop.hasNotifySignal())
1796 return prop.notifySignal();
1800 return QMetaMethod();
1803 static inline int QMetaObject_methods(const QMetaObject *metaObject)
1809 int classInfoCount, classInfoData;
1810 int methodCount, methodData;
1811 int propertyCount, propertyData;
1814 return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
1817 static inline int QMetaObject_properties(const QMetaObject *metaObject)
1823 int classInfoCount, classInfoData;
1824 int methodCount, methodData;
1825 int propertyCount, propertyData;
1828 return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
1831 static inline void flush_vme_signal(const QObject *object, int index)
1833 QDeclarativeData *data = static_cast<QDeclarativeData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1834 if (data && data->propertyCache) {
1835 QDeclarativePropertyData *property = data->propertyCache->method(index);
1837 if (property && property->isVMESignal()) {
1838 const QMetaObject *metaObject = object->metaObject();
1839 int methodOffset = metaObject->methodOffset();
1841 while (methodOffset > index) {
1842 metaObject = metaObject->d.superdata;
1843 methodOffset -= QMetaObject_methods(metaObject);
1846 QDeclarativeVMEMetaObject *vme =
1847 static_cast<QDeclarativeVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
1849 vme->connectAliasSignal(index);
1855 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1856 \a type and \a types. This behaves identically to QMetaObject::connect() except that
1857 it connects any lazy "proxy" signal connections set up by QML.
1859 It is possible that this logic should be moved to QMetaObject::connect().
1861 bool QDeclarativePropertyPrivate::connect(const QObject *sender, int signal_index,
1862 const QObject *receiver, int method_index,
1863 int type, int *types)
1865 flush_vme_signal(sender, signal_index);
1866 flush_vme_signal(receiver, method_index);
1868 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1871 void QDeclarativePropertyPrivate::flushSignal(const QObject *sender, int signal_index)
1873 flush_vme_signal(sender, signal_index);
1877 Return \a metaObject's [super] meta object that provides data for \a property.
1879 const QMetaObject *QDeclarativePropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
1881 int propertyOffset = metaObject->propertyOffset();
1883 while (propertyOffset > property) {
1884 metaObject = metaObject->d.superdata;
1885 propertyOffset -= QMetaObject_properties(metaObject);