summaryrefslogtreecommitdiffstats
path: root/src/declarative/qml/qdeclarativeproperty.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/qml/qdeclarativeproperty.cpp')
-rw-r--r--src/declarative/qml/qdeclarativeproperty.cpp1654
1 files changed, 1654 insertions, 0 deletions
diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp
new file mode 100644
index 00000000..05bec635
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeproperty.cpp
@@ -0,0 +1,1654 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativeproperty.h"
+#include "private/qdeclarativeproperty_p.h"
+
+#include "qdeclarative.h"
+#include "private/qdeclarativebinding_p.h"
+#include "qdeclarativecontext.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativeboundsignal_p.h"
+#include "qdeclarativeengine.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativedata_p.h"
+#include "private/qdeclarativestringconverters_p.h"
+#include "private/qdeclarativelist_p.h"
+#include "private/qdeclarativecompiler_p.h"
+#include "private/qdeclarativevmemetaobject_p.h"
+
+#include <QStringList>
+#include <QtCore/qdebug.h>
+
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+\class QDeclarativeProperty
+\since 4.7
+\brief The QDeclarativeProperty class abstracts accessing properties on objects created from QML.
+
+As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect
+and interact with objects created by QML. However, some of the new features provided by QML - such
+as type safety and attached properties - are most easily used through the QDeclarativeProperty class
+that simplifies some of their natural complexity.
+
+Unlike QMetaProperty which represents a property on a class type, QDeclarativeProperty encapsulates
+a property on a specific object instance. To read a property's value, programmers create a
+QDeclarativeProperty instance and call the read() method. Likewise to write a property value the
+write() method is used.
+
+For example, for the following QML code:
+
+\qml
+// MyItem.qml
+import QtQuick 1.0
+
+Text { text: "A bit of text" }
+\endqml
+
+The \l Text object's properties could be accessed using QDeclarativeProperty, like this:
+
+\code
+#include <QDeclarativeProperty>
+#include <QGraphicsObject>
+
+...
+
+QDeclarativeView view(QUrl::fromLocalFile("MyItem.qml"));
+QDeclarativeProperty property(view.rootObject(), "font.pixelSize");
+qWarning() << "Current pixel size:" << property.read().toInt();
+property.write(24);
+qWarning() << "Pixel size should now be 24:" << property.read().toInt();
+\endcode
+*/
+
+/*!
+ Create an invalid QDeclarativeProperty.
+*/
+QDeclarativeProperty::QDeclarativeProperty()
+: d(0)
+{
+}
+
+/*! \internal */
+QDeclarativeProperty::~QDeclarativeProperty()
+{
+ if (d)
+ d->release();
+ d = 0;
+}
+
+/*!
+ Creates a QDeclarativeProperty for the default property of \a obj. If there is no
+ default property, an invalid QDeclarativeProperty will be created.
+ */
+QDeclarativeProperty::QDeclarativeProperty(QObject *obj)
+: d(new QDeclarativePropertyPrivate)
+{
+ d->initDefault(obj);
+}
+
+/*!
+ Creates a QDeclarativeProperty for the default property of \a obj
+ using the \l{QDeclarativeContext} {context} \a ctxt. If there is
+ no default property, an invalid QDeclarativeProperty will be
+ created.
+ */
+QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeContext *ctxt)
+: d(new QDeclarativePropertyPrivate)
+{
+ d->context = ctxt?QDeclarativeContextData::get(ctxt):0;
+ d->engine = ctxt?ctxt->engine():0;
+ d->initDefault(obj);
+}
+
+/*!
+ Creates a QDeclarativeProperty for the default property of \a obj
+ using the environment for instantiating QML components that is
+ provided by \a engine. If there is no default property, an
+ invalid QDeclarativeProperty will be created.
+ */
+QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeEngine *engine)
+ : d(new QDeclarativePropertyPrivate)
+{
+ d->context = 0;
+ d->engine = engine;
+ d->initDefault(obj);
+}
+
+/*!
+ Initialize from the default property of \a obj
+*/
+void QDeclarativePropertyPrivate::initDefault(QObject *obj)
+{
+ if (!obj)
+ return;
+
+ QMetaProperty p = QDeclarativeMetaType::defaultProperty(obj);
+ core.load(p);
+ if (core.isValid())
+ object = obj;
+}
+
+/*!
+ Creates a QDeclarativeProperty for the property \a name of \a obj.
+ */
+QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name)
+: d(new QDeclarativePropertyPrivate)
+{
+ d->initProperty(obj, name);
+ if (!isValid()) d->object = 0;
+}
+
+/*!
+ Creates a QDeclarativeProperty for the property \a name of \a obj
+ using the \l{QDeclarativeContext} {context} \a ctxt.
+
+ Creating a QDeclarativeProperty without a context will render some
+ properties - like attached properties - inaccessible.
+*/
+QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeContext *ctxt)
+: d(new QDeclarativePropertyPrivate)
+{
+ d->context = ctxt?QDeclarativeContextData::get(ctxt):0;
+ d->engine = ctxt?ctxt->engine():0;
+ d->initProperty(obj, name);
+ if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
+}
+
+/*!
+ Creates a QDeclarativeProperty for the property \a name of \a obj
+ using the environment for instantiating QML components that is
+ provided by \a engine.
+ */
+QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeEngine *engine)
+: d(new QDeclarativePropertyPrivate)
+{
+ d->context = 0;
+ d->engine = engine;
+ d->initProperty(obj, name);
+ if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
+}
+
+Q_GLOBAL_STATIC(QDeclarativeValueTypeFactory, qmlValueTypes);
+
+void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name)
+{
+ if (!obj) return;
+
+ QDeclarativeTypeNameCache *typeNameCache = context?context->imports:0;
+
+ QStringList path = name.split(QLatin1Char('.'));
+ if (path.isEmpty()) return;
+
+ QObject *currentObject = obj;
+
+ // Everything up to the last property must be an "object type" property
+ for (int ii = 0; ii < path.count() - 1; ++ii) {
+ const QString &pathName = path.at(ii);
+
+ if (QDeclarativeTypeNameCache::Data *data = typeNameCache?typeNameCache->data(pathName):0) {
+ if (data->type) {
+ QDeclarativeAttachedPropertiesFunc func = data->type->attachedPropertiesFunction();
+ if (!func) return; // Not an attachable type
+
+ currentObject = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), currentObject);
+ if (!currentObject) return; // Something is broken with the attachable type
+ } else {
+ Q_ASSERT(data->typeNamespace);
+ if ((ii + 1) == path.count()) return; // No type following the namespace
+
+ ++ii; data = data->typeNamespace->data(path.at(ii));
+ if (!data || !data->type) return; // Invalid type in namespace
+
+ QDeclarativeAttachedPropertiesFunc func = data->type->attachedPropertiesFunction();
+ if (!func) return; // Not an attachable type
+
+ currentObject = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), currentObject);
+ if (!currentObject) return; // Something is broken with the attachable type
+ }
+ } else {
+
+ QDeclarativePropertyCache::Data local;
+ QDeclarativePropertyCache::Data *property =
+ QDeclarativePropertyCache::property(engine, obj, pathName, local);
+
+ if (!property) return; // Not a property
+ if (property->flags & QDeclarativePropertyCache::Data::IsFunction)
+ return; // Not an object property
+
+ if (ii == (path.count() - 2) && QDeclarativeValueTypeFactory::isValueType(property->propType)) {
+ // We're now at a value type property. We can use a global valuetypes array as we
+ // never actually use the objects, just look up their properties.
+ QObject *typeObject = (*qmlValueTypes())[property->propType];
+ if (!typeObject) return; // Not a value type
+
+ int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
+ if (idx == -1) return; // Value type property does not exist
+
+ QMetaProperty vtProp = typeObject->metaObject()->property(idx);
+
+ object = currentObject;
+ core = *property;
+ valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(vtProp);
+ valueType.valueTypeCoreIdx = idx;
+ valueType.valueTypePropType = vtProp.userType();
+
+ return;
+ } else {
+ if (!(property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived))
+ return; // Not an object property
+
+ void *args[] = { &currentObject, 0 };
+ QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
+ if (!currentObject) return; // No value
+
+ }
+ }
+
+ }
+
+ const QString &terminal = path.last();
+
+ if (terminal.count() >= 3 &&
+ terminal.at(0) == QLatin1Char('o') &&
+ terminal.at(1) == QLatin1Char('n') &&
+ terminal.at(2).isUpper()) {
+
+ QString signalName = terminal.mid(2);
+ signalName[0] = signalName.at(0).toLower();
+
+ QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName.toLatin1().constData());
+ if (method.signature()) {
+ object = currentObject;
+ core.load(method);
+ return;
+ }
+ }
+
+ // Property
+ QDeclarativePropertyCache::Data local;
+ QDeclarativePropertyCache::Data *property =
+ QDeclarativePropertyCache::property(engine, currentObject, terminal, local);
+ if (property && !(property->flags & QDeclarativePropertyCache::Data::IsFunction)) {
+ object = currentObject;
+ core = *property;
+ nameCache = terminal;
+ isNameCached = true;
+ }
+}
+
+/*!
+ Create a copy of \a other.
+*/
+QDeclarativeProperty::QDeclarativeProperty(const QDeclarativeProperty &other)
+{
+ d = other.d;
+ if (d)
+ d->addref();
+}
+
+/*!
+ \enum QDeclarativeProperty::PropertyTypeCategory
+
+ This enum specifies a category of QML property.
+
+ \value InvalidCategory The property is invalid, or is a signal property.
+ \value List The property is a QDeclarativeListProperty list property
+ \value Object The property is a QObject derived type pointer
+ \value Normal The property is a normal value property.
+ */
+
+/*!
+ \enum QDeclarativeProperty::Type
+
+ This enum specifies a type of QML property.
+
+ \value Invalid The property is invalid.
+ \value Property The property is a regular Qt property.
+ \value SignalProperty The property is a signal property.
+*/
+
+/*!
+ Returns the property category.
+*/
+QDeclarativeProperty::PropertyTypeCategory QDeclarativeProperty::propertyTypeCategory() const
+{
+ return d ? d->propertyTypeCategory() : InvalidCategory;
+}
+
+QDeclarativeProperty::PropertyTypeCategory
+QDeclarativePropertyPrivate::propertyTypeCategory() const
+{
+ uint type = this->type();
+
+ if (isValueType()) {
+ return QDeclarativeProperty::Normal;
+ } else if (type & QDeclarativeProperty::Property) {
+ int type = propertyType();
+ if (type == QVariant::Invalid)
+ return QDeclarativeProperty::InvalidCategory;
+ else if (QDeclarativeValueTypeFactory::isValueType((uint)type))
+ return QDeclarativeProperty::Normal;
+ else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived)
+ return QDeclarativeProperty::Object;
+ else if (core.flags & QDeclarativePropertyCache::Data::IsQList)
+ return QDeclarativeProperty::List;
+ else
+ return QDeclarativeProperty::Normal;
+ } else {
+ return QDeclarativeProperty::InvalidCategory;
+ }
+}
+
+/*!
+ Returns the type name of the property, or 0 if the property has no type
+ name.
+*/
+const char *QDeclarativeProperty::propertyTypeName() const
+{
+ if (!d)
+ return 0;
+ if (d->isValueType()) {
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context);
+ QDeclarativeValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[d->core.propType];
+ else valueType = QDeclarativeValueTypeFactory::valueType(d->core.propType);
+ Q_ASSERT(valueType);
+
+ const char *rv = valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).typeName();
+
+ if (!ep) delete valueType;
+
+ return rv;
+ } else if (d->object && type() & Property && d->core.isValid()) {
+ return d->object->metaObject()->property(d->core.coreIndex).typeName();
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ Returns true if \a other and this QDeclarativeProperty represent the same
+ property.
+*/
+bool QDeclarativeProperty::operator==(const QDeclarativeProperty &other) const
+{
+ if (!d || !other.d)
+ return false;
+ // category is intentially omitted here as it is generated
+ // from the other members
+ return d->object == other.d->object &&
+ d->core == other.d->core &&
+ d->valueType == other.d->valueType;
+}
+
+/*!
+ Returns the QVariant type of the property, or QVariant::Invalid if the
+ property has no QVariant type.
+*/
+int QDeclarativeProperty::propertyType() const
+{
+ return d ? d->propertyType() : int(QVariant::Invalid);
+}
+
+bool QDeclarativePropertyPrivate::isValueType() const
+{
+ return valueType.valueTypeCoreIdx != -1;
+}
+
+int QDeclarativePropertyPrivate::propertyType() const
+{
+ uint type = this->type();
+ if (isValueType()) {
+ return valueType.valueTypePropType;
+ } else if (type & QDeclarativeProperty::Property) {
+ if (core.propType == (int)QVariant::LastType)
+ return qMetaTypeId<QVariant>();
+ else
+ return core.propType;
+ } else {
+ return QVariant::Invalid;
+ }
+}
+
+QDeclarativeProperty::Type QDeclarativePropertyPrivate::type() const
+{
+ if (core.flags & QDeclarativePropertyCache::Data::IsFunction)
+ return QDeclarativeProperty::SignalProperty;
+ else if (core.isValid())
+ return QDeclarativeProperty::Property;
+ else
+ return QDeclarativeProperty::Invalid;
+}
+
+/*!
+ Returns the type of the property.
+*/
+QDeclarativeProperty::Type QDeclarativeProperty::type() const
+{
+ return d ? d->type() : Invalid;
+}
+
+/*!
+ Returns true if this QDeclarativeProperty represents a regular Qt property.
+*/
+bool QDeclarativeProperty::isProperty() const
+{
+ return type() & Property;
+}
+
+/*!
+ Returns true if this QDeclarativeProperty represents a QML signal property.
+*/
+bool QDeclarativeProperty::isSignalProperty() const
+{
+ return type() & SignalProperty;
+}
+
+/*!
+ Returns the QDeclarativeProperty's QObject.
+*/
+QObject *QDeclarativeProperty::object() const
+{
+ return d ? d->object : 0;
+}
+
+/*!
+ Assign \a other to this QDeclarativeProperty.
+*/
+QDeclarativeProperty &QDeclarativeProperty::operator=(const QDeclarativeProperty &other)
+{
+ if (d)
+ d->release();
+ d = other.d;
+ if (d)
+ d->addref();
+
+ return *this;
+}
+
+/*!
+ Returns true if the property is writable, otherwise false.
+*/
+bool QDeclarativeProperty::isWritable() const
+{
+ if (!d)
+ return false;
+ if (!d->object)
+ return false;
+ if (d->core.flags & QDeclarativePropertyCache::Data::IsQList) //list
+ return true;
+ else if (d->core.flags & QDeclarativePropertyCache::Data::IsFunction) //signal handler
+ return false;
+ else if (d->core.isValid()) //normal property
+ return d->core.flags & QDeclarativePropertyCache::Data::IsWritable;
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is designable, otherwise false.
+*/
+bool QDeclarativeProperty::isDesignable() const
+{
+ if (!d)
+ return false;
+ if (type() & Property && d->core.isValid() && d->object)
+ return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is resettable, otherwise false.
+*/
+bool QDeclarativeProperty::isResettable() const
+{
+ if (!d)
+ return false;
+ if (type() & Property && d->core.isValid() && d->object)
+ return d->core.flags & QDeclarativePropertyCache::Data::IsResettable;
+ else
+ return false;
+}
+
+/*!
+ Returns true if the QDeclarativeProperty refers to a valid property, otherwise
+ false.
+*/
+bool QDeclarativeProperty::isValid() const
+{
+ if (!d)
+ return false;
+ return type() != Invalid;
+}
+
+/*!
+ Return the name of this QML property.
+*/
+QString QDeclarativeProperty::name() const
+{
+ if (!d)
+ return QString();
+ if (!d->isNameCached) {
+ // ###
+ if (!d->object) {
+ } else if (d->isValueType()) {
+ QString rv = d->core.name(d->object) + QLatin1Char('.');
+
+ QDeclarativeEnginePrivate *ep = d->engine?QDeclarativeEnginePrivate::get(d->engine):0;
+ QDeclarativeValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[d->core.propType];
+ else valueType = QDeclarativeValueTypeFactory::valueType(d->core.propType);
+ Q_ASSERT(valueType);
+
+ rv += QString::fromUtf8(valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).name());
+
+ if (!ep) delete valueType;
+
+ d->nameCache = rv;
+ } else if (type() & SignalProperty) {
+ QString name = QLatin1String("on") + d->core.name(d->object);
+ name[2] = name.at(2).toUpper();
+ d->nameCache = name;
+ } else {
+ d->nameCache = d->core.name(d->object);
+ }
+ d->isNameCached = true;
+ }
+
+ return d->nameCache;
+}
+
+/*!
+ Returns the \l{QMetaProperty} {Qt property} associated with
+ this QML property.
+ */
+QMetaProperty QDeclarativeProperty::property() const
+{
+ if (!d)
+ return QMetaProperty();
+ if (type() & Property && d->core.isValid() && d->object)
+ return d->object->metaObject()->property(d->core.coreIndex);
+ else
+ return QMetaProperty();
+}
+
+/*!
+ Return the QMetaMethod for this property if it is a SignalProperty,
+ otherwise returns an invalid QMetaMethod.
+*/
+QMetaMethod QDeclarativeProperty::method() const
+{
+ if (!d)
+ return QMetaMethod();
+ if (type() & SignalProperty && d->object)
+ return d->object->metaObject()->method(d->core.coreIndex);
+ else
+ return QMetaMethod();
+}
+
+/*!
+ Returns the binding associated with this property, or 0 if no binding
+ exists.
+*/
+QDeclarativeAbstractBinding *
+QDeclarativePropertyPrivate::binding(const QDeclarativeProperty &that)
+{
+ if (!that.d || !that.isProperty() || !that.d->object)
+ return 0;
+
+ return binding(that.d->object, that.d->core.coreIndex, that.d->valueType.valueTypeCoreIdx);
+}
+
+/*!
+ Set the binding associated with this property to \a newBinding. Returns
+ the existing binding (if any), otherwise 0.
+
+ \a newBinding will be enabled, and the returned binding (if any) will be
+ disabled.
+
+ Ownership of \a newBinding transfers to QML. Ownership of the return value
+ is assumed by the caller.
+
+ \a flags is passed through to the binding and is used for the initial update (when
+ the binding sets the initial value, it will use these flags for the write).
+*/
+QDeclarativeAbstractBinding *
+QDeclarativePropertyPrivate::setBinding(const QDeclarativeProperty &that,
+ QDeclarativeAbstractBinding *newBinding,
+ WriteFlags flags)
+{
+ if (!that.d || !that.isProperty() || !that.d->object) {
+ if (newBinding)
+ newBinding->destroy();
+ return 0;
+ }
+
+ return that.d->setBinding(that.d->object, that.d->core.coreIndex,
+ that.d->valueType.valueTypeCoreIdx, newBinding, flags);
+}
+
+QDeclarativeAbstractBinding *
+QDeclarativePropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
+{
+ QDeclarativeData *data = QDeclarativeData::get(object);
+ if (!data)
+ return 0;
+
+ QDeclarativePropertyCache::Data *propertyData =
+ data->propertyCache?data->propertyCache->property(coreIndex):0;
+ if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
+ const QDeclarativeVMEMetaObject *vme =
+ static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
+
+ QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
+ if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
+ return 0;
+
+ // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
+ Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
+ return binding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex);
+ }
+
+ if (!data->hasBindingBit(coreIndex))
+ return 0;
+
+ QDeclarativeAbstractBinding *binding = data->bindings;
+ while (binding && binding->propertyIndex() != coreIndex)
+ binding = binding->m_nextBinding;
+
+ if (binding && valueTypeIndex != -1) {
+ if (binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) {
+ int index = coreIndex | (valueTypeIndex << 24);
+ binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
+ }
+ }
+
+ return binding;
+}
+
+void QDeclarativePropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
+ QObject **targetObject, int *targetBindingIndex)
+{
+ int coreIndex = bindingIndex & 0xFFFFFF;
+ int valueTypeIndex = bindingIndex >> 24;
+ if (valueTypeIndex == 0) valueTypeIndex = -1;
+
+ QDeclarativeData *data = QDeclarativeData::get(object, false);
+ if (data) {
+ QDeclarativePropertyCache::Data *propertyData =
+ data->propertyCache?data->propertyCache->property(coreIndex):0;
+ if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
+ const QDeclarativeVMEMetaObject *vme =
+ static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
+ QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
+ if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
+ // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
+ Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
+
+ int aBindingIndex = aCoreIndex;
+ if (aValueTypeIndex != -1)
+ aBindingIndex |= aValueTypeIndex << 24;
+ else if (valueTypeIndex != -1)
+ aBindingIndex |= valueTypeIndex << 24;
+
+ findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
+ return;
+ }
+ }
+ }
+
+ *targetObject = object;
+ *targetBindingIndex = bindingIndex;
+}
+
+QDeclarativeAbstractBinding *
+QDeclarativePropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
+ QDeclarativeAbstractBinding *newBinding, WriteFlags flags)
+{
+ QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
+ QDeclarativeAbstractBinding *binding = 0;
+
+ if (data) {
+ QDeclarativePropertyCache::Data *propertyData =
+ data->propertyCache?data->propertyCache->property(coreIndex):0;
+ if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
+ const QDeclarativeVMEMetaObject *vme =
+ static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
+
+ QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
+ if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
+ if (newBinding) newBinding->destroy();
+ return 0;
+ }
+
+ // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
+ Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
+ return setBinding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex,
+ newBinding, flags);
+ }
+ }
+
+ if (data && data->hasBindingBit(coreIndex)) {
+ binding = data->bindings;
+
+ while (binding && binding->propertyIndex() != coreIndex)
+ binding = binding->m_nextBinding;
+ }
+
+ int index = coreIndex;
+ if (valueTypeIndex != -1)
+ index |= (valueTypeIndex << 24);
+
+ if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy)
+ binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
+
+ if (binding) {
+ binding->removeFromObject();
+ binding->setEnabled(false, 0);
+ }
+
+ if (newBinding) {
+ newBinding->addToObject(object, index);
+ newBinding->setEnabled(true, flags);
+ }
+
+ return binding;
+}
+
+QDeclarativeAbstractBinding *
+QDeclarativePropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
+ QDeclarativeAbstractBinding *newBinding)
+{
+ QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
+ QDeclarativeAbstractBinding *binding = 0;
+
+ if (data) {
+ QDeclarativePropertyCache::Data *propertyData =
+ data->propertyCache?data->propertyCache->property(coreIndex):0;
+ if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
+ const QDeclarativeVMEMetaObject *vme =
+ static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
+
+ QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
+ if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
+ if (newBinding) newBinding->destroy();
+ return 0;
+ }
+
+ // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
+ Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
+ return setBindingNoEnable(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex,
+ newBinding);
+ }
+ }
+
+ if (data && data->hasBindingBit(coreIndex)) {
+ binding = data->bindings;
+
+ while (binding && binding->propertyIndex() != coreIndex)
+ binding = binding->m_nextBinding;
+ }
+
+ int index = coreIndex;
+ if (valueTypeIndex != -1)
+ index |= (valueTypeIndex << 24);
+
+ if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy)
+ binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
+
+ if (binding)
+ binding->removeFromObject();
+
+ if (newBinding)
+ newBinding->addToObject(object, index);
+
+ return binding;
+}
+
+/*!
+ Returns the expression associated with this signal property, or 0 if no
+ signal expression exists.
+*/
+QDeclarativeExpression *
+QDeclarativePropertyPrivate::signalExpression(const QDeclarativeProperty &that)
+{
+ if (!(that.type() & QDeclarativeProperty::SignalProperty))
+ return 0;
+
+ const QObjectList &children = that.d->object->children();
+
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+
+ QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
+ if (signal && signal->index() == that.index())
+ return signal->expression();
+ }
+
+ return 0;
+}
+
+/*!
+ Set the signal expression associated with this signal property to \a expr.
+ Returns the existing signal expression (if any), otherwise 0.
+
+ Ownership of \a expr transfers to QML. Ownership of the return value is
+ assumed by the caller.
+*/
+QDeclarativeExpression *
+QDeclarativePropertyPrivate::setSignalExpression(const QDeclarativeProperty &that,
+ QDeclarativeExpression *expr)
+{
+ if (!(that.type() & QDeclarativeProperty::SignalProperty)) {
+ delete expr;
+ return 0;
+ }
+
+ const QObjectList &children = that.d->object->children();
+
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+
+ QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
+ if (signal && signal->index() == that.index())
+ return signal->setExpression(expr);
+ }
+
+ if (expr) {
+ QDeclarativeBoundSignal *signal = new QDeclarativeBoundSignal(that.d->object, that.method(), that.d->object);
+ return signal->setExpression(expr);
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ Returns the property value.
+*/
+QVariant QDeclarativeProperty::read() const
+{
+ if (!d)
+ return QVariant();
+ if (!d->object)
+ return QVariant();
+
+ if (type() & SignalProperty) {
+
+ return QVariant();
+
+ } else if (type() & Property) {
+
+ return d->readValueProperty();
+
+ }
+ return QVariant();
+}
+
+/*!
+Return the \a name property value of \a object. This method is equivalent to:
+\code
+ QDeclarativeProperty p(object, name);
+ p.read();
+\endcode
+*/
+QVariant QDeclarativeProperty::read(QObject *object, const QString &name)
+{
+ QDeclarativeProperty p(object, name);
+ return p.read();
+}
+
+/*!
+ Return the \a name property value of \a object using the
+ \l{QDeclarativeContext} {context} \a ctxt. This method is
+ equivalent to:
+
+ \code
+ QDeclarativeProperty p(object, name, context);
+ p.read();
+ \endcode
+*/
+QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeContext *ctxt)
+{
+ QDeclarativeProperty p(object, name, ctxt);
+ return p.read();
+}
+
+/*!
+
+ Return the \a name property value of \a object using the environment
+ for instantiating QML components that is provided by \a engine. .
+ This method is equivalent to:
+
+ \code
+ QDeclarativeProperty p(object, name, engine);
+ p.read();
+ \endcode
+*/
+QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeEngine *engine)
+{
+ QDeclarativeProperty p(object, name, engine);
+ return p.read();
+}
+
+QVariant QDeclarativePropertyPrivate::readValueProperty()
+{
+ if (isValueType()) {
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context);
+ QDeclarativeValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[core.propType];
+ else valueType = QDeclarativeValueTypeFactory::valueType(core.propType);
+ Q_ASSERT(valueType);
+
+ valueType->read(object, core.coreIndex);
+
+ QVariant rv =
+ valueType->metaObject()->property(this->valueType.valueTypeCoreIdx).read(valueType);
+
+ if (!ep) delete valueType;
+ return rv;
+
+ } else if (core.flags & QDeclarativePropertyCache::Data::IsQList) {
+
+ QDeclarativeListProperty<QObject> prop;
+ void *args[] = { &prop, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
+ return QVariant::fromValue(QDeclarativeListReferencePrivate::init(prop, core.propType, engine));
+
+ } else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
+
+ QObject *rv = 0;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
+ return QVariant::fromValue(rv);
+
+ } else {
+
+ return object->metaObject()->property(core.coreIndex).read(object.data());
+
+ }
+}
+
+//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
+bool QDeclarativePropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
+{
+ if (!object || !prop.isWritable())
+ return false;
+
+ QVariant v = value;
+ if (prop.isEnumType()) {
+ QMetaEnum menum = prop.enumerator();
+ if (v.userType() == QVariant::String
+#ifdef QT3_SUPPORT
+ || v.userType() == QVariant::CString
+#endif
+ ) {
+ if (prop.isFlagType())
+ v = QVariant(menum.keysToValue(value.toByteArray()));
+ else
+ v = QVariant(menum.keyToValue(value.toByteArray()));
+ } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
+ int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
+ if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData())
+ return false;
+ v = QVariant(*reinterpret_cast<const int *>(v.constData()));
+ }
+ v.convert(QVariant::Int);
+ }
+
+ // the status variable is changed by qt_metacall to indicate what it did
+ // this feature is currently only used by QtDBus and should not be depended
+ // upon. Don't change it without looking into QDBusAbstractInterface first
+ // -1 (unchanged): normal qt_metacall, result stored in argv[0]
+ // changed: result stored directly in value, return the value of status
+ int status = -1;
+ void *argv[] = { v.data(), &v, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
+ return status;
+}
+
+bool QDeclarativePropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
+{
+ // Remove any existing bindings on this property
+ if (!(flags & DontRemoveBinding) &&
+ (type() & QDeclarativeProperty::Property) && object) {
+ QDeclarativeAbstractBinding *binding = setBinding(object, core.coreIndex,
+ valueType.valueTypeCoreIdx, 0, flags);
+ if (binding) binding->destroy();
+ }
+
+ bool rv = false;
+ if (isValueType()) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context);
+
+ QDeclarativeValueType *writeBack = 0;
+ if (ep) {
+ writeBack = ep->valueTypes[core.propType];
+ } else {
+ writeBack = QDeclarativeValueTypeFactory::valueType(core.propType);
+ }
+
+ writeBack->read(object, core.coreIndex);
+
+ QDeclarativePropertyCache::Data data = core;
+ data.flags = valueType.flags;
+ data.coreIndex = valueType.valueTypeCoreIdx;
+ data.propType = valueType.valueTypePropType;
+ rv = write(writeBack, data, value, context, flags);
+
+ writeBack->write(object, core.coreIndex, flags);
+ if (!ep) delete writeBack;
+
+ } else {
+
+ rv = write(object, core, value, context, flags);
+
+ }
+
+ return rv;
+}
+
+bool QDeclarativePropertyPrivate::write(QObject *object, const QDeclarativePropertyCache::Data &property,
+ const QVariant &value, QDeclarativeContextData *context,
+ WriteFlags flags)
+{
+ int coreIdx = property.coreIndex;
+ int status = -1; //for dbus
+
+ if (property.flags & QDeclarativePropertyCache::Data::IsEnumType) {
+ QMetaProperty prop = object->metaObject()->property(property.coreIndex);
+ QVariant v = value;
+ // Enum values come through the script engine as doubles
+ if (value.userType() == QVariant::Double) {
+ double integral;
+ double fractional = modf(value.toDouble(), &integral);
+ if (qFuzzyIsNull(fractional))
+ v.convert(QVariant::Int);
+ }
+ return writeEnumProperty(prop, coreIdx, object, v, flags);
+ }
+
+ int propertyType = property.propType;
+ int variantType = value.userType();
+
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context);
+
+ if (propertyType == QVariant::Url) {
+
+ QUrl u;
+ bool found = false;
+ if (variantType == QVariant::Url) {
+ u = value.toUrl();
+ found = true;
+ } else if (variantType == QVariant::ByteArray) {
+ u = QUrl(QString::fromUtf8(value.toByteArray()));
+ found = true;
+ } else if (variantType == QVariant::String) {
+ u = QUrl(value.toString());
+ found = true;
+ }
+
+ if (!found)
+ return false;
+
+ if (context && u.isRelative() && !u.isEmpty())
+ u = context->resolvedUrl(u);
+ int status = -1;
+ void *argv[] = { &u, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
+
+ } else if (variantType == propertyType) {
+
+ void *a[] = { (void *)value.constData(), 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+
+ } else if (qMetaTypeId<QVariant>() == propertyType) {
+
+ void *a[] = { (void *)&value, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+
+ } else if (property.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
+
+ const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType());
+
+ if (!valMo)
+ return false;
+
+ QObject *o = *(QObject **)value.constData();
+ const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType);
+
+ if (o) valMo = o->metaObject();
+
+ if (canConvert(valMo, propMo)) {
+ void *args[] = { &o, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
+ args);
+ } else if (!o && canConvert(propMo, valMo)) {
+ // In the case of a null QObject, we assign the null if there is
+ // any change that the null variant type could be up or down cast to
+ // the property type.
+ void *args[] = { &o, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
+ args);
+ } else {
+ return false;
+ }
+
+ } else if (property.flags & QDeclarativePropertyCache::Data::IsQList) {
+
+ const QMetaObject *listType = 0;
+ if (enginePriv) {
+ listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
+ } else {
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(QDeclarativeMetaType::listType(property.propType));
+ if (!type) return false;
+ listType = type->baseMetaObject();
+ }
+ if (!listType) return false;
+
+ QDeclarativeListProperty<void> prop;
+ void *args[] = { &prop, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
+
+ if (!prop.clear) return false;
+
+ prop.clear(&prop);
+
+ if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
+ const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
+
+ for (int ii = 0; ii < list.count(); ++ii) {
+ QObject *o = list.at(ii);
+ if (o && !canConvert(o->metaObject(), listType))
+ o = 0;
+ prop.append(&prop, (void *)o);
+ }
+ } else {
+ QObject *o = enginePriv?enginePriv->toQObject(value):QDeclarativeMetaType::toQObject(value);
+ if (o && !canConvert(o->metaObject(), listType))
+ o = 0;
+ prop.append(&prop, (void *)o);
+ }
+
+ } else {
+ Q_ASSERT(variantType != propertyType);
+
+ bool ok = false;
+ QVariant v;
+ if (variantType == QVariant::String)
+ v = QDeclarativeStringConverters::variantFromString(value.toString(), propertyType, &ok);
+ if (!ok) {
+ v = value;
+ if (v.convert((QVariant::Type)propertyType)) {
+ ok = true;
+ } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
+ QDeclarativeMetaType::StringConverter con = QDeclarativeMetaType::customStringConverter(propertyType);
+ if (con) {
+ v = con(value.toString());
+ if (v.userType() == propertyType)
+ ok = true;
+ }
+ }
+ }
+ if (ok) {
+ void *a[] = { (void *)v.constData(), 0, &status, &flags};
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+const QMetaObject *QDeclarativePropertyPrivate::rawMetaObjectForType(QDeclarativeEnginePrivate *engine, int userType)
+{
+ if (engine) {
+ return engine->rawMetaObjectForType(userType);
+ } else {
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(userType);
+ return type?type->baseMetaObject():0;
+ }
+}
+
+/*!
+ Sets the property value to \a value and returns true.
+ Returns false if the property can't be set because the
+ \a value is the wrong type, for example.
+ */
+bool QDeclarativeProperty::write(const QVariant &value) const
+{
+ return QDeclarativePropertyPrivate::write(*this, value, 0);
+}
+
+/*!
+ Writes \a value to the \a name property of \a object. This method
+ is equivalent to:
+
+ \code
+ QDeclarativeProperty p(object, name);
+ p.write(value);
+ \endcode
+*/
+bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value)
+{
+ QDeclarativeProperty p(object, name);
+ return p.write(value);
+}
+
+/*!
+ Writes \a value to the \a name property of \a object using the
+ \l{QDeclarativeContext} {context} \a ctxt. This method is
+ equivalent to:
+
+ \code
+ QDeclarativeProperty p(object, name, ctxt);
+ p.write(value);
+ \endcode
+*/
+bool QDeclarativeProperty::write(QObject *object,
+ const QString &name,
+ const QVariant &value,
+ QDeclarativeContext *ctxt)
+{
+ QDeclarativeProperty p(object, name, ctxt);
+ return p.write(value);
+}
+
+/*!
+
+ Writes \a value to the \a name property of \a object using the
+ environment for instantiating QML components that is provided by
+ \a engine. This method is equivalent to:
+
+ \code
+ QDeclarativeProperty p(object, name, engine);
+ p.write(value);
+ \endcode
+*/
+bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value,
+ QDeclarativeEngine *engine)
+{
+ QDeclarativeProperty p(object, name, engine);
+ return p.write(value);
+}
+
+/*!
+ Resets the property and returns true if the property is
+ resettable. If the property is not resettable, nothing happens
+ and false is returned.
+*/
+bool QDeclarativeProperty::reset() const
+{
+ if (isResettable()) {
+ void *args[] = { 0 };
+ QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QDeclarativePropertyPrivate::write(const QDeclarativeProperty &that,
+ const QVariant &value, WriteFlags flags)
+{
+ if (!that.d)
+ return false;
+ if (that.d->object && that.type() & QDeclarativeProperty::Property &&
+ that.d->core.isValid() && that.isWritable())
+ return that.d->writeValueProperty(value, flags);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property has a change notifier signal, otherwise false.
+*/
+bool QDeclarativeProperty::hasNotifySignal() const
+{
+ if (type() & Property && d->object) {
+ return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
+ }
+ return false;
+}
+
+/*!
+ Returns true if the property needs a change notifier signal for bindings
+ to remain upto date, false otherwise.
+
+ Some properties, such as attached properties or those whose value never
+ changes, do not require a change notifier.
+*/
+bool QDeclarativeProperty::needsNotifySignal() const
+{
+ return type() & Property && !property().isConstant();
+}
+
+/*!
+ Connects the property's change notifier signal to the
+ specified \a method of the \a dest object and returns
+ true. Returns false if this metaproperty does not
+ represent a regular Qt property or if it has no
+ change notifier signal, or if the \a dest object does
+ not have the specified \a method.
+*/
+bool QDeclarativeProperty::connectNotifySignal(QObject *dest, int method) const
+{
+ if (!(type() & Property) || !d->object)
+ return false;
+
+ QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
+ if (prop.hasNotifySignal()) {
+ return QDeclarativePropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
+ } else {
+ return false;
+ }
+}
+
+/*!
+ Connects the property's change notifier signal to the
+ specified \a slot of the \a dest object and returns
+ true. Returns false if this metaproperty does not
+ represent a regular Qt property or if it has no
+ change notifier signal, or if the \a dest object does
+ not have the specified \a slot.
+*/
+bool QDeclarativeProperty::connectNotifySignal(QObject *dest, const char *slot) const
+{
+ if (!(type() & Property) || !d->object)
+ return false;
+
+ QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
+ if (prop.hasNotifySignal()) {
+ QByteArray signal(QByteArray("2") + prop.notifySignal().signature());
+ return QObject::connect(d->object, signal.constData(), dest, slot);
+ } else {
+ return false;
+ }
+}
+
+/*!
+ Return the Qt metaobject index of the property.
+*/
+int QDeclarativeProperty::index() const
+{
+ return d ? d->core.coreIndex : -1;
+}
+
+int QDeclarativePropertyPrivate::valueTypeCoreIndex(const QDeclarativeProperty &that)
+{
+ return that.d ? that.d->valueType.valueTypeCoreIdx : -1;
+}
+
+/*!
+ Returns the "property index" for use in bindings. The top 8 bits are the value type
+ offset, and 0 otherwise. The bottom 24-bits are the regular property index.
+*/
+int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativeProperty &that)
+{
+ if (!that.d)
+ return -1;
+ int rv = that.d->core.coreIndex;
+ if (rv != -1 && that.d->valueType.valueTypeCoreIdx != -1)
+ rv = rv | (that.d->valueType.valueTypeCoreIdx << 24);
+ return rv;
+}
+
+struct SerializedData {
+ bool isValueType;
+ QDeclarativePropertyCache::Data core;
+};
+
+struct ValueTypeSerializedData : public SerializedData {
+ QDeclarativePropertyCache::ValueTypeData valueType;
+};
+
+QByteArray QDeclarativePropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
+ const QMetaObject *subObject, int subIndex)
+{
+ QMetaProperty prop = metaObject->property(index);
+ QMetaProperty subProp = subObject->property(subIndex);
+
+ ValueTypeSerializedData sd;
+ memset(&sd, 0, sizeof(sd));
+ sd.isValueType = true;
+ sd.core.load(metaObject->property(index));
+ sd.valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(subProp);
+ sd.valueType.valueTypeCoreIdx = subIndex;
+ sd.valueType.valueTypePropType = subProp.userType();
+
+ QByteArray rv((const char *)&sd, sizeof(sd));
+
+ return rv;
+}
+
+QByteArray QDeclarativePropertyPrivate::saveProperty(const QMetaObject *metaObject, int index)
+{
+ SerializedData sd;
+ memset(&sd, 0, sizeof(sd));
+ sd.isValueType = false;
+ sd.core.load(metaObject->property(index));
+
+ QByteArray rv((const char *)&sd, sizeof(sd));
+ return rv;
+}
+
+QDeclarativeProperty
+QDeclarativePropertyPrivate::restore(const QByteArray &data, QObject *object, QDeclarativeContextData *ctxt)
+{
+ QDeclarativeProperty prop;
+
+ if (data.isEmpty())
+ return prop;
+
+ const SerializedData *sd = (const SerializedData *)data.constData();
+ if (sd->isValueType) {
+ const ValueTypeSerializedData *vt = (const ValueTypeSerializedData *)sd;
+ return restore(vt->core, vt->valueType, object, ctxt);
+ } else {
+ QDeclarativePropertyCache::ValueTypeData data;
+ return restore(sd->core, data, object, ctxt);
+ }
+}
+
+QDeclarativeProperty
+QDeclarativePropertyPrivate::restore(const QDeclarativePropertyCache::Data &data, const QDeclarativePropertyCache::ValueTypeData &valueType, QObject *object, QDeclarativeContextData *ctxt)
+{
+ QDeclarativeProperty prop;
+
+ prop.d = new QDeclarativePropertyPrivate;
+ prop.d->object = object;
+ prop.d->context = ctxt;
+ prop.d->engine = ctxt->engine;
+
+ prop.d->core = data;
+ prop.d->valueType = valueType;
+
+ return prop;
+}
+
+/*!
+ Returns true if lhs and rhs refer to the same metaobject data
+*/
+bool QDeclarativePropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
+{
+ return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
+}
+
+/*!
+ Returns true if from inherits to.
+*/
+bool QDeclarativePropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
+{
+ if (from && to == &QObject::staticMetaObject)
+ return true;
+
+ while (from) {
+ if (equal(from, to))
+ return true;
+ from = from->superClass();
+ }
+
+ return false;
+}
+
+/*!
+ Return the signal corresponding to \a name
+*/
+QMetaMethod QDeclarativePropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
+{
+ Q_ASSERT(mo);
+ int methods = mo->methodCount();
+ for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
+ QMetaMethod method = mo->method(ii);
+ QByteArray methodName = method.signature();
+ int idx = methodName.indexOf('(');
+ methodName = methodName.left(idx);
+
+ if (methodName == name)
+ return method;
+ }
+
+ // If no signal is found, but the signal is of the form "onBlahChanged",
+ // return the notify signal for the property "Blah"
+ if (name.endsWith("Changed")) {
+ QByteArray propName = name.mid(0, name.length() - 7);
+ int propIdx = mo->indexOfProperty(propName.constData());
+ if (propIdx >= 0) {
+ QMetaProperty prop = mo->property(propIdx);
+ if (prop.hasNotifySignal())
+ return prop.notifySignal();
+ }
+ }
+
+ return QMetaMethod();
+}
+
+static inline int QMetaObject_methods(const QMetaObject *metaObject)
+{
+ struct Private
+ {
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ };
+
+ return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
+}
+
+static inline int QMetaObject_properties(const QMetaObject *metaObject)
+{
+ struct Private
+ {
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ };
+
+ return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
+}
+
+static inline void flush_vme_signal(const QObject *object, int index)
+{
+ QDeclarativeData *data = static_cast<QDeclarativeData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
+ if (data && data->propertyCache) {
+ QDeclarativePropertyCache::Data *property = data->propertyCache->method(index);
+
+ if (property && property->flags & QDeclarativePropertyCache::Data::IsVMESignal) {
+ const QMetaObject *metaObject = object->metaObject();
+ int methodOffset = metaObject->methodOffset();
+
+ while (methodOffset > index) {
+ metaObject = metaObject->d.superdata;
+ methodOffset -= QMetaObject_methods(metaObject);
+ }
+
+ QDeclarativeVMEMetaObject *vme =
+ static_cast<QDeclarativeVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
+
+ vme->connectAliasSignal(index);
+ }
+ }
+}
+
+/*!
+Connect \a sender \a signal_index to \a receiver \a method_index with the specified
+\a type and \a types. This behaves identically to QMetaObject::connect() except that
+it connects any lazy "proxy" signal connections set up by QML.
+
+It is possible that this logic should be moved to QMetaObject::connect().
+*/
+bool QDeclarativePropertyPrivate::connect(const QObject *sender, int signal_index,
+ const QObject *receiver, int method_index,
+ int type, int *types)
+{
+ flush_vme_signal(sender, signal_index);
+ flush_vme_signal(receiver, method_index);
+
+ return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
+}
+
+/*!
+Return \a metaObject's [super] meta object that provides data for \a property.
+*/
+const QMetaObject *QDeclarativePropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
+{
+ int propertyOffset = metaObject->propertyOffset();
+
+ while (propertyOffset > property) {
+ metaObject = metaObject->d.superdata;
+ propertyOffset -= QMetaObject_properties(metaObject);
+ }
+
+ return metaObject;
+}
+
+QT_END_NAMESPACE