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 ** 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 "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 Creating a QDeclarativeProperty without a context will render some
188 properties - like attached properties - inaccessible.
190 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeContext *ctxt)
191 : d(new QDeclarativePropertyPrivate)
193 d->context = ctxt?QDeclarativeContextData::get(ctxt):0;
194 d->engine = ctxt?ctxt->engine():0;
195 d->initProperty(obj, name);
196 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
200 Creates a QDeclarativeProperty for the property \a name of \a obj
201 using the environment for instantiating QML components that is
202 provided by \a engine.
204 QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeEngine *engine)
205 : d(new QDeclarativePropertyPrivate)
209 d->initProperty(obj, name);
210 if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
213 Q_GLOBAL_STATIC(QDeclarativeValueTypeFactory, qmlValueTypes);
215 void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name)
219 QDeclarativeTypeNameCache *typeNameCache = context?context->imports:0;
221 QStringList path = name.split(QLatin1Char('.'));
222 if (path.isEmpty()) return;
224 QObject *currentObject = obj;
226 // Everything up to the last property must be an "object type" property
227 for (int ii = 0; ii < path.count() - 1; ++ii) {
228 const QString &pathName = path.at(ii);
230 if (QDeclarativeTypeNameCache::Data *data = typeNameCache?typeNameCache->data(pathName):0) {
232 QDeclarativeAttachedPropertiesFunc func = data->type->attachedPropertiesFunction();
233 if (!func) return; // Not an attachable type
235 currentObject = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), currentObject);
236 if (!currentObject) return; // Something is broken with the attachable type
238 Q_ASSERT(data->typeNamespace);
239 if ((ii + 1) == path.count()) return; // No type following the namespace
241 ++ii; data = data->typeNamespace->data(path.at(ii));
242 if (!data || !data->type) return; // Invalid type in namespace
244 QDeclarativeAttachedPropertiesFunc func = data->type->attachedPropertiesFunction();
245 if (!func) return; // Not an attachable type
247 currentObject = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), currentObject);
248 if (!currentObject) return; // Something is broken with the attachable type
252 QDeclarativePropertyCache::Data local;
253 QDeclarativePropertyCache::Data *property =
254 QDeclarativePropertyCache::property(engine, obj, pathName, local);
256 if (!property) return; // Not a property
257 if (property->flags & QDeclarativePropertyCache::Data::IsFunction)
258 return; // Not an object property
260 if (ii == (path.count() - 2) && QDeclarativeValueTypeFactory::isValueType(property->propType)) {
261 // We're now at a value type property. We can use a global valuetypes array as we
262 // never actually use the objects, just look up their properties.
263 QObject *typeObject = (*qmlValueTypes())[property->propType];
264 if (!typeObject) return; // Not a value type
266 int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
267 if (idx == -1) return; // Value type property does not exist
269 QMetaProperty vtProp = typeObject->metaObject()->property(idx);
271 object = currentObject;
273 valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(vtProp);
274 valueType.valueTypeCoreIdx = idx;
275 valueType.valueTypePropType = vtProp.userType();
279 if (!(property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived))
280 return; // Not an object property
282 void *args[] = { ¤tObject, 0 };
283 QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
284 if (!currentObject) return; // No value
291 const QString &terminal = path.last();
293 if (terminal.count() >= 3 &&
294 terminal.at(0) == QLatin1Char('o') &&
295 terminal.at(1) == QLatin1Char('n') &&
296 terminal.at(2).isUpper()) {
298 QString signalName = terminal.mid(2);
299 signalName[0] = signalName.at(0).toLower();
301 QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName.toLatin1().constData());
302 if (method.signature()) {
303 object = currentObject;
310 QDeclarativePropertyCache::Data local;
311 QDeclarativePropertyCache::Data *property =
312 QDeclarativePropertyCache::property(engine, currentObject, terminal, local);
313 if (property && !(property->flags & QDeclarativePropertyCache::Data::IsFunction)) {
314 object = currentObject;
316 nameCache = terminal;
322 Create a copy of \a other.
324 QDeclarativeProperty::QDeclarativeProperty(const QDeclarativeProperty &other)
332 \enum QDeclarativeProperty::PropertyTypeCategory
334 This enum specifies a category of QML property.
336 \value InvalidCategory The property is invalid, or is a signal property.
337 \value List The property is a QDeclarativeListProperty list property
338 \value Object The property is a QObject derived type pointer
339 \value Normal The property is a normal value property.
343 \enum QDeclarativeProperty::Type
345 This enum specifies a type of QML property.
347 \value Invalid The property is invalid.
348 \value Property The property is a regular Qt property.
349 \value SignalProperty The property is a signal property.
353 Returns the property category.
355 QDeclarativeProperty::PropertyTypeCategory QDeclarativeProperty::propertyTypeCategory() const
357 return d ? d->propertyTypeCategory() : InvalidCategory;
360 QDeclarativeProperty::PropertyTypeCategory
361 QDeclarativePropertyPrivate::propertyTypeCategory() const
363 uint type = this->type();
366 return QDeclarativeProperty::Normal;
367 } else if (type & QDeclarativeProperty::Property) {
368 int type = propertyType();
369 if (type == QVariant::Invalid)
370 return QDeclarativeProperty::InvalidCategory;
371 else if (QDeclarativeValueTypeFactory::isValueType((uint)type))
372 return QDeclarativeProperty::Normal;
373 else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived)
374 return QDeclarativeProperty::Object;
375 else if (core.flags & QDeclarativePropertyCache::Data::IsQList)
376 return QDeclarativeProperty::List;
378 return QDeclarativeProperty::Normal;
380 return QDeclarativeProperty::InvalidCategory;
385 Returns the type name of the property, or 0 if the property has no type
388 const char *QDeclarativeProperty::propertyTypeName() const
392 if (d->isValueType()) {
394 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context);
395 QDeclarativeValueType *valueType = 0;
396 if (ep) valueType = ep->valueTypes[d->core.propType];
397 else valueType = QDeclarativeValueTypeFactory::valueType(d->core.propType);
400 const char *rv = valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).typeName();
402 if (!ep) delete valueType;
405 } else if (d->object && type() & Property && d->core.isValid()) {
406 return d->object->metaObject()->property(d->core.coreIndex).typeName();
413 Returns true if \a other and this QDeclarativeProperty represent the same
416 bool QDeclarativeProperty::operator==(const QDeclarativeProperty &other) const
420 // category is intentially omitted here as it is generated
421 // from the other members
422 return d->object == other.d->object &&
423 d->core == other.d->core &&
424 d->valueType == other.d->valueType;
428 Returns the QVariant type of the property, or QVariant::Invalid if the
429 property has no QVariant type.
431 int QDeclarativeProperty::propertyType() const
433 return d ? d->propertyType() : int(QVariant::Invalid);
436 bool QDeclarativePropertyPrivate::isValueType() const
438 return valueType.valueTypeCoreIdx != -1;
441 int QDeclarativePropertyPrivate::propertyType() const
443 uint type = this->type();
445 return valueType.valueTypePropType;
446 } else if (type & QDeclarativeProperty::Property) {
447 if (core.propType == (int)QVariant::LastType)
448 return qMetaTypeId<QVariant>();
450 return core.propType;
452 return QVariant::Invalid;
456 QDeclarativeProperty::Type QDeclarativePropertyPrivate::type() const
458 if (core.flags & QDeclarativePropertyCache::Data::IsFunction)
459 return QDeclarativeProperty::SignalProperty;
460 else if (core.isValid())
461 return QDeclarativeProperty::Property;
463 return QDeclarativeProperty::Invalid;
467 Returns the type of the property.
469 QDeclarativeProperty::Type QDeclarativeProperty::type() const
471 return d ? d->type() : Invalid;
475 Returns true if this QDeclarativeProperty represents a regular Qt property.
477 bool QDeclarativeProperty::isProperty() const
479 return type() & Property;
483 Returns true if this QDeclarativeProperty represents a QML signal property.
485 bool QDeclarativeProperty::isSignalProperty() const
487 return type() & SignalProperty;
491 Returns the QDeclarativeProperty's QObject.
493 QObject *QDeclarativeProperty::object() const
495 return d ? d->object : 0;
499 Assign \a other to this QDeclarativeProperty.
501 QDeclarativeProperty &QDeclarativeProperty::operator=(const QDeclarativeProperty &other)
513 Returns true if the property is writable, otherwise false.
515 bool QDeclarativeProperty::isWritable() const
521 if (d->core.flags & QDeclarativePropertyCache::Data::IsQList) //list
523 else if (d->core.flags & QDeclarativePropertyCache::Data::IsFunction) //signal handler
525 else if (d->core.isValid()) //normal property
526 return d->core.flags & QDeclarativePropertyCache::Data::IsWritable;
532 Returns true if the property is designable, otherwise false.
534 bool QDeclarativeProperty::isDesignable() const
538 if (type() & Property && d->core.isValid() && d->object)
539 return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
545 Returns true if the property is resettable, otherwise false.
547 bool QDeclarativeProperty::isResettable() const
551 if (type() & Property && d->core.isValid() && d->object)
552 return d->core.flags & QDeclarativePropertyCache::Data::IsResettable;
558 Returns true if the QDeclarativeProperty refers to a valid property, otherwise
561 bool QDeclarativeProperty::isValid() const
565 return type() != Invalid;
569 Return the name of this QML property.
571 QString QDeclarativeProperty::name() const
575 if (!d->isNameCached) {
578 } else if (d->isValueType()) {
579 QString rv = d->core.name(d->object) + QLatin1Char('.');
581 QDeclarativeEnginePrivate *ep = d->engine?QDeclarativeEnginePrivate::get(d->engine):0;
582 QDeclarativeValueType *valueType = 0;
583 if (ep) valueType = ep->valueTypes[d->core.propType];
584 else valueType = QDeclarativeValueTypeFactory::valueType(d->core.propType);
587 rv += QString::fromUtf8(valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).name());
589 if (!ep) delete valueType;
592 } else if (type() & SignalProperty) {
593 QString name = QLatin1String("on") + d->core.name(d->object);
594 name[2] = name.at(2).toUpper();
597 d->nameCache = d->core.name(d->object);
599 d->isNameCached = true;
606 Returns the \l{QMetaProperty} {Qt property} associated with
609 QMetaProperty QDeclarativeProperty::property() const
612 return QMetaProperty();
613 if (type() & Property && d->core.isValid() && d->object)
614 return d->object->metaObject()->property(d->core.coreIndex);
616 return QMetaProperty();
620 Return the QMetaMethod for this property if it is a SignalProperty,
621 otherwise returns an invalid QMetaMethod.
623 QMetaMethod QDeclarativeProperty::method() const
626 return QMetaMethod();
627 if (type() & SignalProperty && d->object)
628 return d->object->metaObject()->method(d->core.coreIndex);
630 return QMetaMethod();
634 Returns the binding associated with this property, or 0 if no binding
637 QDeclarativeAbstractBinding *
638 QDeclarativePropertyPrivate::binding(const QDeclarativeProperty &that)
640 if (!that.d || !that.isProperty() || !that.d->object)
643 return binding(that.d->object, that.d->core.coreIndex, that.d->valueType.valueTypeCoreIdx);
647 Set the binding associated with this property to \a newBinding. Returns
648 the existing binding (if any), otherwise 0.
650 \a newBinding will be enabled, and the returned binding (if any) will be
653 Ownership of \a newBinding transfers to QML. Ownership of the return value
654 is assumed by the caller.
656 \a flags is passed through to the binding and is used for the initial update (when
657 the binding sets the initial value, it will use these flags for the write).
659 QDeclarativeAbstractBinding *
660 QDeclarativePropertyPrivate::setBinding(const QDeclarativeProperty &that,
661 QDeclarativeAbstractBinding *newBinding,
664 if (!that.d || !that.isProperty() || !that.d->object) {
666 newBinding->destroy();
670 return that.d->setBinding(that.d->object, that.d->core.coreIndex,
671 that.d->valueType.valueTypeCoreIdx, newBinding, flags);
674 QDeclarativeAbstractBinding *
675 QDeclarativePropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
677 QDeclarativeData *data = QDeclarativeData::get(object);
681 QDeclarativePropertyCache::Data *propertyData =
682 data->propertyCache?data->propertyCache->property(coreIndex):0;
683 if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
684 const QDeclarativeVMEMetaObject *vme =
685 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
687 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
688 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
691 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
692 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
693 return binding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex);
696 if (!data->hasBindingBit(coreIndex))
699 QDeclarativeAbstractBinding *binding = data->bindings;
700 while (binding && binding->propertyIndex() != coreIndex)
701 binding = binding->m_nextBinding;
703 if (binding && valueTypeIndex != -1) {
704 if (binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) {
705 int index = coreIndex | (valueTypeIndex << 24);
706 binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
713 void QDeclarativePropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
714 QObject **targetObject, int *targetBindingIndex)
716 int coreIndex = bindingIndex & 0xFFFFFF;
717 int valueTypeIndex = bindingIndex >> 24;
718 if (valueTypeIndex == 0) valueTypeIndex = -1;
720 QDeclarativeData *data = QDeclarativeData::get(object, false);
722 QDeclarativePropertyCache::Data *propertyData =
723 data->propertyCache?data->propertyCache->property(coreIndex):0;
724 if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
725 const QDeclarativeVMEMetaObject *vme =
726 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
727 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
728 if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
729 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
730 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
732 int aBindingIndex = aCoreIndex;
733 if (aValueTypeIndex != -1)
734 aBindingIndex |= aValueTypeIndex << 24;
735 else if (valueTypeIndex != -1)
736 aBindingIndex |= valueTypeIndex << 24;
738 findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
744 *targetObject = object;
745 *targetBindingIndex = bindingIndex;
748 QDeclarativeAbstractBinding *
749 QDeclarativePropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
750 QDeclarativeAbstractBinding *newBinding, WriteFlags flags)
752 QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
753 QDeclarativeAbstractBinding *binding = 0;
756 QDeclarativePropertyCache::Data *propertyData =
757 data->propertyCache?data->propertyCache->property(coreIndex):0;
758 if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
759 const QDeclarativeVMEMetaObject *vme =
760 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
762 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
763 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
764 if (newBinding) newBinding->destroy();
768 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
769 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
770 return setBinding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex,
775 if (data && data->hasBindingBit(coreIndex)) {
776 binding = data->bindings;
778 while (binding && binding->propertyIndex() != coreIndex)
779 binding = binding->m_nextBinding;
782 int index = coreIndex;
783 if (valueTypeIndex != -1)
784 index |= (valueTypeIndex << 24);
786 if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy)
787 binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
790 binding->removeFromObject();
791 binding->setEnabled(false, 0);
795 newBinding->addToObject(object, index);
796 newBinding->setEnabled(true, flags);
802 QDeclarativeAbstractBinding *
803 QDeclarativePropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
804 QDeclarativeAbstractBinding *newBinding)
806 QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
807 QDeclarativeAbstractBinding *binding = 0;
810 QDeclarativePropertyCache::Data *propertyData =
811 data->propertyCache?data->propertyCache->property(coreIndex):0;
812 if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
813 const QDeclarativeVMEMetaObject *vme =
814 static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
816 QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
817 if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
818 if (newBinding) newBinding->destroy();
822 // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
823 Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
824 return setBindingNoEnable(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex,
829 if (data && data->hasBindingBit(coreIndex)) {
830 binding = data->bindings;
832 while (binding && binding->propertyIndex() != coreIndex)
833 binding = binding->m_nextBinding;
836 int index = coreIndex;
837 if (valueTypeIndex != -1)
838 index |= (valueTypeIndex << 24);
840 if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy)
841 binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
844 binding->removeFromObject();
847 newBinding->addToObject(object, index);
853 Returns the expression associated with this signal property, or 0 if no
854 signal expression exists.
856 QDeclarativeExpression *
857 QDeclarativePropertyPrivate::signalExpression(const QDeclarativeProperty &that)
859 if (!(that.type() & QDeclarativeProperty::SignalProperty))
862 const QObjectList &children = that.d->object->children();
864 for (int ii = 0; ii < children.count(); ++ii) {
865 QObject *child = children.at(ii);
867 QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
868 if (signal && signal->index() == that.index())
869 return signal->expression();
876 Set the signal expression associated with this signal property to \a expr.
877 Returns the existing signal expression (if any), otherwise 0.
879 Ownership of \a expr transfers to QML. Ownership of the return value is
880 assumed by the caller.
882 QDeclarativeExpression *
883 QDeclarativePropertyPrivate::setSignalExpression(const QDeclarativeProperty &that,
884 QDeclarativeExpression *expr)
886 if (!(that.type() & QDeclarativeProperty::SignalProperty)) {
891 const QObjectList &children = that.d->object->children();
893 for (int ii = 0; ii < children.count(); ++ii) {
894 QObject *child = children.at(ii);
896 QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
897 if (signal && signal->index() == that.index())
898 return signal->setExpression(expr);
902 QDeclarativeBoundSignal *signal = new QDeclarativeBoundSignal(that.d->object, that.method(), that.d->object);
903 return signal->setExpression(expr);
910 Returns the property value.
912 QVariant QDeclarativeProperty::read() const
919 if (type() & SignalProperty) {
923 } else if (type() & Property) {
925 return d->readValueProperty();
932 Return the \a name property value of \a object. This method is equivalent to:
934 QDeclarativeProperty p(object, name);
938 QVariant QDeclarativeProperty::read(QObject *object, const QString &name)
940 QDeclarativeProperty p(object, name);
945 Return the \a name property value of \a object using the
946 \l{QDeclarativeContext} {context} \a ctxt. This method is
950 QDeclarativeProperty p(object, name, context);
954 QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeContext *ctxt)
956 QDeclarativeProperty p(object, name, ctxt);
962 Return the \a name property value of \a object using the environment
963 for instantiating QML components that is provided by \a engine. .
964 This method is equivalent to:
967 QDeclarativeProperty p(object, name, engine);
971 QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeEngine *engine)
973 QDeclarativeProperty p(object, name, engine);
977 QVariant QDeclarativePropertyPrivate::readValueProperty()
981 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context);
982 QDeclarativeValueType *valueType = 0;
983 if (ep) valueType = ep->valueTypes[core.propType];
984 else valueType = QDeclarativeValueTypeFactory::valueType(core.propType);
987 valueType->read(object, core.coreIndex);
990 valueType->metaObject()->property(this->valueType.valueTypeCoreIdx).read(valueType);
992 if (!ep) delete valueType;
995 } else if (core.flags & QDeclarativePropertyCache::Data::IsQList) {
997 QDeclarativeListProperty<QObject> prop;
998 void *args[] = { &prop, 0 };
999 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1000 return QVariant::fromValue(QDeclarativeListReferencePrivate::init(prop, core.propType, engine));
1002 } else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
1005 void *args[] = { &rv, 0 };
1006 QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
1007 return QVariant::fromValue(rv);
1011 return object->metaObject()->property(core.coreIndex).read(object.data());
1016 //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
1017 bool QDeclarativePropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
1019 if (!object || !prop.isWritable())
1023 if (prop.isEnumType()) {
1024 QMetaEnum menum = prop.enumerator();
1025 if (v.userType() == QVariant::String
1027 || v.userType() == QVariant::CString
1030 if (prop.isFlagType())
1031 v = QVariant(menum.keysToValue(value.toByteArray()));
1033 v = QVariant(menum.keyToValue(value.toByteArray()));
1034 } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
1035 int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
1036 if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData())
1038 v = QVariant(*reinterpret_cast<const int *>(v.constData()));
1040 v.convert(QVariant::Int);
1043 // the status variable is changed by qt_metacall to indicate what it did
1044 // this feature is currently only used by QtDBus and should not be depended
1045 // upon. Don't change it without looking into QDBusAbstractInterface first
1046 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
1047 // changed: result stored directly in value, return the value of status
1049 void *argv[] = { v.data(), &v, &status, &flags };
1050 QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
1054 bool QDeclarativePropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
1056 // Remove any existing bindings on this property
1057 if (!(flags & DontRemoveBinding) &&
1058 (type() & QDeclarativeProperty::Property) && object) {
1059 QDeclarativeAbstractBinding *binding = setBinding(object, core.coreIndex,
1060 valueType.valueTypeCoreIdx, 0, flags);
1061 if (binding) binding->destroy();
1065 if (isValueType()) {
1066 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context);
1068 QDeclarativeValueType *writeBack = 0;
1070 writeBack = ep->valueTypes[core.propType];
1072 writeBack = QDeclarativeValueTypeFactory::valueType(core.propType);
1075 writeBack->read(object, core.coreIndex);
1077 QDeclarativePropertyCache::Data data = core;
1078 data.flags = valueType.flags;
1079 data.coreIndex = valueType.valueTypeCoreIdx;
1080 data.propType = valueType.valueTypePropType;
1081 rv = write(writeBack, data, value, context, flags);
1083 writeBack->write(object, core.coreIndex, flags);
1084 if (!ep) delete writeBack;
1088 rv = write(object, core, value, context, flags);
1095 bool QDeclarativePropertyPrivate::write(QObject *object, const QDeclarativePropertyCache::Data &property,
1096 const QVariant &value, QDeclarativeContextData *context,
1099 int coreIdx = property.coreIndex;
1100 int status = -1; //for dbus
1102 if (property.flags & QDeclarativePropertyCache::Data::IsEnumType) {
1103 QMetaProperty prop = object->metaObject()->property(property.coreIndex);
1105 // Enum values come through the script engine as doubles
1106 if (value.userType() == QVariant::Double) {
1108 double fractional = modf(value.toDouble(), &integral);
1109 if (qFuzzyIsNull(fractional))
1110 v.convert(QVariant::Int);
1112 return writeEnumProperty(prop, coreIdx, object, v, flags);
1115 int propertyType = property.propType;
1116 int variantType = value.userType();
1118 QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context);
1120 if (propertyType == QVariant::Url) {
1124 if (variantType == QVariant::Url) {
1127 } else if (variantType == QVariant::ByteArray) {
1128 u = QUrl(QString::fromUtf8(value.toByteArray()));
1130 } else if (variantType == QVariant::String) {
1131 u = QUrl(value.toString());
1138 if (context && u.isRelative() && !u.isEmpty())
1139 u = context->resolvedUrl(u);
1141 void *argv[] = { &u, 0, &status, &flags };
1142 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
1144 } else if (variantType == propertyType) {
1146 void *a[] = { (void *)value.constData(), 0, &status, &flags };
1147 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1149 } else if (qMetaTypeId<QVariant>() == propertyType) {
1151 void *a[] = { (void *)&value, 0, &status, &flags };
1152 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1154 } else if (property.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
1156 const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType());
1161 QObject *o = *(QObject **)value.constData();
1162 const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType);
1164 if (o) valMo = o->metaObject();
1166 if (canConvert(valMo, propMo)) {
1167 void *args[] = { &o, 0, &status, &flags };
1168 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
1170 } else if (!o && canConvert(propMo, valMo)) {
1171 // In the case of a null QObject, we assign the null if there is
1172 // any change that the null variant type could be up or down cast to
1173 // the property type.
1174 void *args[] = { &o, 0, &status, &flags };
1175 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
1181 } else if (property.flags & QDeclarativePropertyCache::Data::IsQList) {
1183 const QMetaObject *listType = 0;
1185 listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
1187 QDeclarativeType *type = QDeclarativeMetaType::qmlType(QDeclarativeMetaType::listType(property.propType));
1188 if (!type) return false;
1189 listType = type->baseMetaObject();
1191 if (!listType) return false;
1193 QDeclarativeListProperty<void> prop;
1194 void *args[] = { &prop, 0 };
1195 QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
1197 if (!prop.clear) return false;
1201 if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
1202 const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
1204 for (int ii = 0; ii < list.count(); ++ii) {
1205 QObject *o = list.at(ii);
1206 if (o && !canConvert(o->metaObject(), listType))
1208 prop.append(&prop, (void *)o);
1211 QObject *o = enginePriv?enginePriv->toQObject(value):QDeclarativeMetaType::toQObject(value);
1212 if (o && !canConvert(o->metaObject(), listType))
1214 prop.append(&prop, (void *)o);
1218 Q_ASSERT(variantType != propertyType);
1222 if (variantType == QVariant::String)
1223 v = QDeclarativeStringConverters::variantFromString(value.toString(), propertyType, &ok);
1226 if (v.convert((QVariant::Type)propertyType)) {
1228 } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
1229 QDeclarativeMetaType::StringConverter con = QDeclarativeMetaType::customStringConverter(propertyType);
1231 v = con(value.toString());
1232 if (v.userType() == propertyType)
1238 void *a[] = { (void *)v.constData(), 0, &status, &flags};
1239 QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
1248 const QMetaObject *QDeclarativePropertyPrivate::rawMetaObjectForType(QDeclarativeEnginePrivate *engine, int userType)
1251 return engine->rawMetaObjectForType(userType);
1253 QDeclarativeType *type = QDeclarativeMetaType::qmlType(userType);
1254 return type?type->baseMetaObject():0;
1259 Sets the property value to \a value and returns true.
1260 Returns false if the property can't be set because the
1261 \a value is the wrong type, for example.
1263 bool QDeclarativeProperty::write(const QVariant &value) const
1265 return QDeclarativePropertyPrivate::write(*this, value, 0);
1269 Writes \a value to the \a name property of \a object. This method
1273 QDeclarativeProperty p(object, name);
1277 bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value)
1279 QDeclarativeProperty p(object, name);
1280 return p.write(value);
1284 Writes \a value to the \a name property of \a object using the
1285 \l{QDeclarativeContext} {context} \a ctxt. This method is
1289 QDeclarativeProperty p(object, name, ctxt);
1293 bool QDeclarativeProperty::write(QObject *object,
1294 const QString &name,
1295 const QVariant &value,
1296 QDeclarativeContext *ctxt)
1298 QDeclarativeProperty p(object, name, ctxt);
1299 return p.write(value);
1304 Writes \a value to the \a name property of \a object using the
1305 environment for instantiating QML components that is provided by
1306 \a engine. This method is equivalent to:
1309 QDeclarativeProperty p(object, name, engine);
1313 bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value,
1314 QDeclarativeEngine *engine)
1316 QDeclarativeProperty p(object, name, engine);
1317 return p.write(value);
1321 Resets the property and returns true if the property is
1322 resettable. If the property is not resettable, nothing happens
1323 and false is returned.
1325 bool QDeclarativeProperty::reset() const
1327 if (isResettable()) {
1328 void *args[] = { 0 };
1329 QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
1336 bool QDeclarativePropertyPrivate::write(const QDeclarativeProperty &that,
1337 const QVariant &value, WriteFlags flags)
1341 if (that.d->object && that.type() & QDeclarativeProperty::Property &&
1342 that.d->core.isValid() && that.isWritable())
1343 return that.d->writeValueProperty(value, flags);
1349 Returns true if the property has a change notifier signal, otherwise false.
1351 bool QDeclarativeProperty::hasNotifySignal() const
1353 if (type() & Property && d->object) {
1354 return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
1360 Returns true if the property needs a change notifier signal for bindings
1361 to remain upto date, false otherwise.
1363 Some properties, such as attached properties or those whose value never
1364 changes, do not require a change notifier.
1366 bool QDeclarativeProperty::needsNotifySignal() const
1368 return type() & Property && !property().isConstant();
1372 Connects the property's change notifier signal to the
1373 specified \a method of the \a dest object and returns
1374 true. Returns false if this metaproperty does not
1375 represent a regular Qt property or if it has no
1376 change notifier signal, or if the \a dest object does
1377 not have the specified \a method.
1379 bool QDeclarativeProperty::connectNotifySignal(QObject *dest, int method) const
1381 if (!(type() & Property) || !d->object)
1384 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1385 if (prop.hasNotifySignal()) {
1386 return QDeclarativePropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
1393 Connects the property's change notifier signal to the
1394 specified \a slot of the \a dest object and returns
1395 true. Returns false if this metaproperty does not
1396 represent a regular Qt property or if it has no
1397 change notifier signal, or if the \a dest object does
1398 not have the specified \a slot.
1400 bool QDeclarativeProperty::connectNotifySignal(QObject *dest, const char *slot) const
1402 if (!(type() & Property) || !d->object)
1405 QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
1406 if (prop.hasNotifySignal()) {
1407 QByteArray signal(QByteArray("2") + prop.notifySignal().signature());
1408 return QObject::connect(d->object, signal.constData(), dest, slot);
1415 Return the Qt metaobject index of the property.
1417 int QDeclarativeProperty::index() const
1419 return d ? d->core.coreIndex : -1;
1422 int QDeclarativePropertyPrivate::valueTypeCoreIndex(const QDeclarativeProperty &that)
1424 return that.d ? that.d->valueType.valueTypeCoreIdx : -1;
1428 Returns the "property index" for use in bindings. The top 8 bits are the value type
1429 offset, and 0 otherwise. The bottom 24-bits are the regular property index.
1431 int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativeProperty &that)
1435 int rv = that.d->core.coreIndex;
1436 if (rv != -1 && that.d->valueType.valueTypeCoreIdx != -1)
1437 rv = rv | (that.d->valueType.valueTypeCoreIdx << 24);
1441 struct SerializedData {
1443 QDeclarativePropertyCache::Data core;
1446 struct ValueTypeSerializedData : public SerializedData {
1447 QDeclarativePropertyCache::ValueTypeData valueType;
1450 QByteArray QDeclarativePropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
1451 const QMetaObject *subObject, int subIndex)
1453 QMetaProperty prop = metaObject->property(index);
1454 QMetaProperty subProp = subObject->property(subIndex);
1456 ValueTypeSerializedData sd;
1457 memset(&sd, 0, sizeof(sd));
1458 sd.isValueType = true;
1459 sd.core.load(metaObject->property(index));
1460 sd.valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(subProp);
1461 sd.valueType.valueTypeCoreIdx = subIndex;
1462 sd.valueType.valueTypePropType = subProp.userType();
1464 QByteArray rv((const char *)&sd, sizeof(sd));
1469 QByteArray QDeclarativePropertyPrivate::saveProperty(const QMetaObject *metaObject, int index)
1472 memset(&sd, 0, sizeof(sd));
1473 sd.isValueType = false;
1474 sd.core.load(metaObject->property(index));
1476 QByteArray rv((const char *)&sd, sizeof(sd));
1480 QDeclarativeProperty
1481 QDeclarativePropertyPrivate::restore(const QByteArray &data, QObject *object, QDeclarativeContextData *ctxt)
1483 QDeclarativeProperty prop;
1488 const SerializedData *sd = (const SerializedData *)data.constData();
1489 if (sd->isValueType) {
1490 const ValueTypeSerializedData *vt = (const ValueTypeSerializedData *)sd;
1491 return restore(vt->core, vt->valueType, object, ctxt);
1493 QDeclarativePropertyCache::ValueTypeData data;
1494 return restore(sd->core, data, object, ctxt);
1498 QDeclarativeProperty
1499 QDeclarativePropertyPrivate::restore(const QDeclarativePropertyCache::Data &data, const QDeclarativePropertyCache::ValueTypeData &valueType, QObject *object, QDeclarativeContextData *ctxt)
1501 QDeclarativeProperty prop;
1503 prop.d = new QDeclarativePropertyPrivate;
1504 prop.d->object = object;
1505 prop.d->context = ctxt;
1506 prop.d->engine = ctxt->engine;
1508 prop.d->core = data;
1509 prop.d->valueType = valueType;
1515 Returns true if lhs and rhs refer to the same metaobject data
1517 bool QDeclarativePropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
1519 return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1523 Returns true if from inherits to.
1525 bool QDeclarativePropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
1527 if (from && to == &QObject::staticMetaObject)
1531 if (equal(from, to))
1533 from = from->superClass();
1540 Return the signal corresponding to \a name
1542 QMetaMethod QDeclarativePropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
1545 int methods = mo->methodCount();
1546 for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
1547 QMetaMethod method = mo->method(ii);
1548 QByteArray methodName = method.signature();
1549 int idx = methodName.indexOf('(');
1550 methodName = methodName.left(idx);
1552 if (methodName == name)
1556 // If no signal is found, but the signal is of the form "onBlahChanged",
1557 // return the notify signal for the property "Blah"
1558 if (name.endsWith("Changed")) {
1559 QByteArray propName = name.mid(0, name.length() - 7);
1560 int propIdx = mo->indexOfProperty(propName.constData());
1562 QMetaProperty prop = mo->property(propIdx);
1563 if (prop.hasNotifySignal())
1564 return prop.notifySignal();
1568 return QMetaMethod();
1571 static inline int QMetaObject_methods(const QMetaObject *metaObject)
1577 int classInfoCount, classInfoData;
1578 int methodCount, methodData;
1579 int propertyCount, propertyData;
1582 return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
1585 static inline int QMetaObject_properties(const QMetaObject *metaObject)
1591 int classInfoCount, classInfoData;
1592 int methodCount, methodData;
1593 int propertyCount, propertyData;
1596 return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
1599 static inline void flush_vme_signal(const QObject *object, int index)
1601 QDeclarativeData *data = static_cast<QDeclarativeData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
1602 if (data && data->propertyCache) {
1603 QDeclarativePropertyCache::Data *property = data->propertyCache->method(index);
1605 if (property && property->flags & QDeclarativePropertyCache::Data::IsVMESignal) {
1606 const QMetaObject *metaObject = object->metaObject();
1607 int methodOffset = metaObject->methodOffset();
1609 while (methodOffset > index) {
1610 metaObject = metaObject->d.superdata;
1611 methodOffset -= QMetaObject_methods(metaObject);
1614 QDeclarativeVMEMetaObject *vme =
1615 static_cast<QDeclarativeVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
1617 vme->connectAliasSignal(index);
1623 Connect \a sender \a signal_index to \a receiver \a method_index with the specified
1624 \a type and \a types. This behaves identically to QMetaObject::connect() except that
1625 it connects any lazy "proxy" signal connections set up by QML.
1627 It is possible that this logic should be moved to QMetaObject::connect().
1629 bool QDeclarativePropertyPrivate::connect(const QObject *sender, int signal_index,
1630 const QObject *receiver, int method_index,
1631 int type, int *types)
1633 flush_vme_signal(sender, signal_index);
1634 flush_vme_signal(receiver, method_index);
1636 return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
1640 Return \a metaObject's [super] meta object that provides data for \a property.
1642 const QMetaObject *QDeclarativePropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
1644 int propertyOffset = metaObject->propertyOffset();
1646 while (propertyOffset > property) {
1647 metaObject = metaObject->d.superdata;
1648 propertyOffset -= QMetaObject_properties(metaObject);