summaryrefslogtreecommitdiffstats
path: root/src/declarative/qml/qmlmetaproperty.cpp
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2010-02-11 15:45:07 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2010-02-11 15:45:07 (GMT)
commitb02508a00d82dd2a4bd097af22861dcdef14adea (patch)
tree96e26fcf6ce4bb3930ca0425107a43a5f829fa68 /src/declarative/qml/qmlmetaproperty.cpp
parent163b383404f25f5e951959a8d5056124567ef183 (diff)
parent1c2d8e41377644df27ac0ef5cdeeecb79598661c (diff)
downloadQt-b02508a00d82dd2a4bd097af22861dcdef14adea.zip
Qt-b02508a00d82dd2a4bd097af22861dcdef14adea.tar.gz
Qt-b02508a00d82dd2a4bd097af22861dcdef14adea.tar.bz2
Merge branch 'master' of scm.dev.nokia.troll.no:qt/qt-qml into master-integration
* 'master' of scm.dev.nokia.troll.no:qt/qt-qml: (3398 commits) Fixed compile of these recently renamed tests. Update QmlChanges.txt Adds qml prefix to all declarative autotests Removed "running: true" for animations used as propertyvaluesource Animations are running by default when used as property source value Fix QmlEngine offlineStoragePath test. Fix Image test on Windows. Fix FontLoader test on Windows. Test should use ceil() not floor() since ceil() is used for calculating Fix BorderImage tests on Windows. Test should use ceil() not floor() since ceil() is used for calculating Clean up Must pass app arguments onto qExec() or else test system cannot QML Object toString should use 64-bit address on 64-bit platforms Improve stability of tst_qmlecmascript::dynamicDestruction Fix tst_qmlecmascript::callQtInvokables Fixed qmldebug* tests crashing. Fix declarative/qmldom::loadDynamicProperty autotest Fix declarative/animatedimage autotest Removed the tests/auto/declarative/visual(&examples) from .pro ...
Diffstat (limited to 'src/declarative/qml/qmlmetaproperty.cpp')
-rw-r--r--src/declarative/qml/qmlmetaproperty.cpp1240
1 files changed, 1240 insertions, 0 deletions
diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp
new file mode 100644
index 0000000..09c936e
--- /dev/null
+++ b/src/declarative/qml/qmlmetaproperty.cpp
@@ -0,0 +1,1240 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlmetaproperty.h"
+#include "qmlmetaproperty_p.h"
+
+#include "qmlcompositetypedata_p.h"
+#include "qml.h"
+#include "qmlbinding.h"
+#include "qmlcontext.h"
+#include "qmlcontext_p.h"
+#include "qmlboundsignal_p.h"
+#include "qmlengine.h"
+#include "qmlengine_p.h"
+#include "qmldeclarativedata_p.h"
+#include "qmlstringconverters_p.h"
+
+#include <qfxperf_p_p.h>
+
+#include <QStringList>
+#include <QtCore/qdebug.h>
+
+#include <math.h>
+
+Q_DECLARE_METATYPE(QList<QObject *>);
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QmlMetaProperty
+ \brief The QmlMetaProperty class abstracts accessing QML properties.
+ \internal
+ */
+
+/*!
+ Create an invalid QmlMetaProperty.
+*/
+QmlMetaProperty::QmlMetaProperty()
+: d(new QmlMetaPropertyPrivate)
+{
+ d->q = this;
+}
+
+/*! \internal */
+QmlMetaProperty::~QmlMetaProperty()
+{
+ delete d; d = 0;
+}
+
+/*!
+ Creates a QmlMetaProperty for the default property of \a obj. If there is no
+ default property, an invalid QmlMetaProperty will be created.
+ */
+QmlMetaProperty::QmlMetaProperty(QObject *obj)
+: d(new QmlMetaPropertyPrivate)
+{
+ d->q = this;
+ d->initDefault(obj);
+}
+
+/*!
+ \internal
+ Creates a QmlMetaProperty for the default property of \a obj. If there is no
+ default property, an invalid QmlMetaProperty will be created.
+ */
+QmlMetaProperty::QmlMetaProperty(QObject *obj, QmlContext *ctxt)
+: d(new QmlMetaPropertyPrivate)
+{
+ d->q = this;
+ d->context = ctxt;
+ d->initDefault(obj);
+}
+
+/*!
+ Initialize from the default property of \a obj
+*/
+void QmlMetaPropertyPrivate::initDefault(QObject *obj)
+{
+ if (!obj)
+ return;
+
+ QMetaProperty p = QmlMetaType::defaultProperty(obj);
+ core.load(p);
+ if (core.isValid()) {
+ isDefaultProperty = true;
+ object = obj;
+ }
+}
+
+/*!
+ Creates a QmlMetaProperty for the property \a name of \a obj.
+ */
+QmlMetaProperty::QmlMetaProperty(QObject *obj, const QString &name)
+: d(new QmlMetaPropertyPrivate)
+{
+ d->q = this;
+ d->initProperty(obj, name);
+ if (!isValid()) d->object = 0;
+}
+
+/*!
+ \internal
+ Creates a QmlMetaProperty for the property \a name of \a obj.
+ */
+QmlMetaProperty::QmlMetaProperty(QObject *obj, const QString &name, QmlContext *ctxt)
+: d(new QmlMetaPropertyPrivate)
+{
+ d->q = this;
+ d->context = ctxt;
+ d->initProperty(obj, name);
+ if (!isValid()) { d->object = 0; d->context = 0; }
+}
+
+void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name)
+{
+ QmlEnginePrivate *enginePrivate = 0;
+ if (context && context->engine())
+ enginePrivate = QmlEnginePrivate::get(context->engine());
+
+ object = obj;
+
+ if (name.isEmpty() || !obj)
+ return;
+
+ if (enginePrivate && name.at(0).isUpper()) {
+ // Attached property
+ // ### What about qualified types?
+ QmlTypeNameCache *tnCache = QmlContextPrivate::get(context)->imports;
+ if (tnCache) {
+ QmlTypeNameCache::Data *d = tnCache->data(name);
+ if (d && d->type && d->type->attachedPropertiesFunction()) {
+ attachedFunc = d->type->index();
+ }
+ }
+ return;
+
+ } else if (name.count() >= 3 &&
+ name.at(0) == QChar(QLatin1Char('o')) &&
+ name.at(1) == QChar(QLatin1Char('n')) &&
+ name.at(2).isUpper()) {
+ // Signal
+ QString signalName = name.mid(2);
+ signalName[0] = signalName.at(0).toLower();
+
+ QMetaMethod method = findSignal(obj, signalName);
+ if (method.signature()) {
+ core.load(method);
+ return;
+ }
+ }
+
+ // Property
+ QmlPropertyCache::Data local;
+ QmlPropertyCache::Data *property =
+ QmlPropertyCache::property(context?context->engine():0, obj, name, local);
+ if (property && !(property->flags & QmlPropertyCache::Data::IsFunction))
+ core = *property;
+}
+
+/*!
+ Create a copy of \a other.
+*/
+QmlMetaProperty::QmlMetaProperty(const QmlMetaProperty &other)
+: d(new QmlMetaPropertyPrivate(*other.d))
+{
+ d->q = this;
+}
+
+/*!
+ \enum QmlMetaProperty::PropertyCategory
+
+ This enum specifies a category of QML property.
+
+ \value Unknown The category is unknown. This will never be returned from propertyCategory()
+ \value InvalidProperty The property is invalid.
+ \value Bindable The property is a QmlBinding.
+ \value List The property is a QList pointer
+ \value QmlList The property is a QmlList pointer
+ \value Object The property is a QObject derived type pointer
+ \value Normal The property is none of the above.
+ */
+
+/*!
+ \enum QmlMetaProperty::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.
+ \value Default The property is the default property.
+ \value Attached The property is an attached property.
+*/
+
+/*!
+ Returns the property category.
+*/
+QmlMetaProperty::PropertyCategory QmlMetaProperty::propertyCategory() const
+{
+ return d->propertyCategory();
+}
+
+QmlMetaProperty::PropertyCategory
+QmlMetaPropertyPrivate::propertyCategory() const
+{
+ uint type = q->type();
+
+ if (type & QmlMetaProperty::ValueTypeProperty) {
+ return QmlMetaProperty::Normal;
+ } else if (type & QmlMetaProperty::Attached) {
+ return QmlMetaProperty::Object;
+ } else if (type & QmlMetaProperty::Property) {
+ int type = propertyType();
+ if (type == QVariant::Invalid)
+ return QmlMetaProperty::InvalidProperty;
+ else if ((uint)type < QVariant::UserType)
+ return QmlMetaProperty::Normal;
+ else if (type == qMetaTypeId<QmlBinding *>())
+ return QmlMetaProperty::Bindable;
+ else if (core.flags & QmlPropertyCache::Data::IsQObjectDerived)
+ return QmlMetaProperty::Object;
+ else if (core.flags & QmlPropertyCache::Data::IsQmlList)
+ return QmlMetaProperty::QmlList;
+ else if (core.flags & QmlPropertyCache::Data::IsQList)
+ return QmlMetaProperty::List;
+ else
+ return QmlMetaProperty::Normal;
+ } else {
+ return QmlMetaProperty::InvalidProperty;
+ }
+}
+
+/*!
+ Returns the type name of the property, or 0 if the property has no type
+ name.
+*/
+const char *QmlMetaProperty::propertyTypeName() const
+{
+ if (type() & ValueTypeProperty) {
+
+ QmlEnginePrivate *ep = d->context?QmlEnginePrivate::get(d->context->engine()):0;
+ QmlValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[d->core.propType];
+ else valueType = QmlValueTypeFactory::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 QmlMetaProperty represent the same
+ property.
+*/
+bool QmlMetaProperty::operator==(const QmlMetaProperty &other) const
+{
+ // 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 &&
+ d->attachedFunc == other.d->attachedFunc;
+}
+
+/*!
+ Returns the QVariant type of the property, or QVariant::Invalid if the
+ property has no QVariant type.
+*/
+int QmlMetaProperty::propertyType() const
+{
+ return d->propertyType();
+}
+
+int QmlMetaPropertyPrivate::propertyType() const
+{
+ uint type = q->type();
+ if (type & QmlMetaProperty::ValueTypeProperty) {
+ return valueType.valueTypePropType;
+ } else if (type & QmlMetaProperty::Attached) {
+ return qMetaTypeId<QObject *>();
+ } else if (type & QmlMetaProperty::Property) {
+ if (core.propType == (int)QVariant::LastType)
+ return qMetaTypeId<QVariant>();
+ else
+ return core.propType;
+ } else {
+ return QVariant::Invalid;
+ }
+}
+
+/*!
+ Returns the type of the property.
+*/
+QmlMetaProperty::Type QmlMetaProperty::type() const
+{
+ if (d->core.flags & QmlPropertyCache::Data::IsFunction)
+ return SignalProperty;
+ else if (d->attachedFunc != -1)
+ return Attached;
+ else if (d->valueType.valueTypeCoreIdx != -1)
+ return (Type)(Property | ValueTypeProperty);
+ else if (d->core.isValid())
+ return (Type)(Property | ((d->isDefaultProperty)?Default:0));
+ else
+ return Invalid;
+}
+
+/*!
+ Returns true if this QmlMetaProperty represents a regular Qt property.
+*/
+bool QmlMetaProperty::isProperty() const
+{
+ return type() & Property;
+}
+
+/*!
+ Returns true if this QmlMetaProperty represents a default property.
+*/
+bool QmlMetaProperty::isDefault() const
+{
+ return type() & Default;
+}
+
+/*!
+ Returns the QmlMetaProperty's QObject.
+*/
+QObject *QmlMetaProperty::object() const
+{
+ return d->object;
+}
+
+/*!
+ Assign \a other to this QmlMetaProperty.
+*/
+QmlMetaProperty &QmlMetaProperty::operator=(const QmlMetaProperty &other)
+{
+ d->context = other.d->context;
+ d->object = other.d->object;
+
+ d->isDefaultProperty = other.d->isDefaultProperty;
+ d->core = other.d->core;
+
+ d->valueType = other.d->valueType;
+
+ d->attachedFunc = other.d->attachedFunc;
+ return *this;
+}
+
+/*!
+ Returns true if the property is writable, otherwise false.
+*/
+bool QmlMetaProperty::isWritable() const
+{
+ QmlMetaProperty::PropertyCategory category = propertyCategory();
+
+ if (!d->object)
+ return false;
+ if (category == List || category == QmlList)
+ return true;
+ else if (type() & SignalProperty)
+ return false;
+ else if (d->core.isValid() && d->object)
+ return d->core.flags & QmlPropertyCache::Data::IsWritable;
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is designable, otherwise false.
+*/
+bool QmlMetaProperty::isDesignable() const
+{
+ 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 QmlMetaProperty::isResettable() const
+{
+ if (type() & Property && d->core.isValid() && d->object)
+ return d->core.flags & QmlPropertyCache::Data::IsResettable;
+ else
+ return false;
+}
+
+/*!
+ Returns true if the QmlMetaProperty refers to a valid property, otherwise
+ false.
+*/
+bool QmlMetaProperty::isValid() const
+{
+ return type() != Invalid;
+}
+
+/*!
+ Return the name of this QML property.
+*/
+QString QmlMetaProperty::name() const
+{
+ if (!d->isNameCached) {
+ // ###
+ if (!d->object) {
+ } else if (type() & ValueTypeProperty) {
+ QString rv = d->core.name(d->object) + QLatin1Char('.');
+
+ QmlEnginePrivate *ep = d->context?QmlEnginePrivate::get(d->context->engine()):0;
+ QmlValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[d->core.propType];
+ else valueType = QmlValueTypeFactory::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 QmlMetaProperty::property() const
+{
+ 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 QmlMetaProperty::method() const
+{
+ 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.
+*/
+QmlAbstractBinding *QmlMetaProperty::binding() const
+{
+ if (!isProperty() || (type() & Attached) || !d->object)
+ return 0;
+
+ QmlDeclarativeData *data = QmlDeclarativeData::get(d->object);
+ if (!data)
+ return 0;
+
+ if (!data->hasBindingBit(d->core.coreIndex))
+ return 0;
+
+ QmlAbstractBinding *binding = data->bindings;
+ while (binding) {
+ // ### This wont work for value types
+ if (binding->propertyIndex() == d->core.coreIndex)
+ return binding;
+ binding = binding->m_nextBinding;
+ }
+ return 0;
+}
+
+/*!
+ 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 intial value, it will use these flags for the write).
+*/
+QmlAbstractBinding *
+QmlMetaProperty::setBinding(QmlAbstractBinding *newBinding, QmlMetaProperty::WriteFlags flags) const
+{
+ if (!isProperty() || (type() & Attached) || !d->object) {
+ if (newBinding)
+ newBinding->destroy();
+ return 0;
+ }
+
+ return d->setBinding(d->object, d->core, newBinding, flags);
+}
+
+QmlAbstractBinding *
+QmlMetaPropertyPrivate::setBinding(QObject *object, const QmlPropertyCache::Data &core,
+ QmlAbstractBinding *newBinding, QmlMetaProperty::WriteFlags flags)
+{
+ QmlDeclarativeData *data = QmlDeclarativeData::get(object, 0 != newBinding);
+
+ if (data && data->hasBindingBit(core.coreIndex)) {
+ QmlAbstractBinding *binding = data->bindings;
+ while (binding) {
+ // ### This wont work for value types
+ if (binding->propertyIndex() == core.coreIndex) {
+ binding->setEnabled(false);
+
+ if (newBinding)
+ newBinding->setEnabled(true, flags);
+
+ return binding; // ### QmlAbstractBinding;
+ }
+
+ binding = binding->m_nextBinding;
+ }
+ }
+
+ if (newBinding)
+ newBinding->setEnabled(true, flags);
+
+ return 0;
+}
+/*!
+ Returns the expression associated with this signal property, or 0 if no
+ signal expression exists.
+*/
+QmlExpression *QmlMetaProperty::signalExpression() const
+{
+ if (!(type() & SignalProperty))
+ return 0;
+
+ const QObjectList &children = d->object->children();
+
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+
+ QmlBoundSignal *signal = QmlBoundSignal::cast(child);
+ if (signal && signal->index() == coreIndex())
+ 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.
+*/
+QmlExpression *QmlMetaProperty::setSignalExpression(QmlExpression *expr) const
+{
+ if (!(type() & SignalProperty)) {
+ delete expr;
+ return 0;
+ }
+
+ const QObjectList &children = d->object->children();
+
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+
+ QmlBoundSignal *signal = QmlBoundSignal::cast(child);
+ if (signal && signal->index() == coreIndex())
+ return signal->setExpression(expr);
+ }
+
+ if (expr) {
+ QmlBoundSignal *signal = new QmlBoundSignal(d->object, method(), d->object);
+ return signal->setExpression(expr);
+ } else {
+ return 0;
+ }
+}
+
+QMetaMethod QmlMetaPropertyPrivate::findSignal(QObject *obj, const QString &name)
+{
+ const QMetaObject *mo = obj->metaObject();
+
+ int methods = mo->methodCount();
+ for (int ii = methods - 1; ii >= 0; --ii) {
+ QMetaMethod method = mo->method(ii);
+ QString methodName = QString::fromUtf8(method.signature());
+ int idx = methodName.indexOf(QLatin1Char('('));
+ methodName = methodName.left(idx);
+
+ if (methodName == name)
+ return method;
+ }
+ return QMetaMethod();
+}
+
+QObject *QmlMetaPropertyPrivate::attachedObject() const
+{
+ if (attachedFunc == -1)
+ return 0;
+ else
+ return qmlAttachedPropertiesObjectById(attachedFunc, object);
+}
+
+/*!
+ Returns the property value.
+*/
+QVariant QmlMetaProperty::read() const
+{
+ if (!d->object)
+ return QVariant();
+
+ if (type() & SignalProperty) {
+
+ return QVariant();
+
+ } else if (type() & Property || type() & Attached) {
+
+ return d->readValueProperty();
+
+ }
+ return QVariant();
+}
+
+QVariant QmlMetaPropertyPrivate::readValueProperty()
+{
+ uint type = q->type();
+ if (type & QmlMetaProperty::Attached) {
+
+ return QVariant::fromValue(attachedObject());
+
+ } else if(type & QmlMetaProperty::ValueTypeProperty) {
+
+ QmlEnginePrivate *ep = context?QmlEnginePrivate::get(context->engine()):0;
+ QmlValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[core.propType];
+ else valueType = QmlValueTypeFactory::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 {
+
+ return object->metaObject()->property(core.coreIndex).read(object.data());
+
+ }
+}
+
+//###
+//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
+//###
+bool QmlMetaPropertyPrivate::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()) + "::" + 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 QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value,
+ QmlMetaProperty::WriteFlags flags)
+{
+ // Remove any existing bindings on this property
+ if (!(flags & QmlMetaProperty::DontRemoveBinding))
+ delete q->setBinding(0);
+
+ bool rv = false;
+ uint type = q->type();
+ if (type & QmlMetaProperty::ValueTypeProperty) {
+ QmlEnginePrivate *ep =
+ context?static_cast<QmlEnginePrivate *>(QObjectPrivate::get(context->engine())):0;
+
+ QmlValueType *writeBack = 0;
+ if (ep) {
+ writeBack = ep->valueTypes[core.propType];
+ } else {
+ writeBack = QmlValueTypeFactory::valueType(core.propType);
+ }
+
+ writeBack->read(object, core.coreIndex);
+
+ QmlPropertyCache::Data data = core;
+ 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 QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data &property,
+ const QVariant &value, QmlContext *context,
+ QmlMetaProperty::WriteFlags flags)
+{
+ int coreIdx = property.coreIndex;
+ int status = -1; //for dbus
+
+ if (property.flags & QmlPropertyCache::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 t = property.propType;
+ int vt = value.userType();
+
+ QmlEnginePrivate *enginePriv = 0;
+ if (context && context->engine())
+ enginePriv = QmlEnginePrivate::get(context->engine());
+
+ if (t == QVariant::Url) {
+
+ QUrl u;
+ bool found = false;
+ if (vt == QVariant::Url) {
+ u = value.toUrl();
+ found = true;
+ } else if (vt == QVariant::ByteArray) {
+ u = QUrl(QString::fromUtf8(value.toByteArray()));
+ found = true;
+ } else if (vt == 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 (vt == t) {
+
+ void *a[] = { (void *)value.constData(), 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+
+ } else if (qMetaTypeId<QVariant>() == t) {
+
+ void *a[] = { (void *)&value, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+
+ } else if (property.flags & QmlPropertyCache::Data::IsQObjectDerived) {
+
+ const QMetaObject *valMo = 0;
+ if (enginePriv) valMo = enginePriv->rawMetaObjectForType(value.userType());
+ else valMo = QmlMetaType::rawMetaObjectForType(value.userType());
+
+ if (!valMo)
+ return false;
+
+ QObject *o = *(QObject **)value.constData();
+ const QMetaObject *propMo = 0;
+ if (enginePriv) propMo = enginePriv->rawMetaObjectForType(t);
+ else propMo = QmlMetaType::rawMetaObjectForType(t);
+
+ 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 & QmlPropertyCache::Data::IsQList) {
+
+ int listType = QmlMetaType::listType(t);
+ QMetaProperty prop = object->metaObject()->property(property.coreIndex);
+
+ if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
+ const QList<QObject *> &list =
+ qvariant_cast<QList<QObject *> >(value);
+ QVariant listVar = prop.read(object);
+ QmlMetaType::clear(listVar);
+ for (int ii = 0; ii < list.count(); ++ii) {
+ QVariant v = QmlMetaType::fromObject(list.at(ii), listType);
+ QmlMetaType::append(listVar, v);
+ }
+
+ } else if (vt == listType ||
+ value.userType() == listType) {
+ QVariant listVar = prop.read(object);
+ QmlMetaType::append(listVar, value);
+ }
+
+ } else if (property.flags & QmlPropertyCache::Data::IsQmlList) {
+
+ // XXX - optimize!
+ QMetaProperty prop = object->metaObject()->property(property.coreIndex);
+ QVariant list = prop.read(object);
+ QmlPrivate::ListInterface *li =
+ *(QmlPrivate::ListInterface **)list.constData();
+
+ int type = li->type();
+
+ if (QObject *obj = QmlMetaType::toQObject(value)) {
+ const QMetaObject *mo =
+ QmlMetaType::rawMetaObjectForType(type);
+
+ const QMetaObject *objMo = obj->metaObject();
+ bool found = false;
+ while(!found && objMo) {
+ if (equal(objMo, mo))
+ found = true;
+ else
+ objMo = objMo->superClass();
+ }
+
+ if (!found)
+ return false;
+
+ // NOTE: This assumes a cast to QObject does not alter
+ // the object pointer
+ void *d = (void *)&obj;
+ li->append(d);
+ }
+ } else {
+ Q_ASSERT(vt != t);
+
+ QVariant v = value;
+ if (v.convert((QVariant::Type)t)) {
+ void *a[] = { (void *)v.constData(), 0, &status, &flags};
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+ } else if ((uint)t >= QVariant::UserType && vt == QVariant::String) {
+ QmlMetaType::StringConverter con = QmlMetaType::customStringConverter(t);
+ if (!con)
+ return false;
+
+ QVariant v = con(value.toString());
+ if (v.userType() == t) {
+ void *a[] = { (void *)v.constData(), 0, &status, &flags};
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+ }
+ } else if (vt == QVariant::String) {
+ bool ok = false;
+ QVariant v = QmlStringConverters::variantFromString(value.toString(), t, &ok);
+ if (!ok)
+ return false;
+
+ void *a[] = { (void *)v.constData(), 0, &status, &flags};
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*!
+ Set the property value to \a value.
+*/
+bool QmlMetaProperty::write(const QVariant &value) const
+{
+ return write(value, 0);
+}
+
+/*!
+ Resets the property value.
+*/
+bool QmlMetaProperty::reset() const
+{
+ if (isResettable()) {
+ void *args[] = { 0 };
+ QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QmlMetaProperty::write(const QVariant &value, QmlMetaProperty::WriteFlags flags) const
+{
+ if (d->object && type() & Property && d->core.isValid() && isWritable())
+ return d->writeValueProperty(value, flags);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property has a change notifier signal, otherwise false.
+*/
+bool QmlMetaProperty::hasChangedNotifier() const
+{
+ if (type() & Property && !(type() & Attached) && 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 QmlMetaProperty::needsChangedNotifier() const
+{
+ return type() & Property && !(type() & Attached) &&
+ !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 QmlMetaProperty::connectNotifier(QObject *dest, int method) const
+{
+ if (!(type() & Property) || (type() & Attached) || !d->object)
+ return false;
+
+ QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
+ if (prop.hasNotifySignal()) {
+ return QMetaObject::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 QmlMetaProperty::connectNotifier(QObject *dest, const char *slot) const
+{
+ if (!(type() & Property) || (type() & Attached) || !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 QmlMetaProperty::coreIndex() const
+{
+ return d->core.coreIndex;
+}
+
+/*! \internal */
+int QmlMetaProperty::valueTypeCoreIndex() const
+{
+ return d->valueType.valueTypeCoreIdx;
+}
+
+Q_GLOBAL_STATIC(QmlValueTypeFactory, qmlValueTypes);
+
+
+struct SerializedData {
+ QmlMetaProperty::Type type;
+ QmlPropertyCache::Data core;
+};
+
+struct ValueTypeSerializedData : public SerializedData {
+ QmlPropertyCache::ValueTypeData valueType;
+};
+
+QByteArray QmlMetaPropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
+ int subIndex, int subType)
+{
+ ValueTypeSerializedData sd;
+ sd.type = QmlMetaProperty::ValueTypeProperty;
+ sd.core.load(metaObject->property(index));
+ sd.valueType.valueTypeCoreIdx = subIndex;
+ sd.valueType.valueTypePropType = subType;
+
+ QByteArray rv((const char *)&sd, sizeof(sd));
+ return rv;
+}
+
+QByteArray QmlMetaPropertyPrivate::saveProperty(const QMetaObject *metaObject, int index)
+{
+ SerializedData sd;
+ sd.type = QmlMetaProperty::Property;
+ sd.core.load(metaObject->property(index));
+
+ QByteArray rv((const char *)&sd, sizeof(sd));
+ return rv;
+}
+
+QmlMetaProperty
+QmlMetaPropertyPrivate::restore(const QByteArray &data, QObject *object, QmlContext *ctxt)
+{
+ QmlMetaProperty prop;
+
+ if (data.isEmpty())
+ return prop;
+
+ prop.d->object = object;
+ prop.d->context = ctxt;
+
+ const SerializedData *sd = (const SerializedData *)data.constData();
+ if (sd->type == QmlMetaProperty::Property) {
+ prop.d->core = sd->core;
+ } else if(sd->type == QmlMetaProperty::ValueTypeProperty) {
+ const ValueTypeSerializedData *vt = (const ValueTypeSerializedData *)sd;
+ prop.d->core = vt->core;
+ prop.d->valueType = vt->valueType;
+ }
+
+ return prop;
+}
+
+/*!
+ \internal
+
+ Creates a QmlMetaProperty for the property \a name of \a obj. Unlike
+ the QmlMetaProperty(QObject*, QString, QmlContext*) constructor, this static function
+ will correctly handle dot properties, including value types and attached properties.
+*/
+QmlMetaProperty QmlMetaProperty::createProperty(QObject *obj,
+ const QString &name,
+ QmlContext *context)
+{
+ QmlTypeNameCache *typeNameCache = context?QmlContextPrivate::get(context)->imports:0;
+
+ QStringList path = name.split(QLatin1Char('.'));
+ QObject *object = obj;
+
+ for (int jj = 0; jj < path.count() - 1; ++jj) {
+ const QString &pathName = path.at(jj);
+
+ if (QmlTypeNameCache::Data *data = typeNameCache?typeNameCache->data(pathName):0) {
+ if (data->type) {
+ QmlAttachedPropertiesFunc func = data->type->attachedPropertiesFunction();
+ if (!func)
+ return QmlMetaProperty();
+ object = qmlAttachedPropertiesObjectById(data->type->index(), object);
+ if (!object)
+ return QmlMetaProperty();
+ continue;
+ } else {
+ Q_ASSERT(data->typeNamespace);
+ ++jj;
+ data = data->typeNamespace->data(path.at(jj));
+ if (!data || !data->type)
+ return QmlMetaProperty();
+ QmlAttachedPropertiesFunc func = data->type->attachedPropertiesFunction();
+ if (!func)
+ return QmlMetaProperty();
+ object = qmlAttachedPropertiesObjectById(data->type->index(), object);
+ if (!object)
+ return QmlMetaProperty();
+ continue;
+ }
+ }
+
+ QmlMetaProperty prop(object, pathName, context);
+
+ if (jj == path.count() - 2 && prop.propertyType() < (int)QVariant::UserType &&
+ qmlValueTypes()->valueTypes[prop.propertyType()]) {
+ // 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()->valueTypes[prop.propertyType()];
+ int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
+ if (idx == -1)
+ return QmlMetaProperty();
+ QMetaProperty vtProp = typeObject->metaObject()->property(idx);
+
+ QmlMetaProperty p = prop;
+ p.d->valueType.valueTypeCoreIdx = idx;
+ p.d->valueType.valueTypePropType = vtProp.userType();
+ return p;
+ }
+
+ QObject *objVal = QmlMetaType::toQObject(prop.read());
+ if (!objVal)
+ return QmlMetaProperty();
+ object = objVal;
+ }
+
+ const QString &propName = path.last();
+ QmlMetaProperty prop(object, propName, context);
+ if (!prop.isValid())
+ return QmlMetaProperty();
+ else
+ return prop;
+}
+
+/*!
+ Returns true if lhs and rhs refer to the same metaobject data
+*/
+bool QmlMetaPropertyPrivate::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 QmlMetaPropertyPrivate::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;
+}
+
+QT_END_NAMESPACE