summaryrefslogtreecommitdiffstats
path: root/qtscriptclassic/src/qscriptextqobject.cpp
diff options
context:
space:
mode:
authoraavit <qt-info@nokia.com>2010-10-06 12:57:48 +0200
committeraavit <qt-info@nokia.com>2010-10-06 12:57:48 +0200
commit5019ece540d1f9dc08157f67b55d1c4ed896ae39 (patch)
tree2983f19a546336def390f7a43fa4f8426eea8bc8 /qtscriptclassic/src/qscriptextqobject.cpp
Long live the Qt Solutions archive!
This commit adds the contents of distribution packages of the relevant subset of the Qt Solutions components, generated from the last versions in Perforce.
Diffstat (limited to 'qtscriptclassic/src/qscriptextqobject.cpp')
-rw-r--r--qtscriptclassic/src/qscriptextqobject.cpp2241
1 files changed, 2241 insertions, 0 deletions
diff --git a/qtscriptclassic/src/qscriptextqobject.cpp b/qtscriptclassic/src/qscriptextqobject.cpp
new file mode 100644
index 0000000..51c3757
--- /dev/null
+++ b/qtscriptclassic/src/qscriptextqobject.cpp
@@ -0,0 +1,2241 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of a Qt Solutions component.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+****************************************************************************/
+
+
+#include <QtCore/qglobal.h>
+
+
+#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() || actual.isString()) {
+ // 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()) {
+ if (actual.isNumber()) {
+ int ival = actual.toInt32();
+ if (m.valueToKey(ival) != 0) {
+ qVariantSetValue(v, ival);
+ converted = true;
+ matchDistance += 10;
+ }
+ } else {
+ QString sval = actual.toString();
+ int ival = m.keyToValue(sval.toLatin1());
+ if (ival != -1) {
+ 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);
+ QMetaObject::metacall(thisQObject, 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,
+ Qt::ConnectionType type);
+ 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);
+ QScriptValueImpl actual;
+ if (i < argc) {
+ void *arg = argv[i + 1];
+ QByteArray typeName = parameterTypes.at(i);
+ int argType = QMetaType::type(typeName);
+ if (!argType) {
+ if (typeName == "QVariant") {
+ actual = eng->valueFromVariant(*reinterpret_cast<QVariant*>(arg));
+ } else {
+ qWarning("QScriptEngine: Unable to handle unregistered datatype '%s' "
+ "when invoking handler of signal %s::%s",
+ typeName.constData(), meta->className(), method.signature());
+ actual = eng->undefinedValue();
+ }
+ } else {
+ actual = eng->create(argType, arg);
+ }
+ } else {
+ actual = eng->undefinedValue();
+ }
+ activation_data->m_values[i] = actual;
+ }
+
+ 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,
+ Qt::ConnectionType type)
+{
+ 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, type);
+ 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
+ QScriptValueImpl arg = context->argument(0);
+ QVariant v;
+ if (prop.isEnumType() && arg.isString()
+ && !eng_p->demarshalFunction(prop.userType())) {
+ // give QMetaProperty::write() a chance to convert from
+ // string to enum value
+ v = arg.toString();
+ } else {
+ v = variantFromValue(eng_p, prop.userType(), arg);
+ }
+
+ 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;
+ }
+
+ 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
+ | QScriptValue::Undeletable);
+ *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,
+ Qt::ConnectionType type)
+{
+ if (!m_connectionManager)
+ m_connectionManager = new QScript::QObjectConnectionManager();
+ return m_connectionManager->addSignalHandler(
+ sender, signalIndex, receiver, slot, senderWrapper, type);
+}
+
+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"
+