summaryrefslogtreecommitdiffstats
path: root/src/declarative/qml/qmlvmemetaobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/qml/qmlvmemetaobject.cpp')
-rw-r--r--src/declarative/qml/qmlvmemetaobject.cpp340
1 files changed, 340 insertions, 0 deletions
diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp
new file mode 100644
index 0000000..8faa922
--- /dev/null
+++ b/src/declarative/qml/qmlvmemetaobject.cpp
@@ -0,0 +1,340 @@
+/****************************************************************************
+**
+** 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 "qmlvmemetaobject_p.h"
+
+#include "qml.h"
+#include "qmlrefcount_p.h"
+#include "qmlexpression.h"
+#include "qmlexpression_p.h"
+#include "qmlcontext_p.h"
+
+#include <QColor>
+#include <QDate>
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj,
+ const QMetaObject *other,
+ const QmlVMEMetaData *meta,
+ QmlCompiledData *cdata)
+: object(obj), compiledData(cdata), ctxt(qmlContext(obj)), metaData(meta), methods(0),
+ parent(0)
+{
+ compiledData->addref();
+
+ *static_cast<QMetaObject *>(this) = *other;
+ this->d.superdata = obj->metaObject();
+
+ QObjectPrivate *op = QObjectPrivate::get(obj);
+ if (op->metaObject)
+ parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
+ op->metaObject = this;
+
+ propOffset = QAbstractDynamicMetaObject::propertyOffset();
+ methodOffset = QAbstractDynamicMetaObject::methodOffset();
+
+ data = new QVariant[metaData->propertyCount];
+ aConnected.resize(metaData->aliasCount);
+
+ int list_type = qMetaTypeId<QmlList<QObject*>* >();
+ // ### Optimize
+ for (int ii = 0; ii < metaData->propertyCount; ++ii) {
+ int t = (metaData->propertyData() + ii)->propertyType;
+ if (t == list_type) {
+ listProperties.append(new List(this, ii));
+ data[ii] = QVariant::fromValue((QmlList<QObject *>*)listProperties.last());
+ } else if (t != -1) {
+ data[ii] = QVariant((QVariant::Type)t);
+ }
+ }
+}
+
+QmlVMEMetaObject::~QmlVMEMetaObject()
+{
+ compiledData->release();
+ delete parent;
+ qDeleteAll(listProperties);
+ delete [] data;
+ delete [] methods;
+}
+
+int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
+{
+ int id = _id;
+ if(c == QMetaObject::WriteProperty) {
+ int flags = *reinterpret_cast<int*>(a[3]);
+ if (!(flags & QmlMetaProperty::BypassInterceptor)
+ && !aInterceptors.isEmpty()
+ && aInterceptors.testBit(id)) {
+ QPair<int, QmlPropertyValueInterceptor*> pair = interceptors.value(id);
+ int valueIndex = pair.first;
+ QmlPropertyValueInterceptor *vi = pair.second;
+ int type = property(id).userType();
+
+ if (type != QVariant::Invalid) {
+ if (valueIndex != -1) {
+ QmlEnginePrivate *ep = ctxt?QmlEnginePrivate::get(ctxt->engine()):0;
+ QmlValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[type];
+ else valueType = QmlValueTypeFactory::valueType(type);
+ Q_ASSERT(valueType);
+
+ valueType->setValue(QVariant(type, a[0]));
+ QMetaProperty valueProp = valueType->metaObject()->property(valueIndex);
+ vi->write(valueProp.read(valueType));
+
+ if (!ep) delete valueType;
+ return -1;
+ } else {
+ vi->write(QVariant(type, a[0]));
+ return -1;
+ }
+ }
+ }
+ }
+ if(c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) {
+ if (id >= propOffset) {
+ id -= propOffset;
+
+ if (id < metaData->propertyCount) {
+ int t = (metaData->propertyData() + id)->propertyType;
+ bool needActivate = false;
+
+ if (t == -1) {
+
+ if (c == QMetaObject::ReadProperty) {
+ *reinterpret_cast<QVariant *>(a[0]) = data[id];
+ } else if (c == QMetaObject::WriteProperty) {
+ needActivate =
+ (data[id] != *reinterpret_cast<QVariant *>(a[0]));
+ data[id] = *reinterpret_cast<QVariant *>(a[0]);
+ }
+
+ } else {
+
+ if (c == QMetaObject::ReadProperty) {
+ switch(t) {
+ case QVariant::Int:
+ *reinterpret_cast<int *>(a[0]) = data[id].toInt();
+ break;
+ case QVariant::Bool:
+ *reinterpret_cast<bool *>(a[0]) = data[id].toBool();
+ break;
+ case QVariant::Double:
+ *reinterpret_cast<double *>(a[0]) = data[id].toDouble();
+ break;
+ case QVariant::String:
+ *reinterpret_cast<QString *>(a[0]) = data[id].toString();
+ break;
+ case QVariant::Url:
+ *reinterpret_cast<QUrl *>(a[0]) = data[id].toUrl();
+ break;
+ case QVariant::Color:
+ *reinterpret_cast<QColor *>(a[0]) = data[id].value<QColor>();
+ break;
+ case QVariant::Date:
+ *reinterpret_cast<QDate *>(a[0]) = data[id].toDate();
+ break;
+ case QMetaType::QObjectStar:
+ *reinterpret_cast<QObject **>(a[0]) = data[id].value<QObject*>();
+ break;
+ default:
+ break;
+ }
+ if (t == qMetaTypeId<QmlList<QObject*>* >()) {
+ *reinterpret_cast<QmlList<QObject *> **>(a[0]) = data[id].value<QmlList<QObject*>*>();
+ }
+
+ } else if (c == QMetaObject::WriteProperty) {
+
+ QVariant value = QVariant((QVariant::Type)data[id].type(), a[0]);
+ needActivate = (data[id] != value);
+ data[id] = value;
+ }
+
+ }
+
+ if (c == QMetaObject::WriteProperty && needActivate) {
+ activate(object, methodOffset + id, 0);
+ }
+
+ return -1;
+ }
+
+ id -= metaData->propertyCount;
+
+ if (id < metaData->aliasCount) {
+
+ QmlVMEMetaData::AliasData *d = metaData->aliasData() + id;
+
+ if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty)
+ *reinterpret_cast<void **>(a[0]) = 0;
+
+ if (!ctxt) return -1;
+ QmlContextPrivate *ctxtPriv =
+ (QmlContextPrivate *)QObjectPrivate::get(ctxt);
+
+ QObject *target = ctxtPriv->idValues[d->contextIdx].data();
+ if (!target)
+ return -1;
+
+ if (c == QMetaObject::ReadProperty && !aConnected.testBit(id)) {
+ int sigIdx = methodOffset + id + metaData->propertyCount;
+ QMetaObject::connect(ctxt, d->contextIdx + ctxtPriv->notifyIndex, object, sigIdx);
+
+ if (d->propertyIdx != -1) {
+ QMetaProperty prop =
+ target->metaObject()->property(d->propertyIdx);
+ if (prop.hasNotifySignal())
+ QMetaObject::connect(target, prop.notifySignalIndex(),
+ object, sigIdx);
+ }
+ aConnected.setBit(id);
+ }
+
+ if (d->propertyIdx == -1) {
+ *reinterpret_cast<QObject **>(a[0]) = target;
+ return -1;
+ } else {
+ return QMetaObject::metacall(target, c, d->propertyIdx, a);
+ }
+
+ }
+ return -1;
+
+ }
+
+ } else if(c == QMetaObject::InvokeMetaMethod) {
+
+ if (id >= methodOffset) {
+
+ id -= methodOffset;
+ int plainSignals = metaData->signalCount + metaData->propertyCount +
+ metaData->aliasCount;
+ if (id < plainSignals) {
+ QMetaObject::activate(object, _id, a);
+ return -1;
+ }
+
+ id -= plainSignals;
+
+ if (id < metaData->methodCount) {
+ if (!ctxt->engine())
+ return -1; // We can't run the method
+
+ QmlEnginePrivate *ep = QmlEnginePrivate::get(ctxt->engine());
+
+ QScriptValue function = method(id);
+
+ QScriptValueList args;
+ QmlVMEMetaData::MethodData *data = metaData->methodData() + id;
+ if (data->parameterCount) {
+ for (int ii = 0; ii < data->parameterCount; ++ii) {
+ args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]);
+ }
+ }
+ QScriptValue rv = function.call(ep->objectClass->newQObject(object), args);
+
+ if (a[0]) *reinterpret_cast<QVariant *>(a[0]) = ep->scriptValueToVariant(rv);
+
+ return -1;
+ }
+ return -1;
+ }
+ }
+
+ if (parent)
+ return parent->metaCall(c, _id, a);
+ else
+ return object->qt_metacall(c, _id, a);
+}
+
+QScriptValue QmlVMEMetaObject::method(int index)
+{
+ if (!methods)
+ methods = new QScriptValue[metaData->methodCount];
+
+ if (!methods[index].isValid()) {
+ QmlVMEMetaData::MethodData *data = metaData->methodData() + index;
+
+ const QChar *body =
+ (const QChar *)(((const char*)metaData) + data->bodyOffset);
+
+ QString code = QString::fromRawData(body, data->bodyLength);
+
+ // XXX Use QScriptProgram
+ // XXX We should evaluate all methods in a single big script block to
+ // improve the call time between dynamic methods defined on the same
+ // object
+ methods[index] = QmlExpressionPrivate::evalInObjectScope(ctxt, object, code);
+ }
+
+ return methods[index];
+}
+
+void QmlVMEMetaObject::listChanged(int id)
+{
+ activate(object, methodOffset + id, 0);
+}
+
+void QmlVMEMetaObject::registerInterceptor(int index, int valueIndex, QmlPropertyValueInterceptor *interceptor)
+{
+ if (aInterceptors.isEmpty())
+ aInterceptors.resize(propertyCount() + metaData->propertyCount);
+ aInterceptors.setBit(index);
+ interceptors.insert(index, qMakePair(valueIndex, interceptor));
+}
+
+QScriptValue QmlVMEMetaObject::vmeMethod(int index)
+{
+ if (index < methodOffset) {
+ Q_ASSERT(parent);
+ return static_cast<QmlVMEMetaObject *>(parent)->vmeMethod(index);
+ }
+ int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
+ Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+ return method(index - methodOffset - plainSignals);
+}
+
+QT_END_NAMESPACE