##// END OF EJS Templates
performance improvement (merged from MeVisLab PythonQt)...
florianlink -
r198:0dcd933258e0
parent child
Show More
@@ -1,1793 +1,1796
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 "PythonQtSignal.h"
47 47 #include "PythonQtSignalReceiver.h"
48 48 #include "PythonQtConversion.h"
49 49 #include "PythonQtStdIn.h"
50 50 #include "PythonQtStdOut.h"
51 51 #include "PythonQtCppWrapperFactory.h"
52 52 #include "PythonQtVariants.h"
53 53 #include "PythonQtStdDecorators.h"
54 54 #include "PythonQtQFileImporter.h"
55 55 #include <pydebug.h>
56 56 #include <vector>
57 57
58 58 PythonQt* PythonQt::_self = NULL;
59 59 int PythonQt::_uniqueModuleCount = 0;
60 60
61 61 void PythonQt_init_QtGuiBuiltin(PyObject*);
62 62 void PythonQt_init_QtCoreBuiltin(PyObject*);
63 63
64 64
65 65 PyObject* PythonQtConvertFromStringRef(const void* inObject, int /*metaTypeId*/)
66 66 {
67 67 return PythonQtConv::QStringToPyObject(((QStringRef*)inObject)->toString());
68 68 }
69 69
70 70 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
71 71 {
72 72 if (!_self) {
73 73 _self = new PythonQt(flags, pythonQtModuleName);
74 74
75 75 PythonQt::priv()->setupSharedLibrarySuffixes();
76 76
77 77 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
78 78 qRegisterMetaType<QList<QObject*> >("QList<void*>");
79 79
80 80 int stringRefId = qRegisterMetaType<QStringRef>("QStringRef");
81 81 PythonQtConv::registerMetaTypeToPythonConverter(stringRefId, PythonQtConvertFromStringRef);
82 82
83 83 PythonQtRegisterToolClassesTemplateConverter(int);
84 84 PythonQtRegisterToolClassesTemplateConverter(float);
85 85 PythonQtRegisterToolClassesTemplateConverter(double);
86 86 PythonQtRegisterToolClassesTemplateConverter(qint32);
87 87 PythonQtRegisterToolClassesTemplateConverter(quint32);
88 88 PythonQtRegisterToolClassesTemplateConverter(qint64);
89 89 PythonQtRegisterToolClassesTemplateConverter(quint64);
90 90 // TODO: which other POD types should be available for QList etc.
91 91
92 92 PythonQt_init_QtCoreBuiltin(NULL);
93 93 PythonQt_init_QtGuiBuiltin(NULL);
94 94
95 95 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
96 96 PythonQt::self()->registerCPPClass("QMetaObject",0, "QtCore", PythonQtCreateObject<PythonQtWrapper_QMetaObject>);
97 97
98 98 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
99 99 PythonQtRegisterToolClassesTemplateConverter(QDate);
100 100 PythonQtRegisterToolClassesTemplateConverter(QTime);
101 101 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
102 102 PythonQtRegisterToolClassesTemplateConverter(QUrl);
103 103 PythonQtRegisterToolClassesTemplateConverter(QLocale);
104 104 PythonQtRegisterToolClassesTemplateConverter(QRect);
105 105 PythonQtRegisterToolClassesTemplateConverter(QRectF);
106 106 PythonQtRegisterToolClassesTemplateConverter(QSize);
107 107 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
108 108 PythonQtRegisterToolClassesTemplateConverter(QLine);
109 109 PythonQtRegisterToolClassesTemplateConverter(QLineF);
110 110 PythonQtRegisterToolClassesTemplateConverter(QPoint);
111 111 PythonQtRegisterToolClassesTemplateConverter(QPointF);
112 112 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
113 113
114 114 PythonQtRegisterToolClassesTemplateConverter(QFont);
115 115 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
116 116 PythonQtRegisterToolClassesTemplateConverter(QBrush);
117 117 PythonQtRegisterToolClassesTemplateConverter(QColor);
118 118 PythonQtRegisterToolClassesTemplateConverter(QPalette);
119 119 PythonQtRegisterToolClassesTemplateConverter(QIcon);
120 120 PythonQtRegisterToolClassesTemplateConverter(QImage);
121 121 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
122 122 PythonQtRegisterToolClassesTemplateConverter(QRegion);
123 123 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
124 124 PythonQtRegisterToolClassesTemplateConverter(QCursor);
125 125 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
126 126 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
127 127 PythonQtRegisterToolClassesTemplateConverter(QPen);
128 128 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
129 129 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
130 130 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
131 131
132 132
133 133 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
134 134 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
135 135 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
136 136 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
137 137 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
138 138 for (unsigned int i = 0;i<16; i++) {
139 139 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
140 140 if (obj) {
141 141 PyModule_AddObject(pack, names[i], obj);
142 142 Py_INCREF(obj);
143 143 PyModule_AddObject(pack2, names[i], obj);
144 144 } else {
145 145 std::cerr << "method not found " << names[i];
146 146 }
147 147 }
148 148 }
149 149 }
150 150
151 151 void PythonQt::cleanup()
152 152 {
153 153 if (_self) {
154 154 delete _self;
155 155 _self = NULL;
156 156 }
157 157 }
158 158
159 159 PythonQt* PythonQt::self() { return _self; }
160 160
161 161 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
162 162 {
163 163 _p = new PythonQtPrivate;
164 164 _p->_initFlags = flags;
165 165
166 166 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
167 167
168 168 if ((flags & PythonAlreadyInitialized) == 0) {
169 169 Py_SetProgramName(const_cast<char*>("PythonQt"));
170 170 if (flags & IgnoreSiteModule) {
171 171 // this prevents the automatic importing of Python site files
172 172 Py_NoSiteFlag = 1;
173 173 }
174 174 Py_Initialize();
175 175 }
176 176
177 177 // add our own python object types for qt object slots
178 178 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
179 179 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
180 180 }
181 181 Py_INCREF(&PythonQtSlotFunction_Type);
182 182
183 183 if (PyType_Ready(&PythonQtSignalFunction_Type) < 0) {
184 184 std::cerr << "could not initialize PythonQtSignalFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 185 }
186 186 Py_INCREF(&PythonQtSignalFunction_Type);
187 187
188 188 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
189 189 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
190 190 // add our own python object types for classes
191 191 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
192 192 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
193 193 }
194 194 Py_INCREF(&PythonQtClassWrapper_Type);
195 195
196 196 // add our own python object types for CPP instances
197 197 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
198 198 PythonQt::handleError();
199 199 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
200 200 }
201 201 Py_INCREF(&PythonQtInstanceWrapper_Type);
202 202
203 203 // add our own python object types for redirection of stdout
204 204 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
205 205 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
206 206 }
207 207 Py_INCREF(&PythonQtStdOutRedirectType);
208 208
209 209 // add our own python object types for redirection of stdin
210 210 if (PyType_Ready(&PythonQtStdInRedirectType) < 0) {
211 211 std::cerr << "could not initialize PythonQtStdInRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
212 212 }
213 213 Py_INCREF(&PythonQtStdInRedirectType);
214 214
215 215 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
216 216
217 217 }
218 218
219 219 PythonQt::~PythonQt() {
220 220 delete _p;
221 221 _p = NULL;
222 222 }
223 223
224 224 PythonQtPrivate::~PythonQtPrivate() {
225 225 delete _defaultImporter;
226 226 _defaultImporter = NULL;
227 227
228 228 {
229 229 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
230 230 while (i.hasNext()) {
231 231 delete i.next().value();
232 232 }
233 233 }
234 234 PythonQtConv::global_valueStorage.clear();
235 235 PythonQtConv::global_ptrStorage.clear();
236 236 PythonQtConv::global_variantStorage.clear();
237 237
238 238 PythonQtMethodInfo::cleanupCachedMethodInfos();
239 239 }
240 240
241 241 void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData)
242 242 {
243 243 if (!callback)
244 244 {
245 245 std::cerr << "PythonQt::setRedirectStdInCallback - callback parameter is NULL !" << std::endl;
246 246 return;
247 247 }
248 248
249 249 PythonQtObjectPtr sys;
250 250 PythonQtObjectPtr in;
251 251 sys.setNewRef(PyImport_ImportModule("sys"));
252 252
253 253 // Backup original 'sys.stdin' if not yet done
254 254 PyRun_SimpleString("if not hasattr(sys, 'pythonqt_original_stdin'):"
255 255 "sys.pythonqt_original_stdin = sys.stdin");
256 256
257 257 in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, NULL, NULL);
258 258 ((PythonQtStdInRedirect*)in.object())->_cb = callback;
259 259 ((PythonQtStdInRedirect*)in.object())->_callData = callbackData;
260 260 // replace the built in file objects with our own objects
261 261 PyModule_AddObject(sys, "stdin", in);
262 262
263 263 // Backup custom 'stdin' into 'pythonqt_stdin'
264 264 PyRun_SimpleString("sys.pythonqt_stdin = sys.stdin");
265 265 }
266 266
267 267 void PythonQt::setRedirectStdInCallbackEnabled(bool enabled)
268 268 {
269 269 if (enabled)
270 270 {
271 271 PyRun_SimpleString("if hasattr(sys, 'pythonqt_stdin'):"
272 272 "sys.stdin = sys.pythonqt_stdin");
273 273 }
274 274 else
275 275 {
276 276 PyRun_SimpleString("if hasattr(sys,'pythonqt_original_stdin'):"
277 277 "sys.stdin = sys.pythonqt_original_stdin");
278 278 }
279 279 }
280 280
281 281 PythonQtImportFileInterface* PythonQt::importInterface()
282 282 {
283 283 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
284 284 }
285 285
286 286 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
287 287 {
288 288 if (_self->_p->_noLongerWrappedCB) {
289 289 (*_self->_p->_noLongerWrappedCB)(o);
290 290 };
291 291 }
292 292
293 293 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
294 294 {
295 295 _p->registerClass(metaobject, package, wrapperCreator, shell);
296 296 }
297 297
298 298 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
299 299 {
300 300 // we register all classes in the hierarchy
301 301 const QMetaObject* m = metaobject;
302 302 bool first = true;
303 303 while (m) {
304 304 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
305 305 if (!info->pythonQtClassWrapper()) {
306 306 info->setTypeSlots(typeSlots);
307 307 info->setupQObject(m);
308 308 createPythonQtClassWrapper(info, package, module);
309 309 if (m->superClass()) {
310 310 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
311 311 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
312 312 }
313 313 } else if (first && module) {
314 314 // There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
315 315 // since it might have been placed into "private" earlier on.
316 316 // If the wrapper was already added to module before, it is just readded, which does no harm.
317 317 PyObject* classWrapper = info->pythonQtClassWrapper();
318 318 // AddObject steals a reference, so we need to INCREF
319 319 Py_INCREF(classWrapper);
320 320 PyModule_AddObject(module, info->className(), classWrapper);
321 321 }
322 322 if (first) {
323 323 first = false;
324 324 if (wrapperCreator) {
325 325 info->setDecoratorProvider(wrapperCreator);
326 326 }
327 327 if (shell) {
328 328 info->setShellSetInstanceWrapperCB(shell);
329 329 }
330 330 }
331 331 m = m->superClass();
332 332 }
333 333 }
334 334
335 335 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
336 336 {
337 337 PyObject* pack = module?module:packageByName(package);
338 338 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
339 339 PyModule_AddObject(pack, info->className(), pyobj);
340 340 if (!module && package && strncmp(package,"Qt",2)==0) {
341 341 // since PyModule_AddObject steals the reference, we need a incref once more...
342 342 Py_INCREF(pyobj);
343 343 // put all qt objects into Qt as well
344 344 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
345 345 }
346 346 info->setPythonQtClassWrapper(pyobj);
347 347 }
348 348
349 349 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
350 350 {
351 351 if (!obj) {
352 352 Py_INCREF(Py_None);
353 353 return Py_None;
354 354 }
355 355 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
356 356 if (wrap && wrap->_wrappedPtr) {
357 357 // uh oh, we want to wrap a QObject, but have a C++ wrapper at that
358 358 // address, so probably that C++ wrapper has been deleted earlier and
359 359 // now we see a QObject with the same address.
360 360 // Do not use the old wrapper anymore.
361 361 wrap = NULL;
362 362 }
363 363 if (!wrap) {
364 364 // smuggling it in...
365 365 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
366 366 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
367 367 registerClass(obj->metaObject());
368 368 classInfo = _knownClassInfos.value(obj->metaObject()->className());
369 369 }
370 370 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
371 371 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
372 372 } else {
373 373 Py_INCREF(wrap);
374 374 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
375 375 }
376 376 return (PyObject*)wrap;
377 377 }
378 378
379 379 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
380 380 {
381 381 if (!ptr) {
382 382 Py_INCREF(Py_None);
383 383 return Py_None;
384 384 }
385 385
386 386 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
387 387 PythonQtInstanceWrapper* possibleStillAliveWrapper = NULL;
388 388 if (wrap && wrap->_wrappedPtr) {
389 389 // we have a previous C++ wrapper... if the wrapper is for a C++ object,
390 390 // we are not sure if it may have been deleted earlier and we just see the same C++
391 391 // pointer once again. To make sure that we do not reuse a wrapper of the wrong type,
392 392 // we compare the classInfo() pointer and only reuse the wrapper if it has the same
393 393 // info. This is only needed for non-QObjects, since we know it when a QObject gets deleted.
394 394 possibleStillAliveWrapper = wrap;
395 395 wrap = NULL;
396 396 }
397 397 if (!wrap) {
398 398 PythonQtClassInfo* info = _knownClassInfos.value(name);
399 399 if (!info) {
400 400 // maybe it is a PyObject, which we can return directly
401 401 if (name == "PyObject") {
402 402 PyObject* p = (PyObject*)ptr;
403 403 Py_INCREF(p);
404 404 return p;
405 405 }
406 406
407 407 // we do not know the metaobject yet, but we might know it by its name:
408 408 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
409 409 // yes, we know it, so we can convert to QObject
410 410 QObject* qptr = (QObject*)ptr;
411 411 registerClass(qptr->metaObject());
412 412 info = _knownClassInfos.value(qptr->metaObject()->className());
413 413 }
414 414 }
415 415 if (info && info->isQObject()) {
416 416 QObject* qptr = (QObject*)ptr;
417 417 // if the object is a derived object, we want to switch the class info to the one of the derived class:
418 418 if (name!=(qptr->metaObject()->className())) {
419 registerClass(qptr->metaObject());
420 419 info = _knownClassInfos.value(qptr->metaObject()->className());
420 if (!info) {
421 registerClass(qptr->metaObject());
422 info = _knownClassInfos.value(qptr->metaObject()->className());
423 }
421 424 }
422 425 wrap = createNewPythonQtInstanceWrapper(qptr, info);
423 426 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
424 427 return (PyObject*)wrap;
425 428 }
426 429
427 430 // not a known QObject, try to wrap via foreign wrapper factories
428 431 PyObject* foreignWrapper = NULL;
429 432 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
430 433 foreignWrapper = _foreignWrapperFactories.at(i)->wrap(name, ptr);
431 434 if (foreignWrapper) {
432 435 return foreignWrapper;
433 436 }
434 437 }
435 438
436 439 // not a known QObject, so try our wrapper factory:
437 440 QObject* wrapper = NULL;
438 441 for (int i=0; i<_cppWrapperFactories.size(); i++) {
439 442 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
440 443 if (wrapper) {
441 444 break;
442 445 }
443 446 }
444 447
445 448 if (info) {
446 449 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
447 450 ptr = info->castDownIfPossible(ptr, &info);
448 451
449 452 // if downcasting found out that the object is a QObject,
450 453 // handle it like one:
451 454 if (info && info->isQObject()) {
452 455 QObject* qptr = (QObject*)ptr;
453 456 // if the object is a derived object, we want to switch the class info to the one of the derived class:
454 457 if (name!=(qptr->metaObject()->className())) {
455 458 registerClass(qptr->metaObject());
456 459 info = _knownClassInfos.value(qptr->metaObject()->className());
457 460 }
458 461 wrap = createNewPythonQtInstanceWrapper(qptr, info);
459 462 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
460 463 return (PyObject*)wrap;
461 464 }
462 465 }
463 466
464 467 if (!info || info->pythonQtClassWrapper()==NULL) {
465 468 // still unknown, register as CPP class
466 469 registerCPPClass(name.constData());
467 470 info = _knownClassInfos.value(name);
468 471 }
469 472 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
470 473 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
471 474 info->setMetaObject(wrapper->metaObject());
472 475 }
473 476
474 477 if (possibleStillAliveWrapper && possibleStillAliveWrapper->classInfo() == info) {
475 478 wrap = possibleStillAliveWrapper;
476 479 Py_INCREF(wrap);
477 480 } else {
478 481 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
479 482 }
480 483 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
481 484 } else {
482 485 Py_INCREF(wrap);
483 486 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
484 487 }
485 488 return (PyObject*)wrap;
486 489 }
487 490
488 491 PyObject* PythonQtPrivate::dummyTuple() {
489 492 static PyObject* dummyTuple = NULL;
490 493 if (dummyTuple==NULL) {
491 494 dummyTuple = PyTuple_New(1);
492 495 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
493 496 }
494 497 return dummyTuple;
495 498 }
496 499
497 500
498 501 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
499 502 // call the associated class type to create a new instance...
500 503 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
501 504
502 505 result->setQObject(obj);
503 506 result->_wrappedPtr = wrappedPtr;
504 507 result->_ownedByPythonQt = false;
505 508 result->_useQMetaTypeDestroy = false;
506 509
507 510 if (wrappedPtr) {
508 511 _wrappedObjects.insert(wrappedPtr, result);
509 512 } else {
510 513 _wrappedObjects.insert(obj, result);
511 514 if (obj->parent()== NULL && _wrappedCB) {
512 515 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
513 516 (*_wrappedCB)(obj);
514 517 }
515 518 }
516 519 return result;
517 520 }
518 521
519 522 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
520 523 PythonQtClassWrapper* result;
521 524
522 525 PyObject* className = PyString_FromString(info->className());
523 526
524 527 PyObject* baseClasses = PyTuple_New(1);
525 528 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
526 529
527 530 PyObject* typeDict = PyDict_New();
528 531 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
529 532 PyDict_SetItemString(typeDict, "__module__", moduleName);
530 533
531 534 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
532 535
533 536 // set the class info so that PythonQtClassWrapper_new can read it
534 537 _currentClassInfoForClassWrapperCreation = info;
535 538 // create the new type object by calling the type
536 539 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
537 540
538 541 Py_DECREF(baseClasses);
539 542 Py_DECREF(typeDict);
540 543 Py_DECREF(args);
541 544 Py_DECREF(className);
542 545
543 546 return result;
544 547 }
545 548
546 549 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
547 550 {
548 551 PyObject* args = Py_BuildValue("(i)", enumValue);
549 552 PyObject* result = PyObject_Call(enumType, args, NULL);
550 553 Py_DECREF(args);
551 554 return result;
552 555 }
553 556
554 557 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
555 558 PyObject* result;
556 559
557 560 PyObject* className = PyString_FromString(enumName);
558 561
559 562 PyObject* baseClasses = PyTuple_New(1);
560 563 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
561 564
562 565 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
563 566 PyObject* typeDict = PyDict_New();
564 567 PyDict_SetItemString(typeDict, "__module__", module);
565 568
566 569 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
567 570
568 571 // create the new int derived type object by calling the core type
569 572 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
570 573
571 574 Py_DECREF(baseClasses);
572 575 Py_DECREF(typeDict);
573 576 Py_DECREF(args);
574 577 Py_DECREF(className);
575 578
576 579 return result;
577 580 }
578 581
579 582 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
580 583 {
581 584 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
582 585 if (!r) {
583 586 r = new PythonQtSignalReceiver(obj);
584 587 _p->_signalReceivers.insert(obj, r);
585 588 }
586 589 return r;
587 590 }
588 591
589 592 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
590 593 {
591 594 bool flag = false;
592 595 PythonQtObjectPtr callable = lookupCallable(module, objectname);
593 596 if (callable) {
594 597 PythonQtSignalReceiver* r = getSignalReceiver(obj);
595 598 flag = r->addSignalHandler(signal, callable);
596 599 if (!flag) {
597 600 // signal not found
598 601 }
599 602 } else {
600 603 // callable not found
601 604 }
602 605 return flag;
603 606 }
604 607
605 608 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
606 609 {
607 610 bool flag = false;
608 611 PythonQtSignalReceiver* r = getSignalReceiver(obj);
609 612 if (r) {
610 613 flag = r->addSignalHandler(signal, receiver);
611 614 }
612 615 return flag;
613 616 }
614 617
615 618 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
616 619 {
617 620 bool flag = false;
618 621 PythonQtObjectPtr callable = lookupCallable(module, objectname);
619 622 if (callable) {
620 623 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
621 624 if (r) {
622 625 flag = r->removeSignalHandler(signal, callable);
623 626 }
624 627 } else {
625 628 // callable not found
626 629 }
627 630 return flag;
628 631 }
629 632
630 633 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
631 634 {
632 635 bool flag = false;
633 636 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
634 637 if (r) {
635 638 flag = r->removeSignalHandler(signal, receiver);
636 639 }
637 640 return flag;
638 641 }
639 642
640 643 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
641 644 {
642 645 PythonQtObjectPtr p = lookupObject(module, name);
643 646 if (p) {
644 647 if (PyCallable_Check(p)) {
645 648 return p;
646 649 }
647 650 }
648 651 PyErr_Clear();
649 652 return NULL;
650 653 }
651 654
652 655 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
653 656 {
654 657 QStringList l = name.split('.');
655 658 PythonQtObjectPtr p = module;
656 659 PythonQtObjectPtr prev;
657 660 QByteArray b;
658 661 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
659 662 prev = p;
660 663 b = (*i).toLatin1();
661 664 if (PyDict_Check(p)) {
662 665 p = PyDict_GetItemString(p, b.data());
663 666 } else {
664 667 p.setNewRef(PyObject_GetAttrString(p, b.data()));
665 668 }
666 669 }
667 670 PyErr_Clear();
668 671 return p;
669 672 }
670 673
671 674 PythonQtObjectPtr PythonQt::getMainModule() {
672 675 //both borrowed
673 676 PythonQtObjectPtr dict = PyImport_GetModuleDict();
674 677 return PyDict_GetItemString(dict, "__main__");
675 678 }
676 679
677 680 PythonQtObjectPtr PythonQt::importModule(const QString& name)
678 681 {
679 682 PythonQtObjectPtr mod;
680 683 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
681 684 return mod;
682 685 }
683 686
684 687
685 688 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
686 689 QVariant result;
687 690 if (pycode) {
688 691 PyObject* dict = NULL;
689 692 PyObject* globals = NULL;
690 693 if (PyModule_Check(object)) {
691 694 dict = PyModule_GetDict(object);
692 695 globals = dict;
693 696 } else if (PyDict_Check(object)) {
694 697 dict = object;
695 698 globals = dict;
696 699 } else {
697 700 dict = PyObject_GetAttrString(object, "__dict__");
698 701 globals = PyObject_GetAttrString(PyImport_ImportModule(PyString_AS_STRING(PyObject_GetAttrString(object, "__module__"))),"__dict__");
699 702 }
700 703 PyObject* r = NULL;
701 704 if (dict) {
702 705 r = PyEval_EvalCode((PyCodeObject*)pycode, globals , dict);
703 706 }
704 707 if (r) {
705 708 result = PythonQtConv::PyObjToQVariant(r);
706 709 Py_DECREF(r);
707 710 } else {
708 711 handleError();
709 712 }
710 713 } else {
711 714 handleError();
712 715 }
713 716 return result;
714 717 }
715 718
716 719 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
717 720 {
718 721 QVariant result;
719 722 PythonQtObjectPtr p;
720 723 PyObject* dict = NULL;
721 724 if (PyModule_Check(object)) {
722 725 dict = PyModule_GetDict(object);
723 726 } else if (PyDict_Check(object)) {
724 727 dict = object;
725 728 }
726 729 if (dict) {
727 730 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
728 731 }
729 732 if (p) {
730 733 result = PythonQtConv::PyObjToQVariant(p);
731 734 } else {
732 735 handleError();
733 736 }
734 737 return result;
735 738 }
736 739
737 740 void PythonQt::evalFile(PyObject* module, const QString& filename)
738 741 {
739 742 PythonQtObjectPtr code = parseFile(filename);
740 743 if (code) {
741 744 evalCode(module, code);
742 745 } else {
743 746 handleError();
744 747 }
745 748 }
746 749
747 750 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
748 751 {
749 752 PythonQtObjectPtr p;
750 753 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
751 754 if (!p) {
752 755 handleError();
753 756 }
754 757 return p;
755 758 }
756 759
757 760 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
758 761 {
759 762 PythonQtObjectPtr code = parseFile(filename);
760 763 PythonQtObjectPtr module = _p->createModule(name, code);
761 764 return module;
762 765 }
763 766
764 767 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
765 768 {
766 769 PyErr_Clear();
767 770 QString scriptCode = script;
768 771 if (scriptCode.isEmpty()) {
769 772 // we always need at least a linefeed
770 773 scriptCode = "\n";
771 774 }
772 775 PythonQtObjectPtr pycode;
773 776 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
774 777 PythonQtObjectPtr module = _p->createModule(name, pycode);
775 778 return module;
776 779 }
777 780
778 781 PythonQtObjectPtr PythonQt::createUniqueModule()
779 782 {
780 783 static QString pyQtStr("PythonQt_module");
781 784 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
782 785 return createModuleFromScript(moduleName);
783 786 }
784 787
785 788 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
786 789 {
787 790 if (PyModule_Check(object)) {
788 791 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
789 792 } else if (PyDict_Check(object)) {
790 793 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
791 794 } else {
792 795 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
793 796 }
794 797 }
795 798
796 799 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
797 800 {
798 801 if (PyModule_Check(object)) {
799 802 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
800 803 } else if (PyDict_Check(object)) {
801 804 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
802 805 } else {
803 806 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
804 807 }
805 808 }
806 809
807 810 void PythonQt::removeVariable(PyObject* object, const QString& name)
808 811 {
809 812 if (PyDict_Check(object)) {
810 813 PyDict_DelItemString(object, name.toLatin1().data());
811 814 } else {
812 815 PyObject_DelAttrString(object, name.toLatin1().data());
813 816 }
814 817 }
815 818
816 819 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
817 820 {
818 821 QVariant result;
819 822 PythonQtObjectPtr obj = lookupObject(object, objectname);
820 823 if (obj) {
821 824 result = PythonQtConv::PyObjToQVariant(obj);
822 825 }
823 826 return result;
824 827 }
825 828
826 829 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
827 830 {
828 831 QStringList results;
829 832
830 833 PythonQtObjectPtr object;
831 834 if (objectname.isEmpty()) {
832 835 object = module;
833 836 } else {
834 837 object = lookupObject(module, objectname);
835 838 if (!object && type == CallOverloads) {
836 839 PyObject* dict = lookupObject(module, "__builtins__");
837 840 if (dict) {
838 841 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
839 842 }
840 843 }
841 844 }
842 845
843 846 if (object) {
844 847 results = introspectObject(object, type);
845 848 }
846 849
847 850 return results;
848 851 }
849 852
850 853 QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
851 854 {
852 855 QStringList results;
853 856
854 857 if (type == CallOverloads) {
855 858 if (PythonQtSlotFunction_Check(object)) {
856 859 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object;
857 860 PythonQtSlotInfo* info = o->m_ml;
858 861
859 862 while (info) {
860 863 results << info->fullSignature();
861 864 info = info->nextInfo();
862 865 }
863 866 } else if (PythonQtSignalFunction_Check(object)) {
864 867 PythonQtSignalFunctionObject* o = (PythonQtSignalFunctionObject*)object;
865 868 PythonQtSlotInfo* info = o->m_ml;
866 869
867 870 while (info) {
868 871 results << info->fullSignature();
869 872 info = info->nextInfo();
870 873 }
871 874 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
872 875 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
873 876 PythonQtSlotInfo* info = o->classInfo()->constructors();
874 877
875 878 while (info) {
876 879 results << info->fullSignature();
877 880 info = info->nextInfo();
878 881 }
879 882 } else {
880 883 QString signature = _p->getSignature(object);
881 884 if (!signature.isEmpty()) {
882 885 results << signature;
883 886 } else {
884 887 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
885 888 if (doc) {
886 889 results << PyString_AsString(doc);
887 890 Py_DECREF(doc);
888 891 }
889 892 }
890 893 }
891 894 } else {
892 895 PyObject* keys = NULL;
893 896 bool isDict = false;
894 897 if (PyDict_Check(object)) {
895 898 keys = PyDict_Keys(object);
896 899 isDict = true;
897 900 } else {
898 901 keys = PyObject_Dir(object);
899 902 }
900 903 if (keys) {
901 904 int count = PyList_Size(keys);
902 905 PyObject* key;
903 906 PyObject* value;
904 907 QString keystr;
905 908 for (int i = 0;i<count;i++) {
906 909 key = PyList_GetItem(keys,i);
907 910 if (isDict) {
908 911 value = PyDict_GetItem(object, key);
909 912 Py_INCREF(value);
910 913 } else {
911 914 value = PyObject_GetAttr(object, key);
912 915 }
913 916 if (!value) continue;
914 917 keystr = PyString_AsString(key);
915 918 static const QString underscoreStr("__tmp");
916 919 if (!keystr.startsWith(underscoreStr)) {
917 920 switch (type) {
918 921 case Anything:
919 922 results << keystr;
920 923 break;
921 924 case Class:
922 925 if (value->ob_type == &PyClass_Type || value->ob_type == &PyType_Type) {
923 926 results << keystr;
924 927 }
925 928 break;
926 929 case Variable:
927 930 if (value->ob_type != &PyClass_Type
928 931 && value->ob_type != &PyCFunction_Type
929 932 && value->ob_type != &PyFunction_Type
930 933 && value->ob_type != &PyMethod_Type
931 934 && value->ob_type != &PyModule_Type
932 935 && value->ob_type != &PyType_Type
933 936 && value->ob_type != &PythonQtSlotFunction_Type
934 937 ) {
935 938 results << keystr;
936 939 }
937 940 break;
938 941 case Function:
939 942 if (value->ob_type == &PyCFunction_Type ||
940 943 value->ob_type == &PyFunction_Type ||
941 944 value->ob_type == &PyMethod_Type ||
942 945 value->ob_type == &PythonQtSlotFunction_Type
943 946 ) {
944 947 results << keystr;
945 948 }
946 949 break;
947 950 case Module:
948 951 if (value->ob_type == &PyModule_Type) {
949 952 results << keystr;
950 953 }
951 954 break;
952 955 default:
953 956 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
954 957 }
955 958 }
956 959 Py_DECREF(value);
957 960 }
958 961 Py_DECREF(keys);
959 962 }
960 963 if ((type == Anything) || (type == Variable)) {
961 964 if (object->ob_type == &PythonQtClassWrapper_Type) {
962 965 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
963 966 PythonQtClassInfo* info = o->classInfo();
964 967 results += info->propertyList();
965 968 }
966 969 }
967 970 }
968 971 return results;
969 972 }
970 973
971 974 PyObject* PythonQt::getObjectByType(const QString& typeName)
972 975 {
973 976 PythonQtObjectPtr sys;
974 977 sys.setNewRef(PyImport_ImportModule("sys"));
975 978 PythonQtObjectPtr modules = lookupObject(sys, "modules");
976 979 Q_ASSERT(PyDict_Check(modules));
977 980
978 981 QStringList tmp = typeName.split(".");
979 982 QString simpleTypeName = tmp.takeLast();
980 983 QString moduleName = tmp.join(".");
981 984
982 985 PyObject* object = NULL;
983 986 PyObject* moduleObject = PyDict_GetItemString(modules, moduleName.toLatin1().constData());
984 987 if (moduleObject) {
985 988 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
986 989 }
987 990
988 991 if (!object) {
989 992 moduleObject = PyDict_GetItemString(modules, "__builtin__");
990 993 if (moduleObject) {
991 994 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
992 995 }
993 996 }
994 997
995 998 return object;
996 999 }
997 1000
998 1001 QStringList PythonQt::introspectType(const QString& typeName, ObjectType type)
999 1002 {
1000 1003 QStringList results;
1001 1004 PyObject* object = getObjectByType(typeName);
1002 1005 if (!object) {
1003 1006 // the last item may be a member, split it away and try again
1004 1007 QStringList tmp = typeName.split(".");
1005 1008 QString memberName = tmp.takeLast();
1006 1009 QString typeName;
1007 1010 if (tmp.isEmpty()) {
1008 1011 typeName = memberName;
1009 1012 memberName.clear();
1010 1013 } else {
1011 1014 typeName = tmp.takeLast();
1012 1015 }
1013 1016 PyObject* typeObject = getObjectByType(typeName);
1014 1017 if (typeObject) {
1015 1018 object = PyObject_GetAttrString(typeObject, memberName.toLatin1().constData());
1016 1019 }
1017 1020 }
1018 1021 if (object) {
1019 1022 results = introspectObject(object, type);
1020 1023 Py_DECREF(object);
1021 1024 }
1022 1025 return results;
1023 1026 }
1024 1027
1025 1028 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args, const QVariantMap& kwargs)
1026 1029 {
1027 1030 PythonQtObjectPtr callable = lookupCallable(object, name);
1028 1031 if (callable) {
1029 1032 return call(callable, args, kwargs);
1030 1033 } else {
1031 1034 return QVariant();
1032 1035 }
1033 1036 }
1034 1037
1035 1038 QVariant PythonQt::call(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
1036 1039 {
1037 1040 QVariant r;
1038 1041 PythonQtObjectPtr result;
1039 1042 result.setNewRef(callAndReturnPyObject(callable, args, kwargs));
1040 1043 if (result) {
1041 1044 r = PythonQtConv::PyObjToQVariant(result);
1042 1045 } else {
1043 1046 PythonQt::self()->handleError();
1044 1047 }
1045 1048 return r;
1046 1049 }
1047 1050
1048 1051 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
1049 1052 {
1050 1053 PyObject* result = NULL;
1051 1054 if (callable) {
1052 1055 bool err = false;
1053 1056 PythonQtObjectPtr pargs;
1054 1057 int count = args.size();
1055 1058 if ((count > 0) || (kwargs.count() > 0)) { // create empty tuple if kwargs are given
1056 1059 pargs.setNewRef(PyTuple_New(count));
1057 1060
1058 1061 // transform QVariant arguments to Python
1059 1062 for (int i = 0; i < count; i++) {
1060 1063 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
1061 1064 if (arg) {
1062 1065 // steals reference, no unref
1063 1066 PyTuple_SetItem(pargs, i,arg);
1064 1067 } else {
1065 1068 err = true;
1066 1069 break;
1067 1070 }
1068 1071 }
1069 1072 }
1070 1073 if (!err) {
1071 1074 if (kwargs.isEmpty()) {
1072 1075 // do a direct call if we have no keyword arguments
1073 1076 PyErr_Clear();
1074 1077 result = PyObject_CallObject(callable, pargs);
1075 1078 } else {
1076 1079 // convert keyword arguments to Python
1077 1080 PythonQtObjectPtr pkwargs;
1078 1081 pkwargs.setNewRef(PyDict_New());
1079 1082 QMapIterator<QString, QVariant> it(kwargs);
1080 1083 while (it.hasNext()) {
1081 1084 it.next();
1082 1085 PyObject* arg = PythonQtConv::QVariantToPyObject(it.value());
1083 1086 if (arg) {
1084 1087 PyDict_SetItemString(pkwargs, it.key().toLatin1().constData(), arg);
1085 1088 } else {
1086 1089 err = true;
1087 1090 break;
1088 1091 }
1089 1092 }
1090 1093 if (!err) {
1091 1094 // call with arguments and keyword arguments
1092 1095 PyErr_Clear();
1093 1096 result = PyObject_Call(callable, pargs, pkwargs);
1094 1097 }
1095 1098 }
1096 1099 }
1097 1100 }
1098 1101 return result;
1099 1102 }
1100 1103
1101 1104 void PythonQt::addInstanceDecorators(QObject* o)
1102 1105 {
1103 1106 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
1104 1107 }
1105 1108
1106 1109 void PythonQt::addClassDecorators(QObject* o)
1107 1110 {
1108 1111 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
1109 1112 }
1110 1113
1111 1114 void PythonQt::addDecorators(QObject* o)
1112 1115 {
1113 1116 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
1114 1117 }
1115 1118
1116 1119 void PythonQt::registerQObjectClassNames(const QStringList& names)
1117 1120 {
1118 1121 _p->registerQObjectClassNames(names);
1119 1122 }
1120 1123
1121 1124 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
1122 1125 {
1123 1126 _p->_importInterface = importInterface;
1124 1127 PythonQtImport::init();
1125 1128 }
1126 1129
1127 1130 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
1128 1131 {
1129 1132 _p->_importIgnorePaths = paths;
1130 1133 }
1131 1134
1132 1135 const QStringList& PythonQt::getImporterIgnorePaths()
1133 1136 {
1134 1137 return _p->_importIgnorePaths;
1135 1138 }
1136 1139
1137 1140 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
1138 1141 {
1139 1142 _p->_cppWrapperFactories.append(factory);
1140 1143 }
1141 1144
1142 1145 void PythonQt::addWrapperFactory( PythonQtForeignWrapperFactory* factory )
1143 1146 {
1144 1147 _p->_foreignWrapperFactories.append(factory);
1145 1148 }
1146 1149
1147 1150 //---------------------------------------------------------------------------------------------------
1148 1151 PythonQtPrivate::PythonQtPrivate()
1149 1152 {
1150 1153 _importInterface = NULL;
1151 1154 _defaultImporter = new PythonQtQFileImporter;
1152 1155 _noLongerWrappedCB = NULL;
1153 1156 _wrappedCB = NULL;
1154 1157 _currentClassInfoForClassWrapperCreation = NULL;
1155 1158 _profilingCB = NULL;
1156 1159 }
1157 1160
1158 1161 void PythonQtPrivate::setupSharedLibrarySuffixes()
1159 1162 {
1160 1163 _sharedLibrarySuffixes.clear();
1161 1164 PythonQtObjectPtr imp;
1162 1165 imp.setNewRef(PyImport_ImportModule("imp"));
1163 1166 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
1164 1167 QVariant result = imp.call("get_suffixes");
1165 1168 #ifdef __linux
1166 1169 #ifdef _DEBUG
1167 1170 // First look for shared libraries with the '_d' suffix in debug mode on Linux.
1168 1171 // This is a workaround, because python does not append the '_d' suffix on Linux
1169 1172 // and would always load the release library otherwise.
1170 1173 _sharedLibrarySuffixes << "_d.so";
1171 1174 #endif
1172 1175 #endif
1173 1176 foreach (QVariant entry, result.toList()) {
1174 1177 QVariantList suffixEntry = entry.toList();
1175 1178 if (suffixEntry.count()==3) {
1176 1179 int code = suffixEntry.at(2).toInt();
1177 1180 if (code == cExtensionCode) {
1178 1181 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
1179 1182 }
1180 1183 }
1181 1184 }
1182 1185 }
1183 1186
1184 1187 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
1185 1188 {
1186 1189 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
1187 1190 _currentClassInfoForClassWrapperCreation = NULL;
1188 1191 return info;
1189 1192 }
1190 1193
1191 1194 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
1192 1195 {
1193 1196 o->setParent(this);
1194 1197 int numMethods = o->metaObject()->methodCount();
1195 1198 for (int i = 0; i < numMethods; i++) {
1196 1199 QMetaMethod m = o->metaObject()->method(i);
1197 1200 if ((m.methodType() == QMetaMethod::Method ||
1198 1201 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
1199 1202 if (qstrncmp(m.signature(), "new_", 4)==0) {
1200 1203 if ((decoTypes & ConstructorDecorator) == 0) continue;
1201 1204 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1202 1205 if (info->parameters().at(0).pointerCount == 1) {
1203 1206 QByteArray signature = m.signature();
1204 1207 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
1205 1208 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1206 1209 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1207 1210 classInfo->addConstructor(newSlot);
1208 1211 }
1209 1212 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
1210 1213 if ((decoTypes & DestructorDecorator) == 0) continue;
1211 1214 QByteArray signature = m.signature();
1212 1215 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
1213 1216 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1214 1217 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1215 1218 classInfo->setDestructor(newSlot);
1216 1219 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
1217 1220 if ((decoTypes & StaticDecorator) == 0) continue;
1218 1221 QByteArray signature = m.signature();
1219 1222 QByteArray nameOfClass = signature.mid(7);
1220 1223 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
1221 1224 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1222 1225 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1223 1226 classInfo->addDecoratorSlot(newSlot);
1224 1227 } else {
1225 1228 if ((decoTypes & InstanceDecorator) == 0) continue;
1226 1229 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1227 1230 if (info->parameters().count()>1) {
1228 1231 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
1229 1232 if (p.pointerCount==1) {
1230 1233 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
1231 1234 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
1232 1235 classInfo->addDecoratorSlot(newSlot);
1233 1236 }
1234 1237 }
1235 1238 }
1236 1239 }
1237 1240 }
1238 1241 }
1239 1242
1240 1243 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
1241 1244 {
1242 1245 foreach(QString name, names) {
1243 1246 _knownQObjectClassNames.insert(name.toLatin1(), true);
1244 1247 }
1245 1248 }
1246 1249
1247 1250 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1248 1251 {
1249 1252 _signalReceivers.remove(obj);
1250 1253 }
1251 1254
1252 1255 bool PythonQt::handleError()
1253 1256 {
1254 1257 bool flag = false;
1255 1258 if (PyErr_Occurred()) {
1256 1259
1257 1260 // currently we just print the error and the stderr handler parses the errors
1258 1261 PyErr_Print();
1259 1262
1260 1263 /*
1261 1264 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1262 1265 PyObject *ptype;
1263 1266 PyObject *pvalue;
1264 1267 PyObject *ptraceback;
1265 1268 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1266 1269
1267 1270 Py_XDECREF(ptype);
1268 1271 Py_XDECREF(pvalue);
1269 1272 Py_XDECREF(ptraceback);
1270 1273 */
1271 1274 PyErr_Clear();
1272 1275 flag = true;
1273 1276 }
1274 1277 return flag;
1275 1278 }
1276 1279
1277 1280 void PythonQt::addSysPath(const QString& path)
1278 1281 {
1279 1282 PythonQtObjectPtr sys;
1280 1283 sys.setNewRef(PyImport_ImportModule("sys"));
1281 1284 PythonQtObjectPtr obj = lookupObject(sys, "path");
1282 1285 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1283 1286 }
1284 1287
1285 1288 void PythonQt::overwriteSysPath(const QStringList& paths)
1286 1289 {
1287 1290 PythonQtObjectPtr sys;
1288 1291 sys.setNewRef(PyImport_ImportModule("sys"));
1289 1292 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1290 1293 }
1291 1294
1292 1295 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1293 1296 {
1294 1297 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1295 1298 }
1296 1299
1297 1300 void PythonQt::stdOutRedirectCB(const QString& str)
1298 1301 {
1299 1302 if (!PythonQt::self()) {
1300 1303 std::cout << str.toLatin1().data() << std::endl;
1301 1304 return;
1302 1305 }
1303 1306 emit PythonQt::self()->pythonStdOut(str);
1304 1307 }
1305 1308
1306 1309 void PythonQt::stdErrRedirectCB(const QString& str)
1307 1310 {
1308 1311 if (!PythonQt::self()) {
1309 1312 std::cerr << str.toLatin1().data() << std::endl;
1310 1313 return;
1311 1314 }
1312 1315 emit PythonQt::self()->pythonStdErr(str);
1313 1316 }
1314 1317
1315 1318 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1316 1319 {
1317 1320 _p->_wrappedCB = cb;
1318 1321 }
1319 1322
1320 1323 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1321 1324 {
1322 1325 _p->_noLongerWrappedCB = cb;
1323 1326 }
1324 1327
1325 1328 void PythonQt::setProfilingCallback(ProfilingCB* cb)
1326 1329 {
1327 1330 _p->_profilingCB = cb;
1328 1331 }
1329 1332
1330 1333
1331 1334 static PyMethodDef PythonQtMethods[] = {
1332 1335 {NULL, NULL, 0, NULL}
1333 1336 };
1334 1337
1335 1338 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1336 1339 {
1337 1340 QByteArray name = "PythonQt";
1338 1341 if (!pythonQtModuleName.isEmpty()) {
1339 1342 name = pythonQtModuleName;
1340 1343 }
1341 1344 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1342 1345 _p->_pythonQtModuleName = name;
1343 1346
1344 1347 if (redirectStdOut) {
1345 1348 PythonQtObjectPtr sys;
1346 1349 PythonQtObjectPtr out;
1347 1350 PythonQtObjectPtr err;
1348 1351 sys.setNewRef(PyImport_ImportModule("sys"));
1349 1352 // create a redirection object for stdout and stderr
1350 1353 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1351 1354 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1352 1355 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1353 1356 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1354 1357 // replace the built in file objects with our own objects
1355 1358 PyModule_AddObject(sys, "stdout", out);
1356 1359 PyModule_AddObject(sys, "stderr", err);
1357 1360 }
1358 1361 }
1359 1362
1360 1363 QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString& name)
1361 1364 {
1362 1365 QStringList tmp = name.split(".");
1363 1366 QString methodName = tmp.takeLast();
1364 1367 QString variableName = tmp.join(".");
1365 1368 // TODO: the variableName may be a type name, this needs to be handled differently,
1366 1369 // because it is not necessarily known in the module context
1367 1370 PythonQtObjectPtr variableObject = lookupObject(module, variableName);
1368 1371 if (variableObject.isNull()) {
1369 1372 return "";
1370 1373 }
1371 1374
1372 1375 return getReturnTypeOfWrappedMethodHelper(variableObject, methodName, name);
1373 1376 }
1374 1377
1375 1378 QString PythonQt::getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName)
1376 1379 {
1377 1380 PythonQtObjectPtr typeObject = getObjectByType(typeName);
1378 1381 if (typeObject.isNull()) {
1379 1382 return "";
1380 1383 }
1381 1384 return getReturnTypeOfWrappedMethodHelper(typeObject, methodName, typeName + "." + methodName);
1382 1385 }
1383 1386
1384 1387 QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context)
1385 1388 {
1386 1389 PythonQtObjectPtr methodObject;
1387 1390 if (PyDict_Check(variableObject)) {
1388 1391 methodObject = PyDict_GetItemString(variableObject, methodName.toLatin1().constData());
1389 1392 } else {
1390 1393 methodObject.setNewRef(PyObject_GetAttrString(variableObject, methodName.toLatin1().constData()));
1391 1394 }
1392 1395 if (methodObject.isNull()) {
1393 1396 return "";
1394 1397 }
1395 1398
1396 1399 QString type;
1397 1400
1398 1401 if (methodObject->ob_type == &PyClass_Type || methodObject->ob_type == &PyType_Type) {
1399 1402 // the methodObject is not a method, but the name of a type/class. This means
1400 1403 // a constructor is called. Return the context.
1401 1404 type = context;
1402 1405 } else if (methodObject->ob_type == &PythonQtSlotFunction_Type) {
1403 1406 QString className;
1404 1407
1405 1408 if (PyObject_TypeCheck(variableObject, &PythonQtInstanceWrapper_Type)) {
1406 1409 // the type name of wrapped instance is the class name
1407 1410 className = variableObject->ob_type->tp_name;
1408 1411 } else {
1409 1412 PyObject* classNameObject = PyObject_GetAttrString(variableObject, "__name__");
1410 1413 if (classNameObject) {
1411 1414 Q_ASSERT(PyString_Check(classNameObject));
1412 1415 className = PyString_AsString(classNameObject);
1413 1416 Py_DECREF(classNameObject);
1414 1417 }
1415 1418 }
1416 1419
1417 1420 if (!className.isEmpty()) {
1418 1421 PythonQtClassInfo* info = _p->_knownClassInfos.value(className.toLatin1().constData());
1419 1422 if (info) {
1420 1423 PythonQtSlotInfo* slotInfo = info->member(methodName.toLatin1().constData())._slot;
1421 1424 if (slotInfo) {
1422 1425 if (slotInfo->metaMethod()) {
1423 1426 type = slotInfo->metaMethod()->typeName();
1424 1427 if (!type.isEmpty()) {
1425 1428 QChar c = type.at(type.length()-1);
1426 1429 while (c == '*' || c == '&') {
1427 1430 type.truncate(type.length()-1);
1428 1431 if (!type.isEmpty()) {
1429 1432 c = type.at(type.length()-1);
1430 1433 } else {
1431 1434 break;
1432 1435 }
1433 1436 }
1434 1437 // split away template arguments
1435 1438 type = type.split("<").first();
1436 1439 // split away const
1437 1440 type = type.split(" ").last().trimmed();
1438 1441
1439 1442 // if the type is a known class info, then create the full type name, i.e. include the
1440 1443 // module name. For example, the slot may return a QDate, then this looks up the
1441 1444 // name _PythonQt.QtCore.QDate.
1442 1445 PythonQtClassInfo* typeInfo = _p->_knownClassInfos.value(type.toLatin1().constData());
1443 1446 if (typeInfo && typeInfo->pythonQtClassWrapper()) {
1444 1447 PyObject* s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__module__");
1445 1448 Q_ASSERT(PyString_Check(s));
1446 1449 type = QString(PyString_AsString(s)) + "." + type;
1447 1450 Py_DECREF(s);
1448 1451 s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__name__");
1449 1452 Q_ASSERT(PyString_Check(s));
1450 1453 Py_DECREF(s);
1451 1454 }
1452 1455 }
1453 1456 }
1454 1457 }
1455 1458 }
1456 1459 }
1457 1460 }
1458 1461 return type;
1459 1462 }
1460 1463
1461 1464 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1462 1465 {
1463 1466 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1464 1467 }
1465 1468
1466 1469
1467 1470 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1468 1471 {
1469 1472 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1470 1473 if (!info) {
1471 1474 info = new PythonQtClassInfo();
1472 1475 info->setupCPPObject(typeName);
1473 1476 _knownClassInfos.insert(typeName, info);
1474 1477 }
1475 1478 return info;
1476 1479 }
1477 1480
1478 1481 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1479 1482 {
1480 1483 _p->addPolymorphicHandler(typeName, cb);
1481 1484 }
1482 1485
1483 1486 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1484 1487 {
1485 1488 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1486 1489 info->addPolymorphicHandler(cb);
1487 1490 }
1488 1491
1489 1492 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1490 1493 {
1491 1494 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1492 1495 }
1493 1496
1494 1497 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1495 1498 {
1496 1499 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1497 1500 if (info) {
1498 1501 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1499 1502 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1500 1503 return true;
1501 1504 } else {
1502 1505 return false;
1503 1506 }
1504 1507 }
1505 1508
1506 1509 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1507 1510 {
1508 1511 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1509 1512 if (!info->pythonQtClassWrapper()) {
1510 1513 info->setTypeSlots(typeSlots);
1511 1514 info->setupCPPObject(typeName);
1512 1515 createPythonQtClassWrapper(info, package, module);
1513 1516 }
1514 1517 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1515 1518 addParentClass(typeName, parentTypeName, 0);
1516 1519 }
1517 1520 if (wrapperCreator) {
1518 1521 info->setDecoratorProvider(wrapperCreator);
1519 1522 }
1520 1523 if (shell) {
1521 1524 info->setShellSetInstanceWrapperCB(shell);
1522 1525 }
1523 1526 }
1524 1527
1525 1528 PyObject* PythonQtPrivate::packageByName(const char* name)
1526 1529 {
1527 1530 if (name==NULL || name[0]==0) {
1528 1531 name = "private";
1529 1532 }
1530 1533 PyObject* v = _packages.value(name);
1531 1534 if (!v) {
1532 1535 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1533 1536 _packages.insert(name, v);
1534 1537 // AddObject steals the reference, so increment it!
1535 1538 Py_INCREF(v);
1536 1539 PyModule_AddObject(_pythonQtModule, name, v);
1537 1540 }
1538 1541 return v;
1539 1542 }
1540 1543
1541 1544 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1542 1545 {
1543 1546 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;
1544 1547 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1545 1548 PythonQt::self()->handleError();
1546 1549 }
1547 1550
1548 1551 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1549 1552 {
1550 1553 if (_p->_initFlags & ExternalHelp) {
1551 1554 emit pythonHelpRequest(QByteArray(info->className()));
1552 1555 return Py_BuildValue("");
1553 1556 } else {
1554 1557 return PyString_FromString(info->help().toLatin1().data());
1555 1558 }
1556 1559 }
1557 1560
1558 1561 void PythonQt::clearNotFoundCachedMembers()
1559 1562 {
1560 1563 foreach(PythonQtClassInfo* info, _p->_knownClassInfos) {
1561 1564 info->clearNotFoundCachedMembers();
1562 1565 }
1563 1566 }
1564 1567
1565 1568 void PythonQt::removeWrapperFactory( PythonQtCppWrapperFactory* factory )
1566 1569 {
1567 1570 _p->_cppWrapperFactories.removeAll(factory);
1568 1571 }
1569 1572
1570 1573 void PythonQt::removeWrapperFactory( PythonQtForeignWrapperFactory* factory )
1571 1574 {
1572 1575 _p->_foreignWrapperFactories.removeAll(factory);
1573 1576 }
1574 1577
1575 1578 void PythonQtPrivate::removeWrapperPointer(void* obj)
1576 1579 {
1577 1580 _wrappedObjects.remove(obj);
1578 1581 }
1579 1582
1580 1583 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1581 1584 {
1582 1585 _wrappedObjects.insert(obj, wrapper);
1583 1586 }
1584 1587
1585 1588 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1586 1589 {
1587 1590 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1588 1591 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1589 1592 // this is a wrapper whose QObject was already removed due to destruction
1590 1593 // so the obj pointer has to be a new QObject with the same address...
1591 1594 // we remove the old one and set the copy to NULL
1592 1595 wrap->_objPointerCopy = NULL;
1593 1596 removeWrapperPointer(obj);
1594 1597 wrap = NULL;
1595 1598 }
1596 1599 return wrap;
1597 1600 }
1598 1601
1599 1602 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1600 1603 {
1601 1604 PythonQtObjectPtr result;
1602 1605 if (pycode) {
1603 1606 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1604 1607 } else {
1605 1608 PythonQt::self()->handleError();
1606 1609 }
1607 1610 return result;
1608 1611 }
1609 1612
1610 1613 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObject* obj )
1611 1614 {
1612 1615 void* foreignObject = NULL;
1613 1616 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
1614 1617 foreignObject = _foreignWrapperFactories.at(i)->unwrap(classname, obj);
1615 1618 if (foreignObject) {
1616 1619 return foreignObject;
1617 1620 }
1618 1621 }
1619 1622 return NULL;
1620 1623 }
1621 1624
1622 1625 bool PythonQtPrivate::isMethodDescriptor(PyObject* object) const
1623 1626 {
1624 1627 // This implementation is the same as in inspect.ismethoddescriptor(), inspect.py.
1625 1628 if (PyObject_HasAttrString(object, "__get__") &&
1626 1629 !PyObject_HasAttrString(object, "__set__") &&
1627 1630 !PyMethod_Check(object) &&
1628 1631 !PyFunction_Check(object) &&
1629 1632 !PyClass_Check(object)) {
1630 1633 return true;
1631 1634 }
1632 1635 return false;
1633 1636 }
1634 1637
1635 1638 QString PythonQtPrivate::getSignature(PyObject* object)
1636 1639 {
1637 1640 QString signature;
1638 1641
1639 1642 if (object) {
1640 1643 PyMethodObject* method = NULL;
1641 1644 PyFunctionObject* func = NULL;
1642 1645
1643 1646 bool decrefMethod = false;
1644 1647
1645 1648 if (object->ob_type == &PyClass_Type || object->ob_type == &PyType_Type) {
1646 1649 method = (PyMethodObject*)PyObject_GetAttrString(object, "__init__");
1647 1650 decrefMethod = true;
1648 1651 } else if (object->ob_type == &PyFunction_Type) {
1649 1652 func = (PyFunctionObject*)object;
1650 1653 } else if (object->ob_type == &PyMethod_Type) {
1651 1654 method = (PyMethodObject*)object;
1652 1655 }
1653 1656 if (method) {
1654 1657 if (PyFunction_Check(method->im_func)) {
1655 1658 func = (PyFunctionObject*)method->im_func;
1656 1659 } else if (isMethodDescriptor((PyObject*)method)) {
1657 1660 QString docstr;
1658 1661 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
1659 1662 if (doc) {
1660 1663 docstr = PyString_AsString(doc);
1661 1664 Py_DECREF(doc);
1662 1665 }
1663 1666
1664 1667 PyObject* s = PyObject_GetAttrString(object, "__name__");
1665 1668 if (s) {
1666 1669 Q_ASSERT(PyString_Check(s));
1667 1670 signature = PyString_AsString(s);
1668 1671 if (docstr.startsWith(signature + "(")) {
1669 1672 signature = docstr;
1670 1673 } else {
1671 1674 signature += "(...)";
1672 1675 if (!docstr.isEmpty()) {
1673 1676 signature += "\n\n" + docstr;
1674 1677 }
1675 1678 }
1676 1679 Py_DECREF(s);
1677 1680 }
1678 1681 }
1679 1682 }
1680 1683
1681 1684 if (func) {
1682 1685 QString funcName;
1683 1686 PyObject* s = PyObject_GetAttrString((PyObject*)func, "__name__");
1684 1687 if (s) {
1685 1688 Q_ASSERT(PyString_Check(s));
1686 1689 funcName = PyString_AsString(s);
1687 1690 Py_DECREF(s);
1688 1691 }
1689 1692 if (method && funcName == "__init__") {
1690 1693 PyObject* s = PyObject_GetAttrString(object, "__name__");
1691 1694 if (s) {
1692 1695 Q_ASSERT(PyString_Check(s));
1693 1696 funcName = PyString_AsString(s);
1694 1697 Py_DECREF(s);
1695 1698 }
1696 1699 }
1697 1700
1698 1701 QStringList arguments;
1699 1702 QStringList defaults;
1700 1703 QString varargs;
1701 1704 QString varkeywords;
1702 1705 // NOTE: This implementation is based on function getargs() in inspect.py.
1703 1706 // inspect.getargs() can handle anonymous (tuple) arguments, while this code does not.
1704 1707 // It can be implemented, but it may be rarely needed and not necessary.
1705 1708 PyCodeObject* code = (PyCodeObject*)func->func_code;
1706 1709 if (code->co_varnames) {
1707 1710 int nargs = code->co_argcount;
1708 1711 Q_ASSERT(PyTuple_Check(code->co_varnames));
1709 1712 for (int i=0; i<nargs; i++) {
1710 1713 PyObject* name = PyTuple_GetItem(code->co_varnames, i);
1711 1714 Q_ASSERT(PyString_Check(name));
1712 1715 arguments << PyString_AsString(name);
1713 1716 }
1714 1717 if (code->co_flags & CO_VARARGS) {
1715 1718 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1716 1719 Q_ASSERT(PyString_Check(s));
1717 1720 varargs = PyString_AsString(s);
1718 1721 nargs += 1;
1719 1722 }
1720 1723 if (code->co_flags & CO_VARKEYWORDS) {
1721 1724 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1722 1725 Q_ASSERT(PyString_Check(s));
1723 1726 varkeywords = PyString_AsString(s);
1724 1727 }
1725 1728 }
1726 1729
1727 1730 PyObject* defaultsTuple = func->func_defaults;
1728 1731 if (defaultsTuple) {
1729 1732 Q_ASSERT(PyTuple_Check(defaultsTuple));
1730 1733 for (Py_ssize_t i=0; i<PyTuple_Size(defaultsTuple); i++) {
1731 1734 PyObject* d = PyTuple_GetItem(defaultsTuple, i);
1732 1735 PyObject* s = PyObject_Repr(d);
1733 1736 Q_ASSERT(PyString_Check(s));
1734 1737 defaults << PyString_AsString(s);
1735 1738 Py_DECREF(s);
1736 1739 }
1737 1740 }
1738 1741
1739 1742 int firstdefault = arguments.size() - defaults.size();
1740 1743 for (int i=0; i<arguments.size(); i++) {
1741 1744 if (!signature.isEmpty()) { signature += ", "; }
1742 1745 if (!method || i>0 || arguments[i] != "self") {
1743 1746 signature += arguments[i];
1744 1747 if (i >= firstdefault) {
1745 1748 signature += "=" + defaults[i-firstdefault];
1746 1749 }
1747 1750 }
1748 1751 }
1749 1752 if (!varargs.isEmpty()) {
1750 1753 if (!signature.isEmpty()) { signature += ", "; }
1751 1754 signature += "*" + varargs;
1752 1755 }
1753 1756 if (!varkeywords.isEmpty()) {
1754 1757 if (!signature.isEmpty()) { signature += ", "; }
1755 1758 signature += "**" + varkeywords;
1756 1759 }
1757 1760 signature = funcName + "(" + signature + ")";
1758 1761 }
1759 1762
1760 1763 if (method && decrefMethod) {
1761 1764 Py_DECREF(method);
1762 1765 }
1763 1766 }
1764 1767
1765 1768 return signature;
1766 1769 }
1767 1770
1768 1771 void PythonQtPrivate::shellClassDeleted( void* shellClass )
1769 1772 {
1770 1773 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(shellClass);
1771 1774 if (wrap && wrap->_wrappedPtr) {
1772 1775 // this is a pure C++ wrapper and the shell has gone, so we need
1773 1776 // to set the _wrappedPtr to NULL on the wrapper
1774 1777 wrap->_wrappedPtr = NULL;
1775 1778 // and then we remove the wrapper, since the wrapped class is gone
1776 1779 _wrappedObjects.remove(shellClass);
1777 1780 }
1778 1781 // if the wrapper is a QObject, we do not handle this here,
1779 1782 // it will be handled by the QPointer<> to the QObject, which becomes NULL
1780 1783 // via the QObject destructor.
1781 1784 }
1782 1785
1783 1786 PyObject* PythonQtPrivate::wrapMemoryAsBuffer( const void* data, Py_ssize_t size )
1784 1787 {
1785 1788 // P3K port needed later on!
1786 1789 return PyBuffer_FromMemory((void*)data, size);
1787 1790 }
1788 1791
1789 1792 PyObject* PythonQtPrivate::wrapMemoryAsBuffer( void* data, Py_ssize_t size )
1790 1793 {
1791 1794 // P3K port needed later on!
1792 1795 return PyBuffer_FromReadWriteMemory(data, size);
1793 1796 } No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now