1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qdeclarativeproperty.h"
43 #include "private/qdeclarativeproperty_p.h"
45 #include "qdeclarative.h"
46 #include "private/qdeclarativebinding_p.h"
47 #include "qdeclarativecontext.h"
48 #include "private/qdeclarativecontext_p.h"
49 #include "private/qdeclarativeboundsignal_p.h"
50 #include "qdeclarativeengine.h"
51 #include "private/qdeclarativeengine_p.h"
52 #include "private/qdeclarativedata_p.h"
53 #include "private/qdeclarativestringconverters_p.h"
54 #include "private/qdeclarativelist_p.h"
55 #include "private/qdeclarativecompiler_p.h"
56 #include "private/qdeclarativevmemetaobject_p.h"
58 #include <QStringList>
59 #include <QtCore/qdebug.h>
66 \class QDeclarativeProperty
68 \brief The QDeclarativeProperty class abstracts accessing properties on objects created from QML.
70 As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect
71 and interact with objects created by QML. However, some of the new features provided by QML - such
72 as type safety and attached properties - are most easily used through the QDeclarativeProperty class
73 that simplifies some of their natural complexity.
75 Unlike QMetaProperty which represents a property on a class type, QDeclarativeProperty encapsulates
76 a property on a specific object instance. To read a property's value, programmers create a
77 QDeclarativeProperty instance and call the read() method. Likewise to write a property value the
78 write() method is used.
80 For example, for the following QML code:
86 Text { text: "A bit of text" }
89 The \l Text object's properties could be accessed using QDeclarativeProperty, like this:
92 #include <QDeclarativeProperty>
93 #include <QGraphicsObject>
97 QDeclarativeView view(QUrl::fromLocalFile("MyItem.qml"));
98 QDeclarativeProperty property(view.rootObject(), "font.pixelSize");
99 qWarning() << "Current pixel size:" << property.read().toInt();
101 qWarning() << "Pixel size should now be 24:" << property.read().toInt();
106 Create an invalid QDeclarativeProperty.
108 QDeclarativeProperty::QDeclarativeProperty()
114 QDeclarativeProperty::~QDeclarativeProperty()
122 Creates a QDeclarativeProperty for the default property of \a obj. If there is no
123 default property, an invalid QDeclarativeProperty will be created.
125 QDeclarativeProperty::QDeclarativeProperty(QObject *obj)
126 : d(new QDeclarativePropertyPrivate)
132 Creates a QDeclarativeProperty for the default property of \a obj
133 using the \l{QDeclarativeContext} {context} \a ctxt. If there is
134 no default property, an invalid QDeclarativeProperty will be
137 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeContext *ctxt)
138 : d(new QDeclarativePropertyPrivate)
140 d->context = ctxt?QDeclarativeContextData::get(ctxt):0;
141 d->engine = ctxt?ctxt->engine():0;
146 Creates a QDeclarativeProperty for the default property of \a obj
147 using the environment for instantiating QML components that is
148 provided by \a engine. If there is no default property, an
149 invalid QDeclarativeProperty will be created.
151 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeEngine *engine)
152 : d(new QDeclarativePropertyPrivate)
160 Initialize from the default property of \a obj
162 void QDeclarativePropertyPrivate::initDefault(QObject *obj)
167 QMetaProperty p = QDeclarativeMetaType::defaultProperty(obj);
174 Creates a QDeclarativeProperty for the property \a name of \a obj.
176 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name)
177 : d(new QDeclarativePropertyPrivate)
179 d->initProperty(obj, name);
180 if (!isValid()) d->object = 0;
184 Creates a QDeclarativeProperty for the property \a name of \a obj
185 using the \l{QDeclarativeContext} {context} \a ctxt.
187 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeContext *ctxt)
188 : d(new QDeclarativePropertyPrivate)
190 d->context = ctxt?QDeclarativeContextData::get(ctxt):0;
191 d->engine = ctxt?ctxt->engine():0;
192 d->initProperty(obj, name);
193 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
197 Creates a QDeclarativeProperty for the property \a name of \a obj
198 using the environment for instantiating QML components that is
199 provided by \a engine.
201 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeEngine *engine)
202 : d(new QDeclarativePropertyPrivate)
206 d->initProperty(obj, name);
207 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
210 Q_GLOBAL_STATIC(QDeclarativeValueTypeFactory, qmlValueTypes);
212 void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name)
216 QDeclarativeTypeNameCache *typeNameCache = context?context->imports:0;
218 QStringList path = name.split(QLatin1Char('.'));
219 if (path.isEmpty()) return;
221 QObject *currentObject = obj;
223 // Everything up to the last property must be an "object type" property
224 for (int ii = 0; ii < path.count() - 1; ++ii) {
225 const QString &pathName = path.at(ii);
227 if (QDeclarativeTypeNameCache::Data *data = typeNameCache?typeNameCache->data(pathName):0) {
229 QDeclarativeAttachedPropertiesFunc func = data->type->attachedPropertiesFunction();
230 if (!func) return; // Not an attachable type
232 currentObject = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), currentObject);
233 if (!currentObject) return; // Something is broken with the attachable type
235 Q_ASSERT(data->typeNamespace);
236 if ((ii + 1) == path.count()) return; // No type following the namespace
238 ++ii; data = data->typeNamespace->data(path.at(ii));
239 if (!data || !data->type) return; // Invalid type in namespace
241 QDeclarativeAttachedPropertiesFunc func = data->type->attachedPropertiesFunction();
242 if (!func) return; // Not an attachable type
244 currentObject = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), currentObject);
245 if (!currentObject) return; // Something is broken with the attachable type
249 QDeclarativePropertyCache::Data local;
250 QDeclarativePropertyCache::Data *property =
251 QDeclarativePropertyCache::property(engine, obj, pathName, local);
253 if (!property) return; // Not a property
254 if (property->flags & QDeclarativePropertyCache::Data::IsFunction)
255 return; // Not an object property
257 if (ii == (path.count() - 2) && QDeclarativeValueTypeFactory::isValueType(property->propType)) {
258 // We're now at a value type property. We can use a global valuetypes array as we
259 // never actually use the objects, just look up their properties.
260 QObject *typeObject = (*qmlValueTypes())[property->propType];
261 if (!typeObject) return; // Not a value type
263 int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
264 if (idx == -1) return; // Value type property does not exist
266 QMetaProperty vtProp = typeObject->metaObject()->property(idx);
268 object = currentObject;
270 valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(vtProp);
271 valueType.valueTypeCoreIdx = idx;
272 valueType.valueTypePropType = vtProp.userType();
276 if (!(property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived))
277 return; // Not an object property
279 void *args[] = { ¤tObject, 0 };
280 QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
281 if (!currentObject) return; // No value
288 const QString &terminal = path.last();
290 if (terminal.count() >= 3 &&
291 terminal.at(0) == QLatin1Char('o') &&
292 terminal.at(1) == QLatin1Char('n') &&
293 terminal.at(2).isUpper()) {
295 QString signalName = terminal.mid(2);
296 signalName[0] = signalName.at(0).toLower();
298 QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName.toLatin1().constData());
299 if (method.signature()) {
300 object = currentObject;
307 QDeclarativePropertyCache::Data local;
308 QDeclarativePropertyCache::Data *property =
309 QDeclarativePropertyCache::property(engine, currentObject, terminal, local);
310 if (property && !(property->flags & QDeclarativePropertyCache::Data::IsFunction)) {
311 object = currentObject;
313 nameCache = terminal;
319 Create a copy of \a other.
321 QDeclarativeProperty::QDeclarativeProperty(const QDeclarativeProperty &other)
329 \enum QDeclarativeProperty::PropertyTypeCategory
331 This enum specifies a category of QML property.
333 \value InvalidCategory The property is invalid, or is a signal property.
334 \value List The property is a QDeclarativeListProperty list property
335 \value Object The property is a QObject derived type pointer
336 \value Normal The property is a normal value property.
340 \enum QDeclarativeProperty::Type
342 This enum specifies a type of QML property.
344 \value Invalid The property is invalid.
345 \value Property The property is a regular Qt property.
346 \value SignalProperty The property is a signal property.
350 Returns the property category.
352 QDeclarativeProperty::PropertyTypeCategory QDeclarativeProperty::propertyTypeCategory() const
354 return d ? d->propertyTypeCategory() : InvalidCategory;
357 QDeclarativeProperty::PropertyTypeCategory
358 QDeclarativePropertyPrivate::propertyTypeCategory() const
360 uint type = this->type();
363 return QDeclarativeProperty::Normal;
364 } else if (type & QDeclarativeProperty::Property) {
365 int type = propertyType();
366 if (type == QVariant::Invalid)
367 return QDeclarativeProperty::InvalidCategory;
368 else if (QDeclarativeValueTypeFactory::isValueType((uint)type))
369 return QDeclarativeProperty::Normal;
370 else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived)
371 return QDeclarativeProperty::Object;
372 else if (core.flags & QDeclarativePropertyCache::Data::IsQList)
373 return QDeclarativeProperty::List;
375 return QDeclarativeProperty::Normal;
377 return QDeclarativeProperty::InvalidCategory;
382 Returns the type name of the property, or 0 if the property has no type
385 const char *QDeclarativeProperty::propertyTypeName() const
389 if (d->isValueType()) {
391 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context);
392 QDeclarativeValueType *valueType = 0;
393 if (ep) valueType = ep->valueTypes[d->core.propType];
394 else valueType = QDeclarativeValueTypeFactory::valueType(d->core.propType);
397 const char *rv = valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).typeName();
399 if (!ep) delete valueType;
402 } else if (d->object && type() & Property && d->core.isValid()) {
403 return d->object->metaObject()->property(d->core.coreIndex).typeName();
410 Returns true if \a other and this QDeclarativeProperty represent the same
413 bool QDeclarativeProperty::operator==(const QDeclarativeProperty &other) const
417 // category is intentially omitted here as it is generated
418 // from the other members
419 return d->object == other.d->object &&
420 d->core == other.d->core &&
421 d->valueType == other.d->valueType;
425 Returns the QVariant type of the property, or QVariant::Invalid if the
426 property has no QVariant type.
428 int QDeclarativeProperty::propertyType() const
430 return d ? d->propertyType() : int(QVariant::Invalid);
433 bool QDeclarativePropertyPrivate::isValueType() const
435 return valueType.valueTypeCoreIdx != -1;
438 int QDeclarativePropertyPrivate::propertyType() const
440 uint type = this->type();
442 return valueType.valueTypePropType;
443 } else if (type & QDeclarativeProperty::Property) {
444 if (core.propType == (int)QVariant::LastType)
445 return qMetaTypeId<QVariant>();
447 return core.propType;
449 return QVariant::Invalid;
453 QDeclarativeProperty::Type QDeclarativePropertyPrivate::type() const
455 if (core.flags & QDeclarativePropertyCache::Data::IsFunction)
456 return QDeclarativeProperty::SignalProperty;
457 else if (core.isValid())
458 return QDeclarativeProperty::Property;
460 return QDeclarativeProperty::Invalid;
464 Returns the type of the property.
466 QDeclarativeProperty::Type QDeclarativeProperty::type() const
468 return d ? d->type() : Invalid;
472 Returns true if this QDeclarativeProperty represents a regular Qt property.
474 bool QDeclarativeProperty::isProperty() const
476 return type() & Property;
480 Returns true if this QDeclarativeProperty represents a QML signal property.
482 bool QDeclarativeProperty::isSignalProperty() const
484 return type() & SignalProperty;
488 Returns the QDeclarativeProperty's QObject.
490 QObject *QDeclarativeProperty::object() const
492 return d ? d->object : 0;
496 Assign \a other to this QDeclarativeProperty.
498 QDeclarativeProperty &QDeclarativeProperty::operator=(const QDeclarativeProperty &other)
510 Returns true if the property is writable, otherwise false.
512 bool QDeclarativeProperty::isWritable() const
518 if (d->core.flags & QDeclarativePropertyCache::Data::IsQList) //list
520 else if (d->core.flags & QDeclarativePropertyCache::Data::IsFunction) //signal handler
522 else if (d->core.isValid()) //normal property
523 return d->core.flags & QDeclarativePropertyCache::Data::IsWritable;
529 Returns true if the property is designable, otherwise false.
531 bool QDeclarativeProperty::isDesignable() const
535 if (type() & Property && d->core.isValid() && d->object)
536 return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
542 Returns true if the property is resettable, otherwise false.
544 bool QDeclarativeProperty::isResettable() const
548 if (type() & Property && d->core.isValid() && d->object)
549 return d->core.flags & QDeclarativePropertyCache::Data::IsResettable;
555 Returns true if the QDeclarativeProperty refers to a valid property, otherwise
558 bool QDeclarativeProperty::isValid() const
562 return type() != Invalid;
566 Return the name of this QML property.
568 QString QDeclarativeProperty::name() const
572 if (!d->isNameCached) {
575 } else if (d->isValueType()) {
576 QString rv = d->core.name(d->object) + QLatin1Char('.');
578 QDeclarativeEnginePrivate *ep = d->engine?QDeclarativeEnginePrivate::get(d->engine):0;
579 QDeclarativeValueType *valueType = 0;
580 if (ep) valueType = ep->valueTypes[d->core.propType];
581 else valueType = QDeclarativeValueTypeFactory::valueType(d->core.propType);
584 rv += QString::fromUtf8(valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).name());
586 if (!ep) delete valueType;
589 } else if (type() & SignalProperty) {
590 QString name = QLatin1String("on") + d->core.name(d->object);
591 name[2] = name.at(2).toUpper();
594 d->nameCache = d->core.name(d->object);
596 d->isNameCached = true;
603 Returns the \l{QMetaProperty} {Qt property} associated with
606 QMetaProperty QDeclarativeProperty::property() const
609 return QMetaProperty();
610 if (type() & Property && d->core.isValid() && d->object)
611 return d->object->metaObject()->property(d->core.coreIndex);
613 return QMetaProperty();
617 Return the QMetaMethod for this property if it is a SignalProperty,
618 otherwise returns an invalid QMetaMethod.
620 QMetaMethod QDeclarativeProperty::method() const
623 return QMetaMethod();
624 if (type() & SignalProperty && d->object)
625 return d->object->metaObject()->method(d->core.coreIndex);
627 return QMetaMethod();
631 Returns the binding associated with this property, or 0 if no binding
634 QDeclarativeAbstractBinding *
635 QDeclarativePropertyPrivate::binding(const QDeclarativeProperty &that)
637 if (!that.d || !that.isProperty() || !that.d->object)
640 return binding(that.d->object, that.d->core.coreIndex, that.d->valueType.valueTypeCoreIdx);
644 Set the binding associated with this property to \a newBinding. Returns
645 the existing binding (if any), otherwise 0.
647 \a newBinding will be enabled, and the returned binding (if any) will be
650 Ownership of \a newBinding transfers to QML. Ownership of the return value
651 is assumed by the caller.
653 \a flags is passed through to the binding and is used for the initial update (when
654 the binding sets the initial value, it will use these flags for the write).
656 QDeclarativeAbstractBinding *
657 QDeclarativePropertyPrivate::setBinding(const QDeclarativeProperty &that,
658 QDeclarativeAbstractBinding *newBinding,
661 if (!that.d || !that.isProperty() || !that.d->object) {
663 newBinding->destroy();
667 return that.d->setBinding(that.d->object, that.d->core.coreIndex,
668 that.d->valueType.valueTypeCoreIdx, newBinding, flags);
671 QDeclarativeAbstractBinding *
672 QDeclarativePropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
674 QDeclarativeData *data = QDeclarativeData::get(object);
678 QDeclarativePropertyCache::Data *propertyData =
679 data->propertyCache?data->propertyCache->property(coreIndex):0;
680 if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
681 const QDeclarativeVMEMetaObject *vme =
682 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
684 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
685 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
688 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
689 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
690 return binding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex);
693 if (!data->hasBindingBit(coreIndex))
696 QDeclarativeAbstractBinding *binding = data->bindings;
697 while (binding && binding->propertyIndex() != coreIndex)
698 binding = binding->m_nextBinding;
700 if (binding && valueTypeIndex != -1) {
701 if (binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) {
702 int index = coreIndex | (valueTypeIndex << 24);
703 binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
710 void QDeclarativePropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
711 QObject **targetObject, int *targetBindingIndex)
713 int coreIndex = bindingIndex & 0xFFFFFF;
714 int valueTypeIndex = bindingIndex >> 24;
715 if (valueTypeIndex == 0) valueTypeIndex = -1;
717 QDeclarativeData *data = QDeclarativeData::get(object, false);
719 QDeclarativePropertyCache::Data *propertyData =
720 data->propertyCache?data->propertyCache->property(coreIndex):0;
721 if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
722 const QDeclarativeVMEMetaObject *vme =
723 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)) {
726 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
727 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
729 int aBindingIndex = aCoreIndex;
730 if (aValueTypeIndex != -1)
731 aBindingIndex |= aValueTypeIndex << 24;
732 else if (valueTypeIndex != -1)
733 aBindingIndex |= valueTypeIndex << 24;
735 findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
741 *targetObject = object;
742 *targetBindingIndex = bindingIndex;
745 QDeclarativeAbstractBinding *
746 QDeclarativePropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
747 QDeclarativeAbstractBinding *newBinding, WriteFlags flags)
749 QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
750 QDeclarativeAbstractBinding *binding = 0;
753 QDeclarativePropertyCache::Data *propertyData =
754 data->propertyCache?data->propertyCache->property(coreIndex):0;
755 if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
756 const QDeclarativeVMEMetaObject *vme =
757 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
759 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
760 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
761 if (newBinding) newBinding->destroy();
765 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
766 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
767 return setBinding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex,
772 if (data && data->hasBindingBit(coreIndex)) {
773 binding = data->bindings;
775 while (binding && binding->propertyIndex() != coreIndex)
776 binding = binding->m_nextBinding;
779 int index = coreIndex;
780 if (valueTypeIndex != -1)
781 index |= (valueTypeIndex << 24);
783 if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy)
784 binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
787 binding->removeFromObject();
788 binding->setEnabled(false, 0);
792 newBinding->addToObject(object, index);
793 newBinding->setEnabled(true, flags);
799 QDeclarativeAbstractBinding *
800 QDeclarativePropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
801 QDeclarativeAbstractBinding *newBinding)
803 QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
804 QDeclarativeAbstractBinding *binding = 0;
807 QDeclarativePropertyCache::Data *propertyData =
808 data->propertyCache?data->propertyCache->property(coreIndex):0;
809 if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
810 const QDeclarativeVMEMetaObject *vme =
811 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
813 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
814 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
815 if (newBinding) newBinding->destroy();
819 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
820 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
821 return setBindingNoEnable(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex,
826 if (data && data->hasBindingBit(coreIndex)) {
827 binding = data->bindings;
829 while (binding && binding->propertyIndex() != coreIndex)
830 binding = binding->m_nextBinding;
833 int index = coreIndex;
834 if (valueTypeIndex != -1)
835 index |= (valueTypeIndex << 24);
837 if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy)
838 binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
841 binding->removeFromObject();
844 newBinding->addToObject(object, index);
850 Returns the expression associated with this signal property, or 0 if no
851 signal expression exists.
853 QDeclarativeExpression *
854 QDeclarativePropertyPrivate::signalExpression(const QDeclarativeProperty &that)
856 if (!(that.type() & QDeclarativeProperty::SignalProperty))
859 const QObjectList &children = that.d->object->children();
861 for (int ii = 0; ii < children.count(); ++ii) {
862 QObject *child = children.at(ii);
864 QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
865 if (signal && signal->index() == that.index())
866 return signal->expression();
873 Set the signal expression associated with this signal property to \a expr.
874 Returns the existing signal expression (if any), otherwise 0.
876 Ownership of \a expr transfers to QML. Ownership of the return value is
877 assumed by the caller.
879 QDeclarativeExpression *
880 QDeclarativePropertyPrivate::setSignalExpression(const QDeclarativeProperty &that,
881 QDeclarativeExpression *expr)
883 if (!(that.type() & QDeclarativeProperty::SignalProperty)) {
888 const QObjectList &children = that.d->object->children();
890 for (int ii = 0; ii < children.count(); ++ii) {
891 QObject *child = children.at(ii);
893 QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
894 if (signal && signal->index() == that.index())
895 return signal->setExpression(expr);
899 QDeclarativeBoundSignal *signal = new QDeclarativeBoundSignal(that.d->object, that.method(), that.d->object);
900 return signal->setExpression(expr);
907 Returns the property value.
909 QVariant QDeclarativeProperty::read() const
916 if (type() & SignalProperty) {
920 } else if (type() & Property) {
922 return d->readValueProperty();
929 Return the \a name property value of \a object. This method is equivalent to:
931 QDeclarativeProperty p(object, name);
935 QVariant QDeclarativeProperty::read(QObject *object, const QString &name)
937 QDeclarativeProperty p(object, name);
942 Return the \a name property value of \a object using the
943 \l{QDeclarativeContext} {context} \a ctxt. This method is
947 QDeclarativeProperty p(object, name, context);
951 QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeContext *ctxt)
953 QDeclarativeProperty p(object, name, ctxt);
959 Return the \a name property value of \a object using the environment
960 for instantiating QML components that is provided by \a engine. .
961 This method is equivalent to:
964 QDeclarativeProperty p(object, name, engine);
968 QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeEngine *engine)
970 QDeclarativeProperty p(object, name, engine);
974 QVariant QDeclarativePropertyPrivate::readValueProperty()
978 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context);
979 QDeclarativeValueType *valueType = 0;
980 if (ep) valueType = ep->valueTypes[core.propType];
981 else valueType = QDeclarativeValueTypeFactory::valueType(core.propType);
984 valueType->read(object, core.coreIndex);
987 valueType->metaObject()->property(this->valueType.valueTypeCoreIdx).read(valueType);
989 if (!ep) delete valueType;
992 } else if (core.flags & QDeclarativePropertyCache::Data::IsQList) {
994 QDeclarativeListProperty<QObject> prop;
995 void *args[] = { &prop, 0 };
996 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
997 return QVariant::fromValue(QDeclarativeListReferencePrivate::init(prop, core.propType, engine));
999 } else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
1002 void *args[] = { &rv, 0 };
1003 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1004 return QVariant::fromValue(rv);
1008 return object->metaObject()->property(core.coreIndex).read(object.data());
1013 //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1014 bool QDeclarativePropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1016 if (!object || !prop.isWritable())
1020 if (prop.isEnumType()) {
1021 QMetaEnum menum = prop.enumerator();
1022 if (v.userType() == QVariant::String
1024 || v.userType() == QVariant::CString
1027 if (prop.isFlagType())
1028 v = QVariant(menum.keysToValue(value.toByteArray()));
1030 v = QVariant(menum.keyToValue(value.toByteArray()));
1031 } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
1032 int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
1033 if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData())
1035 v = QVariant(*reinterpret_cast<const int *>(v.constData()));
1037 v.convert(QVariant::Int);
1040 // the status variable is changed by qt_metacall to indicate what it did
1041 // this feature is currently only used by QtDBus and should not be depended
1042 // upon. Don't change it without looking into QDBusAbstractInterface first
1043 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1044 // changed: result stored directly in value, return the value of status
1046 void *argv[] = { v.data(), &v, &status, &flags };
1047 QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
1051 bool QDeclarativePropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
1053 // Remove any existing bindings on this property
1054 if (!(flags & DontRemoveBinding) &&
1055 (type() & QDeclarativeProperty::Property) && object) {
1056 QDeclarativeAbstractBinding *binding = setBinding(object, core.coreIndex,
1057 valueType.valueTypeCoreIdx, 0, flags);
1058 if (binding) binding->destroy();
1062 if (isValueType()) {
1063 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context);
1065 QDeclarativeValueType *writeBack = 0;
1067 writeBack = ep->valueTypes[core.propType];
1069 writeBack = QDeclarativeValueTypeFactory::valueType(core.propType);
1072 writeBack->read(object, core.coreIndex);
1074 QDeclarativePropertyCache::Data data = core;
1075 data.flags = valueType.flags;
1076 data.coreIndex = valueType.valueTypeCoreIdx;
1077 data.propType = valueType.valueTypePropType;
1078 rv = write(writeBack, data, value, context, flags);
1080 writeBack->write(object, core.coreIndex, flags);
1081 if (!ep) delete writeBack;
1085 rv = write(object, core, value, context, flags);
1092 bool QDeclarativePropertyPrivate::write(QObject *object, const QDeclarativePropertyCache::Data &property,
1093 const QVariant &value, QDeclarativeContextData *context,
1096 int coreIdx = property.coreIndex;
1097 int status = -1; //for dbus
1099 if (property.flags & QDeclarativePropertyCache::Data::IsEnumType) {
1100 QMetaProperty prop = object->metaObject()->property(property.coreIndex);
1102 // Enum values come through the script engine as doubles
1103 if (value.userType() == QVariant::Double) {
1105 double fractional = modf(value.toDouble(), &integral);
1106 if (qFuzzyIsNull(fractional))
1107 v.convert(QVariant::Int);
1109 return writeEnumProperty(prop, coreIdx, object, v, flags);
1112 int propertyType = property.propType;
1113 int variantType = value.userType();
1115 QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context);
1117 if (propertyType == QVariant::Url) {
1121 if (variantType == QVariant::Url) {
1124 } else if (variantType == QVariant::ByteArray) {
1125 u = QUrl(QString::fromUtf8(value.toByteArray()));
1127 } else if (variantType == QVariant::String) {
1128 u = QUrl(value.toString());
1135 if (context && u.isRelative() && !u.isEmpty())
1136 u = context->resolvedUrl(u);
1138 void *argv[] = { &u, 0, &status, &flags };
1139 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1141 } else if (variantType == propertyType) {
1143 void *a[] = { (void *)value.constData(), 0, &status, &flags };
1144 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1146 } else if (qMetaTypeId<QVariant>() == propertyType) {
1148 void *a[] = { (void *)&value, 0, &status, &flags };
1149 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1151 } else if (property.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
1153 const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType());
1158 QObject *o = *(QObject **)value.constData();
1159 const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType);
1161 if (o) valMo = o->metaObject();
1163 if (canConvert(valMo, propMo)) {
1164 void *args[] = { &o, 0, &status, &flags };
1165 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
1167 } else if (!o && canConvert(propMo, valMo)) {
1168 // In the case of a null QObject, we assign the null if there is
1169 // any change that the null variant type could be up or down cast to
1170 // the property type.
1171 void *args[] = { &o, 0, &status, &flags };
1172 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
1178 } else if (property.flags & QDeclarativePropertyCache::Data::IsQList) {
1180 const QMetaObject *listType = 0;
1182 listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
1184 QDeclarativeType *type = QDeclarativeMetaType::qmlType(QDeclarativeMetaType::listType(property.propType));
1185 if (!type) return false;
1186 listType = type->baseMetaObject();
1188 if (!listType) return false;
1190 QDeclarativeListProperty<void> prop;
1191 void *args[] = { &prop, 0 };
1192 QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
1194 if (!prop.clear) return false;
1198 if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
1199 const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1201 for (int ii = 0; ii < list.count(); ++ii) {
1202 QObject *o = list.at(ii);
1203 if (o && !canConvert(o->metaObject(), listType))
1205 prop.append(&prop, (void *)o);
1208 QObject *o = enginePriv?enginePriv->toQObject(value):QDeclarativeMetaType::toQObject(value);
1209 if (o && !canConvert(o->metaObject(), listType))
1211 prop.append(&prop, (void *)o);
1215 Q_ASSERT(variantType != propertyType);
1219 if (variantType == QVariant::String)
1220 v = QDeclarativeStringConverters::variantFromString(value.toString(), propertyType, &ok);
1223 if (v.convert((QVariant::Type)propertyType)) {
1225 } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
1226 QDeclarativeMetaType::StringConverter con = QDeclarativeMetaType::customStringConverter(propertyType);
1228 v = con(value.toString());
1229 if (v.userType() == propertyType)
1235 void *a[] = { (void *)v.constData(), 0, &status, &flags};
1236 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1245 const QMetaObject *QDeclarativePropertyPrivate::rawMetaObjectForType(QDeclarativeEnginePrivate *engine, int userType)
1248 return engine->rawMetaObjectForType(userType);
1250 QDeclarativeType *type = QDeclarativeMetaType::qmlType(userType);
1251 return type?type->baseMetaObject():0;
1256 Sets the property value to \a value and returns true.
1257 Returns false if the property can't be set because the
1258 \a value is the wrong type, for example.
1260 bool QDeclarativeProperty::write(const QVariant &value) const
1262 return QDeclarativePropertyPrivate::write(*this, value, 0);
1266 Writes \a value to the \a name property of \a object. This method
1270 QDeclarativeProperty p(object, name);
1274 bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value)
1276 QDeclarativeProperty p(object, name);
1277 return p.write(value);
1281 Writes \a value to the \a name property of \a object using the
1282 \l{QDeclarativeContext} {context} \a ctxt. This method is
1286 QDeclarativeProperty p(object, name, ctxt);
1290 bool QDeclarativeProperty::write(QObject *object,
1291 const QString &name,
1292 const QVariant &value,
1293 QDeclarativeContext *ctxt)
1295 QDeclarativeProperty p(object, name, ctxt);
1296 return p.write(value);
1301 Writes \a value to the \a name property of \a object using the
1302 environment for instantiating QML components that is provided by
1303 \a engine. This method is equivalent to:
1306 QDeclarativeProperty p(object, name, engine);
1310 bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value,
1311 QDeclarativeEngine *engine)
1313 QDeclarativeProperty p(object, name, engine);
1314 return p.write(value);
1318 Resets the property and returns true if the property is
1319 resettable. If the property is not resettable, nothing happens
1320 and false is returned.
1322 bool QDeclarativeProperty::reset() const
1324 if (isResettable()) {
1325 void *args[] = { 0 };
1326 QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1333 bool QDeclarativePropertyPrivate::write(const QDeclarativeProperty &that,
1334 const QVariant &value, WriteFlags flags)
1338 if (that.d->object && that.type() & QDeclarativeProperty::Property &&
1339 that.d->core.isValid() && that.isWritable())
1340 return that.d->writeValueProperty(value, flags);
1346 Returns true if the property has a change notifier signal, otherwise false.
1348 bool QDeclarativeProperty::hasNotifySignal() const
1350 if (type() & Property && d->object) {
1351 return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1357 Returns true if the property needs a change notifier signal for bindings
1358 to remain upto date, false otherwise.
1360 Some properties, such as attached properties or those whose value never
1361 changes, do not require a change notifier.
1363 bool QDeclarativeProperty::needsNotifySignal() const
1365 return type() & Property && !property().isConstant();
1369 Connects the property's change notifier signal to the
1370 specified \a method of the \a dest object and returns
1371 true. Returns false if this metaproperty does not
1372 represent a regular Qt property or if it has no
1373 change notifier signal, or if the \a dest object does
1374 not have the specified \a method.
1376 bool QDeclarativeProperty::connectNotifySignal(QObject *dest, int method) const
1378 if (!(type() & Property) || !d->object)
1381 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1382 if (prop.hasNotifySignal()) {
1383 return QDeclarativePropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1390 Connects the property's change notifier signal to the
1391 specified \a slot of the \a dest object and returns
1392 true. Returns false if this metaproperty does not
1393 represent a regular Qt property or if it has no
1394 change notifier signal, or if the \a dest object does
1395 not have the specified \a slot.
1397 bool QDeclarativeProperty::connectNotifySignal(QObject *dest, const char *slot) const
1399 if (!(type() & Property) || !d->object)
1402 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1403 if (prop.hasNotifySignal()) {
1404 QByteArray signal(QByteArray("2") + prop.notifySignal().signature());
1405 return QObject::connect(d->object, signal.constData(), dest, slot);
1412 Return the Qt metaobject index of the property.
1414 int QDeclarativeProperty::index() const
1416 return d ? d->core.coreIndex : -1;
1419 int QDeclarativePropertyPrivate::valueTypeCoreIndex(const QDeclarativeProperty &that)
1421 return that.d ? that.d->valueType.valueTypeCoreIdx : -1;
1425 Returns the "property index" for use in bindings. The top 8 bits are the value type
1426 offset, and 0 otherwise. The bottom 24-bits are the regular property index.
1428 int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativeProperty &that)
1432 int rv = that.d->core.coreIndex;
1433 if (rv != -1 && that.d->valueType.valueTypeCoreIdx != -1)
1434 rv = rv | (that.d->valueType.valueTypeCoreIdx << 24);
1438 struct SerializedData {
1440 QDeclarativePropertyCache::Data core;
1443 struct ValueTypeSerializedData : public SerializedData {
1444 QDeclarativePropertyCache::ValueTypeData valueType;
1447 QByteArray QDeclarativePropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
1448 const QMetaObject *subObject, int subIndex)
1450 QMetaProperty prop = metaObject->property(index);
1451 QMetaProperty subProp = subObject->property(subIndex);
1453 ValueTypeSerializedData sd;
1454 memset(&sd, 0, sizeof(sd));
1455 sd.isValueType = true;
1456 sd.core.load(metaObject->property(index));
1457 sd.valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(subProp);
1458 sd.valueType.valueTypeCoreIdx = subIndex;
1459 sd.valueType.valueTypePropType = subProp.userType();
1461 QByteArray rv((const char *)&sd, sizeof(sd));
1466 QByteArray QDeclarativePropertyPrivate::saveProperty(const QMetaObject *metaObject, int index)
1469 memset(&sd, 0, sizeof(sd));
1470 sd.isValueType = false;
1471 sd.core.load(metaObject->property(index));
1473 QByteArray rv((const char *)&sd, sizeof(sd));
1477 QDeclarativeProperty
1478 QDeclarativePropertyPrivate::restore(const QByteArray &data, QObject *object, QDeclarativeContextData *ctxt)
1480 QDeclarativeProperty prop;
1485 const SerializedData *sd = (const SerializedData *)data.constData();
1486 if (sd->isValueType) {
1487 const ValueTypeSerializedData *vt = (const ValueTypeSerializedData *)sd;
1488 return restore(vt->core, vt->valueType, object, ctxt);
1490 QDeclarativePropertyCache::ValueTypeData data;
1491 return restore(sd->core, data, object, ctxt);
1495 QDeclarativeProperty
1496 QDeclarativePropertyPrivate::restore(const QDeclarativePropertyCache::Data &data, const QDeclarativePropertyCache::ValueTypeData &valueType, QObject *object, QDeclarativeContextData *ctxt)
1498 QDeclarativeProperty prop;
1500 prop.d = new QDeclarativePropertyPrivate;
1501 prop.d->object = object;
1502 prop.d->context = ctxt;
1503 prop.d->engine = ctxt->engine;
1505 prop.d->core = data;
1506 prop.d->valueType = valueType;
1512 Returns true if lhs and rhs refer to the same metaobject data
1514 bool QDeclarativePropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
1516 return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1520 Returns true if from inherits to.
1522 bool QDeclarativePropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
1524 if (from && to == &QObject::staticMetaObject)
1528 if (equal(from, to))
1530 from = from->superClass();
1537 Return the signal corresponding to \a name
1539 QMetaMethod QDeclarativePropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1542 int methods = mo->methodCount();
1543 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1544 QMetaMethod method = mo->method(ii);
1545 QByteArray methodName = method.signature();
1546 int idx = methodName.indexOf('(');
1547 methodName = methodName.left(idx);
1549 if (methodName == name)
1553 // If no signal is found, but the signal is of the form "onBlahChanged",
1554 // return the notify signal for the property "Blah"
1555 if (name.endsWith("Changed")) {
1556 QByteArray propName = name.mid(0, name.length() - 7);
1557 int propIdx = mo->indexOfProperty(propName.constData());
1559 QMetaProperty prop = mo->property(propIdx);
1560 if (prop.hasNotifySignal())
1561 return prop.notifySignal();
1565 return QMetaMethod();
1568 static inline int QMetaObject_methods(const QMetaObject *metaObject)
1574 int classInfoCount, classInfoData;
1575 int methodCount, methodData;
1576 int propertyCount, propertyData;
1579 return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
1582 static inline int QMetaObject_properties(const QMetaObject *metaObject)
1588 int classInfoCount, classInfoData;
1589 int methodCount, methodData;
1590 int propertyCount, propertyData;
1593 return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
1596 static inline void flush_vme_signal(const QObject *object, int index)
1598 QDeclarativeData *data = static_cast<QDeclarativeData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1599 if (data && data->propertyCache) {
1600 QDeclarativePropertyCache::Data *property = data->propertyCache->method(index);
1602 if (property && property->flags & QDeclarativePropertyCache::Data::IsVMESignal) {
1603 const QMetaObject *metaObject = object->metaObject();
1604 int methodOffset = metaObject->methodOffset();
1606 while (methodOffset > index) {
1607 metaObject = metaObject->d.superdata;
1608 methodOffset -= QMetaObject_methods(metaObject);
1611 QDeclarativeVMEMetaObject *vme =
1612 static_cast<QDeclarativeVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
1614 vme->connectAliasSignal(index);
1620 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1621 \a type and \a types. This behaves identically to QMetaObject::connect() except that
1622 it connects any lazy "proxy" signal connections set up by QML.
1624 It is possible that this logic should be moved to QMetaObject::connect().
1626 bool QDeclarativePropertyPrivate::connect(const QObject *sender, int signal_index,
1627 const QObject *receiver, int method_index,
1628 int type, int *types)
1630 flush_vme_signal(sender, signal_index);
1631 flush_vme_signal(receiver, method_index);
1633 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1637 Return \a metaObject's [super] meta object that provides data for \a property.
1639 const QMetaObject *QDeclarativePropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
1641 int propertyOffset = metaObject->propertyOffset();
1643 while (propertyOffset > property) {
1644 metaObject = metaObject->d.superdata;
1645 propertyOffset -= QMetaObject_properties(metaObject);