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