KJsEmbed

slotproxy.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 2005, 2006 Ian Reinhart Geiser <[email protected]>
3  Copyright (C) 2005, 2006 Matt Broadstone <[email protected]>
4  Copyright (C) 2005, 2006 Richard J. Moore <[email protected]>
5  Copyright (C) 2005, 2006 Erik L. Bunce <[email protected]>
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License as published by the Free Software Foundation; either
10  version 2 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Library General Public License for more details.
16 
17  You should have received a copy of the GNU Library General Public License
18  along with this library; see the file COPYING.LIB. If not, write to
19  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  Boston, MA 02110-1301, USA.
21 */
22 #include "slotproxy.h"
23 
24 #include <QMetaEnum>
25 #include <QMetaType>
26 #include <QDebug>
27 #include <QWidget>
28 
29 #include <kjs/interpreter.h>
30 
31 #include "variant_binding.h"
32 #include "qobject_binding.h"
33 
34 //#define DEBUG_SLOTPROXY 1
35 
36 using namespace KJSEmbed;
37 
38 SlotProxy::SlotProxy(KJS::JSObject *obj, KJS::Interpreter *interpreter, QObject *parent, const QByteArray &signature)
39  : QObject(parent), m_interpreter(interpreter), m_object(obj)
40 {
41  m_signature = QMetaObject::normalizedSignature(signature.constData());
42  uint signatureSize = m_signature.size() + 1;
43 
44  // content:
45  m_data[0] = 1; // revision
46  m_data[1] = 0; // classname
47  m_data[2] = 0; // classinfo
48  m_data[3] = 0; // classinfo
49  m_data[4] = 1; // methods
50  m_data[5] = 10; // methods
51  m_data[6] = 0; // properties
52  m_data[7] = 0; // properties
53  m_data[8] = 0; // enums/sets
54  m_data[9] = 0; // enums/sets
55  // Q_SLOTS:
56  m_data[10] = 10; //signature start
57  m_data[11] = 10 + signatureSize; //parameters start
58  m_data[12] = 10 + signatureSize; //type start
59  m_data[13] = 10 + signatureSize; //tag start
60  m_data[14] = 0x0a;//flags
61  m_data[15] = 0; // eod
62 
63  m_stringData = QByteArray("SlotProxy\0", 10);
64  m_stringData += m_signature;
65  m_stringData += QByteArray("\0\0", 2);
66 
67  staticMetaObject.d.superdata = &QObject::staticMetaObject;
68  staticMetaObject.d.stringdata = m_stringData.data_ptr();
69  staticMetaObject.d.data = m_data;
70  staticMetaObject.d.extradata = nullptr;
71 #ifdef DEBUG_SLOTPROXY
72  qDebug() << "SlotProxy() obj=" << this << " m_signature=" << m_signature;
73 #endif
74 }
75 
76 SlotProxy::~SlotProxy()
77 {
78 #ifdef DEBUG_SLOTPROXY
79  qDebug() << "??????SlotProxy::~SlotProxy() obj=" << this << " m_signature=" << m_signature;
80 #endif
81 }
82 
83 const QMetaObject *SlotProxy::metaObject() const
84 {
85  return &staticMetaObject;
86 }
87 
88 void *SlotProxy::qt_metacast(const char *_clname)
89 {
90  if (!_clname) {
91  return nullptr;
92  }
93  if (!strcmp(_clname, m_stringData.constData())) {
94  return static_cast<void *>(const_cast<SlotProxy *>(this));
95  }
96  return QObject::qt_metacast(_clname);
97 }
98 
99 KJS::JSValue *SlotProxy::callMethod(const QByteArray &methodName, void **_a)
100 {
101 #ifdef DEBUG_SLOTPROXY
102  qDebug() << "SlotProxy::callMethod(" << methodName << ",_a) obj=" << this;
103 #endif
104  KJS::ExecState *exec = m_interpreter->globalExec();
105  exec->clearException();
106 
107  // Crash
108  // KJS::Interpreter::globalExec()->context().thisValue()
109  KJS::List args = convertArguments(exec, _a);
110  KJS::Identifier id = KJS::Identifier(KJS::UString(methodName.data()));
111  KJS::JSObject *fun = m_object->get(exec, id)->toObject(exec);
112  KJS::JSValue *retValue;
113  if (!fun->implementsCall()) {
114 #ifdef DEBUG_SLOTPROXY
115  qDebug() << "SlotProxy::callMethod got bad handler";
116 #endif
117  QString msg = i18n("Bad slot handler: Object %1 Identifier %2 Method %3 Signature: %4.",
118  m_object->className().ascii(),
119  id.ascii(),
120  methodName.data(),
121  QString(m_signature));
122 
123  retValue = throwError(exec, KJS::TypeError, msg);
124  } else {
125  retValue = fun->call(exec, m_object, args);
126  }
127 
128  if (exec->hadException()) {
129 #ifdef DEBUG_SLOTPROXY
130  qDebug() << "SlotProxy::callMethod had exception";
131 #endif
132  if (m_interpreter->shouldPrintExceptions()) {
133  KJS::JSLock lock;
134  KJS::JSObject *exceptObj = exec->exception()->toObject(exec);//retValue->toObject(exec);
135  QString message = toQString(exceptObj->toString(exec));
136  QString sourceURL = toQString(exceptObj->get(exec, "sourceURL")->toString(exec));
137  int sourceId = exceptObj->get(exec, "sourceId")->toUInt32(exec);
138  // would include the line number, but it's always last line of file
139  int line = exceptObj->get(exec, "line")->toUInt32(exec);
140  (*KJSEmbed::conerr()) << i18n("Exception calling '%1' slot from %2:%3:%4", QString(methodName), !sourceURL.isEmpty() ? sourceURL : QString::number(sourceId), line, message) << Qt::endl;
141  }
142 
143  // clear it so it doesn't stop other things
144  exec->clearException();
145 
146  return KJS::jsNull();
147  } else {
148  if (retValue->type() == 1 || retValue->type() == 0) {
149  return KJS::jsNull();
150  }
151  }
152  return retValue;
153 }
154 
155 KJS::List SlotProxy::convertArguments(KJS::ExecState *exec, void **_a)
156 {
157  KJS::List args;
158  int offset = metaObject()->indexOfMethod(m_signature.constData());
159  QMetaMethod method = metaObject()->method(offset);
160  QList<QByteArray> params = method.parameterTypes();
161  int idx = 1;
162 #ifdef DEBUG_SLOTPROXY
163  qDebug() << "SlotProxy::convertArguments(): obj=" << this << " m_signature=" << m_signature << " offset=" << offset << " params=" << params;
164 #endif
165  foreach (const QByteArray &param, params) {
166 #ifdef DEBUG_SLOTPROXY
167  int type = QMetaType::type(param.constData());
168  qDebug("\tGot a %d - %s - _a[%d] = %p", type, param.data(), idx, _a[idx]);
169  qDebug("\t QMetaType::type()=%d", QMetaType::type(QByteArray("Pinya::") + param.constData()));
170 #endif
171  int tp = QVariant::nameToType(param.constData());
172  switch (tp) {
173  case QVariant::Int:
174  args.append(KJS::jsNumber(*(int *)_a[idx]));
175  break;
176  case QVariant::UInt:
177  args.append(KJS::jsNumber(*(uint *)_a[idx]));
178  break;
179  case QVariant::LongLong:
180  args.append(KJS::jsNumber(*(qlonglong *)_a[idx]));
181  break;
182  case QVariant::ULongLong:
183  args.append(KJS::jsNumber(*(qulonglong *)_a[idx]));
184  break;
185  case QVariant::Double:
186  args.append(KJS::jsNumber(*(double *)_a[idx]));
187  break;
188  case QVariant::Bool:
189  args.append(KJS::jsBoolean(*(bool *)_a[idx]));
190  break;
191  case QVariant::String:
192  args.append(KJS::jsString((*reinterpret_cast<QString(*)>(_a[idx]))));
193  break;
194  case QVariant::UserType: {
195  KJS::JSObject *returnValue;
196  KJS::JSObject *parent = exec->dynamicInterpreter()->globalObject();
197  QByteArray typeName = param.constData();
198  bool isPtr = typeName.contains("*");
199  if (isPtr) {
200  typeName.replace("*", ""); //krazy:exclude=doublequote_chars
201  }
202 #ifdef DEBUG_SLOTPROXY
203  qDebug() << "\tQVariant::UserType: typeName=" << typeName << " param=" << param.constData() << " isPtr" << isPtr;
204 #endif
205  if (parent->hasProperty(exec, KJS::Identifier(toUString(typeName)))) {
206  QObject *qObj;
207  if (isPtr &&
208  ((qObj = *reinterpret_cast<QObject **>(_a[idx])) != nullptr)) {
209 #ifdef DEBUG_SLOTPROXY
210  qDebug() << "qObj=" << qObj;
211 #endif
212  Pointer<QObject> pov(*reinterpret_cast<QObject*(*)>(_a[idx]));
213  returnValue = StaticConstructor::bind(exec, typeName, pov);
214  if (returnValue) {
215  args.append(returnValue);
216  break;
217  } else {
218 #ifdef DEBUG_SLOTPROXY
219  qDebug("\t\tNo binding retrieved");
220 #endif
221  returnValue = StaticConstructor::construct(exec, parent, toUString(typeName));
222  if (returnValue) {
223  if (QObjectBinding *objImp = KJSEmbed::extractBindingImp<QObjectBinding>(exec, returnValue)) {
224 #ifdef DEBUG_SLOTPROXY
225  qDebug() << "\t\t\tFound QObjectBinding";
226 #endif
227  objImp->setOwnership(KJSEmbed::ObjectBinding::JSOwned);
228  objImp->setObject(qObj);
229  if (qObj->parent() != nullptr) {
230  objImp->setOwnership(KJSEmbed::ObjectBinding::QObjOwned);
231  } else {
232  objImp->setOwnership(KJSEmbed::ObjectBinding::CPPOwned);
233  }
234  args.append(returnValue);
235  break;
236  }
237  }
238  }
239  }
240  } else {
241 #ifdef DEBUG_SLOTPROXY
242  qDebug("\t\tNo binding registered");
243 #endif
244  KJS::JSObject *returnValue = nullptr;
245  const int metaTypeId = QMetaType::type(param.constData());
247  QObject *obj = (*reinterpret_cast< QObject*(*)>(_a[idx]));
248  returnValue = KJSEmbed::createQObject(exec, obj, KJSEmbed::ObjectBinding::QObjOwned);
249  }
250  if (returnValue) {
251  args.append(returnValue);
252  break;
253  }
254  }
255  }
257  case QVariant::List:
258  case QVariant::Map:
259  default:
260  //qDebug("\t\tconverting to variant");
261  QVariant variant(tp, _a[idx]);
262  args.append(KJSEmbed::convertToValue(exec, variant));
263  break;
264  }
265  ++idx;
266  }
267 
268  return args;
269 }
270 
271 int SlotProxy::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
272 {
273 #ifdef DEBUG_SLOTPROXY
274  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);
275 #endif
276  _id = QObject::qt_metacall(_c, _id, _a);
277  if (_id < 0) {
278  return _id;
279  }
280  if (_c == QMetaObject::InvokeMetaMethod) {
281  switch (_id) {
282  case 0: {
283  // invoke js method here
284  QByteArray method = m_signature.left(m_signature.indexOf('('));
285  KJS::JSValue *result = callMethod(method, _a);
286  m_tmpResult = convertToVariant(m_interpreter->globalExec(), result);
287 #ifdef DEBUG_SLOTPROXY
288  qDebug() << "SlotProxy::qt_metacall result=" << m_tmpResult.toString();
289 #endif
290  _a[0] = &(m_tmpResult);
291  } break;
292  }
293  _id -= 1;
294  }
295  return _id;
296 }
297 
void append(JSValue *val)
QTextStream & endl(QTextStream &stream)
QString number(int n, int base)
JSGlobalObject * globalObject() const
int type(const char *typeName)
Type type(const QSqlDatabase &db)
QVariant::Type nameToType(const char *name)
QByteArray normalizedSignature(const char *method)
bool hadException() const
QString typeName(const QJsonObject &obj)
void clearException()
QString i18n(const char *text, const TYPE &arg...)
bool isEmpty() const const
KJS::JSObject * construct(KJS::ExecState *exec, const KJS::List &args) override
Calls the callback that will in turn create a new instance of this object with the arguments passed i...
QString & replace(int position, int n, QChar after)
QMetaType::TypeFlags typeFlags(int type)
const char * constData() const const
Interpreter * dynamicInterpreter() const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
JSValue * exception() const
QList< QByteArray > parameterTypes() const const
QObject * parent() const const
QString message
char * data()
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Dec 10 2023 03:59:19 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.