kjsembed
slotproxy.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2005, 2006 Ian Reinhart Geiser <geiseri@kde.org> 00003 Copyright (C) 2005, 2006 Matt Broadstone <mbroadst@gmail.com> 00004 Copyright (C) 2005, 2006 Richard J. Moore <rich@kde.org> 00005 Copyright (C) 2005, 2006 Erik L. Bunce <kde@bunce.us> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 #include "slotproxy.h" 00023 00024 #include <QtCore/QMetaEnum> 00025 #include <QtCore/QMetaType> 00026 #include <QtCore/QDebug> 00027 #include <QtGui/QWidget> 00028 00029 #include <kjs/interpreter.h> 00030 00031 #include "variant_binding.h" 00032 #include "qobject_binding.h" 00033 00034 //#define DEBUG_SLOTPROXY 1 00035 00036 using namespace KJSEmbed; 00037 00038 SlotProxy::SlotProxy(KJS::JSObject *obj, KJS::Interpreter *interpreter, QObject *parent, const QByteArray &signature) 00039 : QObject(parent), m_interpreter(interpreter), m_object(obj) 00040 { 00041 m_signature = QMetaObject::normalizedSignature( signature ); 00042 uint signatureSize = m_signature.size() + 1; 00043 00044 // content: 00045 m_data[0] = 1; // revision 00046 m_data[1] = 0; // classname 00047 m_data[2] = 0; // classinfo 00048 m_data[3] = 0; // classinfo 00049 m_data[4] = 1; // methods 00050 m_data[5] = 10; // methods 00051 m_data[6] = 0; // properties 00052 m_data[7] = 0; // properties 00053 m_data[8] = 0; // enums/sets 00054 m_data[9] = 0; // enums/sets 00055 // slots: 00056 m_data[10] = 10; //signature start 00057 m_data[11] = 10 + signatureSize; //parameters start 00058 m_data[12] = 10 + signatureSize; //type start 00059 m_data[13] = 10 + signatureSize; //tag start 00060 m_data[14] = 0x0a;//flags 00061 m_data[15] = 0; // eod 00062 00063 m_stringData = QByteArray("SlotProxy\0", 10); 00064 m_stringData += m_signature; 00065 m_stringData += QByteArray("\0\0", 2); 00066 00067 staticMetaObject.d.superdata = &QObject::staticMetaObject; 00068 staticMetaObject.d.stringdata = m_stringData.data(); 00069 staticMetaObject.d.data = m_data; 00070 staticMetaObject.d.extradata = 0; 00071 #ifdef DEBUG_SLOTPROXY 00072 qDebug() << "SlotProxy() obj=" << this << " m_signature=" << m_signature; 00073 #endif 00074 } 00075 00076 SlotProxy::~SlotProxy() 00077 { 00078 #ifdef DEBUG_SLOTPROXY 00079 qDebug() << "??????SlotProxy::~SlotProxy() obj=" << this <<" m_signature=" << m_signature; 00080 #endif 00081 } 00082 00083 const QMetaObject *SlotProxy::metaObject() const 00084 { 00085 return &staticMetaObject; 00086 } 00087 00088 void *SlotProxy::qt_metacast(const char *_clname) 00089 { 00090 if (!_clname) return 0; 00091 if (!strcmp(_clname, m_stringData)) 00092 return static_cast<void*>(const_cast<SlotProxy*>(this)); 00093 return QObject::qt_metacast(_clname); 00094 } 00095 00096 KJS::JSValue *SlotProxy::callMethod( const QByteArray & methodName, void **_a ) 00097 { 00098 #ifdef DEBUG_SLOTPROXY 00099 qDebug() << "SlotProxy::callMethod(" << methodName << ",_a) obj=" << this; 00100 #endif 00101 KJS::ExecState *exec = m_interpreter->globalExec(); 00102 exec->clearException(); 00103 00104 // Crash 00105 // KJS::Interpreter::globalExec()->context().thisValue() 00106 KJS::List args = convertArguments(exec, _a); 00107 KJS::Identifier id = KJS::Identifier( KJS::UString(methodName.data())); 00108 KJS::JSObject *fun = m_object->get(exec, id )->toObject( exec ); 00109 KJS::JSValue *retValue; 00110 if ( !fun->implementsCall() ) 00111 { 00112 #ifdef DEBUG_SLOTPROXY 00113 qDebug() << "SlotProxy::callMethod got bad handler"; 00114 #endif 00115 QString msg = i18n( "Bad slot handler: Object %1 Identifier %2 Method %3 Signature: %4.", 00116 m_object->className().ascii(), 00117 id.ascii(), 00118 methodName.data(), 00119 QString(m_signature)); 00120 00121 retValue = throwError(exec, KJS::TypeError, msg); 00122 } 00123 else 00124 retValue = fun->call(exec, m_object, args); 00125 00126 if( exec->hadException() ) 00127 { 00128 #ifdef DEBUG_SLOTPROXY 00129 qDebug() << "SlotProxy::callMethod had exception"; 00130 #endif 00131 if (m_interpreter->shouldPrintExceptions()) 00132 { 00133 KJS::JSLock lock; 00134 KJS::JSObject* exceptObj = exec->exception()->toObject(exec);//retValue->toObject(exec); 00135 QString message = toQString(exceptObj->toString(exec)); 00136 QString sourceURL = toQString(exceptObj->get(exec, "sourceURL")->toString(exec)); 00137 int sourceId = exceptObj->get(exec, "sourceId")->toUInt32(exec); 00138 // would include the line number, but it's always last line of file 00139 int line = exceptObj->get(exec, "line")->toUInt32(exec); 00140 (*KJSEmbed::conerr()) << i18n("Exception calling '%1' slot from %2:%3:%4", QString(methodName), !sourceURL.isEmpty() ? sourceURL : QString::number(sourceId), line, message) << endl; 00141 } 00142 00143 // clear it so it doesn't stop other things 00144 exec->clearException(); 00145 00146 return KJS::jsNull(); 00147 } 00148 else 00149 { 00150 if( retValue->type() == 1 || retValue->type() == 0) 00151 { 00152 return KJS::jsNull(); 00153 } 00154 } 00155 return retValue; 00156 } 00157 00158 KJS::List SlotProxy::convertArguments(KJS::ExecState *exec, void **_a ) 00159 { 00160 KJS::List args; 00161 int offset = metaObject()->indexOfMethod(m_signature); 00162 QMetaMethod method = metaObject()->method(offset); 00163 QList<QByteArray> params = method.parameterTypes(); 00164 int idx = 1; 00165 #ifdef DEBUG_SLOTPROXY 00166 qDebug() << "SlotProxy::convertArguments(): obj=" << this << " m_signature=" << m_signature << " offset=" << offset << " params=" << params ; 00167 #endif 00168 foreach( const QByteArray ¶m, params ) 00169 { 00170 #ifdef DEBUG_SLOTPROXY 00171 int type = QMetaType::type( param.constData() ); 00172 qDebug("\tGot a %d - %s - _a[%d] = %p", type, param.data(), idx, _a[idx]); 00173 qDebug("\t QMetaType::type()=%d", QMetaType::type(QByteArray("Pinya::") + param.constData())); 00174 #endif 00175 int tp = QVariant::nameToType(param.constData()); 00176 switch(tp) 00177 { 00178 case QVariant::Int: 00179 args.append(KJS::jsNumber(*(int*)_a[idx])); 00180 break; 00181 case QVariant::UInt: 00182 args.append(KJS::jsNumber(*(uint*)_a[idx])); 00183 break; 00184 case QVariant::LongLong: 00185 args.append(KJS::jsNumber(*(qlonglong*)_a[idx])); 00186 break; 00187 case QVariant::ULongLong: 00188 args.append(KJS::jsNumber(*(qulonglong*)_a[idx])); 00189 break; 00190 case QVariant::Double: 00191 args.append(KJS::jsNumber(*(double*)_a[idx])); 00192 break; 00193 case QVariant::Bool: 00194 args.append(KJS::jsBoolean(*(bool*)_a[idx])); 00195 break; 00196 case QVariant::String: 00197 args.append(KJS::jsString((*reinterpret_cast<QString(*)>(_a[idx])))); 00198 break; 00199 case QVariant::UserType: 00200 { 00201 KJS::JSObject* returnValue; 00202 KJS::JSObject* parent = exec->dynamicInterpreter()->globalObject(); 00203 QByteArray typeName = param.constData(); 00204 bool isPtr = typeName.contains("*"); 00205 if (isPtr) 00206 typeName.replace("*", ""); //krazy:exclude=doublequote_chars 00207 #ifdef DEBUG_SLOTPROXY 00208 qDebug() << "\tQVariant::UserType: typeName=" << typeName << " param=" << param.constData() << " isPtr" << isPtr; 00209 #endif 00210 if ( parent->hasProperty( exec, KJS::Identifier(toUString(typeName))) ) 00211 { 00212 QObject* qObj; 00213 if (isPtr && 00214 ((qObj = *reinterpret_cast<QObject**>(_a[idx])) != 0)) 00215 { 00216 #ifdef DEBUG_SLOTPROXY 00217 qDebug() << "qObj=" << qObj; 00218 #endif 00219 Pointer<QObject> pov(*reinterpret_cast<QObject*(*)>(_a[idx])); 00220 returnValue = StaticConstructor::bind(exec, typeName, pov); 00221 if ( returnValue ) 00222 { 00223 args.append(returnValue); 00224 break; 00225 } 00226 else 00227 { 00228 #ifdef DEBUG_SLOTPROXY 00229 qDebug("\t\tNo binding retrieved"); 00230 #endif 00231 returnValue = StaticConstructor::construct( exec, parent, toUString(typeName) ); 00232 if( returnValue ) 00233 { 00234 if(QObjectBinding *objImp = KJSEmbed::extractBindingImp<QObjectBinding>(exec, returnValue)) 00235 { 00236 #ifdef DEBUG_SLOTPROXY 00237 qDebug() << "\t\t\tFound QObjectBinding"; 00238 #endif 00239 objImp->setOwnership( KJSEmbed::ObjectBinding::JSOwned ); 00240 objImp->setObject(qObj); 00241 if (qObj->parent() != 0) 00242 objImp->setOwnership(KJSEmbed::ObjectBinding::QObjOwned); 00243 else 00244 objImp->setOwnership(KJSEmbed::ObjectBinding::CPPOwned); 00245 args.append(returnValue); 00246 break; 00247 } 00248 } 00249 } 00250 } 00251 } 00252 else 00253 { 00254 #ifdef DEBUG_SLOTPROXY 00255 qDebug("\t\tNo binding registered"); 00256 #endif 00257 KJS::JSObject* returnValue = 0; 00258 switch( QMetaType::type( param.constData() ) ) 00259 { 00260 case QMetaType::QObjectStar: { 00261 QObject* obj = (*reinterpret_cast< QObject*(*)>( _a[idx] )); 00262 returnValue = KJSEmbed::createQObject(exec, obj, KJSEmbed::ObjectBinding::QObjOwned); 00263 } break; 00264 case QMetaType::QWidgetStar: { 00265 QWidget* obj = (*reinterpret_cast< QWidget*(*)>( _a[idx] )); 00266 returnValue = KJSEmbed::createQObject(exec, obj, KJSEmbed::ObjectBinding::QObjOwned); 00267 } break; 00268 default: { 00269 #ifdef DEBUG_SLOTPROXY 00270 qDebug("\t\tInvalid type !"); 00271 #endif 00272 } break; 00273 } 00274 if( returnValue ) { 00275 args.append(returnValue); 00276 break; 00277 } 00278 } 00279 } 00280 case QVariant::StringList: 00281 case QVariant::List: 00282 case QVariant::Map: 00283 default: 00284 //qDebug("\t\tconverting to variant"); 00285 QVariant variant(tp, _a[idx]); 00286 args.append( KJSEmbed::convertToValue(exec,variant) ); 00287 break; 00288 } 00289 ++idx; 00290 } 00291 00292 return args; 00293 } 00294 00295 int SlotProxy::qt_metacall(QMetaObject::Call _c, int _id, void **_a) 00296 { 00297 #ifdef DEBUG_SLOTPROXY 00298 qDebug("SlotProxy::qt_metacall(_c=%d, _id=%d, _a=%p _a[0]=%p _a[1]=%p) obj=", _c, _id, _a, _a[0], _a[1], this); 00299 #endif 00300 _id = QObject::qt_metacall(_c, _id, _a); 00301 if (_id < 0) 00302 return _id; 00303 if (_c == QMetaObject::InvokeMetaMethod) 00304 { 00305 switch (_id) 00306 { 00307 case 0: { 00308 // invoke js method here 00309 QByteArray method = m_signature.left(m_signature.indexOf('(')); 00310 KJS::JSValue *result = callMethod(method, _a); 00311 m_tmpResult = convertToVariant(m_interpreter->globalExec(), result); 00312 #ifdef DEBUG_SLOTPROXY 00313 qDebug()<<"SlotProxy::qt_metacall result="<<m_tmpResult.toString(); 00314 #endif 00315 _a[0] = &(m_tmpResult); 00316 } break; 00317 } 00318 _id -= 1; 00319 } 00320 return _id; 00321 } 00322 00323 //kate: indent-spaces on; indent-width 4; replace-tabs on; indent-mode cstyle;
KDE 4.6 API Reference