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