summaryrefslogtreecommitdiffstats
path: root/src/script/qscriptextqobject.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2009-03-23 09:34:13 (GMT)
committerSimon Hausmann <simon.hausmann@nokia.com>2009-03-23 09:34:13 (GMT)
commit67ad0519fd165acee4a4d2a94fa502e9e4847bd0 (patch)
tree1dbf50b3dff8d5ca7e9344733968c72704eb15ff /src/script/qscriptextqobject.cpp
downloadQt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.zip
Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.gz
Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.bz2
Long live Qt!
Diffstat (limited to 'src/script/qscriptextqobject.cpp')
-rw-r--r--src/script/qscriptextqobject.cpp2209
1 files changed, 2209 insertions, 0 deletions
diff --git a/src/script/qscriptextqobject.cpp b/src/script/qscriptextqobject.cpp
new file mode 100644
index 0000000..d18c3da
--- /dev/null
+++ b/src/script/qscriptextqobject.cpp
@@ -0,0 +1,2209 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtScript 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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+
+#ifndef QT_NO_SCRIPT
+
+#include "qscriptengine_p.h"
+#include "qscriptvalueimpl_p.h"
+#include "qscriptcontext_p.h"
+#include "qscriptmember_p.h"
+#include "qscriptobject_p.h"
+#include "qscriptable.h"
+#include "qscriptable_p.h"
+#include "qscriptextqobject_p.h"
+
+#include <QtCore/QtDebug>
+#include <QtCore/QMetaMethod>
+#include <QtCore/QRegExp>
+#include <QtCore/QVarLengthArray>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+// we use bits 15..12 of property flags
+enum {
+ PROPERTY_ID = 0 << 12,
+ DYNAPROPERTY_ID = 1 << 12,
+ METHOD_ID = 2 << 12,
+ CHILD_ID = 3 << 12,
+ ID_MASK = 7 << 12,
+ MAYBE_OVERLOADED = 8 << 12
+};
+
+static const bool GeneratePropertyFunctions = true;
+
+int QScriptMetaType::typeId() const
+{
+ if (isVariant())
+ return QMetaType::type("QVariant");
+ return isMetaEnum() ? 2/*int*/ : m_typeId;
+}
+
+QByteArray QScriptMetaType::name() const
+{
+ if (!m_name.isEmpty())
+ return m_name;
+ else if (m_kind == Variant)
+ return "QVariant";
+ return QMetaType::typeName(typeId());
+}
+
+namespace QScript {
+
+class QObjectNotifyCaller : public QObject
+{
+public:
+ void callConnectNotify(const char *signal)
+ { connectNotify(signal); }
+ void callDisconnectNotify(const char *signal)
+ { disconnectNotify(signal); }
+};
+
+class QtPropertyFunction: public QScriptFunction
+{
+public:
+ QtPropertyFunction(const QMetaObject *meta, int index)
+ : m_meta(meta), m_index(index)
+ { }
+
+ ~QtPropertyFunction() { }
+
+ virtual void execute(QScriptContextPrivate *context);
+
+ virtual Type type() const { return QScriptFunction::QtProperty; }
+
+ virtual QString functionName() const;
+
+private:
+ const QMetaObject *m_meta;
+ int m_index;
+};
+
+class QObjectPrototype : public QObject
+{
+ Q_OBJECT
+public:
+ QObjectPrototype(QObject *parent = 0)
+ : QObject(parent) { }
+ ~QObjectPrototype() { }
+};
+
+static inline QByteArray methodName(const QMetaMethod &method)
+{
+ QByteArray signature = method.signature();
+ return signature.left(signature.indexOf('('));
+}
+
+static inline QVariant variantFromValue(QScriptEnginePrivate *eng,
+ int targetType, const QScriptValueImpl &value)
+{
+ QVariant v(targetType, (void *)0);
+ Q_ASSERT(eng);
+ if (QScriptEnginePrivate::convert(value, targetType, v.data(), eng))
+ return v;
+ if (uint(targetType) == QVariant::LastType)
+ return value.toVariant();
+ if (value.isVariant()) {
+ v = value.toVariant();
+ if (v.canConvert(QVariant::Type(targetType))) {
+ v.convert(QVariant::Type(targetType));
+ return v;
+ }
+ QByteArray typeName = v.typeName();
+ if (typeName.endsWith('*')
+ && (QMetaType::type(typeName.left(typeName.size()-1)) == targetType)) {
+ return QVariant(targetType, *reinterpret_cast<void* *>(v.data()));
+ }
+ }
+
+ return QVariant();
+}
+
+void ExtQObject::Instance::finalize(QScriptEnginePrivate *eng)
+{
+ switch (ownership) {
+ case QScriptEngine::QtOwnership:
+ break;
+ case QScriptEngine::ScriptOwnership:
+ if (value)
+ eng->disposeQObject(value);
+ break;
+ case QScriptEngine::AutoOwnership:
+ if (value && !value->parent())
+ eng->disposeQObject(value);
+ break;
+ }
+}
+
+ExtQObject::Instance *ExtQObject::Instance::get(const QScriptValueImpl &object, QScriptClassInfo *klass)
+{
+ if (! klass || klass == object.classInfo())
+ return static_cast<Instance*> (object.objectData());
+
+ return 0;
+}
+
+
+static inline QScriptable *scriptableFromQObject(QObject *qobj)
+{
+ void *ptr = qobj->qt_metacast("QScriptable");
+ return reinterpret_cast<QScriptable*>(ptr);
+}
+
+static bool isObjectProperty(const QScriptValueImpl &object, const char *name)
+{
+ QScriptEnginePrivate *eng = object.engine();
+ QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name));
+ QScript::Member member;
+ QScriptValueImpl base;
+ return object.resolve(nameId, &member, &base, QScriptValue::ResolveLocal, QScript::Read)
+ && member.testFlags(QScript::Member::ObjectProperty);
+}
+
+static bool hasMethodAccess(const QMetaMethod &method, int index, const QScriptEngine::QObjectWrapOptions &opt)
+{
+ return (method.access() != QMetaMethod::Private)
+ && ((index != 2) || !(opt & QScriptEngine::ExcludeDeleteLater));
+}
+
+static bool isEnumerableMetaProperty(const QMetaProperty &prop,
+ const QMetaObject *mo, int index)
+{
+ return prop.isScriptable() && prop.isValid()
+ // the following lookup is to ensure that we have the
+ // "most derived" occurrence of the property with this name
+ && (mo->indexOfProperty(prop.name()) == index);
+}
+
+static uint flagsForMetaProperty(const QMetaProperty &prop)
+{
+ return (QScriptValue::Undeletable
+ | (!prop.isWritable()
+ ? QScriptValue::ReadOnly
+ : QScriptValue::PropertyFlag(0))
+ | (GeneratePropertyFunctions
+ ? (QScriptValue::PropertyGetter
+ | QScriptValue::PropertySetter)
+ : QScriptValue::PropertyFlag(0))
+ | QScriptValue::QObjectMember
+ | PROPERTY_ID);
+}
+
+
+static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
+{
+ QByteArray scope;
+ QByteArray name;
+ int scopeIdx = str.lastIndexOf("::");
+ if (scopeIdx != -1) {
+ scope = str.left(scopeIdx);
+ name = str.mid(scopeIdx + 2);
+ } else {
+ name = str;
+ }
+ for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
+ QMetaEnum m = meta->enumerator(i);
+ if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
+ return i;
+ }
+ return -1;
+}
+
+static QMetaMethod metaMethod(const QMetaObject *meta,
+ QMetaMethod::MethodType type,
+ int index)
+{
+ if (type != QMetaMethod::Constructor)
+ return meta->method(index);
+ else
+ return meta->constructor(index);
+}
+
+static void callQtMethod(QScriptContextPrivate *context, QMetaMethod::MethodType callType,
+ QObject *thisQObject, const QMetaObject *meta, int initialIndex,
+ bool maybeOverloaded)
+{
+ QScriptValueImpl result;
+ QScriptEnginePrivate *engine = context->engine();
+
+ int limit;
+#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
+ int lastFoundIndex = initialIndex;
+ QScriptMetaObject *metaCache = engine->cachedMetaObject(meta);
+ if (callType != QMetaMethod::Constructor)
+ limit = metaCache->methodLowerBound(initialIndex);
+ else
+ limit = 0;
+#else
+ limit = 0;
+#endif
+
+ QByteArray funName;
+ QScriptMetaMethod chosenMethod;
+ int chosenIndex = -1;
+ QVarLengthArray<QVariant, 9> args;
+ QVector<QScriptMetaArguments> candidates;
+ QVector<QScriptMetaArguments> unresolved;
+ QVector<int> tooFewArgs;
+ QVector<int> conversionFailed;
+ int index;
+ for (index = initialIndex; index >= limit; --index) {
+ QScriptMetaMethod mtd;
+#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
+ if (callType != QMetaMethod::Constructor)
+ mtd = metaCache->findMethod(index);
+ if (!mtd.isValid())
+#endif
+ {
+ QMetaMethod method = metaMethod(meta, callType, index);
+
+ QVector<QScriptMetaType> types;
+ // resolve return type
+ QByteArray returnTypeName = method.typeName();
+ int rtype = QMetaType::type(returnTypeName);
+ if ((rtype == 0) && !returnTypeName.isEmpty()) {
+ if (returnTypeName == "QVariant") {
+ types.append(QScriptMetaType::variant());
+ } else {
+ int enumIndex = indexOfMetaEnum(meta, returnTypeName);
+ if (enumIndex != -1)
+ types.append(QScriptMetaType::metaEnum(enumIndex, returnTypeName));
+ else
+ types.append(QScriptMetaType::unresolved(returnTypeName));
+ }
+ } else {
+ if (callType == QMetaMethod::Constructor)
+ types.append(QScriptMetaType::metaType(QMetaType::QObjectStar, "QObject*"));
+ else if (returnTypeName == "QVariant")
+ types.append(QScriptMetaType::variant());
+ else
+ types.append(QScriptMetaType::metaType(rtype, returnTypeName));
+ }
+ // resolve argument types
+ QList<QByteArray> parameterTypeNames = method.parameterTypes();
+ for (int i = 0; i < parameterTypeNames.count(); ++i) {
+ QByteArray argTypeName = parameterTypeNames.at(i);
+ int atype = QMetaType::type(argTypeName);
+ if (atype == 0) {
+ if (argTypeName == "QVariant") {
+ types.append(QScriptMetaType::variant());
+ } else {
+ int enumIndex = indexOfMetaEnum(meta, argTypeName);
+ if (enumIndex != -1)
+ types.append(QScriptMetaType::metaEnum(enumIndex, argTypeName));
+ else
+ types.append(QScriptMetaType::unresolved(argTypeName));
+ }
+ } else {
+ if (argTypeName == "QVariant")
+ types.append(QScriptMetaType::variant());
+ else
+ types.append(QScriptMetaType::metaType(atype, argTypeName));
+ }
+ }
+
+ mtd = QScriptMetaMethod(methodName(method), types);
+
+#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
+ if (mtd.fullyResolved() && (callType != QMetaMethod::Constructor))
+ metaCache->registerMethod(index, mtd);
+#endif
+ }
+
+ if (index == initialIndex)
+ funName = mtd.name();
+ else {
+ if (mtd.name() != funName)
+ continue;
+#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
+ lastFoundIndex = index;
+#endif
+ }
+
+ if (context->argumentCount() < mtd.argumentCount()) {
+ tooFewArgs.append(index);
+ continue;
+ }
+
+ if (!mtd.fullyResolved()) {
+ // remember it so we can give an error message later, if necessary
+ unresolved.append(QScriptMetaArguments(/*matchDistance=*/INT_MAX, index,
+ mtd, QVarLengthArray<QVariant, 9>()));
+ if (mtd.hasUnresolvedReturnType())
+ continue;
+ }
+
+ if (args.count() != mtd.count())
+ args.resize(mtd.count());
+
+ QScriptMetaType retType = mtd.returnType();
+ args[0] = QVariant(retType.typeId(), (void *)0); // the result
+
+ // try to convert arguments
+ bool converted = true;
+ int matchDistance = 0;
+ for (int i = 0; converted && i < mtd.argumentCount(); ++i) {
+ QScriptValueImpl actual = context->argument(i);
+ QScriptMetaType argType = mtd.argumentType(i);
+ int tid = -1;
+ QVariant v;
+ if (argType.isUnresolved()) {
+ v = QVariant(QMetaType::QObjectStar, (void *)0);
+ converted = engine->convertToNativeQObject(
+ actual, argType.name(), reinterpret_cast<void* *>(v.data()));
+ } else if (argType.isVariant()) {
+ if (actual.isVariant()) {
+ v = actual.variantValue();
+ } else {
+ v = actual.toVariant();
+ converted = v.isValid() || actual.isUndefined() || actual.isNull();
+ }
+ } else {
+ tid = argType.typeId();
+ v = QVariant(tid, (void *)0);
+ converted = QScriptEnginePrivate::convert(actual, tid, v.data(), engine);
+ if (engine->hasUncaughtException())
+ return;
+ }
+
+ if (!converted) {
+ if (actual.isVariant()) {
+ if (tid == -1)
+ tid = argType.typeId();
+ QVariant &vv = actual.variantValue();
+ if (vv.canConvert(QVariant::Type(tid))) {
+ v = vv;
+ converted = v.convert(QVariant::Type(tid));
+ if (converted && (vv.userType() != tid))
+ matchDistance += 10;
+ } else {
+ QByteArray vvTypeName = vv.typeName();
+ if (vvTypeName.endsWith('*')
+ && (vvTypeName.left(vvTypeName.size()-1) == argType.name())) {
+ v = QVariant(tid, *reinterpret_cast<void* *>(vv.data()));
+ converted = true;
+ matchDistance += 10;
+ }
+ }
+ } else if (actual.isNumber()) {
+ // see if it's an enum value
+ QMetaEnum m;
+ if (argType.isMetaEnum()) {
+ m = meta->enumerator(argType.enumeratorIndex());
+ } else {
+ int mi = indexOfMetaEnum(meta, argType.name());
+ if (mi != -1)
+ m = meta->enumerator(mi);
+ }
+ if (m.isValid()) {
+ int ival = actual.toInt32();
+ if (m.valueToKey(ival) != 0) {
+ qVariantSetValue(v, ival);
+ converted = true;
+ matchDistance += 10;
+ }
+ }
+ }
+ } else {
+ // determine how well the conversion matched
+ if (actual.isNumber()) {
+ switch (tid) {
+ case QMetaType::Double:
+ // perfect
+ break;
+ case QMetaType::Float:
+ matchDistance += 1;
+ break;
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ matchDistance += 2;
+ break;
+ case QMetaType::Long:
+ case QMetaType::ULong:
+ matchDistance += 3;
+ break;
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ matchDistance += 4;
+ break;
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ matchDistance += 5;
+ break;
+ case QMetaType::Char:
+ case QMetaType::UChar:
+ matchDistance += 6;
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isString()) {
+ switch (tid) {
+ case QMetaType::QString:
+ // perfect
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isBoolean()) {
+ switch (tid) {
+ case QMetaType::Bool:
+ // perfect
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isDate()) {
+ switch (tid) {
+ case QMetaType::QDateTime:
+ // perfect
+ break;
+ case QMetaType::QDate:
+ matchDistance += 1;
+ break;
+ case QMetaType::QTime:
+ matchDistance += 2;
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isRegExp()) {
+ switch (tid) {
+ case QMetaType::QRegExp:
+ // perfect
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isVariant()) {
+ if (argType.isVariant()
+ || (actual.variantValue().userType() == tid)) {
+ // perfect
+ } else {
+ matchDistance += 10;
+ }
+ } else if (actual.isArray()) {
+ switch (tid) {
+ case QMetaType::QStringList:
+ case QMetaType::QVariantList:
+ matchDistance += 5;
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isQObject()) {
+ switch (tid) {
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ // perfect
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isNull()) {
+ switch (tid) {
+ case QMetaType::VoidStar:
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ // perfect
+ break;
+ default:
+ if (!argType.name().endsWith('*'))
+ matchDistance += 10;
+ break;
+ }
+ } else {
+ matchDistance += 10;
+ }
+ }
+
+ if (converted)
+ args[i+1] = v;
+ }
+
+ if (converted) {
+ if ((context->argumentCount() == mtd.argumentCount())
+ && (matchDistance == 0)) {
+ // perfect match, use this one
+ chosenMethod = mtd;
+ chosenIndex = index;
+ break;
+ } else {
+ bool redundant = false;
+ if ((callType != QMetaMethod::Constructor)
+ && (index < meta->methodOffset())) {
+ // it is possible that a virtual method is redeclared in a subclass,
+ // in which case we want to ignore the superclass declaration
+ for (int i = 0; i < candidates.size(); ++i) {
+ const QScriptMetaArguments &other = candidates.at(i);
+ if (mtd.types() == other.method.types()) {
+ redundant = true;
+ break;
+ }
+ }
+ }
+ if (!redundant) {
+ QScriptMetaArguments metaArgs(matchDistance, index, mtd, args);
+ if (candidates.isEmpty()) {
+ candidates.append(metaArgs);
+ } else {
+ const QScriptMetaArguments &otherArgs = candidates.at(0);
+ if ((args.count() > otherArgs.args.count())
+ || ((args.count() == otherArgs.args.count())
+ && (matchDistance <= otherArgs.matchDistance))) {
+ candidates.prepend(metaArgs);
+ } else {
+ candidates.append(metaArgs);
+ }
+ }
+ }
+ }
+ } else if (mtd.fullyResolved()) {
+ conversionFailed.append(index);
+ }
+
+ if (!maybeOverloaded)
+ break;
+ }
+
+#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
+ if ((index == -1) && (lastFoundIndex != limit) && maybeOverloaded
+ && (callType != QMetaMethod::Constructor)) {
+ metaCache->setMethodLowerBound(initialIndex, lastFoundIndex);
+ }
+#endif
+
+ if ((chosenIndex == -1) && candidates.isEmpty()) {
+ context->calleeMetaIndex = initialIndex;
+#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
+ engine->notifyFunctionEntry(context);
+#endif
+ if (!conversionFailed.isEmpty()) {
+ QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
+ .arg(QLatin1String(funName));
+ for (int i = 0; i < conversionFailed.size(); ++i) {
+ if (i > 0)
+ message += QLatin1String("\n");
+ QMetaMethod mtd = metaMethod(meta, callType, conversionFailed.at(i));
+ message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
+ }
+ result = context->throwError(QScriptContext::TypeError, message);
+ } else if (!unresolved.isEmpty()) {
+ QScriptMetaArguments argsInstance = unresolved.first();
+ int unresolvedIndex = argsInstance.method.firstUnresolvedIndex();
+ Q_ASSERT(unresolvedIndex != -1);
+ QScriptMetaType unresolvedType = argsInstance.method.type(unresolvedIndex);
+ QString unresolvedTypeName = QString::fromLatin1(unresolvedType.name());
+ QString message = QString::fromLatin1("cannot call %0(): ")
+ .arg(QString::fromLatin1(funName));
+ if (unresolvedIndex > 0) {
+ message.append(QString::fromLatin1("argument %0 has unknown type `%1'").
+ arg(unresolvedIndex).arg(unresolvedTypeName));
+ } else {
+ message.append(QString::fromLatin1("unknown return type `%0'")
+ .arg(unresolvedTypeName));
+ }
+ message.append(QString::fromLatin1(" (register the type with qScriptRegisterMetaType())"));
+ result = context->throwError(QScriptContext::TypeError, message);
+ } else {
+ QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
+ .arg(QLatin1String(funName));
+ for (int i = 0; i < tooFewArgs.size(); ++i) {
+ if (i > 0)
+ message += QLatin1String("\n");
+ QMetaMethod mtd = metaMethod(meta, callType, tooFewArgs.at(i));
+ message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
+ }
+ result = context->throwError(QScriptContext::SyntaxError, message);
+ }
+ } else {
+ if (chosenIndex == -1) {
+ QScriptMetaArguments metaArgs = candidates.at(0);
+ if ((candidates.size() > 1)
+ && (metaArgs.args.count() == candidates.at(1).args.count())
+ && (metaArgs.matchDistance == candidates.at(1).matchDistance)) {
+ // ambiguous call
+ QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
+ .arg(QLatin1String(funName));
+ for (int i = 0; i < candidates.size(); ++i) {
+ if (i > 0)
+ message += QLatin1String("\n");
+ QMetaMethod mtd = metaMethod(meta, callType, candidates.at(i).index);
+ message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
+ }
+ result = context->throwError(QScriptContext::TypeError, message);
+ } else {
+ chosenMethod = metaArgs.method;
+ chosenIndex = metaArgs.index;
+ args = metaArgs.args;
+ }
+ }
+
+ if (chosenIndex != -1) {
+ // call it
+ context->calleeMetaIndex = chosenIndex;
+
+ QVarLengthArray<void*, 9> array(args.count());
+ void **params = array.data();
+ for (int i = 0; i < args.count(); ++i) {
+ const QVariant &v = args[i];
+ switch (chosenMethod.type(i).kind()) {
+ case QScriptMetaType::Variant:
+ params[i] = const_cast<QVariant*>(&v);
+ break;
+ case QScriptMetaType::MetaType:
+ case QScriptMetaType::MetaEnum:
+ case QScriptMetaType::Unresolved:
+ params[i] = const_cast<void*>(v.constData());
+ break;
+ default:
+ Q_ASSERT(0);
+ }
+ }
+
+ QScriptable *scriptable = 0;
+ if (thisQObject)
+ scriptable = scriptableFromQObject(thisQObject);
+ QScriptEngine *oldEngine = 0;
+ if (scriptable) {
+ oldEngine = QScriptablePrivate::get(scriptable)->engine;
+ QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine);
+ }
+
+#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
+ engine->notifyFunctionEntry(context);
+#endif
+
+ if (callType == QMetaMethod::Constructor) {
+ Q_ASSERT(meta != 0);
+ meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params);
+ } else {
+ Q_ASSERT(thisQObject != 0);
+ thisQObject->qt_metacall(QMetaObject::InvokeMetaMethod, chosenIndex, params);
+ }
+
+ if (scriptable)
+ QScriptablePrivate::get(scriptable)->engine = oldEngine;
+
+ if (context->state() == QScriptContext::ExceptionState) {
+ result = context->returnValue(); // propagate
+ } else {
+ QScriptMetaType retType = chosenMethod.returnType();
+ if (retType.isVariant()) {
+ result = engine->valueFromVariant(*(QVariant *)params[0]);
+ } else if (retType.typeId() != 0) {
+ result = engine->create(retType.typeId(), params[0]);
+ if (!result.isValid())
+ engine->newVariant(&result, QVariant(retType.typeId(), params[0]));
+ } else {
+ result = engine->undefinedValue();
+ }
+ }
+ }
+ }
+
+ context->m_result = result;
+#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
+ engine->notifyFunctionExit(context);
+#endif
+}
+
+
+class ExtQObjectDataIterator: public QScriptClassDataIterator
+{
+public:
+ ExtQObjectDataIterator(const QScriptValueImpl &object);
+ virtual ~ExtQObjectDataIterator();
+
+ virtual bool hasNext() const;
+ virtual void next(QScript::Member *member);
+
+ virtual bool hasPrevious() const;
+ virtual void previous(QScript::Member *member);
+
+ virtual void toFront();
+ virtual void toBack();
+
+private:
+ enum State {
+ MetaProperties,
+ DynamicProperties,
+ MetaMethods
+ };
+
+ QScriptValueImpl m_object;
+ int m_index;
+ State m_state;
+};
+
+ExtQObjectDataIterator::ExtQObjectDataIterator(const QScriptValueImpl &object)
+{
+ m_object = object;
+ toFront();
+}
+
+ExtQObjectDataIterator::~ExtQObjectDataIterator()
+{
+}
+
+bool ExtQObjectDataIterator::hasNext() const
+{
+ ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object);
+ if (!inst->value)
+ return false;
+ const QMetaObject *meta = inst->value->metaObject();
+ int i = m_index;
+
+ switch (m_state) {
+ case MetaProperties: {
+ for ( ; i < meta->propertyCount(); ++i) {
+ QMetaProperty prop = meta->property(i);
+ if (isEnumerableMetaProperty(prop, meta, i)
+ && !isObjectProperty(m_object, prop.name())) {
+ return true;
+ }
+ }
+ i = 0;
+ // fall-through
+ }
+
+ case DynamicProperties: {
+ QList<QByteArray> dpNames = inst->value->dynamicPropertyNames();
+ for ( ; i < dpNames.count(); ++i) {
+ if (!isObjectProperty(m_object, dpNames.at(i))) {
+ return true;
+ }
+ }
+ if (inst->options & QScriptEngine::SkipMethodsInEnumeration)
+ return false;
+ i = (inst->options & QScriptEngine::ExcludeSuperClassMethods)
+ ? meta->methodOffset() : 0;
+ // fall-through
+ }
+
+ case MetaMethods: {
+ for ( ; i < meta->methodCount(); ++i) {
+ QMetaMethod method = meta->method(i);
+ if (hasMethodAccess(method, i, inst->options)
+ && !isObjectProperty(m_object, method.signature())) {
+ return true;
+ }
+ }
+ }
+
+ } // switch
+
+ return false;
+}
+
+void ExtQObjectDataIterator::next(QScript::Member *member)
+{
+ QScriptEnginePrivate *eng = m_object.engine();
+ ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object);
+ if (!inst->value)
+ return;
+ const QMetaObject *meta = inst->value->metaObject();
+ int i = m_index;
+
+ switch (m_state) {
+ case MetaProperties: {
+ for ( ; i < meta->propertyCount(); ++i) {
+ QMetaProperty prop = meta->property(i);
+ if (isEnumerableMetaProperty(prop, meta, i)
+ && !isObjectProperty(m_object, prop.name())) {
+ QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(prop.name()));
+ member->native(nameId, i, flagsForMetaProperty(prop));
+ m_index = i + 1;
+ return;
+ }
+ }
+ m_state = DynamicProperties;
+ m_index = 0;
+ i = m_index;
+ // fall-through
+ }
+
+ case DynamicProperties: {
+ QList<QByteArray> dpNames = inst->value->dynamicPropertyNames();
+ for ( ; i < dpNames.count(); ++i) {
+ if (!isObjectProperty(m_object, dpNames.at(i))) {
+ QByteArray name = dpNames.at(i);
+ QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name));
+ member->native(nameId, i,
+ QScriptValue::QObjectMember
+ | DYNAPROPERTY_ID);
+ m_index = i + 1;
+ return;
+ }
+ }
+ m_state = MetaMethods;
+ m_index = (inst->options & QScriptEngine::ExcludeSuperClassMethods)
+ ? meta->methodOffset() : 0;
+ i = m_index;
+ // fall-through
+ }
+
+ case MetaMethods: {
+ for ( ; i < meta->methodCount(); ++i) {
+ QMetaMethod method = meta->method(i);
+ if (hasMethodAccess(method, i, inst->options)
+ && !isObjectProperty(m_object, method.signature())) {
+ QMetaMethod method = meta->method(i);
+ QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(method.signature()));
+ member->native(nameId, i,
+ QScriptValue::QObjectMember
+ | METHOD_ID);
+ m_index = i + 1;
+ return;
+ }
+ }
+ }
+
+ } // switch
+
+ member->invalidate();
+}
+
+bool ExtQObjectDataIterator::hasPrevious() const
+{
+ ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object);
+ if (!inst->value)
+ return false;
+ const QMetaObject *meta = inst->value->metaObject();
+ int i = m_index - 1;
+
+ switch (m_state) {
+ case MetaMethods: {
+ int limit = (inst->options & QScriptEngine::ExcludeSuperClassMethods)
+ ? meta->methodOffset() : 0;
+ for ( ; i >= limit; --i) {
+ QMetaMethod method = meta->method(i);
+ if (hasMethodAccess(method, i, inst->options)
+ && !isObjectProperty(m_object, method.signature())) {
+ return true;
+ }
+ }
+ i = inst->value->dynamicPropertyNames().count() - 1;
+ // fall-through
+ }
+
+ case DynamicProperties: {
+ QList<QByteArray> dpNames = inst->value->dynamicPropertyNames();
+ for ( ; i >= 0; --i) {
+ if (!isObjectProperty(m_object, dpNames.at(i))) {
+ return true;
+ }
+ }
+ i = meta->propertyCount() - 1;
+ // fall-through
+ }
+
+ case MetaProperties: {
+ int limit = (inst->options & QScriptEngine::ExcludeSuperClassProperties)
+ ? meta->propertyOffset() : 0;
+ for ( ; i >= limit; --i) {
+ QMetaProperty prop = meta->property(i);
+ if (isEnumerableMetaProperty(prop, meta, i)
+ && !isObjectProperty(m_object, prop.name())) {
+ return true;
+ }
+ }
+ }
+
+ } // switch
+
+ return false;
+}
+
+void ExtQObjectDataIterator::previous(QScript::Member *member)
+{
+ QScriptEnginePrivate *eng = m_object.engine();
+ ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object);
+ if (!inst->value)
+ return;
+ const QMetaObject *meta = inst->value->metaObject();
+ int i = m_index - 1;
+
+ switch (m_state) {
+ case MetaMethods: {
+ int limit = (inst->options & QScriptEngine::ExcludeSuperClassMethods)
+ ? meta->methodOffset() : 0;
+ for ( ; i >= limit; --i) {
+ QMetaMethod method = meta->method(i);
+ if (hasMethodAccess(method, i, inst->options)
+ && !isObjectProperty(m_object, method.signature())) {
+ QMetaMethod method = meta->method(i);
+ QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(method.signature()));
+ member->native(nameId, i,
+ QScriptValue::QObjectMember
+ | METHOD_ID);
+ m_index = i;
+ return;
+ }
+ }
+ m_state = DynamicProperties;
+ m_index = inst->value->dynamicPropertyNames().count() - 1;
+ i = m_index;
+ // fall-through
+ }
+
+ case DynamicProperties: {
+ QList<QByteArray> dpNames = inst->value->dynamicPropertyNames();
+ for ( ; i >= 0; --i) {
+ if (!isObjectProperty(m_object, dpNames.at(i))) {
+ QByteArray name = dpNames.at(i);
+ QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name));
+ member->native(nameId, i,
+ QScriptValue::QObjectMember
+ | DYNAPROPERTY_ID);
+ m_index = i;
+ return;
+ }
+ }
+ m_state = MetaProperties;
+ m_index = meta->propertyCount() - 1;
+ i = m_index;
+ // fall-through
+ }
+
+ case MetaProperties: {
+ int limit = (inst->options & QScriptEngine::ExcludeSuperClassProperties)
+ ? meta->propertyOffset() : 0;
+ for ( ; i >= limit; --i) {
+ QMetaProperty prop = meta->property(i);
+ if (isEnumerableMetaProperty(prop, meta, i)
+ && !isObjectProperty(m_object, prop.name())) {
+ QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(prop.name()));
+ member->native(nameId, i, flagsForMetaProperty(prop));
+ m_index = i;
+ return;
+ }
+ }
+ }
+
+ } // switch
+
+ member->invalidate();
+}
+
+void ExtQObjectDataIterator::toFront()
+{
+ ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object);
+ if (!inst->value)
+ return;
+ m_state = MetaProperties;
+ const QMetaObject *meta = inst->value->metaObject();
+ m_index = (inst->options & QScriptEngine::ExcludeSuperClassProperties)
+ ? meta->propertyOffset() : 0;
+}
+
+void ExtQObjectDataIterator::toBack()
+{
+ ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object);
+ if (!inst->value)
+ return;
+ if (inst->options & QScriptEngine::SkipMethodsInEnumeration) {
+ m_state = DynamicProperties;
+ m_index = inst->value->dynamicPropertyNames().count();
+ } else {
+ m_state = MetaMethods;
+ const QMetaObject *meta = inst->value->metaObject();
+ m_index = meta->methodCount();
+ }
+}
+
+class ExtQObjectData: public QScriptClassData
+{
+public:
+ ExtQObjectData(QScriptClassInfo *classInfo)
+ : m_classInfo(classInfo)
+ {
+ }
+
+ virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId,
+ QScript::Member *member, QScriptValueImpl *,
+ QScript::AccessMode access)
+ {
+ ExtQObject::Instance *inst = ExtQObject::Instance::get(object, m_classInfo);
+ QObject *qobject = inst->value;
+ if (! qobject) {
+ // the object was deleted. We return true so we can
+ // throw an error in get()/put()
+ member->native(nameId, /*id=*/-1, /*flags=*/0);
+ return true;
+ }
+
+ const QScriptEngine::QObjectWrapOptions &opt = inst->options;
+ const QMetaObject *meta = qobject->metaObject();
+
+ QScriptEnginePrivate *eng = object.engine();
+
+#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
+ QScriptMetaObject *metaCache = eng->cachedMetaObject(meta);
+ if (metaCache->findMember(nameId, member)) {
+ bool ignore = false;
+ switch (member->flags() & ID_MASK) {
+ case PROPERTY_ID:
+ ignore = (opt & QScriptEngine::ExcludeSuperClassProperties)
+ && (member->id() < meta->propertyOffset());
+ break;
+ case METHOD_ID:
+ ignore = ((opt & QScriptEngine::ExcludeSuperClassMethods)
+ && (member->id() < meta->methodOffset()))
+ || ((opt & QScriptEngine::ExcludeDeleteLater)
+ && (member->id() == 2));
+ break;
+ // we don't cache dynamic properties nor children,
+ // so no need to handle DYNAPROPERTY_ID and CHILD_ID
+ default:
+ break;
+ }
+ if (!ignore)
+ return true;
+ }
+#endif
+
+ QString memberName = eng->toString(nameId);
+ QByteArray name = memberName.toLatin1();
+
+ int index = -1;
+
+ if (name.contains('(')) {
+ QByteArray normalized = QMetaObject::normalizedSignature(name);
+ if (-1 != (index = meta->indexOfMethod(normalized))) {
+ QMetaMethod method = meta->method(index);
+ if (hasMethodAccess(method, index, opt)) {
+ member->native(nameId, index,
+ QScriptValue::QObjectMember
+ | METHOD_ID);
+#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
+ metaCache->registerMember(nameId, *member);
+#endif
+ if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
+ || (index >= meta->methodOffset())) {
+ return true;
+ }
+ }
+ }
+ }
+
+ index = meta->indexOfProperty(name);
+ if (index != -1) {
+ QMetaProperty prop = meta->property(index);
+ if (prop.isScriptable()) {
+ member->native(nameId, index, flagsForMetaProperty(prop));
+#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
+ metaCache->registerMember(nameId, *member);
+#endif
+ if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
+ || (index >= meta->propertyOffset())) {
+ return true;
+ }
+ }
+ }
+
+ index = qobject->dynamicPropertyNames().indexOf(name);
+ if (index != -1) {
+ member->native(nameId, index,
+ QScriptValue::QObjectMember
+ | DYNAPROPERTY_ID);
+ // not cached because it can be removed
+ return true;
+ }
+
+ const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
+ ? meta->methodOffset() : 0;
+ for (index = meta->methodCount() - 1; index >= offset; --index) {
+ QMetaMethod method = meta->method(index);
+ if (hasMethodAccess(method, index, opt)
+ && (methodName(method) == name)) {
+ member->native(nameId, index,
+ QScriptValue::QObjectMember
+ | METHOD_ID
+ | MAYBE_OVERLOADED);
+#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
+ metaCache->registerMember(nameId, *member);
+#endif
+ return true;
+ }
+ }
+
+ if (!(opt & QScriptEngine::ExcludeChildObjects)) {
+ QList<QObject*> children = qobject->children();
+ for (index = 0; index < children.count(); ++index) {
+ QObject *child = children.at(index);
+ if (child->objectName() == memberName) {
+ member->native(nameId, index,
+ QScriptValue::ReadOnly
+ | QScriptValue::Undeletable
+ | QScriptValue::SkipInEnumeration
+ | CHILD_ID);
+ // not cached because it can be removed or change name
+ return true;
+ }
+ }
+ }
+
+ if ((access & QScript::Write) && (opt & QScriptEngine::AutoCreateDynamicProperties)) {
+ member->native(nameId, -1, DYNAPROPERTY_ID);
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual bool get(const QScriptValueImpl &obj, const QScript::Member &member, QScriptValueImpl *result)
+ {
+ if (! member.isNativeProperty())
+ return false;
+
+ QScriptEnginePrivate *eng = obj.engine();
+
+ ExtQObject::Instance *inst = ExtQObject::Instance::get(obj, m_classInfo);
+ QObject *qobject = inst->value;
+ if (!qobject) {
+ QScriptContextPrivate *ctx = eng->currentContext();
+ *result = ctx->throwError(
+ QString::fromLatin1("cannot access member `%0' of deleted QObject")
+ .arg(member.nameId()->s));
+ return true;
+ }
+
+ switch (member.flags() & ID_MASK) {
+ case PROPERTY_ID: {
+ const QMetaObject *meta = qobject->metaObject();
+ const int propertyIndex = member.id();
+ QMetaProperty prop = meta->property(propertyIndex);
+ Q_ASSERT(prop.isScriptable());
+ if (GeneratePropertyFunctions) {
+ QScriptValueImpl accessor;
+#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
+ QScriptMetaObject *metaCache = eng->cachedMetaObject(meta);
+ accessor = metaCache->findPropertyAccessor(propertyIndex);
+ if (!accessor.isValid()) {
+#endif
+ accessor = eng->createFunction(new QtPropertyFunction(meta, propertyIndex));
+#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
+ metaCache->registerPropertyAccessor(propertyIndex, accessor);
+ }
+#endif
+ *result = accessor;
+ } else {
+ QVariant v = prop.read(qobject);
+ *result = eng->valueFromVariant(v);
+ }
+ } break;
+
+ case DYNAPROPERTY_ID: {
+ if (member.id() != -1) {
+ QVariant v = qobject->property(member.nameId()->s.toLatin1());
+ *result = eng->valueFromVariant(v);
+ } else {
+ *result = eng->undefinedValue();
+ }
+ } break;
+
+ case METHOD_ID: {
+ QScript::Member m;
+ bool maybeOverloaded = (member.flags() & MAYBE_OVERLOADED) != 0;
+ *result = eng->createFunction(new QtFunction(obj, member.id(),
+ maybeOverloaded));
+ // make it persist (otherwise Function.prototype.disconnect() would fail)
+ uint flags = QScriptValue::QObjectMember;
+ if (inst->options & QScriptEngine::SkipMethodsInEnumeration)
+ flags |= QScriptValue::SkipInEnumeration;
+ QScriptObject *instance = obj.objectValue();
+ if (!instance->findMember(member.nameId(), &m))
+ instance->createMember(member.nameId(), &m, flags);
+ instance->put(m, *result);
+ } break;
+
+ case CHILD_ID: {
+ QObject *child = qobject->children().at(member.id());
+ result->invalidate();
+ QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
+ eng->newQObject(result, child, QScriptEngine::QtOwnership, opt);
+ } break;
+
+ } // switch
+
+ return true;
+ }
+
+ virtual bool put(QScriptValueImpl *object, const QScript::Member &member, const QScriptValueImpl &value)
+ {
+ if (! member.isNativeProperty() || ! member.isWritable())
+ return false;
+
+ ExtQObject::Instance *inst = ExtQObject::Instance::get(*object, m_classInfo);
+ QObject *qobject = inst->value;
+ if (!qobject) {
+ QScriptEnginePrivate *eng = object->engine();
+ QScriptContextPrivate *ctx = eng->currentContext();
+ ctx->throwError(QString::fromLatin1("cannot access member `%0' of deleted QObject")
+ .arg(member.nameId()->s));
+ return true;
+ }
+
+ switch (member.flags() & ID_MASK) {
+ case CHILD_ID:
+ return false;
+
+ case METHOD_ID: {
+ QScript::Member m;
+ QScriptObject *instance = object->objectValue();
+ if (!instance->findMember(member.nameId(), &m)) {
+ instance->createMember(member.nameId(), &m,
+ /*flags=*/0);
+ }
+ instance->put(m, value);
+ return true;
+ }
+
+ case PROPERTY_ID:
+ if (GeneratePropertyFunctions) {
+ // we shouldn't get here, QScriptValueImpl::setProperty() messed up
+ Q_ASSERT_X(0, "put", "Q_PROPERTY access cannot be overridden");
+ return false;
+ } else {
+ const QMetaObject *meta = qobject->metaObject();
+ QMetaProperty prop = meta->property(member.id());
+ Q_ASSERT(prop.isScriptable());
+ QVariant v = variantFromValue(object->engine(), prop.userType(), value);
+ bool ok = prop.write(qobject, v);
+ return ok;
+ }
+
+ case DYNAPROPERTY_ID: {
+ QVariant v = value.toVariant();
+ return ! qobject->setProperty(member.nameId()->s.toLatin1(), v);
+ }
+
+ } // switch
+ return false;
+ }
+
+ virtual bool removeMember(const QScriptValueImpl &object,
+ const QScript::Member &member)
+ {
+ QObject *qobject = object.toQObject();
+ if (!qobject || !member.isNativeProperty() || !member.isDeletable())
+ return false;
+
+ if ((member.flags() & ID_MASK) == DYNAPROPERTY_ID) {
+ qobject->setProperty(member.nameId()->s.toLatin1(), QVariant());
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void mark(const QScriptValueImpl &, int)
+ {
+ }
+
+ virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object)
+ {
+ return new ExtQObjectDataIterator(object);
+ }
+
+private:
+ QScriptClassInfo *m_classInfo;
+};
+
+struct QObjectConnection
+{
+ int slotIndex;
+ QScriptValueImpl receiver;
+ QScriptValueImpl slot;
+ QScriptValueImpl senderWrapper;
+
+ QObjectConnection(int i, const QScriptValueImpl &r, const QScriptValueImpl &s,
+ const QScriptValueImpl &sw)
+ : slotIndex(i), receiver(r), slot(s), senderWrapper(sw) {}
+ QObjectConnection() : slotIndex(-1) {}
+
+ bool hasTarget(const QScriptValueImpl &r, const QScriptValueImpl &s) const
+ {
+ if (r.isObject() != receiver.isObject())
+ return false;
+ if ((r.isObject() && receiver.isObject())
+ && (r.objectValue() != receiver.objectValue())) {
+ return false;
+ }
+ return (s.objectValue() == slot.objectValue());
+ }
+
+ void mark(int generation)
+ {
+ if (senderWrapper.isValid() && !senderWrapper.isMarked(generation)) {
+ // see if the sender should be marked or not
+ ExtQObject::Instance *inst = ExtQObject::Instance::get(senderWrapper);
+ if ((inst->ownership == QScriptEngine::ScriptOwnership)
+ || ((inst->ownership == QScriptEngine::AutoOwnership)
+ && inst->value && !inst->value->parent())) {
+ senderWrapper.invalidate();
+ } else {
+ senderWrapper.mark(generation);
+ }
+ }
+ if (receiver.isValid())
+ receiver.mark(generation);
+ if (slot.isValid())
+ slot.mark(generation);
+ }
+};
+
+class QObjectConnectionManager: public QObject
+{
+public:
+ QObjectConnectionManager();
+ ~QObjectConnectionManager();
+
+ bool addSignalHandler(QObject *sender, int signalIndex,
+ const QScriptValueImpl &receiver,
+ const QScriptValueImpl &slot,
+ const QScriptValueImpl &senderWrapper = QScriptValueImpl());
+ bool removeSignalHandler(
+ QObject *sender, int signalIndex,
+ const QScriptValueImpl &receiver,
+ const QScriptValueImpl &slot);
+
+ static const QMetaObject staticMetaObject;
+ virtual const QMetaObject *metaObject() const;
+ virtual void *qt_metacast(const char *);
+ virtual int qt_metacall(QMetaObject::Call, int, void **argv);
+
+ void execute(int slotIndex, void **argv);
+
+ void mark(int generation);
+
+private:
+ int m_slotCounter;
+ QVector<QVector<QObjectConnection> > connections;
+};
+
+} // ::QScript
+
+
+
+QScript::ExtQObject::ExtQObject(QScriptEnginePrivate *eng):
+ Ecma::Core(eng, QLatin1String("QObject"), QScriptClassInfo::QObjectType)
+{
+ newQObject(&publicPrototype, new QScript::QObjectPrototype(),
+ QScriptEngine::AutoOwnership,
+ QScriptEngine::ExcludeSuperClassMethods
+ | QScriptEngine::ExcludeSuperClassProperties
+ | QScriptEngine::ExcludeChildObjects);
+
+ eng->newConstructor(&ctor, this, publicPrototype);
+ addPrototypeFunction(QLatin1String("toString"), method_toString, 0);
+ addPrototypeFunction(QLatin1String("findChild"), method_findChild, 1);
+ addPrototypeFunction(QLatin1String("findChildren"), method_findChildren, 1);
+
+ classInfo()->setData(new QScript::ExtQObjectData(classInfo()));
+}
+
+QScript::ExtQObject::~ExtQObject()
+{
+}
+
+void QScript::ExtQObject::execute(QScriptContextPrivate *context)
+{
+ QScriptValueImpl tmp;
+ newQObject(&tmp, 0);
+ context->setReturnValue(tmp);
+}
+
+void QScript::ExtQObject::newQObject(QScriptValueImpl *result, QObject *value,
+ QScriptEngine::ValueOwnership ownership,
+ const QScriptEngine::QObjectWrapOptions &options)
+{
+ Instance *instance;
+ if (!result->isValid()) {
+ engine()->newObject(result, publicPrototype, classInfo());
+ instance = new Instance();
+ result->setObjectData(instance);
+ } else {
+ Q_ASSERT(result->isObject());
+ if (result->classInfo() != classInfo()) {
+ result->destroyObjectData();
+ result->setClassInfo(classInfo());
+ instance = new Instance();
+ result->setObjectData(instance);
+ } else {
+ instance = Instance::get(*result);
+ }
+ }
+ instance->value = value;
+ instance->ownership = ownership;
+ instance->options = options;
+}
+
+QScriptValueImpl QScript::ExtQObject::method_findChild(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo)
+{
+ if (Instance *instance = Instance::get(context->thisObject(), classInfo)) {
+ QObject *obj = instance->value;
+ QString name = context->argument(0).toString();
+ QObject *child = qFindChild<QObject*>(obj, name);
+ QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
+ QScriptValueImpl result;
+ eng->newQObject(&result, child, QScriptEngine::QtOwnership, opt);
+ return result;
+ }
+ return eng->undefinedValue();
+}
+
+QScriptValueImpl QScript::ExtQObject::method_findChildren(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo)
+{
+ if (Instance *instance = Instance::get(context->thisObject(), classInfo)) {
+ QObject *obj = instance->value;
+ QList<QObject*> found;
+ QScriptValueImpl arg = context->argument(0);
+#ifndef QT_NO_REGEXP
+ if (arg.isRegExp()) {
+ QRegExp re = arg.toRegExp();
+ found = qFindChildren<QObject*>(obj, re);
+ } else
+#endif
+ {
+ QString name = arg.isUndefined() ? QString() : arg.toString();
+ found = qFindChildren<QObject*>(obj, name);
+ }
+ QScriptValueImpl result = eng->newArray(found.size());
+ QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
+ for (int i = 0; i < found.size(); ++i) {
+ QScriptValueImpl value;
+ eng->newQObject(&value, found.at(i), QScriptEngine::QtOwnership, opt);
+ result.setProperty(i, value);
+ }
+ return result;
+ }
+ return eng->undefinedValue();
+}
+
+QScriptValueImpl QScript::ExtQObject::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo)
+{
+ if (Instance *instance = Instance::get(context->thisObject(), classInfo)) {
+ QObject *obj = instance->value;
+ const QMetaObject *meta = obj ? obj->metaObject() : &QObject::staticMetaObject;
+ QString name = obj ? obj->objectName() : QString::fromUtf8("unnamed");
+
+ QString str = QString::fromUtf8("%0(name = \"%1\")")
+ .arg(QLatin1String(meta->className())).arg(name);
+ return QScriptValueImpl(eng, str);
+ }
+ return eng->undefinedValue();
+}
+
+
+
+static const uint qt_meta_data_QObjectConnectionManager[] = {
+
+ // content:
+ 1, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 1, 10, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+
+ // slots: signature, parameters, type, tag, flags
+ 35, 34, 34, 34, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_QObjectConnectionManager[] = {
+ "QScript::QObjectConnectionManager\0\0execute()\0"
+};
+
+const QMetaObject QScript::QObjectConnectionManager::staticMetaObject = {
+ { &QObject::staticMetaObject, qt_meta_stringdata_QObjectConnectionManager,
+ qt_meta_data_QObjectConnectionManager, 0 }
+};
+
+const QMetaObject *QScript::QObjectConnectionManager::metaObject() const
+{
+ return &staticMetaObject;
+}
+
+void *QScript::QObjectConnectionManager::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_QObjectConnectionManager))
+ return static_cast<void*>(const_cast<QObjectConnectionManager*>(this));
+ return QObject::qt_metacast(_clname);
+}
+
+int QScript::QObjectConnectionManager::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ execute(_id, _a);
+ _id -= m_slotCounter;
+ }
+ return _id;
+}
+
+void QScript::QObjectConnectionManager::execute(int slotIndex, void **argv)
+{
+ QScriptValueImpl receiver;
+ QScriptValueImpl slot;
+ QScriptValueImpl senderWrapper;
+ int signalIndex = -1;
+ for (int i = 0; i < connections.size(); ++i) {
+ const QVector<QObjectConnection> &cs = connections.at(i);
+ for (int j = 0; j < cs.size(); ++j) {
+ const QObjectConnection &c = cs.at(j);
+ if (c.slotIndex == slotIndex) {
+ receiver = c.receiver;
+ slot = c.slot;
+ senderWrapper = c.senderWrapper;
+ signalIndex = i;
+ break;
+ }
+ }
+ }
+ Q_ASSERT(slot.isValid());
+
+ QScriptEnginePrivate *eng = slot.engine();
+
+ if (eng->isCollecting()) {
+ // we can't do a script function call during GC,
+ // so we're forced to ignore this signal
+ return;
+ }
+
+ QScriptFunction *fun = eng->convertToNativeFunction(slot);
+ if (fun == 0) {
+ // the signal handler has been GC'ed. This can only happen when
+ // a QObject is owned by the engine, the engine is destroyed, and
+ // there is a script function connected to the destroyed() signal
+ Q_ASSERT(signalIndex <= 1); // destroyed(QObject*)
+ return;
+ }
+
+ const QMetaObject *meta = sender()->metaObject();
+ const QMetaMethod method = meta->method(signalIndex);
+
+ QList<QByteArray> parameterTypes = method.parameterTypes();
+ int argc = parameterTypes.count();
+
+ QScriptValueImpl activation;
+ eng->newActivation(&activation);
+ QScriptObject *activation_data = activation.objectValue();
+ activation_data->m_scope = slot.scope();
+
+ int formalCount = fun->formals.count();
+ int mx = qMax(formalCount, argc);
+ activation_data->m_members.resize(mx + 1);
+ activation_data->m_values.resize(mx + 1);
+ for (int i = 0; i < mx; ++i) {
+ QScriptNameIdImpl *nameId;
+ if (i < formalCount)
+ nameId = fun->formals.at(i);
+ else
+ nameId = 0;
+ activation_data->m_members[i].object(nameId, i,
+ QScriptValue::Undeletable
+ | QScriptValue::SkipInEnumeration);
+ if (i < argc) {
+ int argType = QMetaType::type(parameterTypes.at(i));
+ activation_data->m_values[i] = eng->create(argType, argv[i + 1]);
+ } else {
+ activation_data->m_values[i] = eng->undefinedValue();
+ }
+ }
+
+ QScriptValueImpl senderObject;
+ if (senderWrapper.isQObject()) {
+ senderObject = senderWrapper;
+ } else {
+ QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
+ eng->newQObject(&senderObject, sender(), QScriptEngine::QtOwnership, opt);
+ }
+ activation_data->m_members[mx].object(eng->idTable()->id___qt_sender__, mx,
+ QScriptValue::SkipInEnumeration);
+ activation_data->m_values[mx] = senderObject;
+
+ QScriptValueImpl thisObject;
+ if (receiver.isObject())
+ thisObject = receiver;
+ else
+ thisObject = eng->globalObject();
+
+ QScriptContextPrivate *context_data = eng->pushContext();
+ context_data->m_activation = activation;
+ context_data->m_callee = slot;
+ context_data->m_thisObject = thisObject;
+ context_data->argc = argc;
+ context_data->args = const_cast<QScriptValueImpl*> (activation_data->m_values.constData());
+
+ fun->execute(context_data);
+
+ eng->popContext();
+ if (eng->hasUncaughtException())
+ eng->emitSignalHandlerException();
+}
+
+QScript::QObjectConnectionManager::QObjectConnectionManager()
+ : m_slotCounter(0)
+{
+}
+
+QScript::QObjectConnectionManager::~QObjectConnectionManager()
+{
+}
+
+void QScript::QObjectConnectionManager::mark(int generation)
+{
+ for (int i = 0; i < connections.size(); ++i) {
+ QVector<QObjectConnection> &cs = connections[i];
+ for (int j = 0; j < cs.size(); ++j)
+ cs[j].mark(generation);
+ }
+}
+
+bool QScript::QObjectConnectionManager::addSignalHandler(
+ QObject *sender, int signalIndex, const QScriptValueImpl &receiver,
+ const QScriptValueImpl &function, const QScriptValueImpl &senderWrapper)
+{
+ if (connections.size() <= signalIndex)
+ connections.resize(signalIndex+1);
+ QVector<QObjectConnection> &cs = connections[signalIndex];
+ int absSlotIndex = m_slotCounter + metaObject()->methodOffset();
+ bool ok = QMetaObject::connect(sender, signalIndex, this, absSlotIndex);
+ if (ok) {
+ cs.append(QScript::QObjectConnection(m_slotCounter++, receiver, function, senderWrapper));
+ QMetaMethod signal = sender->metaObject()->method(signalIndex);
+ QByteArray signalString;
+ signalString.append('2'); // signal code
+ signalString.append(signal.signature());
+ static_cast<QScript::QObjectNotifyCaller*>(sender)->callConnectNotify(signalString);
+ }
+ return ok;
+}
+
+bool QScript::QObjectConnectionManager::removeSignalHandler(
+ QObject *sender, int signalIndex,
+ const QScriptValueImpl &receiver,
+ const QScriptValueImpl &slot)
+{
+ if (connections.size() <= signalIndex)
+ return false;
+ QVector<QObjectConnection> &cs = connections[signalIndex];
+ for (int i = 0; i < cs.size(); ++i) {
+ const QObjectConnection &c = cs.at(i);
+ if (c.hasTarget(receiver, slot)) {
+ int absSlotIndex = c.slotIndex + metaObject()->methodOffset();
+ bool ok = QMetaObject::disconnect(sender, signalIndex, this, absSlotIndex);
+ if (ok) {
+ cs.remove(i);
+ QMetaMethod signal = sender->metaObject()->method(signalIndex);
+ QByteArray signalString;
+ signalString.append('2'); // signal code
+ signalString.append(signal.signature());
+ static_cast<QScript::QObjectNotifyCaller*>(sender)->callDisconnectNotify(signalString);
+ }
+ return ok;
+ }
+ }
+ return false;
+}
+
+
+
+QString QScript::QtPropertyFunction::functionName() const
+{
+ QMetaProperty prop = m_meta->property(m_index);
+ return QLatin1String(prop.name());
+}
+
+void QScript::QtPropertyFunction::execute(QScriptContextPrivate *context)
+{
+ context->calleeMetaIndex = m_index;
+
+ QScriptEnginePrivate *eng_p = context->engine();
+#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
+ eng_p->notifyFunctionEntry(context);
+#endif
+ QScriptValueImpl result = eng_p->undefinedValue();
+
+ QScriptValueImpl object = context->thisObject();
+ QObject *qobject = object.toQObject();
+ while ((!qobject || (qobject->metaObject() != m_meta))
+ && object.prototype().isObject()) {
+ object = object.prototype();
+ qobject = object.toQObject();
+ }
+ Q_ASSERT(qobject);
+
+ QMetaProperty prop = m_meta->property(m_index);
+ Q_ASSERT(prop.isScriptable());
+ if (context->argumentCount() == 0) {
+ // get
+ if (prop.isValid()) {
+ QScriptable *scriptable = scriptableFromQObject(qobject);
+ QScriptEngine *oldEngine = 0;
+ if (scriptable) {
+ oldEngine = QScriptablePrivate::get(scriptable)->engine;
+ QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(eng_p);
+ }
+
+ QVariant v = prop.read(qobject);
+
+ if (scriptable)
+ QScriptablePrivate::get(scriptable)->engine = oldEngine;
+
+ result = eng_p->valueFromVariant(v);
+ }
+ } else {
+ // set
+ QVariant v = variantFromValue(eng_p, prop.userType(), context->argument(0));
+
+ QScriptable *scriptable = scriptableFromQObject(qobject);
+ QScriptEngine *oldEngine = 0;
+ if (scriptable) {
+ oldEngine = QScriptablePrivate::get(scriptable)->engine;
+ QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(eng_p);
+ }
+
+ prop.write(qobject, v);
+
+ if (scriptable)
+ QScriptablePrivate::get(scriptable)->engine = oldEngine;
+
+ result = context->argument(0);
+ }
+ if (!eng_p->hasUncaughtException())
+ context->m_result = result;
+#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
+ eng_p->notifyFunctionExit(context);
+#endif
+}
+
+QString QScript::QtFunction::functionName() const
+{
+ const QMetaObject *meta = metaObject();
+ if (!meta)
+ return QString();
+ QMetaMethod method = meta->method(m_initialIndex);
+ return QLatin1String(methodName(method));
+}
+
+void QScript::QtFunction::mark(QScriptEnginePrivate *engine, int generation)
+{
+ if (m_object.isValid())
+ engine->markObject(m_object, generation);
+ QScriptFunction::mark(engine, generation);
+}
+
+void QScript::QtFunction::execute(QScriptContextPrivate *context)
+{
+ QScriptEnginePrivate *eng_p = context->engine();
+ QObject *qobj = qobject();
+ if (!qobj) {
+ context->calleeMetaIndex = m_initialIndex;
+#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
+ eng_p->notifyFunctionEntry(context);
+#endif
+ context->throwError(QLatin1String("cannot call function of deleted QObject"));
+#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
+ eng_p->notifyFunctionExit(context);
+#endif
+ return;
+ }
+
+ QScriptValueImpl result = eng_p->undefinedValue();
+
+ const QMetaObject *meta = qobj->metaObject();
+
+ QObject *thisQObject = context->thisObject().toQObject();
+ if (!thisQObject) // ### TypeError
+ thisQObject = qobj;
+
+ if (!meta->cast(thisQObject)) {
+#if 0
+ // ### find common superclass, see if initialIndex is
+ // in that class (or a superclass of that class),
+ // then it's still safe to execute it
+ funName = methodName(meta->method(m_initialIndex));
+ context->throwError(
+ QString::fromUtf8("cannot execute %0: %1 does not inherit %2")
+ .arg(QLatin1String(funName))
+ .arg(QLatin1String(thisQObject->metaObject()->className()))
+ .arg(QLatin1String(meta->className())));
+ return;
+#endif
+ // invoking a function in the prototype
+ thisQObject = qobj;
+ }
+
+ callQtMethod(context, QMetaMethod::Method, thisQObject,
+ meta, m_initialIndex, m_maybeOverloaded);
+}
+
+int QScript::QtFunction::mostGeneralMethod(QMetaMethod *out) const
+{
+ const QMetaObject *meta = metaObject();
+ if (!meta)
+ return -1;
+ int index = m_initialIndex;
+ QMetaMethod method = meta->method(index);
+ if (maybeOverloaded() && (method.attributes() & QMetaMethod::Cloned)) {
+ // find the most general method
+ do {
+ method = meta->method(--index);
+ } while (method.attributes() & QMetaMethod::Cloned);
+ }
+ if (out)
+ *out = method;
+ return index;
+}
+
+QList<int> QScript::QtFunction::overloadedIndexes() const
+{
+ if (!maybeOverloaded())
+ return QList<int>();
+ QList<int> result;
+ QString name = functionName();
+ const QMetaObject *meta = metaObject();
+ for (int index = mostGeneralMethod() - 1; index >= 0; --index) {
+ QString otherName = QString::fromLatin1(methodName(meta->method(index)));
+ if (otherName == name)
+ result.append(index);
+ }
+ return result;
+}
+
+/////////////////////////////////////////////////////////
+
+namespace QScript
+{
+
+ExtQMetaObject::Instance *ExtQMetaObject::Instance::get(const QScriptValueImpl &object,
+ QScriptClassInfo *klass)
+{
+ if (! klass || klass == object.classInfo())
+ return static_cast<Instance*> (object.objectData());
+
+ return 0;
+}
+
+void ExtQMetaObject::Instance::execute(QScriptContextPrivate *context)
+{
+ if (ctor.isFunction()) {
+ QScriptValueImplList args;
+ for (int i = 0; i < context->argumentCount(); ++i)
+ args << context->argument(i);
+ QScriptEnginePrivate *eng = context->engine();
+ context->m_result = eng->call(ctor, context->thisObject(), args,
+ context->isCalledAsConstructor());
+ } else {
+ if (value->constructorCount() > 0) {
+ callQtMethod(context, QMetaMethod::Constructor, /*thisQObject=*/0,
+ value, value->constructorCount()-1, /*maybeOverloaded=*/true);
+ if (context->state() == QScriptContext::NormalState) {
+ ExtQObject::Instance *inst = ExtQObject::Instance::get(context->m_result);
+ Q_ASSERT(inst != 0);
+ inst->ownership = QScriptEngine::AutoOwnership;
+ context->m_result.setPrototype(prototype);
+ }
+ } else {
+ context->m_result = context->throwError(
+ QScriptContext::TypeError,
+ QString::fromUtf8("no constructor for %0")
+ .arg(QLatin1String(value->className())));
+ }
+ }
+}
+
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
+};
+
+class ExtQMetaObjectData: public QScriptClassData
+{
+public:
+ ExtQMetaObjectData(QScriptEnginePrivate *, QScriptClassInfo *classInfo);
+
+ virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId,
+ QScript::Member *member, QScriptValueImpl *base,
+ QScript::AccessMode access);
+ virtual bool get(const QScriptValueImpl &object, const QScript::Member &member,
+ QScriptValueImpl *result);
+ virtual bool put(QScriptValueImpl *object, const QScript::Member &member,
+ const QScriptValueImpl &value);
+ virtual void mark(const QScriptValueImpl &object, int generation);
+
+private:
+ QScriptClassInfo *m_classInfo;
+};
+
+ExtQMetaObjectData::ExtQMetaObjectData(QScriptEnginePrivate *,
+ QScriptClassInfo *classInfo)
+ : m_classInfo(classInfo)
+{
+}
+
+bool ExtQMetaObjectData::resolve(const QScriptValueImpl &object,
+ QScriptNameIdImpl *nameId,
+ QScript::Member *member,
+ QScriptValueImpl *base,
+ QScript::AccessMode /*access*/)
+{
+ const QMetaObject *meta = object.toQMetaObject();
+ if (!meta)
+ return false;
+
+ QScriptEnginePrivate *eng_p = object.engine();
+ if (eng_p->idTable()->id_prototype == nameId) {
+ // prototype property is a proxy to constructor's prototype property
+ member->native(nameId, /*id=*/0, QScriptValue::Undeletable);
+ return true;
+ }
+
+ QByteArray name = eng_p->toString(nameId).toLatin1();
+
+ for (int i = 0; i < meta->enumeratorCount(); ++i) {
+ QMetaEnum e = meta->enumerator(i);
+
+ for (int j = 0; j < e.keyCount(); ++j) {
+ const char *key = e.key(j);
+
+ if (! qstrcmp (key, name.constData())) {
+ member->native(nameId, e.value(j), QScriptValue::ReadOnly);
+ *base = object;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ExtQMetaObjectData::get(const QScriptValueImpl &object,
+ const QScript::Member &member,
+ QScriptValueImpl *result)
+{
+ if (! member.isNativeProperty())
+ return false;
+
+ QScriptEnginePrivate *eng_p = object.engine();
+ if (eng_p->idTable()->id_prototype == member.nameId()) {
+ ExtQMetaObject::Instance *inst = ExtQMetaObject::Instance::get(object, m_classInfo);
+ if (inst->ctor.isFunction())
+ *result = inst->ctor.property(eng_p->idTable()->id_prototype);
+ else
+ *result = inst->prototype;
+ } else {
+ *result = QScriptValueImpl(member.id());
+ }
+ return true;
+}
+
+bool ExtQMetaObjectData::put(QScriptValueImpl *object, const Member &member,
+ const QScriptValueImpl &value)
+{
+ if (! member.isNativeProperty())
+ return false;
+
+ QScriptEnginePrivate *eng_p = object->engine();
+ if (eng_p->idTable()->id_prototype == member.nameId()) {
+ ExtQMetaObject::Instance *inst = ExtQMetaObject::Instance::get(*object, m_classInfo);
+ if (inst->ctor.isFunction())
+ inst->ctor.setProperty(eng_p->idTable()->id_prototype, value);
+ else
+ inst->prototype = value;
+ }
+
+ return true;
+}
+
+void ExtQMetaObjectData::mark(const QScriptValueImpl &object, int generation)
+{
+ ExtQMetaObject::Instance *inst = ExtQMetaObject::Instance::get(object, m_classInfo);
+ if (inst->ctor.isObject() || inst->ctor.isString())
+ inst->ctor.mark(generation);
+}
+
+} // namespace QScript
+
+QScript::ExtQMetaObject::ExtQMetaObject(QScriptEnginePrivate *eng)
+ : Ecma::Core(eng, QLatin1String("QMetaObject"), QScriptClassInfo::QMetaObjectType)
+{
+ newQMetaObject(&publicPrototype, QScript::StaticQtMetaObject::get());
+
+ eng->newConstructor(&ctor, this, publicPrototype);
+ addPrototypeFunction(QLatin1String("className"), method_className, 0);
+
+ classInfo()->setData(new QScript::ExtQMetaObjectData(eng, classInfo()));
+}
+
+QScript::ExtQMetaObject::~ExtQMetaObject()
+{
+}
+
+void QScript::ExtQMetaObject::execute(QScriptContextPrivate *context)
+{
+ QScriptValueImpl tmp;
+ newQMetaObject(&tmp, 0);
+ context->setReturnValue(tmp);
+}
+
+void QScript::ExtQMetaObject::newQMetaObject(QScriptValueImpl *result, const QMetaObject *value,
+ const QScriptValueImpl &ctor)
+{
+ Instance *instance = new Instance();
+ instance->value = value;
+ if (ctor.isFunction()) {
+ instance->ctor = ctor;
+ } else {
+ instance->prototype = engine()->newObject();
+ instance->prototype.setPrototype(engine()->qobjectConstructor->publicPrototype);
+ }
+
+ engine()->newObject(result, publicPrototype, classInfo());
+ result->setObjectData(instance);
+}
+
+QScriptValueImpl QScript::ExtQMetaObject::method_className(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo)
+{
+ if (Instance *instance = Instance::get(context->thisObject(), classInfo)) {
+ return QScriptValueImpl(eng, QString::fromLatin1(instance->value->className()));
+ }
+ return eng->undefinedValue();
+}
+
+QScriptQObjectData::QScriptQObjectData()
+ : m_connectionManager(0)
+{
+}
+
+QScriptQObjectData::~QScriptQObjectData()
+{
+ if (m_connectionManager) {
+ delete m_connectionManager;
+ m_connectionManager = 0;
+ }
+}
+
+bool QScriptQObjectData::addSignalHandler(QObject *sender,
+ int signalIndex,
+ const QScriptValueImpl &receiver,
+ const QScriptValueImpl &slot,
+ const QScriptValueImpl &senderWrapper)
+{
+ if (!m_connectionManager)
+ m_connectionManager = new QScript::QObjectConnectionManager();
+ return m_connectionManager->addSignalHandler(
+ sender, signalIndex, receiver, slot, senderWrapper);
+}
+
+bool QScriptQObjectData::removeSignalHandler(QObject *sender,
+ int signalIndex,
+ const QScriptValueImpl &receiver,
+ const QScriptValueImpl &slot)
+{
+ if (!m_connectionManager)
+ return false;
+ return m_connectionManager->removeSignalHandler(
+ sender, signalIndex, receiver, slot);
+}
+
+bool QScriptQObjectData::findWrapper(QScriptEngine::ValueOwnership ownership,
+ const QScriptEngine::QObjectWrapOptions &options,
+ QScriptValueImpl *out)
+{
+ for (int i = 0; i < wrappers.size(); ++i) {
+ const QScriptQObjectWrapperInfo &info = wrappers.at(i);
+ if ((info.ownership == ownership) && (info.options == options)) {
+ *out = info.object;
+ return true;
+ }
+ }
+ return false;
+}
+
+void QScriptQObjectData::registerWrapper(const QScriptValueImpl &wrapper,
+ QScriptEngine::ValueOwnership ownership,
+ const QScriptEngine::QObjectWrapOptions &options)
+{
+ wrappers.append(QScriptQObjectWrapperInfo(wrapper, ownership, options));
+}
+
+void QScriptQObjectData::mark(int generation)
+{
+ if (m_connectionManager)
+ m_connectionManager->mark(generation);
+
+ {
+ QList<QScriptQObjectWrapperInfo>::iterator it;
+ for (it = wrappers.begin(); it != wrappers.end(); ) {
+ const QScriptQObjectWrapperInfo &info = *it;
+ if (info.object.isMarked(generation)) {
+ ++it;
+ } else {
+ it = wrappers.erase(it);
+ }
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "qscriptextqobject.moc"
+
+#endif // QT_NO_SCRIPT