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