1/* 2 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 3 * 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. 8 * 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. 13 * 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 17 * 18 */ 19 20#include "config.h" 21#include "Identifier.h" 22 23#include "qt_class.h" 24#include "qt_instance.h" 25#include "qt_runtime.h" 26 27#include <qmetaobject.h> 28#include <qdebug.h> 29 30namespace JSC { 31namespace Bindings { 32 33QtClass::QtClass(const QMetaObject* mo) 34 : m_metaObject(mo) 35{ 36} 37 38QtClass::~QtClass() 39{ 40} 41 42typedef HashMap<const QMetaObject*, QtClass*> ClassesByMetaObject; 43static ClassesByMetaObject* classesByMetaObject = 0; 44 45QtClass* QtClass::classForObject(QObject* o) 46{ 47 if (!classesByMetaObject) 48 classesByMetaObject = new ClassesByMetaObject; 49 50 const QMetaObject* mo = o->metaObject(); 51 QtClass* aClass = classesByMetaObject->get(mo); 52 if (!aClass) { 53 aClass = new QtClass(mo); 54 classesByMetaObject->set(mo, aClass); 55 } 56 57 return aClass; 58} 59 60const char* QtClass::name() const 61{ 62 return m_metaObject->className(); 63} 64 65// We use this to get at signals (so we can return a proper function object, 66// and not get wrapped in RuntimeMethod). Also, use this for methods, 67// so we can cache the object and return the same object for the same 68// identifier. 69JSValue QtClass::fallbackObject(ExecState* exec, Instance* inst, const Identifier& identifier) 70{ 71 QtInstance* qtinst = static_cast<QtInstance*>(inst); 72 73 QByteArray name(identifier.ascii()); 74 75 // First see if we have a cache hit 76 JSObject* val = qtinst->m_methods.value(name); 77 if (val) 78 return val; 79 80 // Nope, create an entry 81 QByteArray normal = QMetaObject::normalizedSignature(name.constData()); 82 83 // See if there is an exact match 84 int index = -1; 85 if (normal.contains('(') && (index = m_metaObject->indexOfMethod(normal)) != -1) { 86 QMetaMethod m = m_metaObject->method(index); 87 if (m.access() != QMetaMethod::Private) { 88 QtRuntimeMetaMethod* val = new (exec) QtRuntimeMetaMethod(exec, identifier, static_cast<QtInstance*>(inst), index, normal, false); 89 qtinst->m_methods.insert(name, val); 90 return val; 91 } 92 } 93 94 // Nope.. try a basename match 95 int count = m_metaObject->methodCount(); 96 for (index = count - 1; index >= 0; --index) { 97 const QMetaMethod m = m_metaObject->method(index); 98 if (m.access() == QMetaMethod::Private) 99 continue; 100 101 QByteArray signature = m.signature(); 102 signature.truncate(signature.indexOf('(')); 103 104 if (normal == signature) { 105 QtRuntimeMetaMethod* val = new (exec) QtRuntimeMetaMethod(exec, identifier, static_cast<QtInstance*>(inst), index, normal, false); 106 qtinst->m_methods.insert(name, val); 107 return val; 108 } 109 } 110 111 return jsUndefined(); 112} 113 114// This functionality is handled by the fallback case above... 115MethodList QtClass::methodsNamed(const Identifier&, Instance*) const 116{ 117 return MethodList(); 118} 119 120// ### we may end up with a different search order than QtScript by not 121// folding this code into the fallbackMethod above, but Fields propagate out 122// of the binding code 123Field* QtClass::fieldNamed(const Identifier& identifier, Instance* instance) const 124{ 125 // Check static properties first 126 QtInstance* qtinst = static_cast<QtInstance*>(instance); 127 128 QObject* obj = qtinst->getObject(); 129 UString ustring = identifier.ustring(); 130 QString objName((const QChar*)ustring.rep()->data(), ustring.size()); 131 QByteArray ba = objName.toAscii(); 132 133 // First check for a cached field 134 QtField* f = qtinst->m_fields.value(objName); 135 136 if (obj) { 137 if (f) { 138 // We only cache real metaproperties, but we do store the 139 // other types so we can delete them later 140 if (f->fieldType() == QtField::MetaProperty) 141 return f; 142 else if (f->fieldType() == QtField::DynamicProperty) { 143 if (obj->dynamicPropertyNames().indexOf(ba) >= 0) 144 return f; 145 else { 146 // Dynamic property that disappeared 147 qtinst->m_fields.remove(objName); 148 delete f; 149 } 150 } else { 151 QList<QObject*> children = obj->children(); 152 for (int index = 0; index < children.count(); ++index) { 153 QObject *child = children.at(index); 154 if (child->objectName() == objName) 155 return f; 156 } 157 158 // Didn't find it, delete it from the cache 159 qtinst->m_fields.remove(objName); 160 delete f; 161 } 162 } 163 164 int index = m_metaObject->indexOfProperty(identifier.ascii()); 165 if (index >= 0) { 166 QMetaProperty prop = m_metaObject->property(index); 167 168 if (prop.isScriptable(obj)) { 169 f = new QtField(prop); 170 qtinst->m_fields.insert(objName, f); 171 return f; 172 } 173 } 174 175 // Dynamic properties 176 index = obj->dynamicPropertyNames().indexOf(ba); 177 if (index >= 0) { 178 f = new QtField(ba); 179 qtinst->m_fields.insert(objName, f); 180 return f; 181 } 182 183 // Child objects 184 185 QList<QObject*> children = obj->children(); 186 for (index = 0; index < children.count(); ++index) { 187 QObject *child = children.at(index); 188 if (child->objectName() == objName) { 189 f = new QtField(child); 190 qtinst->m_fields.insert(objName, f); 191 return f; 192 } 193 } 194 195 // Nothing named this 196 return 0; 197 } else { 198 QByteArray ba(identifier.ascii()); 199 // For compatibility with qtscript, cached methods don't cause 200 // errors until they are accessed, so don't blindly create an error 201 // here. 202 if (qtinst->m_methods.contains(ba)) 203 return 0; 204 205 // deleted qobject, but can't throw an error from here (no exec) 206 // create a fake QtField that will throw upon access 207 if (!f) { 208 f = new QtField(ba); 209 qtinst->m_fields.insert(objName, f); 210 } 211 return f; 212 } 213} 214 215} 216} 217 218