📄 qscriptextqobject.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtScript module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.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 GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qscriptextqobject_p.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 <QtCore/QtDebug>#include <QtCore/QMetaMethod>#include <QtCore/QRegExp>#include <QtCore/QVarLengthArray>#include "qscriptextqobject_p.h"// we use bits 15..12 of property flagsenum { 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;QByteArray QScriptMetaType::name() const{ if (!m_name.isEmpty()) return m_name; else if (m_kind == Variant) return "QVariant"; return QByteArray();}namespace QScript {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; }private: const QMetaObject *m_meta; int m_index;};class QObjectPrototype : public QObject{ Q_OBJECTpublic: 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(int targetType, const QScriptValueImpl &value){ QVariant v(targetType, (void *)0); QScriptEngine *eng = value.engine(); Q_ASSERT(eng); if (QScriptEnginePrivate::get(eng)->convert(value, targetType, v.data())) 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();}ExtQObject::Instance *ExtQObject::Instance::get(const QScriptValueImpl &object, QScriptClassInfo *klass){ if (! klass || klass == object.classInfo()) return static_cast<Instance*> (object.objectData().data()); return 0;}void ExtQObject::Instance::execute(QScriptContextPrivate *context){ if (!value) { context->throwError(QLatin1String("cannot call function of deleted QObject")); return; } const QMetaObject *meta = value->metaObject(); // look for qscript_call() QByteArray qscript_call = QByteArray("qscript_call"); int index; for (index = meta->methodCount() - 1; index >= 0; --index) { if (methodName(meta->method(index)) == qscript_call) break; } if (index < 0) { context->throwError(QScriptContext::TypeError, QLatin1String("not a function")); return; } QtFunction fun(value, index, /*maybeOverloaded=*/true); fun.execute(context);}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 = QScriptEnginePrivate::get(object.engine()); QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name)); QScript::Member member; QScriptValueImpl base; return object.resolve(nameId, &member, &base, QScriptValue::ResolveLocal) && member.testFlags(QScript::Member::ObjectProperty);}static bool hasMethodAccess(const QMetaMethod &method){ return (method.access() != QMetaMethod::Private);}class ExtQObjectData: public QScriptClassData{public: ExtQObjectData(QScriptEnginePrivate *, QScriptClassInfo *classInfo) : m_classInfo(classInfo) { } virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId, QScript::Member *member, QScriptValueImpl *) { 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 = QScriptEnginePrivate::get(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()); 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)) { 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, QScriptValue::Undeletable | (!prop.isWritable() ? QScriptValue::ReadOnly : QScriptValue::PropertyFlag(0)) | (GeneratePropertyFunctions ? (QScriptValue::PropertyGetter | QScriptValue::PropertySetter) : QScriptValue::PropertyFlag(0)) | QScriptValue::QObjectMember | PROPERTY_ID);#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) && (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 (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 = QScriptEnginePrivate::get(obj.engine()); ExtQObject::Instance *inst = ExtQObject::Instance::get(obj, m_classInfo); QObject *qobject = inst->value; if (!qobject) { QScriptContextPrivate *ctx = QScriptContextPrivate::get(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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -