2 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "qt_instance.h"
24 #include "JSDOMBinding.h"
25 #include "JSDOMWindowBase.h"
26 #include "JSGlobalObject.h"
28 #include "ObjectPrototype.h"
29 #include "PropertyNameArray.h"
31 #include "qt_runtime.h"
32 #include "runtime_object.h"
33 #include "runtime/FunctionPrototype.h"
37 #include <qmetaobject.h>
38 #include <qmetatype.h>
44 typedef QMultiHash<void*, QtInstance*> QObjectInstanceMap;
45 static QObjectInstanceMap cachedInstances;
47 // Derived RuntimeObject
48 class QtRuntimeObject : public RuntimeObject {
50 typedef RuntimeObject Base;
52 static QtRuntimeObject* create(ExecState* exec, JSGlobalObject* globalObject, PassRefPtr<Instance> instance)
54 Structure* domStructure = WebCore::deprecatedGetDOMStructure<QtRuntimeObject>(exec);
55 QtRuntimeObject* object = new (allocateCell<QtRuntimeObject>(*exec->heap())) QtRuntimeObject(exec, globalObject, domStructure, instance);
56 object->finishCreation(globalObject);
60 static const ClassInfo s_info;
62 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
64 return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
68 static const unsigned StructureFlags = RuntimeObject::StructureFlags | OverridesVisitChildren;
71 QtRuntimeObject(ExecState*, JSGlobalObject*, Structure*, PassRefPtr<Instance>);
74 const ClassInfo QtRuntimeObject::s_info = { "QtRuntimeObject", &RuntimeObject::s_info, 0, 0, CREATE_METHOD_TABLE(QtRuntimeObject) };
76 QtRuntimeObject::QtRuntimeObject(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, PassRefPtr<Instance> instance)
77 : RuntimeObject(exec, globalObject, structure, instance)
82 QtInstance::QtInstance(QObject* o, PassRefPtr<RootObject> rootObject, ValueOwnership ownership)
83 : Instance(rootObject)
87 , m_ownership(ownership)
91 QtInstance::~QtInstance()
93 JSLockHolder lock(WebCore::JSDOMWindowBase::commonJSGlobalData());
95 cachedInstances.remove(m_hashkey);
97 qDeleteAll(m_methods);
100 qDeleteAll(m_fields);
104 switch (m_ownership) {
108 if (m_object.data()->parent())
111 case ScriptOwnership:
112 delete m_object.data();
118 PassRefPtr<QtInstance> QtInstance::getQtInstance(QObject* o, PassRefPtr<RootObject> rootObject, ValueOwnership ownership)
120 JSLockHolder lock(WebCore::JSDOMWindowBase::commonJSGlobalData());
122 foreach (QtInstance* instance, cachedInstances.values(o))
123 if (instance->rootObject() == rootObject) {
124 // The garbage collector removes instances, but it may happen that the wrapped
125 // QObject dies before the gc kicks in. To handle that case we have to do an additional
126 // check if to see if the instance's wrapped object is still alive. If it isn't, then
127 // we have to create a new wrapper.
128 if (!instance->getObject())
129 cachedInstances.remove(instance->hashKey());
134 RefPtr<QtInstance> ret = QtInstance::create(o, rootObject, ownership);
135 cachedInstances.insert(o, ret.get());
137 return ret.release();
140 bool QtInstance::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
142 return JSObject::getOwnPropertySlot(object, exec, propertyName, slot);
145 void QtInstance::put(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
147 JSObject::put(object, exec, propertyName, value, slot);
150 QtInstance* QtInstance::getInstance(JSObject* object)
154 if (!object->inherits(&QtRuntimeObject::s_info))
156 return static_cast<QtInstance*>(static_cast<RuntimeObject*>(object)->getInternalInstance());
159 Class* QtInstance::getClass() const
164 m_class = QtClass::classForObject(m_object.data());
169 RuntimeObject* QtInstance::newRuntimeObject(ExecState* exec)
171 JSLockHolder lock(exec);
172 qDeleteAll(m_methods);
174 return QtRuntimeObject::create(exec, exec->lexicalGlobalObject(), this);
177 void QtInstance::begin()
182 void QtInstance::end()
187 void QtInstance::getPropertyNames(ExecState* exec, PropertyNameArray& array)
189 // This is the enumerable properties, so put:
191 // dynamic properties
193 QObject* obj = getObject();
195 const QMetaObject* meta = obj->metaObject();
198 for (i = 0; i < meta->propertyCount(); i++) {
199 QMetaProperty prop = meta->property(i);
200 if (prop.isScriptable())
201 array.add(Identifier(exec, prop.name()));
204 #ifndef QT_NO_PROPERTIES
205 QList<QByteArray> dynProps = obj->dynamicPropertyNames();
206 foreach (const QByteArray& ba, dynProps)
207 array.add(Identifier(exec, ba.constData()));
210 const int methodCount = meta->methodCount();
211 for (i = 0; i < methodCount; i++) {
212 QMetaMethod method = meta->method(i);
213 if (method.access() != QMetaMethod::Private) {
214 QByteArray sig = method.methodSignature();
215 array.add(Identifier(exec, UString(sig.constData(), sig.length())));
221 JSValue QtInstance::getMethod(ExecState* exec, PropertyName propertyName)
225 MethodList methodList = m_class->methodsNamed(propertyName, this);
226 return RuntimeMethod::create(exec, exec->lexicalGlobalObject(), WebCore::deprecatedGetDOMStructure<RuntimeMethod>(exec), propertyName.publicName(), methodList);
229 JSValue QtInstance::invokeMethod(ExecState*, RuntimeMethod*)
231 // Implemented via fallbackMethod & QtRuntimeMetaMethod::callAsFunction
232 return jsUndefined();
235 JSValue QtInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
237 if (hint == PreferString)
238 return stringValue(exec);
239 if (hint == PreferNumber)
240 return numberValue(exec);
241 return valueOf(exec);
244 JSValue QtInstance::stringValue(ExecState* exec) const
246 QObject* obj = getObject();
250 // Hmm.. see if there is a toString defined
252 bool useDefault = true;
255 // Cheat and don't use the full name resolution
256 int index = obj->metaObject()->indexOfMethod("toString()");
258 QMetaMethod m = obj->metaObject()->method(index);
259 // Check to see how much we can call it
260 if (m.access() != QMetaMethod::Private
261 && m.methodType() != QMetaMethod::Signal
262 && m.parameterCount() == 0
263 && m.returnType() != QMetaType::Void) {
264 QVariant ret(m.returnType(), (void*)0);
266 qargs[0] = ret.data();
268 if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, qargs) < 0) {
269 if (ret.isValid() && ret.canConvert(QVariant::String)) {
270 buf = ret.toString().toLatin1().constData(); // ### Latin 1? Ascii?
279 const QMetaObject* meta = obj ? obj->metaObject() : &QObject::staticMetaObject;
280 QString name = obj ? obj->objectName() : QString::fromUtf8("unnamed");
281 QString str = QString::fromUtf8("%0(name = \"%1\")")
282 .arg(QLatin1String(meta->className())).arg(name);
284 buf = str.toLatin1();
286 return jsString(exec, buf.constData());
289 JSValue QtInstance::numberValue(ExecState*) const
294 JSValue QtInstance::booleanValue() const
297 return jsBoolean(getObject());
300 JSValue QtInstance::valueOf(ExecState* exec) const
302 return stringValue(exec);
306 JSValue convertQVariantToValue(ExecState*, PassRefPtr<RootObject> root, const QVariant& variant);
307 QVariant convertValueToQVariant(ExecState*, JSValue, QMetaType::Type hint, int *distance);
309 QByteArray QtField::name() const
311 if (m_type == MetaProperty)
312 return m_property.name();
313 if (m_type == ChildObject && m_childObject)
314 return m_childObject.data()->objectName().toLatin1();
315 #ifndef QT_NO_PROPERTIES
316 if (m_type == DynamicProperty)
317 return m_dynamicProperty;
319 return QByteArray(); // deleted child object
322 JSValue QtField::valueFromInstance(ExecState* exec, const Instance* inst) const
324 const QtInstance* instance = static_cast<const QtInstance*>(inst);
325 QObject* obj = instance->getObject();
329 if (m_type == MetaProperty) {
330 if (m_property.isReadable())
331 val = m_property.read(obj);
333 return jsUndefined();
334 } else if (m_type == ChildObject)
335 val = QVariant::fromValue((QObject*) m_childObject.data());
336 #ifndef QT_NO_PROPERTIES
337 else if (m_type == DynamicProperty)
338 val = obj->property(m_dynamicProperty);
340 return convertQVariantToValue(exec, inst->rootObject(), val);
342 QString msg = QString(QLatin1String("cannot access member `%1' of deleted QObject")).arg(QLatin1String(name()));
343 return throwError(exec, createError(exec, msg.toLatin1().constData()));
346 void QtField::setValueToInstance(ExecState* exec, const Instance* inst, JSValue aValue) const
348 if (m_type == ChildObject) // QtScript doesn't allow setting to a named child
351 const QtInstance* instance = static_cast<const QtInstance*>(inst);
352 QObject* obj = instance->getObject();
354 QMetaType::Type argtype = QMetaType::Void;
355 if (m_type == MetaProperty)
356 argtype = (QMetaType::Type) m_property.userType();
358 // dynamic properties just get any QVariant
359 QVariant val = convertValueToQVariant(exec, aValue, argtype, 0);
360 if (m_type == MetaProperty) {
361 if (m_property.isWritable())
362 m_property.write(obj, val);
364 #ifndef QT_NO_PROPERTIES
365 else if (m_type == DynamicProperty)
366 obj->setProperty(m_dynamicProperty.constData(), val);
369 QString msg = QString(QLatin1String("cannot access member `%1' of deleted QObject")).arg(QLatin1String(name()));
370 throwError(exec, createError(exec, msg.toLatin1().constData()));