##// END OF EJS Templates
fixed support for more than one * indirection via pointerCount, QPixmap crashed on char** constructor, which was thought to be * only...
florianlink -
r134:1fceea800edd
parent child
Show More
@@ -1,1220 +1,1220
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignalReceiver.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtStdOut.h"
49 49 #include "PythonQtCppWrapperFactory.h"
50 50 #include "PythonQtVariants.h"
51 51 #include "PythonQtStdDecorators.h"
52 52 #include "PythonQtQFileImporter.h"
53 53 #include <pydebug.h>
54 54 #include <vector>
55 55
56 56 PythonQt* PythonQt::_self = NULL;
57 57 int PythonQt::_uniqueModuleCount = 0;
58 58
59 59 void PythonQt_init_QtGuiBuiltin(PyObject*);
60 60 void PythonQt_init_QtCoreBuiltin(PyObject*);
61 61
62 62 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
63 63 {
64 64 if (!_self) {
65 65 _self = new PythonQt(flags, pythonQtModuleName);
66 66
67 67 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
68 68 qRegisterMetaType<QList<QObject*> >("QList<void*>");
69 69
70 70 PythonQtRegisterToolClassesTemplateConverter(int);
71 71 PythonQtRegisterToolClassesTemplateConverter(float);
72 72 PythonQtRegisterToolClassesTemplateConverter(double);
73 73 PythonQtRegisterToolClassesTemplateConverter(qint32);
74 74 PythonQtRegisterToolClassesTemplateConverter(quint32);
75 75 PythonQtRegisterToolClassesTemplateConverter(qint64);
76 76 PythonQtRegisterToolClassesTemplateConverter(quint64);
77 77 // TODO: which other POD types should be available for QList etc.
78 78
79 79 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
80 80
81 81 PythonQt_init_QtCoreBuiltin(NULL);
82 82 PythonQt_init_QtGuiBuiltin(NULL);
83 83
84 84 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
85 85 PythonQtRegisterToolClassesTemplateConverter(QDate);
86 86 PythonQtRegisterToolClassesTemplateConverter(QTime);
87 87 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
88 88 PythonQtRegisterToolClassesTemplateConverter(QUrl);
89 89 PythonQtRegisterToolClassesTemplateConverter(QLocale);
90 90 PythonQtRegisterToolClassesTemplateConverter(QRect);
91 91 PythonQtRegisterToolClassesTemplateConverter(QRectF);
92 92 PythonQtRegisterToolClassesTemplateConverter(QSize);
93 93 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
94 94 PythonQtRegisterToolClassesTemplateConverter(QLine);
95 95 PythonQtRegisterToolClassesTemplateConverter(QLineF);
96 96 PythonQtRegisterToolClassesTemplateConverter(QPoint);
97 97 PythonQtRegisterToolClassesTemplateConverter(QPointF);
98 98 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
99 99
100 100 PythonQtRegisterToolClassesTemplateConverter(QFont);
101 101 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
102 102 PythonQtRegisterToolClassesTemplateConverter(QBrush);
103 103 PythonQtRegisterToolClassesTemplateConverter(QColor);
104 104 PythonQtRegisterToolClassesTemplateConverter(QPalette);
105 105 PythonQtRegisterToolClassesTemplateConverter(QIcon);
106 106 PythonQtRegisterToolClassesTemplateConverter(QImage);
107 107 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
108 108 PythonQtRegisterToolClassesTemplateConverter(QRegion);
109 109 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
110 110 PythonQtRegisterToolClassesTemplateConverter(QCursor);
111 111 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
112 112 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
113 113 PythonQtRegisterToolClassesTemplateConverter(QPen);
114 114 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
115 115 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
116 116 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
117 117
118 118
119 119 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
120 120 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
121 121 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
122 122 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
123 123 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
124 124 for (unsigned int i = 0;i<16; i++) {
125 125 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
126 126 if (obj) {
127 127 PyModule_AddObject(pack, names[i], obj);
128 128 Py_INCREF(obj);
129 129 PyModule_AddObject(pack2, names[i], obj);
130 130 } else {
131 131 std::cerr << "method not found " << names[i];
132 132 }
133 133 }
134 134 }
135 135 }
136 136
137 137 void PythonQt::cleanup()
138 138 {
139 139 if (_self) {
140 140 delete _self;
141 141 _self = NULL;
142 142 }
143 143 }
144 144
145 145 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
146 146 {
147 147 _p = new PythonQtPrivate;
148 148 _p->_initFlags = flags;
149 149
150 150 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
151 151
152 152 Py_SetProgramName("PythonQt");
153 153 if (flags & IgnoreSiteModule) {
154 154 // this prevents the automatic importing of Python site files
155 155 Py_NoSiteFlag = 1;
156 156 }
157 157 Py_Initialize();
158 158
159 159 // add our own python object types for qt object slots
160 160 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
161 161 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
162 162 }
163 163 Py_INCREF(&PythonQtSlotFunction_Type);
164 164
165 165 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
166 166 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
167 167 // add our own python object types for classes
168 168 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
169 169 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
170 170 }
171 171 Py_INCREF(&PythonQtClassWrapper_Type);
172 172
173 173 // add our own python object types for CPP instances
174 174 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
175 175 PythonQt::handleError();
176 176 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
177 177 }
178 178 Py_INCREF(&PythonQtInstanceWrapper_Type);
179 179
180 180 // add our own python object types for redirection of stdout
181 181 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
182 182 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
183 183 }
184 184 Py_INCREF(&PythonQtStdOutRedirectType);
185 185
186 186 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
187 187
188 188 _p->setupSharedLibrarySuffixes();
189 189
190 190 }
191 191
192 192 PythonQt::~PythonQt() {
193 193 delete _p;
194 194 _p = NULL;
195 195 }
196 196
197 197 PythonQtPrivate::~PythonQtPrivate() {
198 198 delete _defaultImporter;
199 199 _defaultImporter = NULL;
200 200
201 201 {
202 202 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
203 203 while (i.hasNext()) {
204 204 delete i.next().value();
205 205 }
206 206 }
207 207 PythonQtConv::global_valueStorage.clear();
208 208 PythonQtConv::global_ptrStorage.clear();
209 209 PythonQtConv::global_variantStorage.clear();
210 210
211 211 PythonQtMethodInfo::cleanupCachedMethodInfos();
212 212 }
213 213
214 214 PythonQtImportFileInterface* PythonQt::importInterface()
215 215 {
216 216 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
217 217 }
218 218
219 219 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
220 220 {
221 221 if (_self->_p->_noLongerWrappedCB) {
222 222 (*_self->_p->_noLongerWrappedCB)(o);
223 223 };
224 224 }
225 225
226 226 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
227 227 {
228 228 _p->registerClass(metaobject, package, wrapperCreator, shell);
229 229 }
230 230
231 231 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
232 232 {
233 233 // we register all classes in the hierarchy
234 234 const QMetaObject* m = metaobject;
235 235 bool first = true;
236 236 while (m) {
237 237 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
238 238 if (!info->pythonQtClassWrapper()) {
239 239 info->setTypeSlots(typeSlots);
240 240 info->setupQObject(m);
241 241 createPythonQtClassWrapper(info, package, module);
242 242 if (m->superClass()) {
243 243 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
244 244 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
245 245 }
246 246 }
247 247 if (first) {
248 248 first = false;
249 249 if (wrapperCreator) {
250 250 info->setDecoratorProvider(wrapperCreator);
251 251 }
252 252 if (shell) {
253 253 info->setShellSetInstanceWrapperCB(shell);
254 254 }
255 255 }
256 256 m = m->superClass();
257 257 }
258 258 }
259 259
260 260 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
261 261 {
262 262 PyObject* pack = module?module:packageByName(package);
263 263 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
264 264 PyModule_AddObject(pack, info->className(), pyobj);
265 265 if (!module && package && strncmp(package,"Qt",2)==0) {
266 266 // since PyModule_AddObject steals the reference, we need a incref once more...
267 267 Py_INCREF(pyobj);
268 268 // put all qt objects into Qt as well
269 269 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
270 270 }
271 271 info->setPythonQtClassWrapper(pyobj);
272 272 }
273 273
274 274 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
275 275 {
276 276 if (!obj) {
277 277 Py_INCREF(Py_None);
278 278 return Py_None;
279 279 }
280 280 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
281 281 if (!wrap) {
282 282 // smuggling it in...
283 283 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
284 284 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
285 285 registerClass(obj->metaObject());
286 286 classInfo = _knownClassInfos.value(obj->metaObject()->className());
287 287 }
288 288 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
289 289 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
290 290 } else {
291 291 Py_INCREF(wrap);
292 292 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
293 293 }
294 294 return (PyObject*)wrap;
295 295 }
296 296
297 297 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
298 298 {
299 299 if (!ptr) {
300 300 Py_INCREF(Py_None);
301 301 return Py_None;
302 302 }
303 303
304 304 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
305 305 if (!wrap) {
306 306 PythonQtClassInfo* info = _knownClassInfos.value(name);
307 307 if (!info) {
308 308 // maybe it is a PyObject, which we can return directly
309 309 if (name == "PyObject") {
310 310 PyObject* p = (PyObject*)ptr;
311 311 Py_INCREF(p);
312 312 return p;
313 313 }
314 314
315 315 // we do not know the metaobject yet, but we might know it by it's name:
316 316 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
317 317 // yes, we know it, so we can convert to QObject
318 318 QObject* qptr = (QObject*)ptr;
319 319 registerClass(qptr->metaObject());
320 320 info = _knownClassInfos.value(qptr->metaObject()->className());
321 321 }
322 322 }
323 323 if (info && info->isQObject()) {
324 324 QObject* qptr = (QObject*)ptr;
325 325 // if the object is a derived object, we want to switch the class info to the one of the derived class:
326 326 if (name!=(qptr->metaObject()->className())) {
327 327 registerClass(qptr->metaObject());
328 328 info = _knownClassInfos.value(qptr->metaObject()->className());
329 329 }
330 330 wrap = createNewPythonQtInstanceWrapper(qptr, info);
331 331 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
332 332 return (PyObject*)wrap;
333 333 }
334 334
335 335 // not a known QObject, so try our wrapper factory:
336 336 QObject* wrapper = NULL;
337 337 for (int i=0; i<_cppWrapperFactories.size(); i++) {
338 338 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
339 339 if (wrapper) {
340 340 break;
341 341 }
342 342 }
343 343
344 344 if (info) {
345 345 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
346 346 ptr = info->castDownIfPossible(ptr, &info);
347 347 }
348 348
349 349 if (!info || info->pythonQtClassWrapper()==NULL) {
350 350 // still unknown, register as CPP class
351 351 registerCPPClass(name.constData());
352 352 info = _knownClassInfos.value(name);
353 353 }
354 354 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
355 355 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
356 356 info->setMetaObject(wrapper->metaObject());
357 357 }
358 358 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
359 359 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
360 360 } else {
361 361 Py_INCREF(wrap);
362 362 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
363 363 }
364 364 return (PyObject*)wrap;
365 365 }
366 366
367 367 PyObject* PythonQtPrivate::dummyTuple() {
368 368 static PyObject* dummyTuple = NULL;
369 369 if (dummyTuple==NULL) {
370 370 dummyTuple = PyTuple_New(1);
371 371 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
372 372 }
373 373 return dummyTuple;
374 374 }
375 375
376 376
377 377 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
378 378 // call the associated class type to create a new instance...
379 379 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
380 380
381 381 result->setQObject(obj);
382 382 result->_wrappedPtr = wrappedPtr;
383 383 result->_ownedByPythonQt = false;
384 384 result->_useQMetaTypeDestroy = false;
385 385
386 386 if (wrappedPtr) {
387 387 _wrappedObjects.insert(wrappedPtr, result);
388 388 } else {
389 389 _wrappedObjects.insert(obj, result);
390 390 if (obj->parent()== NULL && _wrappedCB) {
391 391 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
392 392 (*_wrappedCB)(obj);
393 393 }
394 394 }
395 395 return result;
396 396 }
397 397
398 398 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
399 399 PythonQtClassWrapper* result;
400 400
401 401 PyObject* className = PyString_FromString(info->className());
402 402
403 403 PyObject* baseClasses = PyTuple_New(1);
404 404 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
405 405
406 406 PyObject* typeDict = PyDict_New();
407 407 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
408 408 PyDict_SetItemString(typeDict, "__module__", moduleName);
409 409
410 410 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
411 411
412 412 // set the class info so that PythonQtClassWrapper_new can read it
413 413 _currentClassInfoForClassWrapperCreation = info;
414 414 // create the new type object by calling the type
415 415 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
416 416
417 417 Py_DECREF(baseClasses);
418 418 Py_DECREF(typeDict);
419 419 Py_DECREF(args);
420 420 Py_DECREF(className);
421 421
422 422 return result;
423 423 }
424 424
425 425 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
426 426 {
427 427 PyObject* args = Py_BuildValue("(i)", enumValue);
428 428 PyObject* result = PyObject_Call(enumType, args, NULL);
429 429 Py_DECREF(args);
430 430 return result;
431 431 }
432 432
433 433 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
434 434 PyObject* result;
435 435
436 436 PyObject* className = PyString_FromString(enumName);
437 437
438 438 PyObject* baseClasses = PyTuple_New(1);
439 439 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
440 440
441 441 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
442 442 PyObject* typeDict = PyDict_New();
443 443 PyDict_SetItemString(typeDict, "__module__", module);
444 444
445 445 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
446 446
447 447 // create the new int derived type object by calling the core type
448 448 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
449 449
450 450 Py_DECREF(baseClasses);
451 451 Py_DECREF(typeDict);
452 452 Py_DECREF(args);
453 453 Py_DECREF(className);
454 454
455 455 return result;
456 456 }
457 457
458 458 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
459 459 {
460 460 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
461 461 if (!r) {
462 462 r = new PythonQtSignalReceiver(obj);
463 463 _p->_signalReceivers.insert(obj, r);
464 464 }
465 465 return r;
466 466 }
467 467
468 468 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
469 469 {
470 470 bool flag = false;
471 471 PythonQtObjectPtr callable = lookupCallable(module, objectname);
472 472 if (callable) {
473 473 PythonQtSignalReceiver* r = getSignalReceiver(obj);
474 474 flag = r->addSignalHandler(signal, callable);
475 475 if (!flag) {
476 476 // signal not found
477 477 }
478 478 } else {
479 479 // callable not found
480 480 }
481 481 return flag;
482 482 }
483 483
484 484 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
485 485 {
486 486 bool flag = false;
487 487 PythonQtSignalReceiver* r = getSignalReceiver(obj);
488 488 if (r) {
489 489 flag = r->addSignalHandler(signal, receiver);
490 490 }
491 491 return flag;
492 492 }
493 493
494 494 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
495 495 {
496 496 bool flag = false;
497 497 PythonQtObjectPtr callable = lookupCallable(module, objectname);
498 498 if (callable) {
499 499 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
500 500 if (r) {
501 501 flag = r->removeSignalHandler(signal, callable);
502 502 }
503 503 } else {
504 504 // callable not found
505 505 }
506 506 return flag;
507 507 }
508 508
509 509 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
510 510 {
511 511 bool flag = false;
512 512 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
513 513 if (r) {
514 514 flag = r->removeSignalHandler(signal, receiver);
515 515 }
516 516 return flag;
517 517 }
518 518
519 519 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
520 520 {
521 521 PythonQtObjectPtr p = lookupObject(module, name);
522 522 if (p) {
523 523 if (PyCallable_Check(p)) {
524 524 return p;
525 525 }
526 526 }
527 527 PyErr_Clear();
528 528 return NULL;
529 529 }
530 530
531 531 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
532 532 {
533 533 QStringList l = name.split('.');
534 534 PythonQtObjectPtr p = module;
535 535 PythonQtObjectPtr prev;
536 536 QString s;
537 537 QByteArray b;
538 538 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
539 539 prev = p;
540 540 b = (*i).toLatin1();
541 541 if (PyDict_Check(p)) {
542 542 p = PyDict_GetItemString(p, b.data());
543 543 } else {
544 544 p.setNewRef(PyObject_GetAttrString(p, b.data()));
545 545 }
546 546 }
547 547 PyErr_Clear();
548 548 return p;
549 549 }
550 550
551 551 PythonQtObjectPtr PythonQt::getMainModule() {
552 552 //both borrowed
553 553 PythonQtObjectPtr dict = PyImport_GetModuleDict();
554 554 return PyDict_GetItemString(dict, "__main__");
555 555 }
556 556
557 557 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
558 558 QVariant result;
559 559 if (pycode) {
560 560 PyObject* dict = NULL;
561 561 if (PyModule_Check(object)) {
562 562 dict = PyModule_GetDict(object);
563 563 } else if (PyDict_Check(object)) {
564 564 dict = object;
565 565 }
566 566 PyObject* r = NULL;
567 567 if (dict) {
568 568 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
569 569 }
570 570 if (r) {
571 571 result = PythonQtConv::PyObjToQVariant(r);
572 572 Py_DECREF(r);
573 573 } else {
574 574 handleError();
575 575 }
576 576 } else {
577 577 handleError();
578 578 }
579 579 return result;
580 580 }
581 581
582 582 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
583 583 {
584 584 QVariant result;
585 585 PythonQtObjectPtr p;
586 586 PyObject* dict = NULL;
587 587 if (PyModule_Check(object)) {
588 588 dict = PyModule_GetDict(object);
589 589 } else if (PyDict_Check(object)) {
590 590 dict = object;
591 591 }
592 592 if (dict) {
593 593 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
594 594 }
595 595 if (p) {
596 596 result = PythonQtConv::PyObjToQVariant(p);
597 597 } else {
598 598 handleError();
599 599 }
600 600 return result;
601 601 }
602 602
603 603 void PythonQt::evalFile(PyObject* module, const QString& filename)
604 604 {
605 605 PythonQtObjectPtr code = parseFile(filename);
606 606 if (code) {
607 607 evalCode(module, code);
608 608 } else {
609 609 handleError();
610 610 }
611 611 }
612 612
613 613 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
614 614 {
615 615 PythonQtObjectPtr p;
616 616 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
617 617 if (!p) {
618 618 handleError();
619 619 }
620 620 return p;
621 621 }
622 622
623 623 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
624 624 {
625 625 PythonQtObjectPtr code = parseFile(filename);
626 626 PythonQtObjectPtr module = _p->createModule(name, code);
627 627 return module;
628 628 }
629 629
630 630 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
631 631 {
632 632 PyErr_Clear();
633 633 QString scriptCode = script;
634 634 if (scriptCode.isEmpty()) {
635 635 // we always need at least a linefeed
636 636 scriptCode = "\n";
637 637 }
638 638 PythonQtObjectPtr pycode;
639 639 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
640 640 PythonQtObjectPtr module = _p->createModule(name, pycode);
641 641 return module;
642 642 }
643 643
644 644 PythonQtObjectPtr PythonQt::createUniqueModule()
645 645 {
646 646 static QString pyQtStr("PythonQt_module");
647 647 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
648 648 return createModuleFromScript(moduleName);
649 649 }
650 650
651 651 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
652 652 {
653 653 if (PyModule_Check(object)) {
654 654 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
655 655 } else if (PyDict_Check(object)) {
656 656 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
657 657 } else {
658 658 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
659 659 }
660 660 }
661 661
662 662 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
663 663 {
664 664 if (PyModule_Check(object)) {
665 665 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
666 666 } else if (PyDict_Check(object)) {
667 667 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
668 668 } else {
669 669 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
670 670 }
671 671 }
672 672
673 673 void PythonQt::removeVariable(PyObject* object, const QString& name)
674 674 {
675 675 if (PyDict_Check(object)) {
676 676 PyDict_DelItemString(object, name.toLatin1().data());
677 677 } else {
678 678 PyObject_DelAttrString(object, name.toLatin1().data());
679 679 }
680 680 }
681 681
682 682 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
683 683 {
684 684 QVariant result;
685 685 PythonQtObjectPtr obj = lookupObject(object, objectname);
686 686 if (obj) {
687 687 result = PythonQtConv::PyObjToQVariant(obj);
688 688 }
689 689 return result;
690 690 }
691 691
692 692 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
693 693 {
694 694 QStringList results;
695 695
696 696 PythonQtObjectPtr object;
697 697 if (objectname.isEmpty()) {
698 698 object = module;
699 699 } else {
700 700 object = lookupObject(module, objectname);
701 701 if (!object && type == CallOverloads) {
702 702 PyObject* dict = lookupObject(module, "__builtins__");
703 703 if (dict) {
704 704 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
705 705 }
706 706 }
707 707 }
708 708
709 709 if (object) {
710 710 if (type == CallOverloads) {
711 711 if (PythonQtSlotFunction_Check(object)) {
712 712 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
713 713 PythonQtSlotInfo* info = o->m_ml;
714 714
715 715 while (info) {
716 716 results << info->fullSignature();
717 717 info = info->nextInfo();
718 718 }
719 719 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
720 720 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
721 721 PythonQtSlotInfo* info = o->classInfo()->constructors();
722 722
723 723 while (info) {
724 724 results << info->fullSignature();
725 725 info = info->nextInfo();
726 726 }
727 727 } else {
728 728 //TODO: use pydoc!
729 729 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
730 730 if (doc) {
731 731 results << PyString_AsString(doc);
732 732 Py_DECREF(doc);
733 733 }
734 734 }
735 735 } else {
736 736 PyObject* keys = NULL;
737 737 bool isDict = false;
738 738 if (PyDict_Check(object)) {
739 739 keys = PyDict_Keys(object);
740 740 isDict = true;
741 741 } else {
742 742 keys = PyObject_Dir(object);
743 743 }
744 744 if (keys) {
745 745 int count = PyList_Size(keys);
746 746 PyObject* key;
747 747 PyObject* value;
748 748 QString keystr;
749 749 for (int i = 0;i<count;i++) {
750 750 key = PyList_GetItem(keys,i);
751 751 if (isDict) {
752 752 value = PyDict_GetItem(object, key);
753 753 Py_INCREF(value);
754 754 } else {
755 755 value = PyObject_GetAttr(object, key);
756 756 }
757 757 if (!value) continue;
758 758 keystr = PyString_AsString(key);
759 759 static const QString underscoreStr("__tmp");
760 760 if (!keystr.startsWith(underscoreStr)) {
761 761 switch (type) {
762 762 case Anything:
763 763 results << keystr;
764 764 break;
765 765 case Class:
766 766 if (value->ob_type == &PyClass_Type) {
767 767 results << keystr;
768 768 }
769 769 break;
770 770 case Variable:
771 771 if (value->ob_type != &PyClass_Type
772 772 && value->ob_type != &PyCFunction_Type
773 773 && value->ob_type != &PyFunction_Type
774 774 && value->ob_type != &PyModule_Type
775 775 ) {
776 776 results << keystr;
777 777 }
778 778 break;
779 779 case Function:
780 780 if (value->ob_type == &PyFunction_Type ||
781 781 value->ob_type == &PyMethod_Type
782 782 ) {
783 783 results << keystr;
784 784 }
785 785 break;
786 786 case Module:
787 787 if (value->ob_type == &PyModule_Type) {
788 788 results << keystr;
789 789 }
790 790 break;
791 791 default:
792 792 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
793 793 }
794 794 }
795 795 Py_DECREF(value);
796 796 }
797 797 Py_DECREF(keys);
798 798 }
799 799 }
800 800 }
801 801 return results;
802 802 }
803 803
804 804 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
805 805 {
806 806 PythonQtObjectPtr callable = lookupCallable(object, name);
807 807 if (callable) {
808 808 return call(callable, args);
809 809 } else {
810 810 return QVariant();
811 811 }
812 812 }
813 813
814 814 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
815 815 {
816 816 QVariant r;
817 817 PythonQtObjectPtr result;
818 818 result.setNewRef(callAndReturnPyObject(callable, args));
819 819 if (result) {
820 820 r = PythonQtConv::PyObjToQVariant(result);
821 821 } else {
822 822 PythonQt::self()->handleError();
823 823 }
824 824 return r;
825 825 }
826 826
827 827 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
828 828 {
829 829 PyObject* result = NULL;
830 830 if (callable) {
831 831 PythonQtObjectPtr pargs;
832 832 int count = args.size();
833 833 if (count>0) {
834 834 pargs.setNewRef(PyTuple_New(count));
835 835 }
836 836 bool err = false;
837 837 // transform QVariants to Python
838 838 for (int i = 0; i < count; i++) {
839 839 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
840 840 if (arg) {
841 841 // steals reference, no unref
842 842 PyTuple_SetItem(pargs, i,arg);
843 843 } else {
844 844 err = true;
845 845 break;
846 846 }
847 847 }
848 848
849 849 if (!err) {
850 850 PyErr_Clear();
851 851 result = PyObject_CallObject(callable, pargs);
852 852 }
853 853 }
854 854 return result;
855 855 }
856 856
857 857 void PythonQt::addInstanceDecorators(QObject* o)
858 858 {
859 859 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
860 860 }
861 861
862 862 void PythonQt::addClassDecorators(QObject* o)
863 863 {
864 864 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
865 865 }
866 866
867 867 void PythonQt::addDecorators(QObject* o)
868 868 {
869 869 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
870 870 }
871 871
872 872 void PythonQt::registerQObjectClassNames(const QStringList& names)
873 873 {
874 874 _p->registerQObjectClassNames(names);
875 875 }
876 876
877 877 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
878 878 {
879 879 _p->_importInterface = importInterface;
880 880 PythonQtImport::init();
881 881 }
882 882
883 883 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
884 884 {
885 885 _p->_importIgnorePaths = paths;
886 886 }
887 887
888 888 const QStringList& PythonQt::getImporterIgnorePaths()
889 889 {
890 890 return _p->_importIgnorePaths;
891 891 }
892 892
893 893 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
894 894 {
895 895 _p->_cppWrapperFactories.append(factory);
896 896 }
897 897
898 898 //---------------------------------------------------------------------------------------------------
899 899 PythonQtPrivate::PythonQtPrivate()
900 900 {
901 901 _importInterface = NULL;
902 902 _defaultImporter = new PythonQtQFileImporter;
903 903 _noLongerWrappedCB = NULL;
904 904 _wrappedCB = NULL;
905 905 _currentClassInfoForClassWrapperCreation = NULL;
906 906 }
907 907
908 908 void PythonQtPrivate::setupSharedLibrarySuffixes()
909 909 {
910 910 _sharedLibrarySuffixes.clear();
911 911 PythonQtObjectPtr imp;
912 912 imp.setNewRef(PyImport_ImportModule("imp"));
913 913 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
914 914 QVariant result = imp.call("get_suffixes");
915 915 foreach (QVariant entry, result.toList()) {
916 916 QVariantList suffixEntry = entry.toList();
917 917 if (suffixEntry.count()==3) {
918 918 int code = suffixEntry.at(2).toInt();
919 919 if (code == cExtensionCode) {
920 920 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
921 921 }
922 922 }
923 923 }
924 924 }
925 925
926 926 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
927 927 {
928 928 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
929 929 _currentClassInfoForClassWrapperCreation = NULL;
930 930 return info;
931 931 }
932 932
933 933 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
934 934 {
935 935 o->setParent(this);
936 936 int numMethods = o->metaObject()->methodCount();
937 937 for (int i = 0; i < numMethods; i++) {
938 938 QMetaMethod m = o->metaObject()->method(i);
939 939 if ((m.methodType() == QMetaMethod::Method ||
940 940 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
941 941 if (qstrncmp(m.signature(), "new_", 4)==0) {
942 942 if ((decoTypes & ConstructorDecorator) == 0) continue;
943 943 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
944 if (info->parameters().at(0).isPointer) {
944 if (info->parameters().at(0).pointerCount == 1) {
945 945 QByteArray signature = m.signature();
946 946 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
947 947 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
948 948 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
949 949 classInfo->addConstructor(newSlot);
950 950 }
951 951 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
952 952 if ((decoTypes & DestructorDecorator) == 0) continue;
953 953 QByteArray signature = m.signature();
954 954 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
955 955 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
956 956 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
957 957 classInfo->setDestructor(newSlot);
958 958 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
959 959 if ((decoTypes & StaticDecorator) == 0) continue;
960 960 QByteArray signature = m.signature();
961 961 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
962 962 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
963 963 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
964 964 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
965 965 classInfo->addDecoratorSlot(newSlot);
966 966 } else {
967 967 if ((decoTypes & InstanceDecorator) == 0) continue;
968 968 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
969 969 if (info->parameters().count()>1) {
970 970 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
971 if (p.isPointer) {
971 if (p.pointerCount==1) {
972 972 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
973 973 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
974 974 classInfo->addDecoratorSlot(newSlot);
975 975 }
976 976 }
977 977 }
978 978 }
979 979 }
980 980 }
981 981
982 982 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
983 983 {
984 984 foreach(QString name, names) {
985 985 _knownQObjectClassNames.insert(name.toLatin1(), true);
986 986 }
987 987 }
988 988
989 989 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
990 990 {
991 991 _signalReceivers.remove(obj);
992 992 }
993 993
994 994 bool PythonQt::handleError()
995 995 {
996 996 bool flag = false;
997 997 if (PyErr_Occurred()) {
998 998
999 999 // currently we just print the error and the stderr handler parses the errors
1000 1000 PyErr_Print();
1001 1001
1002 1002 /*
1003 1003 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1004 1004 PyObject *ptype;
1005 1005 PyObject *pvalue;
1006 1006 PyObject *ptraceback;
1007 1007 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1008 1008
1009 1009 Py_XDECREF(ptype);
1010 1010 Py_XDECREF(pvalue);
1011 1011 Py_XDECREF(ptraceback);
1012 1012 */
1013 1013 PyErr_Clear();
1014 1014 flag = true;
1015 1015 }
1016 1016 return flag;
1017 1017 }
1018 1018
1019 1019 void PythonQt::addSysPath(const QString& path)
1020 1020 {
1021 1021 PythonQtObjectPtr sys;
1022 1022 sys.setNewRef(PyImport_ImportModule("sys"));
1023 1023 PythonQtObjectPtr obj = lookupObject(sys, "path");
1024 1024 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1025 1025 }
1026 1026
1027 1027 void PythonQt::overwriteSysPath(const QStringList& paths)
1028 1028 {
1029 1029 PythonQtObjectPtr sys;
1030 1030 sys.setNewRef(PyImport_ImportModule("sys"));
1031 1031 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1032 1032 }
1033 1033
1034 1034 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1035 1035 {
1036 1036 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1037 1037 }
1038 1038
1039 1039 void PythonQt::stdOutRedirectCB(const QString& str)
1040 1040 {
1041 1041 emit PythonQt::self()->pythonStdOut(str);
1042 1042 }
1043 1043
1044 1044 void PythonQt::stdErrRedirectCB(const QString& str)
1045 1045 {
1046 1046 emit PythonQt::self()->pythonStdErr(str);
1047 1047 }
1048 1048
1049 1049 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1050 1050 {
1051 1051 _p->_wrappedCB = cb;
1052 1052 }
1053 1053
1054 1054 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1055 1055 {
1056 1056 _p->_noLongerWrappedCB = cb;
1057 1057 }
1058 1058
1059 1059
1060 1060
1061 1061 static PyMethodDef PythonQtMethods[] = {
1062 1062 {NULL, NULL, 0, NULL}
1063 1063 };
1064 1064
1065 1065 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1066 1066 {
1067 1067 QByteArray name = "PythonQt";
1068 1068 if (!pythonQtModuleName.isEmpty()) {
1069 1069 name = pythonQtModuleName;
1070 1070 }
1071 1071 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1072 1072 _p->_pythonQtModuleName = name;
1073 1073
1074 1074 if (redirectStdOut) {
1075 1075 PythonQtObjectPtr sys;
1076 1076 PythonQtObjectPtr out;
1077 1077 PythonQtObjectPtr err;
1078 1078 sys.setNewRef(PyImport_ImportModule("sys"));
1079 1079 // create a redirection object for stdout and stderr
1080 1080 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1081 1081 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1082 1082 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1083 1083 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1084 1084 // replace the built in file objects with our own objects
1085 1085 PyModule_AddObject(sys, "stdout", out);
1086 1086 PyModule_AddObject(sys, "stderr", err);
1087 1087 }
1088 1088 }
1089 1089
1090 1090 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1091 1091 {
1092 1092 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1093 1093 }
1094 1094
1095 1095
1096 1096 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1097 1097 {
1098 1098 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1099 1099 if (!info) {
1100 1100 info = new PythonQtClassInfo();
1101 1101 info->setupCPPObject(typeName);
1102 1102 _knownClassInfos.insert(typeName, info);
1103 1103 }
1104 1104 return info;
1105 1105 }
1106 1106
1107 1107 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1108 1108 {
1109 1109 _p->addPolymorphicHandler(typeName, cb);
1110 1110 }
1111 1111
1112 1112 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1113 1113 {
1114 1114 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1115 1115 info->addPolymorphicHandler(cb);
1116 1116 }
1117 1117
1118 1118 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1119 1119 {
1120 1120 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1121 1121 }
1122 1122
1123 1123 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1124 1124 {
1125 1125 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1126 1126 if (info) {
1127 1127 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1128 1128 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1129 1129 return true;
1130 1130 } else {
1131 1131 return false;
1132 1132 }
1133 1133 }
1134 1134
1135 1135 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1136 1136 {
1137 1137 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1138 1138 if (!info->pythonQtClassWrapper()) {
1139 1139 info->setTypeSlots(typeSlots);
1140 1140 info->setupCPPObject(typeName);
1141 1141 createPythonQtClassWrapper(info, package, module);
1142 1142 }
1143 1143 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1144 1144 addParentClass(typeName, parentTypeName, 0);
1145 1145 }
1146 1146 if (wrapperCreator) {
1147 1147 info->setDecoratorProvider(wrapperCreator);
1148 1148 }
1149 1149 if (shell) {
1150 1150 info->setShellSetInstanceWrapperCB(shell);
1151 1151 }
1152 1152 }
1153 1153
1154 1154 PyObject* PythonQtPrivate::packageByName(const char* name)
1155 1155 {
1156 1156 if (name==NULL || name[0]==0) {
1157 1157 name = "private";
1158 1158 }
1159 1159 PyObject* v = _packages.value(name);
1160 1160 if (!v) {
1161 1161 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1162 1162 _packages.insert(name, v);
1163 1163 // AddObject steals the reference, so increment it!
1164 1164 Py_INCREF(v);
1165 1165 PyModule_AddObject(_pythonQtModule, name, v);
1166 1166 }
1167 1167 return v;
1168 1168 }
1169 1169
1170 1170 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1171 1171 {
1172 1172 QString error = "Return value '" + PythonQtConv::PyObjGetString(result) + "' can not be converted to expected C++ type '" + methodInfo->parameters().at(0).name + "' as return value of virtual method " + signature;
1173 1173 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1174 1174 PythonQt::self()->handleError();
1175 1175 }
1176 1176
1177 1177 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1178 1178 {
1179 1179 if (_p->_initFlags & ExternalHelp) {
1180 1180 emit pythonHelpRequest(QByteArray(info->className()));
1181 1181 return Py_BuildValue("");
1182 1182 } else {
1183 1183 return PyString_FromString(info->help().toLatin1().data());
1184 1184 }
1185 1185 }
1186 1186
1187 1187 void PythonQtPrivate::removeWrapperPointer(void* obj)
1188 1188 {
1189 1189 _wrappedObjects.remove(obj);
1190 1190 }
1191 1191
1192 1192 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1193 1193 {
1194 1194 _wrappedObjects.insert(obj, wrapper);
1195 1195 }
1196 1196
1197 1197 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1198 1198 {
1199 1199 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1200 1200 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1201 1201 // this is a wrapper whose QObject was already removed due to destruction
1202 1202 // so the obj pointer has to be a new QObject with the same address...
1203 1203 // we remove the old one and set the copy to NULL
1204 1204 wrap->_objPointerCopy = NULL;
1205 1205 removeWrapperPointer(obj);
1206 1206 wrap = NULL;
1207 1207 }
1208 1208 return wrap;
1209 1209 }
1210 1210
1211 1211 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1212 1212 {
1213 1213 PythonQtObjectPtr result;
1214 1214 if (pycode) {
1215 1215 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1216 1216 } else {
1217 1217 PythonQt::self()->handleError();
1218 1218 }
1219 1219 return result;
1220 1220 }
@@ -1,1228 +1,1236
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtConversion.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtConversion.h"
43 43 #include "PythonQtVariants.h"
44 44 #include <QDateTime>
45 45 #include <QTime>
46 46 #include <QDate>
47 47
48 48 PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
49 49 PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
50 50 PythonQtValueStorage<QVariant, 32> PythonQtConv::global_variantStorage;
51 51
52 52 QHash<int, PythonQtConvertMetaTypeToPythonCB*> PythonQtConv::_metaTypeToPythonConverters;
53 53 QHash<int, PythonQtConvertPythonToMetaTypeCB*> PythonQtConv::_pythonToMetaTypeConverters;
54 54
55 55 PyObject* PythonQtConv::GetPyBool(bool val)
56 56 {
57 57 PyObject* r = val?Py_True:Py_False;
58 58 Py_INCREF(r);
59 59 return r;
60 60 }
61 61
62 62 PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data) {
63 63 // is it an enum value?
64 64 if (info.enumWrapper) {
65 if (!info.isPointer) {
65 if (info.pointerCount==0) {
66 66 return PythonQtPrivate::createEnumValueInstance(info.enumWrapper, *((unsigned int*)data));
67 67 } else {
68 68 // we do not support pointers to enums (who needs them?)
69 69 Py_INCREF(Py_None);
70 70 return Py_None;
71 71 }
72 72 }
73 73
74 74 if (info.typeId == QMetaType::Void) {
75 75 Py_INCREF(Py_None);
76 76 return Py_None;
77 } else if (info.isPointer && (info.typeId == QMetaType::Char)) {
77 } else if ((info.pointerCount == 1) && (info.typeId == QMetaType::Char)) {
78 78 // a char ptr will probably be a null terminated string, so we support that:
79 79 return PyString_FromString(*((char**)data));
80 80 } else if ((info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) &&
81 81 info.name.startsWith("QList<")) {
82 82 // it is a QList template:
83 83 QByteArray innerType = info.name.mid(6,info.name.length()-7);
84 84 if (innerType.endsWith("*")) {
85 85 innerType.truncate(innerType.length()-1);
86 QList<void*>* listPtr;
87 if (info.isPointer) {
86 QList<void*>* listPtr = NULL;
87 if (info.pointerCount == 1) {
88 88 listPtr = *((QList<void*>**)data);
89 } else {
89 } else if (info.pointerCount == 0) {
90 90 listPtr = (QList<void*>*)data;
91 91 }
92 if (listPtr) {
92 93 return ConvertQListOfPointerTypeToPythonList(listPtr, innerType);
94 } else {
95 return NULL;
96 }
93 97 }
94 98 }
95 99
96 100 if (info.typeId >= QMetaType::User) {
97 101 // if a converter is registered, we use is:
98 102 PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId);
99 103 if (converter) {
100 104 return (*converter)(data, info.typeId);
101 105 }
102 106 }
103 107
104 108 // special handling did not match, so we convert the usual way (either pointer or value version):
105 if (info.isPointer) {
109 if (info.pointerCount == 1) {
106 110 // convert the pointer to a Python Object (we can handle ANY C++ object, in the worst case we just know the type and the pointer)
107 111 return PythonQt::priv()->wrapPtr(*((void**)data), info.name);
108 } else {
112 } else if (info.pointerCount == 0) {
109 113 // handle values that are not yet handled and not pointers
110 114 return ConvertQtValueToPythonInternal(info.typeId, data);
115 } else {
116 return NULL;
111 117 }
112 118 }
113 119
114 120 PyObject* PythonQtConv::ConvertQtValueToPythonInternal(int type, const void* data) {
115 121 switch (type) {
116 122 case QMetaType::Void:
117 123 Py_INCREF(Py_None);
118 124 return Py_None;
119 125 case QMetaType::Char:
120 126 return PyInt_FromLong(*((char*)data));
121 127 case QMetaType::UChar:
122 128 return PyInt_FromLong(*((unsigned char*)data));
123 129 case QMetaType::Short:
124 130 return PyInt_FromLong(*((short*)data));
125 131 case QMetaType::UShort:
126 132 return PyInt_FromLong(*((unsigned short*)data));
127 133 case QMetaType::Long:
128 134 return PyInt_FromLong(*((long*)data));
129 135 case QMetaType::ULong:
130 136 // does not fit into simple int of python
131 137 return PyLong_FromUnsignedLong(*((unsigned long*)data));
132 138 case QMetaType::Bool:
133 139 return PythonQtConv::GetPyBool(*((bool*)data));
134 140 case QMetaType::Int:
135 141 return PyInt_FromLong(*((int*)data));
136 142 case QMetaType::UInt:
137 143 // does not fit into simple int of python
138 144 return PyLong_FromUnsignedLong(*((unsigned int*)data));
139 145 case QMetaType::QChar:
140 146 return PyInt_FromLong(*((short*)data));
141 147 case QMetaType::Float:
142 148 return PyFloat_FromDouble(*((float*)data));
143 149 case QMetaType::Double:
144 150 return PyFloat_FromDouble(*((double*)data));
145 151 case QMetaType::LongLong:
146 152 return PyLong_FromLongLong(*((qint64*)data));
147 153 case QMetaType::ULongLong:
148 154 return PyLong_FromUnsignedLongLong(*((quint64*)data));
149 155 // implicit conversion from QByteArray to str has been removed:
150 156 //case QMetaType::QByteArray: {
151 157 // QByteArray* v = (QByteArray*) data;
152 158 // return PyString_FromStringAndSize(*v, v->size());
153 159 // }
154 160 case QMetaType::QVariantMap:
155 161 return PythonQtConv::QVariantMapToPyObject(*((QVariantMap*)data));
156 162 case QMetaType::QVariantList:
157 163 return PythonQtConv::QVariantListToPyObject(*((QVariantList*)data));
158 164 case QMetaType::QString:
159 165 return PythonQtConv::QStringToPyObject(*((QString*)data));
160 166 case QMetaType::QStringList:
161 167 return PythonQtConv::QStringListToPyObject(*((QStringList*)data));
162 168
163 169 case PythonQtMethodInfo::Variant:
164 170 return PythonQtConv::QVariantToPyObject(*((QVariant*)data));
165 171 case QMetaType::QObjectStar:
166 172 case QMetaType::QWidgetStar:
167 173 return PythonQt::priv()->wrapQObject(*((QObject**)data));
168 174
169 175 default:
170 176 if (PythonQt::priv()->isPythonQtObjectPtrMetaId(type)) {
171 177 // special case, it is a PythonQtObjectPtr which contains a PyObject, take it directly:
172 178 PyObject* o = ((PythonQtObjectPtr*)data)->object();
173 179 Py_INCREF(o);
174 180 return o;
175 181 } else {
176 182 if (type > 0) {
177 183 // if the type is known, we can construct it via QMetaType::construct
178 184 void* newCPPObject = QMetaType::construct(type, data);
179 185 // XXX this could be optimized by using metatypeid directly
180 186 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type));
181 187 wrap->_ownedByPythonQt = true;
182 188 wrap->_useQMetaTypeDestroy = true;
183 189 return (PyObject*)wrap;
184 190 }
185 191 std::cerr << "Unknown type that can not be converted to Python: " << type << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
186 192 }
187 193 }
188 194 Py_INCREF(Py_None);
189 195 return Py_None;
190 196 }
191 197
192 198 void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) {
193 199 void* ptr = NULL;
194 if (info.isPointer) {
200 if (info.pointerCount>1) {
201 return NULL;
202 } else if (info.pointerCount==1) {
195 203 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr);
196 204 } else if (info.enumWrapper) {
197 205 // create enum return value
198 206 PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, ptr);
199 207 } else {
200 208 switch (info.typeId) {
201 209 case QMetaType::Char:
202 210 case QMetaType::UChar:
203 211 case QMetaType::Short:
204 212 case QMetaType::UShort:
205 213 case QMetaType::Long:
206 214 case QMetaType::ULong:
207 215 case QMetaType::Bool:
208 216 case QMetaType::Int:
209 217 case QMetaType::UInt:
210 218 case QMetaType::QChar:
211 219 case QMetaType::Float:
212 220 case QMetaType::Double:
213 221 PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, 0, ptr);
214 222 break;
215 223 case PythonQtMethodInfo::Variant:
216 224 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr);
217 225 // return the ptr to the variant
218 226 break;
219 227 default:
220 228 if (info.typeId == PythonQtMethodInfo::Unknown) {
221 229 // check if we have a QList of pointers, which we can circumvent with a QList<void*>
222 230 if (info.name.startsWith("QList<")) {
223 231 QByteArray innerType = info.name.mid(6,info.name.length()-7);
224 232 if (innerType.endsWith("*")) {
225 233 static int id = QMetaType::type("QList<void*>");
226 234 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
227 235 // return the constData pointer that will be filled with the result value later on
228 236 ptr = (void*)((QVariant*)ptr)->constData();
229 237 }
230 238 }
231 239 }
232 240
233 241 if (!ptr && info.typeId!=PythonQtMethodInfo::Unknown) {
234 242 // everything else is stored in a QVariant, if we know the meta type...
235 243 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
236 244 // return the constData pointer that will be filled with the result value later on
237 245 ptr = (void*)((QVariant*)ptr)->constData();
238 246 }
239 247 }
240 248 }
241 249 return ptr;
242 250 }
243 251
244 252 void* PythonQtConv::castWrapperTo(PythonQtInstanceWrapper* wrapper, const QByteArray& className, bool& ok)
245 253 {
246 254 void* object;
247 255 if (wrapper->classInfo()->isCPPWrapper()) {
248 256 object = wrapper->_wrappedPtr;
249 257 } else {
250 258 QObject* tmp = wrapper->_obj;
251 259 object = tmp;
252 260 }
253 261 if (object) {
254 262 // if we can be upcasted to the given name, we pass the casted pointer in:
255 263 object = wrapper->classInfo()->castTo(object, className);
256 264 ok = object!=NULL;
257 265 } else {
258 266 // if it is a NULL ptr, we need to check if it inherits, so that we might pass the NULL ptr
259 267 ok = wrapper->classInfo()->inherits(className);
260 268 }
261 269 return object;
262 270 }
263 271
264 272 void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject)
265 273 {
266 274 void* ptr = alreadyAllocatedCPPObject;
267 275
268 276 static int penId = QMetaType::type("QPen");
269 277 static int brushId = QMetaType::type("QBrush");
270 278 static int cursorId = QMetaType::type("QCursor");
271 279 static int colorId = QMetaType::type("QColor");
272 280 static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", NULL);
273 281 if (typeId == cursorId) {
274 282 static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", NULL);
275 283 if ((PyObject*)obj->ob_type == qtCursorShapeEnum) {
276 284 Qt::CursorShape val = (Qt::CursorShape)PyInt_AS_LONG(obj);
277 285 if (!ptr) {
278 286 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QCursor(), ptr);
279 287 ptr = (void*)((QVariant*)ptr)->constData();
280 288 }
281 289 *((QCursor*)ptr) = QCursor(val);
282 290 return ptr;
283 291 }
284 292 } else if (typeId == penId) {
285 293 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
286 294 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
287 295 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
288 296 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
289 297 if (!ptr) {
290 298 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
291 299 ptr = (void*)((QVariant*)ptr)->constData();
292 300 }
293 301 *((QPen*)ptr) = QPen(QColor(val));
294 302 return ptr;
295 303 } else if ((PyObject*)obj->ob_type == qtColorClass) {
296 304 if (!ptr) {
297 305 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr);
298 306 ptr = (void*)((QVariant*)ptr)->constData();
299 307 }
300 308 *((QPen*)ptr) = QPen(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
301 309 return ptr;
302 310 }
303 311 } else if (typeId == brushId) {
304 312 // brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
305 313 static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
306 314 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
307 315 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
308 316 if (!ptr) {
309 317 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
310 318 ptr = (void*)((QVariant*)ptr)->constData();
311 319 }
312 320 *((QBrush*)ptr) = QBrush(QColor(val));
313 321 return ptr;
314 322 } else if ((PyObject*)obj->ob_type == qtColorClass) {
315 323 if (!ptr) {
316 324 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr);
317 325 ptr = (void*)((QVariant*)ptr)->constData();
318 326 }
319 327 *((QBrush*)ptr) = QBrush(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr));
320 328 return ptr;
321 329 }
322 330 } else if (typeId == colorId) {
323 331 // colors can be created from Qt::GlobalColor (and from colors, but that's the default)
324 332 if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
325 333 Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AS_LONG(obj);
326 334 if (!ptr) {
327 335 PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QColor(), ptr);
328 336 ptr = (void*)((QVariant*)ptr)->constData();
329 337 }
330 338 *((QColor*)ptr) = QColor(val);
331 339 return ptr;
332 340 }
333 341 }
334 342 return NULL;
335 343 }
336 344
337 345 void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject)
338 346 {
339 347 bool ok = false;
340 348 void* ptr = NULL;
341 349
342 350 // autoconversion of QPen/QBrush/QCursor/QColor from different type
343 if (!info.isPointer && !strict) {
351 if (info.pointerCount==0 && !strict) {
344 352 ptr = handlePythonToQtAutoConversion(info.typeId, obj, alreadyAllocatedCPPObject);
345 353 if (ptr) {
346 354 return ptr;
347 355 }
348 356 }
349 357
350 358 if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
351 359 // if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
352 360 // (the Variant case is handled below in a switch)
353 361
354 362 // a C++ wrapper (can be passed as pointer or reference)
355 363 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj;
356 364 void* object = castWrapperTo(wrap, info.name, ok);
357 365 if (ok) {
358 if (info.isPointer) {
366 if (info.pointerCount==1) {
359 367 // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer
360 368 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, object, ptr);
361 } else {
369 } else if (info.pointerCount==0) {
362 370 // store the wrapped pointer directly, since we are a reference
363 371 ptr = object;
364 372 }
365 373 } else {
366 374 // not matching
367 375 }
368 } else if (info.isPointer) {
376 } else if (info.pointerCount == 1) {
369 377 // a pointer
370 378 if (info.typeId == QMetaType::Char || info.typeId == QMetaType::UChar)
371 379 {
372 380 QString str = PyObjGetString(obj, strict, ok);
373 381 if (ok) {
374 382 void* ptr2 = NULL;
375 383 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str.toUtf8()), ptr2);
376 384 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr);
377 385 }
378 386 } else if (info.name == "PyObject") {
379 387 // handle low level PyObject directly
380 388 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr);
381 389 } else if (obj == Py_None) {
382 390 // None is treated as a NULL ptr
383 391 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
384 392 } else {
385 393 // if we are not strict, we try if we are passed a 0 integer
386 394 if (!strict) {
387 395 bool ok;
388 396 int value = PyObjGetInt(obj, true, ok);
389 397 if (ok && value==0) {
390 398 // TODOXXX is this wise? or should it be expected from the programmer to use None?
391 399 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr);
392 400 }
393 401 }
394 402 }
395 } else {
403 } else if (info.pointerCount == 0) {
396 404 // not a pointer
397 405 switch (info.typeId) {
398 406 case QMetaType::Char:
399 407 {
400 408 int val = PyObjGetInt(obj, strict, ok);
401 409 if (ok) {
402 410 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr);
403 411 }
404 412 }
405 413 break;
406 414 case QMetaType::UChar:
407 415 {
408 416 int val = PyObjGetInt(obj, strict, ok);
409 417 if (ok) {
410 418 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr);
411 419 }
412 420 }
413 421 break;
414 422 case QMetaType::Short:
415 423 {
416 424 int val = PyObjGetInt(obj, strict, ok);
417 425 if (ok) {
418 426 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
419 427 }
420 428 }
421 429 break;
422 430 case QMetaType::UShort:
423 431 {
424 432 int val = PyObjGetInt(obj, strict, ok);
425 433 if (ok) {
426 434 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr);
427 435 }
428 436 }
429 437 break;
430 438 case QMetaType::Long:
431 439 {
432 440 long val = (long)PyObjGetLongLong(obj, strict, ok);
433 441 if (ok) {
434 442 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr);
435 443 }
436 444 }
437 445 break;
438 446 case QMetaType::ULong:
439 447 {
440 448 unsigned long val = (unsigned long)PyObjGetLongLong(obj, strict, ok);
441 449 if (ok) {
442 450 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr);
443 451 }
444 452 }
445 453 break;
446 454 case QMetaType::Bool:
447 455 {
448 456 bool val = PyObjGetBool(obj, strict, ok);
449 457 if (ok) {
450 458 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr);
451 459 }
452 460 }
453 461 break;
454 462 case QMetaType::Int:
455 463 {
456 464 int val = PyObjGetInt(obj, strict, ok);
457 465 if (ok) {
458 466 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr);
459 467 }
460 468 }
461 469 break;
462 470 case QMetaType::UInt:
463 471 {
464 472 unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok);
465 473 if (ok) {
466 474 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
467 475 }
468 476 }
469 477 break;
470 478 case QMetaType::QChar:
471 479 {
472 480 int val = PyObjGetInt(obj, strict, ok);
473 481 if (ok) {
474 482 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr);
475 483 }
476 484 }
477 485 break;
478 486 case QMetaType::Float:
479 487 {
480 488 float val = (float)PyObjGetDouble(obj, strict, ok);
481 489 if (ok) {
482 490 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr);
483 491 }
484 492 }
485 493 break;
486 494 case QMetaType::Double:
487 495 {
488 496 double val = (double)PyObjGetDouble(obj, strict, ok);
489 497 if (ok) {
490 498 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr);
491 499 }
492 500 }
493 501 break;
494 502 case QMetaType::LongLong:
495 503 {
496 504 qint64 val = PyObjGetLongLong(obj, strict, ok);
497 505 if (ok) {
498 506 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr);
499 507 }
500 508 }
501 509 break;
502 510 case QMetaType::ULongLong:
503 511 {
504 512 quint64 val = PyObjGetULongLong(obj, strict, ok);
505 513 if (ok) {
506 514 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr);
507 515 }
508 516 }
509 517 break;
510 518 case QMetaType::QByteArray:
511 519 {
512 520 QByteArray bytes = PyObjGetBytes(obj, strict, ok);
513 521 if (ok) {
514 522 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr);
515 523 ptr = (void*)((QVariant*)ptr)->constData();
516 524 }
517 525 }
518 526 break;
519 527 case QMetaType::QString:
520 528 {
521 529 QString str = PyObjGetString(obj, strict, ok);
522 530 if (ok) {
523 531 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr);
524 532 ptr = (void*)((QVariant*)ptr)->constData();
525 533 }
526 534 }
527 535 break;
528 536 case QMetaType::QStringList:
529 537 {
530 538 QStringList l = PyObjToStringList(obj, strict, ok);
531 539 if (ok) {
532 540 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr);
533 541 ptr = (void*)((QVariant*)ptr)->constData();
534 542 }
535 543 }
536 544 break;
537 545
538 546 case PythonQtMethodInfo::Variant:
539 547 {
540 548 QVariant v = PyObjToQVariant(obj);
541 549 // the only case where conversion can fail it None and we want to pass that to, e.g. setProperty(),
542 550 // so we do not check v.isValid() here
543 551 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
544 552 }
545 553 break;
546 554 default:
547 555 {
548 556 // check for enum case
549 557 if (info.enumWrapper) {
550 558 unsigned int val;
551 559 ok = false;
552 560 if ((PyObject*)obj->ob_type == info.enumWrapper) {
553 561 // we have a exact enum type match:
554 562 val = PyInt_AS_LONG(obj);
555 563 ok = true;
556 564 } else if (!strict) {
557 565 // we try to get any integer, when not being strict. If we are strict, integers are not wanted because
558 566 // we want an integer overload to be taken first!
559 567 val = (unsigned int)PyObjGetLongLong(obj, false, ok);
560 568 }
561 569 if (ok) {
562 570 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr);
563 571 return ptr;
564 572 } else {
565 573 return NULL;
566 574 }
567 575 }
568 576
569 577 if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
570 578 // check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
571 579 if (info.name.startsWith("QList<")) {
572 580 QByteArray innerType = info.name.mid(6,info.name.length()-7);
573 581 if (innerType.endsWith("*")) {
574 582 innerType.truncate(innerType.length()-1);
575 583 static int id = QMetaType::type("QList<void*>");
576 584 if (!alreadyAllocatedCPPObject) {
577 585 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(id), ptr);
578 586 ptr = (void*)((QVariant*)ptr)->constData();
579 587 } else {
580 588 ptr = alreadyAllocatedCPPObject;
581 589 }
582 590 ok = ConvertPythonListToQListOfPointerType(obj, (QList<void*>*)ptr, innerType, strict);
583 591 if (ok) {
584 592 return ptr;
585 593 } else {
586 594 return NULL;
587 595 }
588 596 }
589 597 }
590 598 }
591 599
592 600 // We only do this for registered type > QMetaType::User for performance reasons.
593 601 if (info.typeId >= QMetaType::User) {
594 602 // Maybe we have a special converter that is registered for that type:
595 603 PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
596 604 if (converter) {
597 605 if (!alreadyAllocatedCPPObject) {
598 606 // create a new empty variant of concrete type:
599 607 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr);
600 608 ptr = (void*)((QVariant*)ptr)->constData();
601 609 } else {
602 610 ptr = alreadyAllocatedCPPObject;
603 611 }
604 612 // now call the converter, passing the internal object of the variant
605 613 ok = (*converter)(obj, ptr, info.typeId, strict);
606 614 if (ok) {
607 615 return ptr;
608 616 } else {
609 617 return NULL;
610 618 }
611 619 }
612 620 }
613 621 // if no type id is available, conversion to a QVariant makes no sense/is not possible
614 622 if (info.typeId != PythonQtMethodInfo::Unknown) {
615 623 // for all other types, we use the same qvariant conversion and pass out the constData of the variant:
616 624 QVariant v = PyObjToQVariant(obj, info.typeId);
617 625 if (v.isValid()) {
618 626 PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr);
619 627 ptr = (void*)((QVariant*)ptr)->constData();
620 628 }
621 629 }
622 630 }
623 631 }
624 632 }
625 633 return ptr;
626 634 }
627 635
628 636
629 637 QStringList PythonQtConv::PyObjToStringList(PyObject* val, bool strict, bool& ok) {
630 638 QStringList v;
631 639 ok = false;
632 640 // if we are strict, we do not want to convert a string to a stringlist
633 641 // (strings in python are detected to be sequences)
634 642 if (strict &&
635 643 (val->ob_type == &PyString_Type ||
636 644 PyUnicode_Check(val))) {
637 645 ok = false;
638 646 return v;
639 647 }
640 648 if (PySequence_Check(val)) {
641 649 int count = PySequence_Size(val);
642 650 for (int i = 0;i<count;i++) {
643 651 PyObject* value = PySequence_GetItem(val,i);
644 652 v.append(PyObjGetString(value,false,ok));
645 653 }
646 654 ok = true;
647 655 }
648 656 return v;
649 657 }
650 658
651 659 QString PythonQtConv::PyObjGetRepresentation(PyObject* val)
652 660 {
653 661 QString r;
654 662 PyObject* str = PyObject_Repr(val);
655 663 if (str) {
656 664 r = QString(PyString_AS_STRING(str));
657 665 Py_DECREF(str);
658 666 }
659 667 return r;
660 668 }
661 669
662 670 QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) {
663 671 QString r;
664 672 ok = true;
665 673 if (val->ob_type == &PyString_Type) {
666 674 r = QString(PyString_AS_STRING(val));
667 675 } else if (PyUnicode_Check(val)) {
668 676 #ifdef WIN32
669 677 r = QString::fromUtf16(PyUnicode_AS_UNICODE(val));
670 678 #else
671 679 PyObject *ptmp = PyUnicode_AsUTF8String(val);
672 680 if(ptmp) {
673 681 r = QString::fromUtf8(PyString_AS_STRING(ptmp));
674 682 Py_DECREF(ptmp);
675 683 }
676 684 #endif
677 685 } else if (!strict) {
678 686 // EXTRA: could also use _Unicode, but why should we?
679 687 PyObject* str = PyObject_Str(val);
680 688 if (str) {
681 689 r = QString(PyString_AS_STRING(str));
682 690 Py_DECREF(str);
683 691 } else {
684 692 ok = false;
685 693 }
686 694 } else {
687 695 ok = false;
688 696 }
689 697 return r;
690 698 }
691 699
692 700 QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) {
693 701 // TODO: support buffer objects in general
694 702 QByteArray r;
695 703 ok = true;
696 704 if (val->ob_type == &PyString_Type) {
697 705 long size = PyString_GET_SIZE(val);
698 706 r = QByteArray(PyString_AS_STRING(val), size);
699 707 } else {
700 708 ok = false;
701 709 }
702 710 return r;
703 711 }
704 712
705 713 bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) {
706 714 bool d = false;
707 715 ok = false;
708 716 if (val == Py_False) {
709 717 d = false;
710 718 ok = true;
711 719 } else if (val == Py_True) {
712 720 d = true;
713 721 ok = true;
714 722 } else if (!strict) {
715 723 d = PyObjGetInt(val, false, ok)!=0;
716 724 ok = true;
717 725 }
718 726 return d;
719 727 }
720 728
721 729 int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) {
722 730 int d = 0;
723 731 ok = true;
724 732 if (val->ob_type == &PyInt_Type) {
725 733 d = PyInt_AS_LONG(val);
726 734 } else if (!strict) {
727 735 if (PyObject_TypeCheck(val, &PyInt_Type)) {
728 736 // support for derived int classes, e.g. for our enums
729 737 d = PyInt_AS_LONG(val);
730 738 } else if (val->ob_type == &PyFloat_Type) {
731 739 d = floor(PyFloat_AS_DOUBLE(val));
732 740 } else if (val->ob_type == &PyLong_Type) {
733 741 // handle error on overflow!
734 742 d = PyLong_AsLong(val);
735 743 } else if (val == Py_False) {
736 744 d = 0;
737 745 } else if (val == Py_True) {
738 746 d = 1;
739 747 } else {
740 748 ok = false;
741 749 }
742 750 } else {
743 751 ok = false;
744 752 }
745 753 return d;
746 754 }
747 755
748 756 qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) {
749 757 qint64 d = 0;
750 758 ok = true;
751 759 if (val->ob_type == &PyInt_Type) {
752 760 d = PyInt_AS_LONG(val);
753 761 } else if (val->ob_type == &PyLong_Type) {
754 762 d = PyLong_AsLongLong(val);
755 763 } else if (!strict) {
756 764 if (PyObject_TypeCheck(val, &PyInt_Type)) {
757 765 // support for derived int classes, e.g. for our enums
758 766 d = PyInt_AS_LONG(val);
759 767 } else if (val->ob_type == &PyFloat_Type) {
760 768 d = floor(PyFloat_AS_DOUBLE(val));
761 769 } else if (val == Py_False) {
762 770 d = 0;
763 771 } else if (val == Py_True) {
764 772 d = 1;
765 773 } else {
766 774 ok = false;
767 775 }
768 776 } else {
769 777 ok = false;
770 778 }
771 779 return d;
772 780 }
773 781
774 782 quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) {
775 783 quint64 d = 0;
776 784 ok = true;
777 785 if (PyObject_TypeCheck(val, &PyInt_Type)) {
778 786 d = PyInt_AS_LONG(val);
779 787 } else if (val->ob_type == &PyLong_Type) {
780 788 d = PyLong_AsLongLong(val);
781 789 } else if (!strict) {
782 790 if (PyObject_TypeCheck(val, &PyInt_Type)) {
783 791 // support for derived int classes, e.g. for our enums
784 792 d = PyInt_AS_LONG(val);
785 793 } else if (val->ob_type == &PyFloat_Type) {
786 794 d = floor(PyFloat_AS_DOUBLE(val));
787 795 } else if (val == Py_False) {
788 796 d = 0;
789 797 } else if (val == Py_True) {
790 798 d = 1;
791 799 } else {
792 800 ok = false;
793 801 }
794 802 } else {
795 803 ok = false;
796 804 }
797 805 return d;
798 806 }
799 807
800 808 double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) {
801 809 double d = 0;
802 810 ok = true;
803 811 if (val->ob_type == &PyFloat_Type) {
804 812 d = PyFloat_AS_DOUBLE(val);
805 813 } else if (!strict) {
806 814 if (PyObject_TypeCheck(val, &PyInt_Type)) {
807 815 d = PyInt_AS_LONG(val);
808 816 } else if (val->ob_type == &PyLong_Type) {
809 817 d = PyLong_AsLong(val);
810 818 } else if (val == Py_False) {
811 819 d = 0;
812 820 } else if (val == Py_True) {
813 821 d = 1;
814 822 } else {
815 823 ok = false;
816 824 }
817 825 } else {
818 826 ok = false;
819 827 }
820 828 return d;
821 829 }
822 830
823 831 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
824 832 {
825 833 QVariant v;
826 834 bool ok = true;
827 835
828 836 if (type==-1) {
829 837 // no special type requested
830 838 if (val->ob_type==&PyString_Type || val->ob_type==&PyUnicode_Type) {
831 839 type = QVariant::String;
832 840 } else if (PyObject_TypeCheck(val, &PyInt_Type)) {
833 841 type = QVariant::Int;
834 842 } else if (val->ob_type==&PyLong_Type) {
835 843 type = QVariant::LongLong;
836 844 } else if (val->ob_type==&PyFloat_Type) {
837 845 type = QVariant::Double;
838 846 } else if (val == Py_False || val == Py_True) {
839 847 type = QVariant::Bool;
840 848 } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
841 849 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
842 850 // c++ wrapper, check if the class names of the c++ objects match
843 851 if (wrap->classInfo()->isCPPWrapper()) {
844 852 if (wrap->classInfo()->metaTypeId()>0) {
845 853 // construct a new variant from the C++ object if it has a meta type (this will COPY the object!)
846 854 v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr);
847 855 } else {
848 856 // TODOXXX we could as well check if there is a registered meta type for "classname*", so that we may pass
849 857 // the pointer here...
850 858 // is this worth anything? we loose the knowledge of the cpp object type
851 859 v = qVariantFromValue(wrap->_wrappedPtr);
852 860 }
853 861 } else {
854 862 // this gives us a QObject pointer
855 863 QObject* myObject = wrap->_obj;
856 864 v = qVariantFromValue(myObject);
857 865 }
858 866 return v;
859 867 } else if (val->ob_type==&PyDict_Type) {
860 868 type = QVariant::Map;
861 869 } else if (val->ob_type==&PyList_Type || val->ob_type==&PyTuple_Type || PySequence_Check(val)) {
862 870 type = QVariant::List;
863 871 } else if (val == Py_None) {
864 872 // none is invalid
865 873 type = QVariant::Invalid;
866 874 } else {
867 875 // this used to be:
868 876 // type = QVariant::String;
869 877 // but now we want to transport the Python Objects directly:
870 878 PythonQtObjectPtr o(val);
871 879 v = qVariantFromValue(o);
872 880 return v;
873 881 }
874 882 }
875 883 // special type request:
876 884 switch (type) {
877 885 case QVariant::Invalid:
878 886 return v;
879 887 break;
880 888 case QVariant::Int:
881 889 {
882 890 int d = PyObjGetInt(val, false, ok);
883 891 if (ok) return QVariant(d);
884 892 }
885 893 break;
886 894 case QVariant::UInt:
887 895 {
888 896 int d = PyObjGetInt(val, false,ok);
889 897 if (ok) v = QVariant((unsigned int)d);
890 898 }
891 899 break;
892 900 case QVariant::Bool:
893 901 {
894 902 int d = PyObjGetBool(val,false,ok);
895 903 if (ok) v = QVariant((bool)(d!=0));
896 904 }
897 905 break;
898 906 case QVariant::Double:
899 907 {
900 908 double d = PyObjGetDouble(val,false,ok);
901 909 if (ok) v = QVariant(d);
902 910 break;
903 911 }
904 912 case QMetaType::Float:
905 913 {
906 914 float d = (float) PyObjGetDouble(val,false,ok);
907 915 if (ok) v = qVariantFromValue(d);
908 916 break;
909 917 }
910 918 case QMetaType::Long:
911 919 {
912 920 long d = (long) PyObjGetLongLong(val,false,ok);
913 921 if (ok) v = qVariantFromValue(d);
914 922 break;
915 923 }
916 924 case QMetaType::ULong:
917 925 {
918 926 unsigned long d = (unsigned long) PyObjGetLongLong(val,false,ok);
919 927 if (ok) v = qVariantFromValue(d);
920 928 break;
921 929 }
922 930 case QMetaType::LongLong:
923 931 {
924 932 qint64 d = PyObjGetLongLong(val, false, ok);
925 933 if (ok) v = qVariantFromValue(d);
926 934 }
927 935 break;
928 936 case QMetaType::ULongLong:
929 937 {
930 938 quint64 d = PyObjGetULongLong(val, false, ok);
931 939 if (ok) v = qVariantFromValue(d);
932 940 }
933 941 break;
934 942 case QMetaType::Short:
935 943 {
936 944 short d = (short) PyObjGetInt(val,false,ok);
937 945 if (ok) v = qVariantFromValue(d);
938 946 break;
939 947 }
940 948 case QMetaType::UShort:
941 949 {
942 950 unsigned short d = (unsigned short) PyObjGetInt(val,false,ok);
943 951 if (ok) v = qVariantFromValue(d);
944 952 break;
945 953 }
946 954 case QMetaType::Char:
947 955 {
948 956 char d = (char) PyObjGetInt(val,false,ok);
949 957 if (ok) v = qVariantFromValue(d);
950 958 break;
951 959 }
952 960 case QMetaType::UChar:
953 961 {
954 962 unsigned char d = (unsigned char) PyObjGetInt(val,false,ok);
955 963 if (ok) v = qVariantFromValue(d);
956 964 break;
957 965 }
958 966
959 967 case QVariant::ByteArray:
960 968 case QVariant::String:
961 969 {
962 970 bool ok;
963 971 v = QVariant(PyObjGetString(val, false, ok));
964 972 }
965 973 break;
966 974
967 975 // these are important for MeVisLab
968 976 case QVariant::Map:
969 977 {
970 978 if (PyMapping_Check(val)) {
971 979 QMap<QString,QVariant> map;
972 980 PyObject* items = PyMapping_Items(val);
973 981 if (items) {
974 982 int count = PyList_Size(items);
975 983 PyObject* value;
976 984 PyObject* key;
977 985 PyObject* tuple;
978 986 for (int i = 0;i<count;i++) {
979 987 tuple = PyList_GetItem(items,i);
980 988 key = PyTuple_GetItem(tuple, 0);
981 989 value = PyTuple_GetItem(tuple, 1);
982 990 map.insert(PyObjGetString(key), PyObjToQVariant(value,-1));
983 991 }
984 992 Py_DECREF(items);
985 993 v = map;
986 994 }
987 995 }
988 996 }
989 997 break;
990 998 case QVariant::List:
991 999 if (PySequence_Check(val)) {
992 1000 QVariantList list;
993 1001 int count = PySequence_Size(val);
994 1002 PyObject* value;
995 1003 for (int i = 0;i<count;i++) {
996 1004 value = PySequence_GetItem(val,i);
997 1005 list.append(PyObjToQVariant(value, -1));
998 1006 }
999 1007 v = list;
1000 1008 }
1001 1009 break;
1002 1010 case QVariant::StringList:
1003 1011 {
1004 1012 bool ok;
1005 1013 QStringList l = PyObjToStringList(val, false, ok);
1006 1014 if (ok) {
1007 1015 v = l;
1008 1016 }
1009 1017 }
1010 1018 break;
1011 1019
1012 1020 default:
1013 1021 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
1014 1022 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
1015 1023 if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) {
1016 1024 // construct a new variant from the C++ object if it has the same meta type
1017 1025 v = QVariant(type, wrap->_wrappedPtr);
1018 1026 } else {
1019 1027 v = QVariant();
1020 1028 }
1021 1029 } else {
1022 1030 v = QVariant();
1023 1031 }
1024 1032 }
1025 1033 return v;
1026 1034 }
1027 1035
1028 1036 PyObject* PythonQtConv::QStringToPyObject(const QString& str)
1029 1037 {
1030 1038 if (str.isNull()) {
1031 1039 return PyString_FromString("");
1032 1040 } else {
1033 1041 #ifdef WIN32
1034 1042 // return PyString_FromString(str.toLatin1().data());
1035 1043 return PyUnicode_FromUnicode(str.utf16(), str.length());
1036 1044 #else
1037 1045 return PyUnicode_DecodeUTF16((const char*)str.utf16(), str.length()*2, NULL, NULL);
1038 1046 #endif
1039 1047 }
1040 1048 }
1041 1049
1042 1050 PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list)
1043 1051 {
1044 1052 PyObject* result = PyTuple_New(list.count());
1045 1053 int i = 0;
1046 1054 QString str;
1047 1055 foreach (str, list) {
1048 1056 PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str));
1049 1057 i++;
1050 1058 }
1051 1059 // why is the error state bad after this?
1052 1060 PyErr_Clear();
1053 1061 return result;
1054 1062 }
1055 1063
1056 1064 PyObject* PythonQtConv::QStringListToPyList(const QStringList& list)
1057 1065 {
1058 1066 PyObject* result = PyList_New(list.count());
1059 1067 int i = 0;
1060 1068 for (QStringList::ConstIterator it = list.begin(); it!=list.end(); ++it) {
1061 1069 PyList_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(*it));
1062 1070 i++;
1063 1071 }
1064 1072 return result;
1065 1073 }
1066 1074
1067 1075 PyObject* PythonQtConv::QVariantToPyObject(const QVariant& v)
1068 1076 {
1069 1077 return ConvertQtValueToPythonInternal(v.userType(), (void*)v.constData());
1070 1078 }
1071 1079
1072 1080 PyObject* PythonQtConv::QVariantMapToPyObject(const QVariantMap& m) {
1073 1081 PyObject* result = PyDict_New();
1074 1082 QVariantMap::const_iterator t = m.constBegin();
1075 1083 PyObject* key;
1076 1084 PyObject* val;
1077 1085 for (;t!=m.end();t++) {
1078 1086 key = QStringToPyObject(t.key());
1079 1087 val = QVariantToPyObject(t.value());
1080 1088 PyDict_SetItem(result, key, val);
1081 1089 Py_DECREF(key);
1082 1090 Py_DECREF(val);
1083 1091 }
1084 1092 return result;
1085 1093 }
1086 1094
1087 1095 PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) {
1088 1096 PyObject* result = PyTuple_New(l.count());
1089 1097 int i = 0;
1090 1098 QVariant v;
1091 1099 foreach (v, l) {
1092 1100 PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v));
1093 1101 i++;
1094 1102 }
1095 1103 // why is the error state bad after this?
1096 1104 PyErr_Clear();
1097 1105 return result;
1098 1106 }
1099 1107
1100 1108 PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList<void*>* list, const QByteArray& typeName)
1101 1109 {
1102 1110 PyObject* result = PyTuple_New(list->count());
1103 1111 int i = 0;
1104 1112 foreach (void* value, *list) {
1105 1113 PyTuple_SET_ITEM(result, i, PythonQt::priv()->wrapPtr(value, typeName));
1106 1114 i++;
1107 1115 }
1108 1116 return result;
1109 1117 }
1110 1118
1111 1119 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<void*>* list, const QByteArray& type, bool /*strict*/)
1112 1120 {
1113 1121 bool result = false;
1114 1122 if (PySequence_Check(obj)) {
1115 1123 result = true;
1116 1124 int count = PySequence_Size(obj);
1117 1125 PyObject* value;
1118 1126 for (int i = 0;i<count;i++) {
1119 1127 value = PySequence_GetItem(obj,i);
1120 1128 if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
1121 1129 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value;
1122 1130 bool ok;
1123 1131 void* object = castWrapperTo(wrap, type, ok);
1124 1132 if (ok) {
1125 1133 list->append(object);
1126 1134 } else {
1127 1135 result = false;
1128 1136 break;
1129 1137 }
1130 1138 }
1131 1139 }
1132 1140 }
1133 1141 return result;
1134 1142 }
1135 1143
1136 1144 int PythonQtConv::getInnerTemplateMetaType(const QByteArray& typeName)
1137 1145 {
1138 1146 int idx = typeName.indexOf("<");
1139 1147 if (idx>0) {
1140 1148 int idx2 = typeName.indexOf(">");
1141 1149 if (idx2>0) {
1142 1150 QByteArray innerType = typeName.mid(idx+1,idx2-idx-1);
1143 1151 return QMetaType::type(innerType.constData());
1144 1152 }
1145 1153 }
1146 1154 return QMetaType::Void;
1147 1155 }
1148 1156
1149 1157
1150 1158 QString PythonQtConv::CPPObjectToString(int type, const void* data) {
1151 1159 QString r;
1152 1160 switch (type) {
1153 1161 case QVariant::Size: {
1154 1162 const QSize* s = static_cast<const QSize*>(data);
1155 1163 r = QString::number(s->width()) + ", " + QString::number(s->height());
1156 1164 }
1157 1165 break;
1158 1166 case QVariant::SizeF: {
1159 1167 const QSizeF* s = static_cast<const QSizeF*>(data);
1160 1168 r = QString::number(s->width()) + ", " + QString::number(s->height());
1161 1169 }
1162 1170 break;
1163 1171 case QVariant::Point: {
1164 1172 const QPoint* s = static_cast<const QPoint*>(data);
1165 1173 r = QString::number(s->x()) + ", " + QString::number(s->y());
1166 1174 }
1167 1175 break;
1168 1176 case QVariant::PointF: {
1169 1177 const QPointF* s = static_cast<const QPointF*>(data);
1170 1178 r = QString::number(s->x()) + ", " + QString::number(s->y());
1171 1179 }
1172 1180 break;
1173 1181 case QVariant::Rect: {
1174 1182 const QRect* s = static_cast<const QRect*>(data);
1175 1183 r = QString::number(s->x()) + ", " + QString::number(s->y());
1176 1184 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1177 1185 }
1178 1186 break;
1179 1187 case QVariant::RectF: {
1180 1188 const QRectF* s = static_cast<const QRectF*>(data);
1181 1189 r = QString::number(s->x()) + ", " + QString::number(s->y());
1182 1190 r += ", " + QString::number(s->width()) + ", " + QString::number(s->height());
1183 1191 }
1184 1192 break;
1185 1193 case QVariant::Date: {
1186 1194 const QDate* s = static_cast<const QDate*>(data);
1187 1195 r = s->toString(Qt::ISODate);
1188 1196 }
1189 1197 break;
1190 1198 case QVariant::DateTime: {
1191 1199 const QDateTime* s = static_cast<const QDateTime*>(data);
1192 1200 r = s->toString(Qt::ISODate);
1193 1201 }
1194 1202 break;
1195 1203 case QVariant::Time: {
1196 1204 const QTime* s = static_cast<const QTime*>(data);
1197 1205 r = s->toString(Qt::ISODate);
1198 1206 }
1199 1207 break;
1200 1208 case QVariant::Pixmap:
1201 1209 {
1202 1210 const QPixmap* s = static_cast<const QPixmap*>(data);
1203 1211 r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height());
1204 1212 }
1205 1213 break;
1206 1214 case QVariant::Image:
1207 1215 {
1208 1216 const QImage* s = static_cast<const QImage*>(data);
1209 1217 r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height());
1210 1218 }
1211 1219 break;
1212 1220 case QVariant::Url:
1213 1221 {
1214 1222 const QUrl* s = static_cast<const QUrl*>(data);
1215 1223 r = s->toString();
1216 1224 }
1217 1225 break;
1218 1226 //TODO: add more printing for other variant types
1219 1227 default:
1220 1228 // this creates a copy, but that should not be expensive for typical simple variants
1221 1229 // (but we do not want to do this for our won user types!
1222 1230 if (type>0 && type < (int)QVariant::UserType) {
1223 1231 QVariant v(type, data);
1224 1232 r = v.toString();
1225 1233 }
1226 1234 }
1227 1235 return r;
1228 1236 }
@@ -1,351 +1,353
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtMethodInfo.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtMethodInfo.h"
43 43 #include "PythonQtClassInfo.h"
44 44 #include <iostream>
45 45
46 46 QHash<QByteArray, PythonQtMethodInfo*> PythonQtMethodInfo::_cachedSignatures;
47 47 QHash<QByteArray, QByteArray> PythonQtMethodInfo::_parameterNameAliases;
48 48
49 49 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo)
50 50 {
51 51 #ifdef PYTHONQT_DEBUG
52 52 QByteArray sig(meta.signature());
53 53 sig = sig.mid(sig.indexOf('('));
54 54 QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig;
55 55 std::cout << "caching " << fullSig.data() << std::endl;
56 56 #endif
57 57
58 58 ParameterInfo type;
59 59 fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
60 60 _parameters.append(type);
61 61 QList<QByteArray> names = meta.parameterTypes();
62 62 foreach (const QByteArray& name, names) {
63 63 fillParameterInfo(type, name, classInfo);
64 64 _parameters.append(type);
65 65 }
66 66 }
67 67
68 68 PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args)
69 69 {
70 70 ParameterInfo type;
71 71 fillParameterInfo(type, typeName, NULL);
72 72 _parameters.append(type);
73 73 foreach (const QByteArray& name, args) {
74 74 fillParameterInfo(type, name, NULL);
75 75 _parameters.append(type);
76 76 }
77 77 }
78 78
79 79 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
80 80 {
81 81 QByteArray sig(signal.signature());
82 82 sig = sig.mid(sig.indexOf('('));
83 83 QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig;
84 84 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
85 85 if (!result) {
86 86 result = new PythonQtMethodInfo(signal, classInfo);
87 87 _cachedSignatures.insert(fullSig, result);
88 88 }
89 89 return result;
90 90 }
91 91
92 92 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args)
93 93 {
94 94 QByteArray typeName = args[0];
95 95 QList<QByteArray> arguments;
96 96 QByteArray fullSig = typeName;
97 97 fullSig += "(";
98 98 for (int i =1;i<numArgs; i++) {
99 99 if (i>1) {
100 100 fullSig += ",";
101 101 }
102 102 arguments << QByteArray(args[i]);
103 103 }
104 104 fullSig += ")";
105 105 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
106 106 if (!result) {
107 107 result = new PythonQtMethodInfo(typeName, arguments);
108 108 _cachedSignatures.insert(fullSig, result);
109 109 }
110 110 return result;
111 111 }
112 112
113 113 void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
114 114 {
115 115 QByteArray name = orgName;
116 116
117 117 type.enumWrapper = NULL;
118 118
119 119 int len = name.length();
120 120 if (len>0) {
121 121 if (strncmp(name.constData(), "const ", 6)==0) {
122 122 name = name.mid(6);
123 123 len -= 6;
124 124 type.isConst = true;
125 125 } else {
126 126 type.isConst = false;
127 127 }
128 bool hadPointer = false;
128 char pointerCount = 0;
129 129 bool hadReference = false;
130 130 // remove * and & from the end of the string, handle & and * the same way
131 131 while (name.at(len-1) == '*') {
132 132 len--;
133 hadPointer = true;
133 pointerCount++;
134 134 }
135 135 while (name.at(len-1) == '&') {
136 136 len--;
137 137 hadReference = true;
138 138 }
139 139 if (len!=name.length()) {
140 140 name = name.left(len);
141 141 }
142 type.isPointer = hadPointer;
142 type.pointerCount = pointerCount;
143 143
144 144 QByteArray alias = _parameterNameAliases.value(name);
145 145 if (!alias.isEmpty()) {
146 146 name = alias;
147 147 }
148 148
149 149 type.typeId = nameToType(name);
150 if (!type.isPointer && type.typeId == Unknown) {
150 if ((type.pointerCount == 0) && type.typeId == Unknown) {
151 151 type.typeId = QMetaType::type(name.constData());
152 152 if (type.typeId == QMetaType::Void) {
153 153 type.typeId = Unknown;
154 154 }
155 155 }
156 156 type.name = name;
157 157
158 158 if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) {
159 159 bool isLocalEnum;
160 160 // TODOXXX: make use of this flag!
161 161 type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, &isLocalEnum);
162 162 }
163 163 } else {
164 164 type.typeId = QMetaType::Void;
165 type.isPointer = false;
165 type.pointerCount = 0;
166 166 type.isConst = false;
167 167 }
168 168 }
169 169
170 170 int PythonQtMethodInfo::nameToType(const char* name)
171 171 {
172 172 if (_parameterTypeDict.isEmpty()) {
173 173 // we could also use QMetaType::nameToType, but that does a string compare search
174 174 // and does not support QVariant
175 175
176 176 // QMetaType names
177 177 _parameterTypeDict.insert("long", QMetaType::Long);
178 178 _parameterTypeDict.insert("int", QMetaType::Int);
179 179 _parameterTypeDict.insert("short", QMetaType::Short);
180 180 _parameterTypeDict.insert("char", QMetaType::Char);
181 181 _parameterTypeDict.insert("ulong", QMetaType::ULong);
182 182 _parameterTypeDict.insert("unsigned long", QMetaType::ULong);
183 183 _parameterTypeDict.insert("uint", QMetaType::UInt);
184 184 _parameterTypeDict.insert("unsigned int", QMetaType::UInt);
185 185 _parameterTypeDict.insert("ushort", QMetaType::UShort);
186 186 _parameterTypeDict.insert("unsigned short", QMetaType::UShort);
187 187 _parameterTypeDict.insert("uchar", QMetaType::UChar);
188 188 _parameterTypeDict.insert("unsigned char", QMetaType::UChar);
189 189 _parameterTypeDict.insert("bool", QMetaType::Bool);
190 190 _parameterTypeDict.insert("float", QMetaType::Float);
191 191 _parameterTypeDict.insert("double", QMetaType::Double);
192 192 _parameterTypeDict.insert("qreal", QMetaType::Double);
193 193 _parameterTypeDict.insert("QChar", QMetaType::QChar);
194 194 _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray);
195 195 _parameterTypeDict.insert("Q3CString", QMetaType::QByteArray);
196 196 _parameterTypeDict.insert("QString", QMetaType::QString);
197 197 _parameterTypeDict.insert("", QMetaType::Void);
198 198 _parameterTypeDict.insert("void", QMetaType::Void);
199 199 // QVariant names
200 200 _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong);
201 201 _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong);
202 202 _parameterTypeDict.insert("qlonglong", QMetaType::LongLong);
203 203 _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong);
204 204 _parameterTypeDict.insert("qint64", QMetaType::LongLong);
205 205 _parameterTypeDict.insert("quint64", QMetaType::ULongLong);
206 206 _parameterTypeDict.insert("QIconSet", QMetaType::QIcon);
207 207 _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap);
208 208 _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList);
209 209 _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap);
210 210 _parameterTypeDict.insert("QList<QVariant>", QMetaType::QVariantList);
211 211 _parameterTypeDict.insert("QStringList", QMetaType::QStringList);
212 212 _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray);
213 213 _parameterTypeDict.insert("QDate", QMetaType::QDate);
214 214 _parameterTypeDict.insert("QTime", QMetaType::QTime);
215 215 _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime);
216 216 _parameterTypeDict.insert("QUrl", QMetaType::QUrl);
217 217 _parameterTypeDict.insert("QLocale", QMetaType::QLocale);
218 218 _parameterTypeDict.insert("QRect", QMetaType::QRect);
219 219 _parameterTypeDict.insert("QRectf", QMetaType::QRectF);
220 220 _parameterTypeDict.insert("QSize", QMetaType::QSize);
221 221 _parameterTypeDict.insert("QSizef", QMetaType::QSizeF);
222 222 _parameterTypeDict.insert("QLine", QMetaType::QLine);
223 223 _parameterTypeDict.insert("QLinef", QMetaType::QLineF);
224 224 _parameterTypeDict.insert("QPoint", QMetaType::QPoint);
225 225 _parameterTypeDict.insert("QPointf", QMetaType::QPointF);
226 226 _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp);
227 227 // _parameterTypeDict.insert("QColorGroup", QMetaType::QColorGroup);
228 228 _parameterTypeDict.insert("QFont", QMetaType::QFont);
229 229 _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap);
230 230 _parameterTypeDict.insert("QBrush", QMetaType::QBrush);
231 231 _parameterTypeDict.insert("QColor", QMetaType::QColor);
232 232 _parameterTypeDict.insert("QCursor", QMetaType::QCursor);
233 233 _parameterTypeDict.insert("QPalette", QMetaType::QPalette);
234 234 _parameterTypeDict.insert("QIcon", QMetaType::QIcon);
235 235 _parameterTypeDict.insert("QImage", QMetaType::QPolygon);
236 236 _parameterTypeDict.insert("QRegion", QMetaType::QRegion);
237 237 _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap);
238 238 _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy);
239 239 _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence);
240 240 _parameterTypeDict.insert("QPen", QMetaType::QPen);
241 241 _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength);
242 242 _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat);
243 243 _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix);
244 244 _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant);
245 245 // own special types... (none so far, could be e.g. ObjectList
246 246 }
247 247 QHash<QByteArray, int>::const_iterator it = _parameterTypeDict.find(name);
248 248 if (it!=_parameterTypeDict.end()) {
249 249 return it.value();
250 250 } else {
251 251 return PythonQtMethodInfo::Unknown;
252 252 }
253 253 }
254 254
255 255 void PythonQtMethodInfo::cleanupCachedMethodInfos()
256 256 {
257 257 QHashIterator<QByteArray, PythonQtMethodInfo *> i(_cachedSignatures);
258 258 while (i.hasNext()) {
259 259 delete i.next().value();
260 260 }
261 261 }
262 262
263 263 void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name)
264 264 {
265 265 _parameterNameAliases.insert(alias, name);
266 266 }
267 267
268 268 //-------------------------------------------------------------------------------------------------
269 269
270 270 void PythonQtSlotInfo::deleteOverloadsAndThis()
271 271 {
272 272 PythonQtSlotInfo* cur = this;
273 273 while(cur->nextInfo()) {
274 274 PythonQtSlotInfo* next = cur->nextInfo();
275 275 delete cur;
276 276 cur = next;
277 277 }
278 278 }
279 279
280 280
281 281 QString PythonQtSlotInfo::fullSignature()
282 282 {
283 283 bool skipFirstArg = isInstanceDecorator();
284 284 QString result = _meta.typeName();
285 285 QByteArray sig = slotName();
286 286 QList<QByteArray> names = _meta.parameterNames();
287 287
288 288 bool isStatic = false;
289 289 bool isConstructor = false;
290 290 bool isDestructor = false;
291 291
292 292 if (_type == ClassDecorator) {
293 293 if (sig.startsWith("new_")) {
294 294 sig = sig.mid(strlen("new_"));
295 295 isConstructor = true;
296 296 } else if (sig.startsWith("delete_")) {
297 297 sig = sig.mid(strlen("delete_"));
298 298 isDestructor = true;
299 299 } else if(sig.startsWith("static_")) {
300 300 isStatic = true;
301 301 sig = sig.mid(strlen("static_"));
302 302 int idx = sig.indexOf("_");
303 303 if (idx>=0) {
304 304 sig = sig.mid(idx+1);
305 305 }
306 306 }
307 307 }
308 308
309 309 result += QByteArray(" ") + sig;
310 310 result += "(";
311 311
312 312 int lastEntry = _parameters.count()-1;
313 313 for (int i = skipFirstArg?2:1; i<_parameters.count(); i++) {
314 314 if (_parameters.at(i).isConst) {
315 315 result += "const ";
316 316 }
317 317 result += _parameters.at(i).name;
318 if (_parameters.at(i).isPointer) {
319 result += "*";
318 if (_parameters.at(i).pointerCount) {
319 QByteArray stars;
320 stars.fill('*', _parameters.at(i).pointerCount);
321 result += stars;
320 322 }
321 323 if (!names.at(i-1).isEmpty()) {
322 324 result += " ";
323 325 result += names.at(i-1);
324 326 }
325 327 if (i!=lastEntry) {
326 328 result += ", ";
327 329 }
328 330 }
329 331 result += ")";
330 332
331 333 if (isStatic) {
332 334 result = QString("static ") + result;
333 335 }
334 336 if (isConstructor) {
335 337 // result = QString("constructor ") + result;
336 338 }
337 339 if (isDestructor) {
338 340 result = QString("~") + result;
339 341 }
340 342 return result;
341 343 }
342 344
343 345
344 346 QByteArray PythonQtSlotInfo::slotName()
345 347 {
346 348 QByteArray sig(_meta.signature());
347 349 int idx = sig.indexOf('(');
348 350 sig = sig.left(idx);
349 351 return sig;
350 352 }
351 353
@@ -1,190 +1,190
1 1 #ifndef _PYTHONQTMETHODINFO_H
2 2 #define _PYTHONQTMETHODINFO_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQtMethodInfo.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46
47 47 #include <QByteArray>
48 48 #include <QHash>
49 49 #include <QList>
50 50 #include <QMetaMethod>
51 51
52 52 class PythonQtClassInfo;
53 53 struct _object;
54 54 typedef struct _object PyObject;
55 55
56 56 //! stores information about a specific signal/slot/method
57 57 class PYTHONQT_EXPORT PythonQtMethodInfo
58 58 {
59 59 public:
60 60 enum ParameterType {
61 61 Unknown = -1,
62 62 Variant = -2
63 63 };
64 64
65 65 //! stores the QVariant id (if available) and the name of the type
66 66 struct ParameterInfo {
67 67 QByteArray name;
68 68 PyObject* enumWrapper; // if it is an enum, a pointer to the enum wrapper
69 69 int typeId; // a mixture from QMetaType and ParameterType
70 bool isPointer;
70 char pointerCount; // the number of pointers indirections
71 71 bool isConst;
72 72 };
73 73
74 74 PythonQtMethodInfo() {};
75 75 ~PythonQtMethodInfo() {};
76 76 PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo);
77 77 PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args);
78 78 PythonQtMethodInfo(const PythonQtMethodInfo& other) {
79 79 _parameters = other._parameters;
80 80 }
81 81
82 82 //! returns the method info of the signature, uses a cache internally to speed up
83 83 //! multiple requests for the same method, classInfo is passed to allow local enum resolution (if NULL is passed, no local enums are recognized)
84 84 static const PythonQtMethodInfo* getCachedMethodInfo(const QMetaMethod& method, PythonQtClassInfo* classInfo);
85 85
86 86 //! get the cached method info using the passed in list of return value and arguments, return value needs to be passed as first arg
87 87 static const PythonQtMethodInfo* getCachedMethodInfoFromArgumentList(int numArgs, const char** args);
88 88
89 89 //! cleanup the cache
90 90 static void cleanupCachedMethodInfos();
91 91
92 92 //! returns the number of parameters including the return value
93 93 int parameterCount() const { return _parameters.size(); };
94 94
95 95 //! returns the id for the given type (using an internal dictionary)
96 96 static int nameToType(const char* name);
97 97
98 98 //! get the parameter infos
99 99 const QList<ParameterInfo>& parameters() const { return _parameters; }
100 100
101 101 //! add an alias for a typename, e.g. QObjectList and QList<QObject*>.
102 102 static void addParameterTypeAlias(const QByteArray& alias, const QByteArray& name);
103 103
104 104 protected:
105 105 static void fillParameterInfo(ParameterInfo& type, const QByteArray& name, PythonQtClassInfo* classInfo);
106 106
107 107 static QHash<QByteArray, int> _parameterTypeDict;
108 108 static QHash<QByteArray, QByteArray> _parameterNameAliases;
109 109
110 110 //! stores the cached signatures of methods to speedup mapping from Qt to Python types
111 111 static QHash<QByteArray, PythonQtMethodInfo*> _cachedSignatures;
112 112
113 113 QList<ParameterInfo> _parameters;
114 114 };
115 115
116 116 //! stores information about a slot, including a next pointer to overloaded slots
117 117 class PythonQtSlotInfo : public PythonQtMethodInfo
118 118 {
119 119 public:
120 120 enum Type {
121 121 MemberSlot, InstanceDecorator, ClassDecorator
122 122 };
123 123
124 124 PythonQtSlotInfo(const PythonQtSlotInfo& info):PythonQtMethodInfo() {
125 125 _meta = info._meta;
126 126 _parameters = info._parameters;
127 127 _slotIndex = info._slotIndex;
128 128 _next = NULL;
129 129 _decorator = info._decorator;
130 130 _type = info._type;
131 131 _upcastingOffset = 0;
132 132 }
133 133
134 134 PythonQtSlotInfo(PythonQtClassInfo* classInfo, const QMetaMethod& meta, int slotIndex, QObject* decorator = NULL, Type type = MemberSlot ):PythonQtMethodInfo()
135 135 {
136 136 const PythonQtMethodInfo* info = getCachedMethodInfo(meta, classInfo);
137 137 _meta = meta;
138 138 _parameters = info->parameters();
139 139 _slotIndex = slotIndex;
140 140 _next = NULL;
141 141 _decorator = decorator;
142 142 _type = type;
143 143 _upcastingOffset = 0;
144 144 }
145 145
146 146
147 147 public:
148 148
149 149 void deleteOverloadsAndThis();
150 150
151 151 const QMetaMethod* metaMethod() const { return &_meta; }
152 152
153 153 void setUpcastingOffset(int upcastingOffset) { _upcastingOffset = upcastingOffset; }
154 154
155 155 int upcastingOffset() const { return _upcastingOffset; }
156 156
157 157 //! get the index of the slot (needed for qt_metacall)
158 158 int slotIndex() const { return _slotIndex; }
159 159
160 160 //! get next overloaded slot (which has the same name)
161 161 PythonQtSlotInfo* nextInfo() const { return _next; }
162 162
163 163 //! set the next overloaded slot
164 164 void setNextInfo(PythonQtSlotInfo* next) { _next = next; }
165 165
166 166 //! returns if the slot is a decorator slot
167 167 bool isInstanceDecorator() { return _decorator!=NULL && _type == InstanceDecorator; }
168 168
169 169 //! returns if the slot is a constructor slot
170 170 bool isClassDecorator() { return _decorator!=NULL && _type == ClassDecorator; }
171 171
172 172 QObject* decorator() { return _decorator; }
173 173
174 174 //! get the full signature including return type
175 175 QString fullSignature();
176 176
177 177 //! get the short slot name
178 178 QByteArray slotName();
179 179
180 180 private:
181 181 int _slotIndex;
182 182 PythonQtSlotInfo* _next;
183 183 QObject* _decorator;
184 184 Type _type;
185 185 QMetaMethod _meta;
186 186 int _upcastingOffset;
187 187 };
188 188
189 189
190 190 #endif
@@ -1,511 +1,509
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtSlot.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtSlot.h"
44 44 #include "PythonQtInstanceWrapper.h"
45 45 #include "PythonQtClassInfo.h"
46 46 #include "PythonQtMisc.h"
47 47 #include "PythonQtConversion.h"
48 48 #include <iostream>
49 49
50 50 #define PYTHONQT_MAX_ARGS 32
51 51
52 52
53 53 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer)
54 54 {
55 55 static unsigned int recursiveEntry = 0;
56 56
57 57 if (directReturnValuePointer) {
58 58 *directReturnValuePointer = NULL;
59 59 }
60 60 // store the current storage position, so that we can get back to this state after a slot is called
61 61 // (do this locally, so that we have all positions on the stack
62 62 PythonQtValueStoragePosition globalValueStoragePos;
63 63 PythonQtValueStoragePosition globalPtrStoragePos;
64 64 PythonQtValueStoragePosition globalVariantStoragePos;
65 65 PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
66 66 PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
67 67 PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
68 68
69 69 recursiveEntry++;
70 70
71 71 // the arguments that are passed to qt_metacall
72 72 void* argList[PYTHONQT_MAX_ARGS];
73 73 PyObject* result = NULL;
74 74 int argc = info->parameterCount();
75 75 const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
76 76
77 77 const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
78 78 // set return argument to NULL
79 79 argList[0] = NULL;
80 80
81 81 bool ok = true;
82 82 bool skipFirst = false;
83 83 if (info->isInstanceDecorator()) {
84 84 skipFirst = true;
85 85
86 86 // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer
87 87 void* arg1 = firstArgument;
88 88 if (!arg1) {
89 89 arg1 = objectToCall;
90 90 }
91 91 if (arg1) {
92 92 // upcast to correct parent class
93 93 arg1 = ((char*)arg1)+info->upcastingOffset();
94 94 }
95 95
96 96 argList[1] = &arg1;
97 97 if (ok) {
98 98 for (int i = 2; i<argc && ok; i++) {
99 99 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
100 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
101 100 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo);
102 101 if (argList[i]==NULL) {
103 102 ok = false;
104 103 break;
105 104 }
106 105 }
107 106 }
108 107 } else {
109 108 for (int i = 1; i<argc && ok; i++) {
110 109 const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
111 //std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
112 110 argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo);
113 111 if (argList[i]==NULL) {
114 112 ok = false;
115 113 break;
116 114 }
117 115 }
118 116 }
119 117
120 118 if (ok) {
121 119 // parameters are ok, now create the qt return value which is assigned to by metacall
122 120 if (returnValueParam.typeId != QMetaType::Void) {
123 121 // create empty default value for the return value
124 122 if (!directReturnValuePointer) {
125 123 // create empty default value for the return value
126 124 argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
127 125 if (argList[0]==NULL) {
128 126 // return value could not be created, maybe we have a registered class with a default constructor, so that we can construct the pythonqt wrapper object and
129 127 // pass its internal pointer
130 128 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name);
131 129 if (info && info->pythonQtClassWrapper()) {
132 130 PyObject* emptyTuple = PyTuple_New(0);
133 131 // 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments
134 132 result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL);
135 133 if (result) {
136 134 argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr;
137 135 }
138 136 Py_DECREF(emptyTuple);
139 137 }
140 138 }
141 139 } else {
142 140 // we can use our pointer directly!
143 141 argList[0] = directReturnValuePointer;
144 142 }
145 143 }
146 144
147 145 // invoke the slot via metacall
148 146 (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
149 147
150 148 // handle the return value (which in most cases still needs to be converted to a Python object)
151 149 if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
152 150 if (directReturnValuePointer) {
153 151 result = NULL;
154 152 } else {
155 153 // the resulting object maybe present already, because we created it above at 1)...
156 154 if (!result) {
157 155 result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
158 156 }
159 157 }
160 158 } else {
161 159 QString e = QString("Called ") + info->fullSignature() + ", return type '" + returnValueParam.name + "' is ignored because it is unknown to PythonQt. Probably you should register it using qRegisterMetaType() or add a default constructor decorator to the class.";
162 160 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
163 161 result = NULL;
164 162 }
165 163 }
166 164 recursiveEntry--;
167 165
168 166 // reset the parameter storage position to the stored pos to "pop" the parameter stack
169 167 PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
170 168 PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
171 169 PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
172 170
173 171 *pythonReturnValue = result;
174 172 // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
175 173 return result || (directReturnValuePointer && *directReturnValuePointer);
176 174 }
177 175
178 176 //-----------------------------------------------------------------------------------
179 177
180 178 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
181 179
182 180 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
183 181 {
184 182 PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
185 183 PythonQtSlotInfo* info = f->m_ml;
186 184 if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) {
187 185 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self;
188 186 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
189 187 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
190 188 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
191 189 return NULL;
192 190 } else {
193 191 return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr);
194 192 }
195 193 } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
196 194 PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self;
197 195 if (info->isClassDecorator()) {
198 196 return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw);
199 197 } else {
200 198 // otherwise, it is an unbound call and we have an instanceDecorator or normal slot...
201 199 Py_ssize_t argc = PyTuple_Size(args);
202 200 if (argc>0) {
203 201 PyObject* firstArg = PyTuple_GET_ITEM(args, 0);
204 202 if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type)
205 203 && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) {
206 204 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg;
207 205 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
208 206 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
209 207 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
210 208 return NULL;
211 209 }
212 210 // strip the first argument...
213 211 PyObject* newargs = PyTuple_GetSlice(args, 1, argc);
214 212 PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr);
215 213 Py_DECREF(newargs);
216 214 return result;
217 215 } else {
218 216 // first arg is not of correct type!
219 217 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name;
220 218 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
221 219 return NULL;
222 220 }
223 221 } else {
224 222 // wrong number of args
225 223 QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument.";
226 224 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
227 225 return NULL;
228 226 }
229 227 }
230 228 }
231 229 return NULL;
232 230 }
233 231
234 232 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer)
235 233 {
236 234 int argc = args?PyTuple_Size(args):0;
237 235
238 236 #ifdef PYTHONQT_DEBUG
239 237 std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
240 238 #endif
241 239
242 240 PyObject* r = NULL;
243 241 bool ok = false;
244 242 if (directReturnValuePointer) {
245 243 *directReturnValuePointer = NULL;
246 244 }
247 245 if (info->nextInfo()) {
248 246 // overloaded slot call, try on all slots with strict conversion first
249 247 bool strict = true;
250 248 PythonQtSlotInfo* i = info;
251 249 while (i) {
252 250 bool skipFirst = i->isInstanceDecorator();
253 251 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
254 252 PyErr_Clear();
255 253 ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer);
256 254 if (PyErr_Occurred() || ok) break;
257 255 }
258 256 i = i->nextInfo();
259 257 if (!i) {
260 258 if (strict) {
261 259 // one more run without being strict
262 260 strict = false;
263 261 i = info;
264 262 }
265 263 }
266 264 }
267 265 if (!ok && !PyErr_Occurred()) {
268 266 QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
269 267 PythonQtSlotInfo* i = info;
270 268 while (i) {
271 269 e += QString(i->fullSignature()) + "\n";
272 270 i = i->nextInfo();
273 271 }
274 272 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
275 273 }
276 274 } else {
277 275 // simple (non-overloaded) slot call
278 276 bool skipFirst = info->isInstanceDecorator();
279 277 if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
280 278 PyErr_Clear();
281 279 ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer);
282 280 if (!ok && !PyErr_Occurred()) {
283 281 QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
284 282 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
285 283 }
286 284 } else {
287 285 QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
288 286 PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
289 287 }
290 288 }
291 289
292 290 return r;
293 291 }
294 292
295 293 PyObject *
296 294 PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
297 295 {
298 296 PythonQtSlotFunctionObject *op;
299 297 op = pythonqtslot_free_list;
300 298 if (op != NULL) {
301 299 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
302 300 PyObject_INIT(op, &PythonQtSlotFunction_Type);
303 301 }
304 302 else {
305 303 op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
306 304 if (op == NULL)
307 305 return NULL;
308 306 }
309 307 op->m_ml = ml;
310 308 Py_XINCREF(self);
311 309 op->m_self = self;
312 310 Py_XINCREF(module);
313 311 op->m_module = module;
314 312 PyObject_GC_Track(op);
315 313 return (PyObject *)op;
316 314 }
317 315
318 316 PythonQtSlotInfo*
319 317 PythonQtSlotFunction_GetSlotInfo(PyObject *op)
320 318 {
321 319 if (!PythonQtSlotFunction_Check(op)) {
322 320 PyErr_BadInternalCall();
323 321 return NULL;
324 322 }
325 323 return ((PythonQtSlotFunctionObject *)op) -> m_ml;
326 324 }
327 325
328 326 PyObject *
329 327 PythonQtSlotFunction_GetSelf(PyObject *op)
330 328 {
331 329 if (!PythonQtSlotFunction_Check(op)) {
332 330 PyErr_BadInternalCall();
333 331 return NULL;
334 332 }
335 333 return ((PythonQtSlotFunctionObject *)op) -> m_self;
336 334 }
337 335
338 336 /* Methods (the standard built-in methods, that is) */
339 337
340 338 static void
341 339 meth_dealloc(PythonQtSlotFunctionObject *m)
342 340 {
343 341 PyObject_GC_UnTrack(m);
344 342 Py_XDECREF(m->m_self);
345 343 Py_XDECREF(m->m_module);
346 344 m->m_self = (PyObject *)pythonqtslot_free_list;
347 345 pythonqtslot_free_list = m;
348 346 }
349 347
350 348 static PyObject *
351 349 meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
352 350 {
353 351 Py_INCREF(Py_None);
354 352 return Py_None;
355 353 }
356 354
357 355 static PyObject *
358 356 meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
359 357 {
360 358 return PyString_FromString(m->m_ml->metaMethod()->signature());
361 359 }
362 360
363 361 static int
364 362 meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
365 363 {
366 364 int err;
367 365 if (m->m_self != NULL) {
368 366 err = visit(m->m_self, arg);
369 367 if (err)
370 368 return err;
371 369 }
372 370 if (m->m_module != NULL) {
373 371 err = visit(m->m_module, arg);
374 372 if (err)
375 373 return err;
376 374 }
377 375 return 0;
378 376 }
379 377
380 378 static PyObject *
381 379 meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
382 380 {
383 381 PyObject *self;
384 382 if (PyEval_GetRestricted()) {
385 383 PyErr_SetString(PyExc_RuntimeError,
386 384 "method.__self__ not accessible in restricted mode");
387 385 return NULL;
388 386 }
389 387 self = m->m_self;
390 388 if (self == NULL)
391 389 self = Py_None;
392 390 Py_INCREF(self);
393 391 return self;
394 392 }
395 393
396 394 static PyGetSetDef meth_getsets [] = {
397 395 {"__doc__", (getter)meth_get__doc__, NULL, NULL},
398 396 {"__name__", (getter)meth_get__name__, NULL, NULL},
399 397 {"__self__", (getter)meth_get__self__, NULL, NULL},
400 398 {NULL, NULL, NULL,NULL},
401 399 };
402 400
403 401 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
404 402 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
405 403 #endif
406 404
407 405 #define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
408 406
409 407 static PyMemberDef meth_members[] = {
410 408 {"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
411 409 {NULL}
412 410 };
413 411
414 412 static PyObject *
415 413 meth_repr(PythonQtSlotFunctionObject *f)
416 414 {
417 415 if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
418 416 PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self;
419 417 return PyString_FromFormat("<unbound qt slot %s of %s type>",
420 418 f->m_ml->slotName().data(),
421 419 self->classInfo()->className());
422 420 } else {
423 421 return PyString_FromFormat("<qt slot %s of %s instance at %p>",
424 422 f->m_ml->slotName().data(),
425 423 f->m_self->ob_type->tp_name,
426 424 f->m_self);
427 425 }
428 426 }
429 427
430 428 static int
431 429 meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
432 430 {
433 431 if (a->m_self != b->m_self)
434 432 return (a->m_self < b->m_self) ? -1 : 1;
435 433 if (a->m_ml == b->m_ml)
436 434 return 0;
437 435 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
438 436 return -1;
439 437 else
440 438 return 1;
441 439 }
442 440
443 441 static long
444 442 meth_hash(PythonQtSlotFunctionObject *a)
445 443 {
446 444 long x,y;
447 445 if (a->m_self == NULL)
448 446 x = 0;
449 447 else {
450 448 x = PyObject_Hash(a->m_self);
451 449 if (x == -1)
452 450 return -1;
453 451 }
454 452 y = _Py_HashPointer((void*)(a->m_ml));
455 453 if (y == -1)
456 454 return -1;
457 455 x ^= y;
458 456 if (x == -1)
459 457 x = -2;
460 458 return x;
461 459 }
462 460
463 461
464 462 PyTypeObject PythonQtSlotFunction_Type = {
465 463 PyObject_HEAD_INIT(&PyType_Type)
466 464 0,
467 465 "builtin_qt_slot",
468 466 sizeof(PythonQtSlotFunctionObject),
469 467 0,
470 468 (destructor)meth_dealloc, /* tp_dealloc */
471 469 0, /* tp_print */
472 470 0, /* tp_getattr */
473 471 0, /* tp_setattr */
474 472 (cmpfunc)meth_compare, /* tp_compare */
475 473 (reprfunc)meth_repr, /* tp_repr */
476 474 0, /* tp_as_number */
477 475 0, /* tp_as_sequence */
478 476 0, /* tp_as_mapping */
479 477 (hashfunc)meth_hash, /* tp_hash */
480 478 PythonQtSlotFunction_Call, /* tp_call */
481 479 0, /* tp_str */
482 480 PyObject_GenericGetAttr, /* tp_getattro */
483 481 0, /* tp_setattro */
484 482 0, /* tp_as_buffer */
485 483 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
486 484 0, /* tp_doc */
487 485 (traverseproc)meth_traverse, /* tp_traverse */
488 486 0, /* tp_clear */
489 487 0, /* tp_richcompare */
490 488 0, /* tp_weaklistoffset */
491 489 0, /* tp_iter */
492 490 0, /* tp_iternext */
493 491 0, /* tp_methods */
494 492 meth_members, /* tp_members */
495 493 meth_getsets, /* tp_getset */
496 494 0, /* tp_base */
497 495 0, /* tp_dict */
498 496 };
499 497
500 498 /* Clear out the free list */
501 499
502 500 void
503 501 PythonQtSlotFunction_Fini(void)
504 502 {
505 503 while (pythonqtslot_free_list) {
506 504 PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
507 505 pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
508 506 PyObject_GC_Del(v);
509 507 }
510 508 }
511 509
General Comments 0
You need to be logged in to leave comments. Login now