+++ /dev/null
-/*
- * Copyright (C) 2006 Trolltech ASA
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include "config.h"
-#include "qt_instance.h"
-
-#include "JSGlobalObject.h"
-#include "list.h"
-#include "qt_class.h"
-#include "qt_runtime.h"
-#include "PropertyNameArray.h"
-#include "runtime_object.h"
-#include "object_object.h"
-
-#include <qmetaobject.h>
-#include <qdebug.h>
-#include <qmetatype.h>
-#include <qhash.h>
-
-namespace KJS {
-namespace Bindings {
-
-// Cache QtInstances
-typedef QMultiHash<void*, QtInstance*> QObjectInstanceMap;
-static QObjectInstanceMap cachedInstances;
-
-// Cache JSObjects
-typedef QHash<QtInstance*, JSObject*> InstanceJSObjectMap;
-static InstanceJSObjectMap cachedObjects;
-
-// Derived RuntimeObject
-class QtRuntimeObjectImp : public RuntimeObjectImp {
- public:
- QtRuntimeObjectImp(Instance*);
- ~QtRuntimeObjectImp();
- virtual void invalidate();
-
- // Additions
- virtual bool implementsConstruct() const {return implementsCall();}
- virtual JSObject* construct(ExecState* exec, const List& args);
- protected:
- void removeFromCache();
-};
-
-QtRuntimeObjectImp::QtRuntimeObjectImp(Instance* instance)
- : RuntimeObjectImp(instance)
-{
-}
-
-QtRuntimeObjectImp::~QtRuntimeObjectImp()
-{
- removeFromCache();
-}
-
-void QtRuntimeObjectImp::invalidate()
-{
- removeFromCache();
- RuntimeObjectImp::invalidate();
-}
-
-void QtRuntimeObjectImp::removeFromCache()
-{
- JSLock lock;
- QtInstance* key = cachedObjects.key(this);
- if (key)
- cachedObjects.remove(key);
-}
-
-JSObject* QtRuntimeObjectImp::construct(ExecState* exec, const List& args)
-{
- // ECMA 15.2.2.1 (?)
- JSValue *val = callAsFunction(exec, this, args);
-
- if (!val || val->type() == NullType || val->type() == UndefinedType)
- return new JSObject(exec->lexicalGlobalObject()->objectPrototype());
- else
- return val->toObject(exec);
-}
-
-// QtInstance
-QtInstance::QtInstance(QObject* o, PassRefPtr<RootObject> rootObject)
- : Instance(rootObject)
- , m_class(0)
- , m_object(o)
- , m_hashkey(o)
- , m_defaultMethod(0)
- , m_defaultMethodIndex(-2)
-{
-}
-
-QtInstance::~QtInstance()
-{
- JSLock lock;
-
- cachedObjects.remove(this);
- cachedInstances.remove(m_hashkey);
-
- // clean up (unprotect from gc) the JSValues we've created
- foreach(JSValue* val, m_methods.values()) {
- gcUnprotect(val);
- }
- m_methods.clear();
-
- foreach(QtField* f, m_fields.values()) {
- delete f;
- }
- m_fields.clear();
-
- if (m_defaultMethod)
- gcUnprotect(m_defaultMethod);
-}
-
-QtInstance* QtInstance::getQtInstance(QObject* o, PassRefPtr<RootObject> rootObject)
-{
- JSLock lock;
-
- foreach(QtInstance* instance, cachedInstances.values(o)) {
- if (instance->rootObject() == rootObject)
- return instance;
- }
-
- QtInstance* ret = new QtInstance(o, rootObject);
- cachedInstances.insert(o, ret);
-
- return ret;
-}
-
-JSObject* QtInstance::getRuntimeObject(QtInstance* instance)
-{
- JSLock lock;
- JSObject* ret = cachedObjects.value(instance);
- if (!ret) {
- ret = new QtRuntimeObjectImp(instance);
- cachedObjects.insert(instance, ret);
- }
- return ret;
-}
-
-Class* QtInstance::getClass() const
-{
- if (!m_class)
- m_class = QtClass::classForObject(m_object);
- return m_class;
-}
-
-void QtInstance::begin()
-{
- // Do nothing.
-}
-
-void QtInstance::end()
-{
- // Do nothing.
-}
-
-void QtInstance::getPropertyNames(ExecState* , PropertyNameArray& array)
-{
- // This is the enumerable properties, so put:
- // properties
- // dynamic properties
- // slots
- QObject* obj = getObject();
- if (obj) {
- const QMetaObject* meta = obj->metaObject();
-
- int i;
- for (i=0; i < meta->propertyCount(); i++) {
- QMetaProperty prop = meta->property(i);
- if (prop.isScriptable()) {
- array.add(Identifier(prop.name()));
- }
- }
-
- QList<QByteArray> dynProps = obj->dynamicPropertyNames();
- foreach(QByteArray ba, dynProps) {
- array.add(Identifier(ba.constData()));
- }
-
- for (i=0; i < meta->methodCount(); i++) {
- QMetaMethod method = meta->method(i);
- if (method.access() != QMetaMethod::Private) {
- array.add(Identifier(method.signature()));
- }
- }
- }
-}
-
-JSValue* QtInstance::invokeMethod(ExecState*, const MethodList&, const List&)
-{
- // Implemented via fallbackMethod & QtRuntimeMetaMethod::callAsFunction
- return jsUndefined();
-}
-
-bool QtInstance::implementsCall() const
-{
- // See if we have qscript_call
- if (m_defaultMethodIndex == -2) {
- if (m_object) {
- const QMetaObject* meta = m_object->metaObject();
- int count = meta->methodCount();
- const QByteArray defsig("qscript_call");
- for (int index = count - 1; index >= 0; --index) {
- const QMetaMethod m = meta->method(index);
-
- QByteArray signature = m.signature();
- signature.truncate(signature.indexOf('('));
-
- if (defsig == signature) {
- m_defaultMethodIndex = index;
- break;
- }
- }
- }
-
- if (m_defaultMethodIndex == -2) // Not checked
- m_defaultMethodIndex = -1; // No qscript_call
- }
-
- // typeof object that implements call == function
- return (m_defaultMethodIndex >= 0);
-}
-
-JSValue* QtInstance::invokeDefaultMethod(ExecState* exec, const List& args)
-{
- // QtScript tries to invoke a meta method qscript_call
- if (!getObject())
- return throwError(exec, GeneralError, "cannot call function of deleted QObject");
-
- // implementsCall will update our default method cache, if possible
- if (implementsCall()) {
- if (!m_defaultMethod) {
- m_defaultMethod = new QtRuntimeMetaMethod(exec, Identifier("[[Call]]"),this, m_defaultMethodIndex, QByteArray("qscript_call"), true);
- gcProtect(m_defaultMethod);
- }
-
- return m_defaultMethod->callAsFunction(exec, 0, args); // Luckily QtRuntimeMetaMethod ignores the obj parameter
- } else
- return throwError(exec, TypeError, "not a function");
-}
-
-JSValue* QtInstance::defaultValue(JSType hint) const
-{
- if (hint == StringType)
- return stringValue();
- if (hint == NumberType)
- return numberValue();
- if (hint == BooleanType)
- return booleanValue();
- return valueOf();
-}
-
-JSValue* QtInstance::stringValue() const
-{
- // Hmm.. see if there is a toString defined
- QByteArray buf;
- bool useDefault = true;
- getClass();
- QObject* obj = getObject();
- if (m_class && obj) {
- // Cheat and don't use the full name resolution
- int index = obj->metaObject()->indexOfMethod("toString()");
- if (index >= 0) {
- QMetaMethod m = obj->metaObject()->method(index);
- // Check to see how much we can call it
- if (m.access() != QMetaMethod::Private
- && m.methodType() != QMetaMethod::Signal
- && m.parameterTypes().count() == 0) {
- const char* retsig = m.typeName();
- if (retsig && *retsig) {
- QVariant ret(QMetaType::type(retsig), (void*)0);
- void * qargs[1];
- qargs[0] = ret.data();
-
- if (obj->qt_metacall(QMetaObject::InvokeMetaMethod, index, qargs) < 0) {
- if (ret.isValid() && ret.canConvert(QVariant::String)) {
- buf = ret.toString().toLatin1().constData(); // ### Latin 1? Ascii?
- useDefault = false;
- }
- }
- }
- }
- }
- }
-
- if (useDefault) {
- 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);
-
- buf = str.toLatin1();
- }
- return jsString(buf.constData());
-}
-
-JSValue* QtInstance::numberValue() const
-{
- return jsNumber(0);
-}
-
-JSValue* QtInstance::booleanValue() const
-{
- // ECMA 9.2
- return jsBoolean(true);
-}
-
-JSValue* QtInstance::valueOf() const
-{
- return stringValue();
-}
-
-// In qt_runtime.cpp
-JSValue* convertQVariantToValue(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& variant);
-QVariant convertValueToQVariant(ExecState* exec, JSValue* value, QMetaType::Type hint, int *distance);
-
-const char* QtField::name() const
-{
- if (m_type == MetaProperty)
- return m_property.name();
- else if (m_type == ChildObject && m_childObject)
- return m_childObject->objectName().toLatin1();
- else if (m_type == DynamicProperty)
- return m_dynamicProperty.constData();
- return ""; // deleted child object
-}
-
-JSValue* QtField::valueFromInstance(ExecState* exec, const Instance* inst) const
-{
- const QtInstance* instance = static_cast<const QtInstance*>(inst);
- QObject* obj = instance->getObject();
-
- if (obj) {
- QVariant val;
- if (m_type == MetaProperty) {
- if (m_property.isReadable())
- val = m_property.read(obj);
- else
- return jsUndefined();
- } else if (m_type == ChildObject)
- val = QVariant::fromValue((QObject*) m_childObject);
- else if (m_type == DynamicProperty)
- val = obj->property(m_dynamicProperty);
-
- return convertQVariantToValue(exec, inst->rootObject(), val);
- } else {
- QString msg = QString("cannot access member `%1' of deleted QObject").arg(name());
- return throwError(exec, GeneralError, msg.toLatin1().constData());
- }
-}
-
-void QtField::setValueToInstance(ExecState* exec, const Instance* inst, JSValue* aValue) const
-{
- if (m_type == ChildObject) // QtScript doesn't allow setting to a named child
- return;
-
- const QtInstance* instance = static_cast<const QtInstance*>(inst);
- QObject* obj = instance->getObject();
- if (obj) {
- QMetaType::Type argtype = QMetaType::Void;
- if (m_type == MetaProperty)
- argtype = (QMetaType::Type) QMetaType::type(m_property.typeName());
-
- // dynamic properties just get any QVariant
- QVariant val = convertValueToQVariant(exec, aValue, argtype, 0);
- if (m_type == MetaProperty) {
- if (m_property.isWritable())
- m_property.write(obj, val);
- } else if (m_type == DynamicProperty)
- obj->setProperty(m_dynamicProperty.constData(), val);
- } else {
- QString msg = QString("cannot access member `%1' of deleted QObject").arg(name());
- throwError(exec, GeneralError, msg.toLatin1().constData());
- }
-}
-
-
-}
-}