##// END OF EJS Templates
florianlink -
r201:4443fddf8142
parent child
Show More
@@ -1,1796 +1,1892
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignal.h"
47 47 #include "PythonQtSignalReceiver.h"
48 48 #include "PythonQtConversion.h"
49 49 #include "PythonQtStdIn.h"
50 50 #include "PythonQtStdOut.h"
51 51 #include "PythonQtCppWrapperFactory.h"
52 52 #include "PythonQtVariants.h"
53 53 #include "PythonQtStdDecorators.h"
54 54 #include "PythonQtQFileImporter.h"
55 55 #include <pydebug.h>
56 56 #include <vector>
57 57
58 58 PythonQt* PythonQt::_self = NULL;
59 59 int PythonQt::_uniqueModuleCount = 0;
60 60
61 61 void PythonQt_init_QtGuiBuiltin(PyObject*);
62 62 void PythonQt_init_QtCoreBuiltin(PyObject*);
63 63
64 64
65 65 PyObject* PythonQtConvertFromStringRef(const void* inObject, int /*metaTypeId*/)
66 66 {
67 67 return PythonQtConv::QStringToPyObject(((QStringRef*)inObject)->toString());
68 68 }
69 69
70 70 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
71 71 {
72 72 if (!_self) {
73 73 _self = new PythonQt(flags, pythonQtModuleName);
74 74
75 75 PythonQt::priv()->setupSharedLibrarySuffixes();
76 76
77 77 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
78 78 qRegisterMetaType<QList<QObject*> >("QList<void*>");
79 79
80 80 int stringRefId = qRegisterMetaType<QStringRef>("QStringRef");
81 81 PythonQtConv::registerMetaTypeToPythonConverter(stringRefId, PythonQtConvertFromStringRef);
82 82
83 83 PythonQtRegisterToolClassesTemplateConverter(int);
84 84 PythonQtRegisterToolClassesTemplateConverter(float);
85 85 PythonQtRegisterToolClassesTemplateConverter(double);
86 86 PythonQtRegisterToolClassesTemplateConverter(qint32);
87 87 PythonQtRegisterToolClassesTemplateConverter(quint32);
88 88 PythonQtRegisterToolClassesTemplateConverter(qint64);
89 89 PythonQtRegisterToolClassesTemplateConverter(quint64);
90 90 // TODO: which other POD types should be available for QList etc.
91 91
92 92 PythonQt_init_QtCoreBuiltin(NULL);
93 93 PythonQt_init_QtGuiBuiltin(NULL);
94 94
95 95 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
96 96 PythonQt::self()->registerCPPClass("QMetaObject",0, "QtCore", PythonQtCreateObject<PythonQtWrapper_QMetaObject>);
97 97
98 98 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
99 99 PythonQtRegisterToolClassesTemplateConverter(QDate);
100 100 PythonQtRegisterToolClassesTemplateConverter(QTime);
101 101 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
102 102 PythonQtRegisterToolClassesTemplateConverter(QUrl);
103 103 PythonQtRegisterToolClassesTemplateConverter(QLocale);
104 104 PythonQtRegisterToolClassesTemplateConverter(QRect);
105 105 PythonQtRegisterToolClassesTemplateConverter(QRectF);
106 106 PythonQtRegisterToolClassesTemplateConverter(QSize);
107 107 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
108 108 PythonQtRegisterToolClassesTemplateConverter(QLine);
109 109 PythonQtRegisterToolClassesTemplateConverter(QLineF);
110 110 PythonQtRegisterToolClassesTemplateConverter(QPoint);
111 111 PythonQtRegisterToolClassesTemplateConverter(QPointF);
112 112 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
113 113
114 114 PythonQtRegisterToolClassesTemplateConverter(QFont);
115 115 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
116 116 PythonQtRegisterToolClassesTemplateConverter(QBrush);
117 117 PythonQtRegisterToolClassesTemplateConverter(QColor);
118 118 PythonQtRegisterToolClassesTemplateConverter(QPalette);
119 119 PythonQtRegisterToolClassesTemplateConverter(QIcon);
120 120 PythonQtRegisterToolClassesTemplateConverter(QImage);
121 121 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
122 122 PythonQtRegisterToolClassesTemplateConverter(QRegion);
123 123 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
124 124 PythonQtRegisterToolClassesTemplateConverter(QCursor);
125 125 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
126 126 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
127 127 PythonQtRegisterToolClassesTemplateConverter(QPen);
128 128 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
129 129 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
130 130 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
131 131
132 132
133 133 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
134 134 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
135 135 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
136 136 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
137 137 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
138 138 for (unsigned int i = 0;i<16; i++) {
139 139 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
140 140 if (obj) {
141 141 PyModule_AddObject(pack, names[i], obj);
142 142 Py_INCREF(obj);
143 143 PyModule_AddObject(pack2, names[i], obj);
144 144 } else {
145 145 std::cerr << "method not found " << names[i];
146 146 }
147 147 }
148 148 }
149 149 }
150 150
151 151 void PythonQt::cleanup()
152 152 {
153 153 if (_self) {
154 154 delete _self;
155 155 _self = NULL;
156 156 }
157 157 }
158 158
159 159 PythonQt* PythonQt::self() { return _self; }
160 160
161 161 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
162 162 {
163 163 _p = new PythonQtPrivate;
164 164 _p->_initFlags = flags;
165 165
166 166 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
167 167
168 168 if ((flags & PythonAlreadyInitialized) == 0) {
169 169 Py_SetProgramName(const_cast<char*>("PythonQt"));
170 170 if (flags & IgnoreSiteModule) {
171 171 // this prevents the automatic importing of Python site files
172 172 Py_NoSiteFlag = 1;
173 173 }
174 174 Py_Initialize();
175 175 }
176 176
177 177 // add our own python object types for qt object slots
178 178 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
179 179 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
180 180 }
181 181 Py_INCREF(&PythonQtSlotFunction_Type);
182 182
183 183 if (PyType_Ready(&PythonQtSignalFunction_Type) < 0) {
184 184 std::cerr << "could not initialize PythonQtSignalFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
185 185 }
186 186 Py_INCREF(&PythonQtSignalFunction_Type);
187 187
188 188 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
189 189 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
190 190 // add our own python object types for classes
191 191 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
192 192 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
193 193 }
194 194 Py_INCREF(&PythonQtClassWrapper_Type);
195 195
196 196 // add our own python object types for CPP instances
197 197 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
198 198 PythonQt::handleError();
199 199 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
200 200 }
201 201 Py_INCREF(&PythonQtInstanceWrapper_Type);
202 202
203 203 // add our own python object types for redirection of stdout
204 204 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
205 205 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
206 206 }
207 207 Py_INCREF(&PythonQtStdOutRedirectType);
208 208
209 209 // add our own python object types for redirection of stdin
210 210 if (PyType_Ready(&PythonQtStdInRedirectType) < 0) {
211 211 std::cerr << "could not initialize PythonQtStdInRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
212 212 }
213 213 Py_INCREF(&PythonQtStdInRedirectType);
214 214
215 215 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
216 216
217 217 }
218 218
219 219 PythonQt::~PythonQt() {
220 220 delete _p;
221 221 _p = NULL;
222 222 }
223 223
224 224 PythonQtPrivate::~PythonQtPrivate() {
225 225 delete _defaultImporter;
226 226 _defaultImporter = NULL;
227 227
228 228 {
229 229 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
230 230 while (i.hasNext()) {
231 231 delete i.next().value();
232 232 }
233 233 }
234 234 PythonQtConv::global_valueStorage.clear();
235 235 PythonQtConv::global_ptrStorage.clear();
236 236 PythonQtConv::global_variantStorage.clear();
237 237
238 238 PythonQtMethodInfo::cleanupCachedMethodInfos();
239 239 }
240 240
241 241 void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData)
242 242 {
243 243 if (!callback)
244 244 {
245 245 std::cerr << "PythonQt::setRedirectStdInCallback - callback parameter is NULL !" << std::endl;
246 246 return;
247 247 }
248 248
249 249 PythonQtObjectPtr sys;
250 250 PythonQtObjectPtr in;
251 251 sys.setNewRef(PyImport_ImportModule("sys"));
252 252
253 253 // Backup original 'sys.stdin' if not yet done
254 254 PyRun_SimpleString("if not hasattr(sys, 'pythonqt_original_stdin'):"
255 255 "sys.pythonqt_original_stdin = sys.stdin");
256 256
257 257 in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, NULL, NULL);
258 258 ((PythonQtStdInRedirect*)in.object())->_cb = callback;
259 259 ((PythonQtStdInRedirect*)in.object())->_callData = callbackData;
260 260 // replace the built in file objects with our own objects
261 261 PyModule_AddObject(sys, "stdin", in);
262 262
263 263 // Backup custom 'stdin' into 'pythonqt_stdin'
264 264 PyRun_SimpleString("sys.pythonqt_stdin = sys.stdin");
265 265 }
266 266
267 267 void PythonQt::setRedirectStdInCallbackEnabled(bool enabled)
268 268 {
269 269 if (enabled)
270 270 {
271 271 PyRun_SimpleString("if hasattr(sys, 'pythonqt_stdin'):"
272 272 "sys.stdin = sys.pythonqt_stdin");
273 273 }
274 274 else
275 275 {
276 276 PyRun_SimpleString("if hasattr(sys,'pythonqt_original_stdin'):"
277 277 "sys.stdin = sys.pythonqt_original_stdin");
278 278 }
279 279 }
280 280
281 281 PythonQtImportFileInterface* PythonQt::importInterface()
282 282 {
283 283 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
284 284 }
285 285
286 286 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
287 287 {
288 288 if (_self->_p->_noLongerWrappedCB) {
289 289 (*_self->_p->_noLongerWrappedCB)(o);
290 290 };
291 291 }
292 292
293 293 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
294 294 {
295 295 _p->registerClass(metaobject, package, wrapperCreator, shell);
296 296 }
297 297
298 298 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
299 299 {
300 300 // we register all classes in the hierarchy
301 301 const QMetaObject* m = metaobject;
302 302 bool first = true;
303 303 while (m) {
304 304 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
305 305 if (!info->pythonQtClassWrapper()) {
306 306 info->setTypeSlots(typeSlots);
307 307 info->setupQObject(m);
308 308 createPythonQtClassWrapper(info, package, module);
309 309 if (m->superClass()) {
310 310 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
311 311 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
312 312 }
313 313 } else if (first && module) {
314 314 // There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
315 315 // since it might have been placed into "private" earlier on.
316 316 // If the wrapper was already added to module before, it is just readded, which does no harm.
317 317 PyObject* classWrapper = info->pythonQtClassWrapper();
318 318 // AddObject steals a reference, so we need to INCREF
319 319 Py_INCREF(classWrapper);
320 320 PyModule_AddObject(module, info->className(), classWrapper);
321 321 }
322 322 if (first) {
323 323 first = false;
324 324 if (wrapperCreator) {
325 325 info->setDecoratorProvider(wrapperCreator);
326 326 }
327 327 if (shell) {
328 328 info->setShellSetInstanceWrapperCB(shell);
329 329 }
330 330 }
331 331 m = m->superClass();
332 332 }
333 333 }
334 334
335 335 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
336 336 {
337 337 PyObject* pack = module?module:packageByName(package);
338 338 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
339 339 PyModule_AddObject(pack, info->className(), pyobj);
340 340 if (!module && package && strncmp(package,"Qt",2)==0) {
341 341 // since PyModule_AddObject steals the reference, we need a incref once more...
342 342 Py_INCREF(pyobj);
343 343 // put all qt objects into Qt as well
344 344 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
345 345 }
346 346 info->setPythonQtClassWrapper(pyobj);
347 347 }
348 348
349 349 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
350 350 {
351 351 if (!obj) {
352 352 Py_INCREF(Py_None);
353 353 return Py_None;
354 354 }
355 355 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
356 356 if (wrap && wrap->_wrappedPtr) {
357 357 // uh oh, we want to wrap a QObject, but have a C++ wrapper at that
358 358 // address, so probably that C++ wrapper has been deleted earlier and
359 359 // now we see a QObject with the same address.
360 360 // Do not use the old wrapper anymore.
361 361 wrap = NULL;
362 362 }
363 363 if (!wrap) {
364 364 // smuggling it in...
365 365 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
366 366 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
367 367 registerClass(obj->metaObject());
368 368 classInfo = _knownClassInfos.value(obj->metaObject()->className());
369 369 }
370 370 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
371 371 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
372 372 } else {
373 373 Py_INCREF(wrap);
374 374 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
375 375 }
376 376 return (PyObject*)wrap;
377 377 }
378 378
379 379 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
380 380 {
381 381 if (!ptr) {
382 382 Py_INCREF(Py_None);
383 383 return Py_None;
384 384 }
385 385
386 386 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
387 387 PythonQtInstanceWrapper* possibleStillAliveWrapper = NULL;
388 388 if (wrap && wrap->_wrappedPtr) {
389 389 // we have a previous C++ wrapper... if the wrapper is for a C++ object,
390 390 // we are not sure if it may have been deleted earlier and we just see the same C++
391 391 // pointer once again. To make sure that we do not reuse a wrapper of the wrong type,
392 392 // we compare the classInfo() pointer and only reuse the wrapper if it has the same
393 393 // info. This is only needed for non-QObjects, since we know it when a QObject gets deleted.
394 394 possibleStillAliveWrapper = wrap;
395 395 wrap = NULL;
396 396 }
397 397 if (!wrap) {
398 398 PythonQtClassInfo* info = _knownClassInfos.value(name);
399 399 if (!info) {
400 400 // maybe it is a PyObject, which we can return directly
401 401 if (name == "PyObject") {
402 402 PyObject* p = (PyObject*)ptr;
403 403 Py_INCREF(p);
404 404 return p;
405 405 }
406 406
407 407 // we do not know the metaobject yet, but we might know it by its name:
408 408 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
409 409 // yes, we know it, so we can convert to QObject
410 410 QObject* qptr = (QObject*)ptr;
411 411 registerClass(qptr->metaObject());
412 412 info = _knownClassInfos.value(qptr->metaObject()->className());
413 413 }
414 414 }
415 415 if (info && info->isQObject()) {
416 416 QObject* qptr = (QObject*)ptr;
417 417 // if the object is a derived object, we want to switch the class info to the one of the derived class:
418 418 if (name!=(qptr->metaObject()->className())) {
419 419 info = _knownClassInfos.value(qptr->metaObject()->className());
420 420 if (!info) {
421 421 registerClass(qptr->metaObject());
422 422 info = _knownClassInfos.value(qptr->metaObject()->className());
423 423 }
424 424 }
425 425 wrap = createNewPythonQtInstanceWrapper(qptr, info);
426 426 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
427 427 return (PyObject*)wrap;
428 428 }
429 429
430 430 // not a known QObject, try to wrap via foreign wrapper factories
431 431 PyObject* foreignWrapper = NULL;
432 432 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
433 433 foreignWrapper = _foreignWrapperFactories.at(i)->wrap(name, ptr);
434 434 if (foreignWrapper) {
435 435 return foreignWrapper;
436 436 }
437 437 }
438 438
439 439 // not a known QObject, so try our wrapper factory:
440 440 QObject* wrapper = NULL;
441 441 for (int i=0; i<_cppWrapperFactories.size(); i++) {
442 442 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
443 443 if (wrapper) {
444 444 break;
445 445 }
446 446 }
447 447
448 448 if (info) {
449 449 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
450 450 ptr = info->castDownIfPossible(ptr, &info);
451 451
452 452 // if downcasting found out that the object is a QObject,
453 453 // handle it like one:
454 454 if (info && info->isQObject()) {
455 455 QObject* qptr = (QObject*)ptr;
456 456 // if the object is a derived object, we want to switch the class info to the one of the derived class:
457 457 if (name!=(qptr->metaObject()->className())) {
458 458 registerClass(qptr->metaObject());
459 459 info = _knownClassInfos.value(qptr->metaObject()->className());
460 460 }
461 461 wrap = createNewPythonQtInstanceWrapper(qptr, info);
462 462 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
463 463 return (PyObject*)wrap;
464 464 }
465 465 }
466 466
467 467 if (!info || info->pythonQtClassWrapper()==NULL) {
468 468 // still unknown, register as CPP class
469 469 registerCPPClass(name.constData());
470 470 info = _knownClassInfos.value(name);
471 471 }
472 472 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
473 473 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
474 474 info->setMetaObject(wrapper->metaObject());
475 475 }
476 476
477 477 if (possibleStillAliveWrapper && possibleStillAliveWrapper->classInfo() == info) {
478 478 wrap = possibleStillAliveWrapper;
479 479 Py_INCREF(wrap);
480 480 } else {
481 481 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
482 482 }
483 483 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
484 484 } else {
485 485 Py_INCREF(wrap);
486 486 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
487 487 }
488 488 return (PyObject*)wrap;
489 489 }
490 490
491 491 PyObject* PythonQtPrivate::dummyTuple() {
492 492 static PyObject* dummyTuple = NULL;
493 493 if (dummyTuple==NULL) {
494 494 dummyTuple = PyTuple_New(1);
495 495 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
496 496 }
497 497 return dummyTuple;
498 498 }
499 499
500 500
501 501 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
502 502 // call the associated class type to create a new instance...
503 503 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
504 504
505 505 result->setQObject(obj);
506 506 result->_wrappedPtr = wrappedPtr;
507 507 result->_ownedByPythonQt = false;
508 508 result->_useQMetaTypeDestroy = false;
509 509
510 510 if (wrappedPtr) {
511 511 _wrappedObjects.insert(wrappedPtr, result);
512 512 } else {
513 513 _wrappedObjects.insert(obj, result);
514 514 if (obj->parent()== NULL && _wrappedCB) {
515 515 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
516 516 (*_wrappedCB)(obj);
517 517 }
518 518 }
519 519 return result;
520 520 }
521 521
522 522 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
523 523 PythonQtClassWrapper* result;
524 524
525 525 PyObject* className = PyString_FromString(info->className());
526 526
527 527 PyObject* baseClasses = PyTuple_New(1);
528 528 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
529 529
530 530 PyObject* typeDict = PyDict_New();
531 531 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
532 532 PyDict_SetItemString(typeDict, "__module__", moduleName);
533 533
534 534 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
535 535
536 536 // set the class info so that PythonQtClassWrapper_new can read it
537 537 _currentClassInfoForClassWrapperCreation = info;
538 538 // create the new type object by calling the type
539 539 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
540 540
541 541 Py_DECREF(baseClasses);
542 542 Py_DECREF(typeDict);
543 543 Py_DECREF(args);
544 544 Py_DECREF(className);
545 545
546 546 return result;
547 547 }
548 548
549 549 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
550 550 {
551 551 PyObject* args = Py_BuildValue("(i)", enumValue);
552 552 PyObject* result = PyObject_Call(enumType, args, NULL);
553 553 Py_DECREF(args);
554 554 return result;
555 555 }
556 556
557 557 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
558 558 PyObject* result;
559 559
560 560 PyObject* className = PyString_FromString(enumName);
561 561
562 562 PyObject* baseClasses = PyTuple_New(1);
563 563 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
564 564
565 565 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
566 566 PyObject* typeDict = PyDict_New();
567 567 PyDict_SetItemString(typeDict, "__module__", module);
568 568
569 569 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
570 570
571 571 // create the new int derived type object by calling the core type
572 572 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
573 573
574 574 Py_DECREF(baseClasses);
575 575 Py_DECREF(typeDict);
576 576 Py_DECREF(args);
577 577 Py_DECREF(className);
578 578
579 579 return result;
580 580 }
581 581
582 582 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
583 583 {
584 584 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
585 585 if (!r) {
586 586 r = new PythonQtSignalReceiver(obj);
587 587 _p->_signalReceivers.insert(obj, r);
588 588 }
589 589 return r;
590 590 }
591 591
592 592 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
593 593 {
594 594 bool flag = false;
595 595 PythonQtObjectPtr callable = lookupCallable(module, objectname);
596 596 if (callable) {
597 597 PythonQtSignalReceiver* r = getSignalReceiver(obj);
598 598 flag = r->addSignalHandler(signal, callable);
599 599 if (!flag) {
600 600 // signal not found
601 601 }
602 602 } else {
603 603 // callable not found
604 604 }
605 605 return flag;
606 606 }
607 607
608 608 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
609 609 {
610 610 bool flag = false;
611 611 PythonQtSignalReceiver* r = getSignalReceiver(obj);
612 612 if (r) {
613 613 flag = r->addSignalHandler(signal, receiver);
614 614 }
615 615 return flag;
616 616 }
617 617
618 618 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
619 619 {
620 620 bool flag = false;
621 621 PythonQtObjectPtr callable = lookupCallable(module, objectname);
622 622 if (callable) {
623 623 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
624 624 if (r) {
625 625 flag = r->removeSignalHandler(signal, callable);
626 626 }
627 627 } else {
628 628 // callable not found
629 629 }
630 630 return flag;
631 631 }
632 632
633 633 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
634 634 {
635 635 bool flag = false;
636 636 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
637 637 if (r) {
638 638 flag = r->removeSignalHandler(signal, receiver);
639 639 }
640 640 return flag;
641 641 }
642 642
643 643 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
644 644 {
645 645 PythonQtObjectPtr p = lookupObject(module, name);
646 646 if (p) {
647 647 if (PyCallable_Check(p)) {
648 648 return p;
649 649 }
650 650 }
651 651 PyErr_Clear();
652 652 return NULL;
653 653 }
654 654
655 655 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
656 656 {
657 657 QStringList l = name.split('.');
658 658 PythonQtObjectPtr p = module;
659 659 PythonQtObjectPtr prev;
660 660 QByteArray b;
661 661 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
662 662 prev = p;
663 663 b = (*i).toLatin1();
664 664 if (PyDict_Check(p)) {
665 665 p = PyDict_GetItemString(p, b.data());
666 666 } else {
667 667 p.setNewRef(PyObject_GetAttrString(p, b.data()));
668 668 }
669 669 }
670 670 PyErr_Clear();
671 671 return p;
672 672 }
673 673
674 674 PythonQtObjectPtr PythonQt::getMainModule() {
675 675 //both borrowed
676 676 PythonQtObjectPtr dict = PyImport_GetModuleDict();
677 677 return PyDict_GetItemString(dict, "__main__");
678 678 }
679 679
680 680 PythonQtObjectPtr PythonQt::importModule(const QString& name)
681 681 {
682 682 PythonQtObjectPtr mod;
683 683 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
684 684 return mod;
685 685 }
686 686
687 687
688 688 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
689 689 QVariant result;
690 clearError();
690 691 if (pycode) {
691 692 PyObject* dict = NULL;
692 693 PyObject* globals = NULL;
693 694 if (PyModule_Check(object)) {
694 695 dict = PyModule_GetDict(object);
695 696 globals = dict;
696 697 } else if (PyDict_Check(object)) {
697 698 dict = object;
698 699 globals = dict;
699 700 } else {
700 701 dict = PyObject_GetAttrString(object, "__dict__");
701 702 globals = PyObject_GetAttrString(PyImport_ImportModule(PyString_AS_STRING(PyObject_GetAttrString(object, "__module__"))),"__dict__");
702 703 }
703 704 PyObject* r = NULL;
704 705 if (dict) {
705 706 r = PyEval_EvalCode((PyCodeObject*)pycode, globals , dict);
706 707 }
707 708 if (r) {
708 709 result = PythonQtConv::PyObjToQVariant(r);
709 710 Py_DECREF(r);
710 711 } else {
711 712 handleError();
712 713 }
713 714 } else {
714 715 handleError();
715 716 }
716 717 return result;
717 718 }
718 719
719 720 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
720 721 {
721 722 QVariant result;
722 723 PythonQtObjectPtr p;
723 724 PyObject* dict = NULL;
725 clearError();
724 726 if (PyModule_Check(object)) {
725 727 dict = PyModule_GetDict(object);
726 728 } else if (PyDict_Check(object)) {
727 729 dict = object;
728 730 }
729 731 if (dict) {
730 732 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
731 733 }
732 734 if (p) {
733 735 result = PythonQtConv::PyObjToQVariant(p);
734 736 } else {
735 737 handleError();
736 738 }
737 739 return result;
738 740 }
739 741
740 742 void PythonQt::evalFile(PyObject* module, const QString& filename)
741 743 {
742 744 PythonQtObjectPtr code = parseFile(filename);
745 clearError();
743 746 if (code) {
744 747 evalCode(module, code);
745 748 } else {
746 749 handleError();
747 750 }
748 751 }
749 752
750 753 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
751 754 {
752 755 PythonQtObjectPtr p;
753 756 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
757 clearError();
754 758 if (!p) {
755 759 handleError();
756 760 }
757 761 return p;
758 762 }
759 763
760 764 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
761 765 {
762 766 PythonQtObjectPtr code = parseFile(filename);
763 767 PythonQtObjectPtr module = _p->createModule(name, code);
764 768 return module;
765 769 }
766 770
767 771 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
768 772 {
769 773 PyErr_Clear();
770 774 QString scriptCode = script;
771 775 if (scriptCode.isEmpty()) {
772 776 // we always need at least a linefeed
773 777 scriptCode = "\n";
774 778 }
775 779 PythonQtObjectPtr pycode;
776 780 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
777 781 PythonQtObjectPtr module = _p->createModule(name, pycode);
778 782 return module;
779 783 }
780 784
781 785 PythonQtObjectPtr PythonQt::createUniqueModule()
782 786 {
783 787 static QString pyQtStr("PythonQt_module");
784 788 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
785 789 return createModuleFromScript(moduleName);
786 790 }
787 791
788 792 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
789 793 {
790 794 if (PyModule_Check(object)) {
791 795 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
792 796 } else if (PyDict_Check(object)) {
793 797 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
794 798 } else {
795 799 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
796 800 }
797 801 }
798 802
799 803 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
800 804 {
801 805 if (PyModule_Check(object)) {
802 806 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
803 807 } else if (PyDict_Check(object)) {
804 808 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
805 809 } else {
806 810 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
807 811 }
808 812 }
809 813
810 814 void PythonQt::removeVariable(PyObject* object, const QString& name)
811 815 {
812 816 if (PyDict_Check(object)) {
813 817 PyDict_DelItemString(object, name.toLatin1().data());
814 818 } else {
815 819 PyObject_DelAttrString(object, name.toLatin1().data());
816 820 }
817 821 }
818 822
819 823 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
820 824 {
821 825 QVariant result;
822 826 PythonQtObjectPtr obj = lookupObject(object, objectname);
823 827 if (obj) {
824 828 result = PythonQtConv::PyObjToQVariant(obj);
825 829 }
826 830 return result;
827 831 }
828 832
829 833 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
830 834 {
831 835 QStringList results;
832 836
833 837 PythonQtObjectPtr object;
834 838 if (objectname.isEmpty()) {
835 839 object = module;
836 840 } else {
837 841 object = lookupObject(module, objectname);
838 842 if (!object && type == CallOverloads) {
839 843 PyObject* dict = lookupObject(module, "__builtins__");
840 844 if (dict) {
841 845 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
842 846 }
843 847 }
844 848 }
845 849
846 850 if (object) {
847 851 results = introspectObject(object, type);
848 852 }
849 853
850 854 return results;
851 855 }
852 856
853 857 QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
854 858 {
855 859 QStringList results;
856 860
857 861 if (type == CallOverloads) {
858 862 if (PythonQtSlotFunction_Check(object)) {
859 863 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object;
860 864 PythonQtSlotInfo* info = o->m_ml;
861 865
862 866 while (info) {
863 867 results << info->fullSignature();
864 868 info = info->nextInfo();
865 869 }
866 870 } else if (PythonQtSignalFunction_Check(object)) {
867 871 PythonQtSignalFunctionObject* o = (PythonQtSignalFunctionObject*)object;
868 872 PythonQtSlotInfo* info = o->m_ml;
869 873
870 874 while (info) {
871 875 results << info->fullSignature();
872 876 info = info->nextInfo();
873 877 }
874 878 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
875 879 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
876 880 PythonQtSlotInfo* info = o->classInfo()->constructors();
877 881
878 882 while (info) {
879 883 results << info->fullSignature();
880 884 info = info->nextInfo();
881 885 }
882 886 } else {
883 887 QString signature = _p->getSignature(object);
884 888 if (!signature.isEmpty()) {
885 889 results << signature;
886 890 } else {
887 891 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
888 892 if (doc) {
889 893 results << PyString_AsString(doc);
890 894 Py_DECREF(doc);
891 895 }
892 896 }
893 897 }
894 898 } else {
895 899 PyObject* keys = NULL;
896 900 bool isDict = false;
897 901 if (PyDict_Check(object)) {
898 902 keys = PyDict_Keys(object);
899 903 isDict = true;
900 904 } else {
901 905 keys = PyObject_Dir(object);
902 906 }
903 907 if (keys) {
904 908 int count = PyList_Size(keys);
905 909 PyObject* key;
906 910 PyObject* value;
907 911 QString keystr;
908 912 for (int i = 0;i<count;i++) {
909 913 key = PyList_GetItem(keys,i);
910 914 if (isDict) {
911 915 value = PyDict_GetItem(object, key);
912 916 Py_INCREF(value);
913 917 } else {
914 918 value = PyObject_GetAttr(object, key);
915 919 }
916 920 if (!value) continue;
917 921 keystr = PyString_AsString(key);
918 922 static const QString underscoreStr("__tmp");
919 923 if (!keystr.startsWith(underscoreStr)) {
920 924 switch (type) {
921 925 case Anything:
922 926 results << keystr;
923 927 break;
924 928 case Class:
925 929 if (value->ob_type == &PyClass_Type || value->ob_type == &PyType_Type) {
926 930 results << keystr;
927 931 }
928 932 break;
929 933 case Variable:
930 934 if (value->ob_type != &PyClass_Type
931 935 && value->ob_type != &PyCFunction_Type
932 936 && value->ob_type != &PyFunction_Type
933 937 && value->ob_type != &PyMethod_Type
934 938 && value->ob_type != &PyModule_Type
935 939 && value->ob_type != &PyType_Type
936 940 && value->ob_type != &PythonQtSlotFunction_Type
937 941 ) {
938 942 results << keystr;
939 943 }
940 944 break;
941 945 case Function:
942 946 if (value->ob_type == &PyCFunction_Type ||
943 947 value->ob_type == &PyFunction_Type ||
944 948 value->ob_type == &PyMethod_Type ||
945 949 value->ob_type == &PythonQtSlotFunction_Type
946 950 ) {
947 951 results << keystr;
948 952 }
949 953 break;
950 954 case Module:
951 955 if (value->ob_type == &PyModule_Type) {
952 956 results << keystr;
953 957 }
954 958 break;
955 959 default:
956 960 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
957 961 }
958 962 }
959 963 Py_DECREF(value);
960 964 }
961 965 Py_DECREF(keys);
962 966 }
963 967 if ((type == Anything) || (type == Variable)) {
964 968 if (object->ob_type == &PythonQtClassWrapper_Type) {
965 969 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
966 970 PythonQtClassInfo* info = o->classInfo();
967 971 results += info->propertyList();
968 972 }
969 973 }
970 974 }
971 975 return results;
972 976 }
973 977
974 978 PyObject* PythonQt::getObjectByType(const QString& typeName)
975 979 {
976 980 PythonQtObjectPtr sys;
977 981 sys.setNewRef(PyImport_ImportModule("sys"));
978 982 PythonQtObjectPtr modules = lookupObject(sys, "modules");
979 983 Q_ASSERT(PyDict_Check(modules));
980 984
981 985 QStringList tmp = typeName.split(".");
982 986 QString simpleTypeName = tmp.takeLast();
983 987 QString moduleName = tmp.join(".");
984 988
985 989 PyObject* object = NULL;
986 990 PyObject* moduleObject = PyDict_GetItemString(modules, moduleName.toLatin1().constData());
987 991 if (moduleObject) {
988 992 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
989 993 }
990 994
991 995 if (!object) {
992 996 moduleObject = PyDict_GetItemString(modules, "__builtin__");
993 997 if (moduleObject) {
994 998 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
995 999 }
996 1000 }
997 1001
998 1002 return object;
999 1003 }
1000 1004
1001 1005 QStringList PythonQt::introspectType(const QString& typeName, ObjectType type)
1002 1006 {
1003 1007 QStringList results;
1004 1008 PyObject* object = getObjectByType(typeName);
1005 1009 if (!object) {
1006 1010 // the last item may be a member, split it away and try again
1007 1011 QStringList tmp = typeName.split(".");
1008 1012 QString memberName = tmp.takeLast();
1009 1013 QString typeName;
1010 1014 if (tmp.isEmpty()) {
1011 1015 typeName = memberName;
1012 1016 memberName.clear();
1013 1017 } else {
1014 1018 typeName = tmp.takeLast();
1015 1019 }
1016 1020 PyObject* typeObject = getObjectByType(typeName);
1017 1021 if (typeObject) {
1018 1022 object = PyObject_GetAttrString(typeObject, memberName.toLatin1().constData());
1019 1023 }
1020 1024 }
1021 1025 if (object) {
1022 1026 results = introspectObject(object, type);
1023 1027 Py_DECREF(object);
1024 1028 }
1025 1029 return results;
1026 1030 }
1027 1031
1028 1032 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args, const QVariantMap& kwargs)
1029 1033 {
1030 1034 PythonQtObjectPtr callable = lookupCallable(object, name);
1031 1035 if (callable) {
1032 1036 return call(callable, args, kwargs);
1033 1037 } else {
1034 1038 return QVariant();
1035 1039 }
1036 1040 }
1037 1041
1038 1042 QVariant PythonQt::call(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
1039 1043 {
1040 1044 QVariant r;
1041 1045 PythonQtObjectPtr result;
1042 1046 result.setNewRef(callAndReturnPyObject(callable, args, kwargs));
1047 clearError();
1043 1048 if (result) {
1044 1049 r = PythonQtConv::PyObjToQVariant(result);
1045 1050 } else {
1046 1051 PythonQt::self()->handleError();
1047 1052 }
1048 1053 return r;
1049 1054 }
1050 1055
1051 1056 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
1052 1057 {
1053 1058 PyObject* result = NULL;
1054 1059 if (callable) {
1055 1060 bool err = false;
1056 1061 PythonQtObjectPtr pargs;
1057 1062 int count = args.size();
1058 1063 if ((count > 0) || (kwargs.count() > 0)) { // create empty tuple if kwargs are given
1059 1064 pargs.setNewRef(PyTuple_New(count));
1060 1065
1061 1066 // transform QVariant arguments to Python
1062 1067 for (int i = 0; i < count; i++) {
1063 1068 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
1064 1069 if (arg) {
1065 1070 // steals reference, no unref
1066 1071 PyTuple_SetItem(pargs, i,arg);
1067 1072 } else {
1068 1073 err = true;
1069 1074 break;
1070 1075 }
1071 1076 }
1072 1077 }
1073 1078 if (!err) {
1074 1079 if (kwargs.isEmpty()) {
1075 1080 // do a direct call if we have no keyword arguments
1076 1081 PyErr_Clear();
1077 1082 result = PyObject_CallObject(callable, pargs);
1078 1083 } else {
1079 1084 // convert keyword arguments to Python
1080 1085 PythonQtObjectPtr pkwargs;
1081 1086 pkwargs.setNewRef(PyDict_New());
1082 1087 QMapIterator<QString, QVariant> it(kwargs);
1083 1088 while (it.hasNext()) {
1084 1089 it.next();
1085 1090 PyObject* arg = PythonQtConv::QVariantToPyObject(it.value());
1086 1091 if (arg) {
1087 1092 PyDict_SetItemString(pkwargs, it.key().toLatin1().constData(), arg);
1088 1093 } else {
1089 1094 err = true;
1090 1095 break;
1091 1096 }
1092 1097 }
1093 1098 if (!err) {
1094 1099 // call with arguments and keyword arguments
1095 1100 PyErr_Clear();
1096 1101 result = PyObject_Call(callable, pargs, pkwargs);
1097 1102 }
1098 1103 }
1099 1104 }
1100 1105 }
1101 1106 return result;
1102 1107 }
1103 1108
1104 1109 void PythonQt::addInstanceDecorators(QObject* o)
1105 1110 {
1106 1111 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
1107 1112 }
1108 1113
1109 1114 void PythonQt::addClassDecorators(QObject* o)
1110 1115 {
1111 1116 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
1112 1117 }
1113 1118
1114 1119 void PythonQt::addDecorators(QObject* o)
1115 1120 {
1116 1121 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
1117 1122 }
1118 1123
1119 1124 void PythonQt::registerQObjectClassNames(const QStringList& names)
1120 1125 {
1121 1126 _p->registerQObjectClassNames(names);
1122 1127 }
1123 1128
1124 1129 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
1125 1130 {
1126 1131 _p->_importInterface = importInterface;
1127 1132 PythonQtImport::init();
1128 1133 }
1129 1134
1130 1135 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
1131 1136 {
1132 1137 _p->_importIgnorePaths = paths;
1133 1138 }
1134 1139
1135 1140 const QStringList& PythonQt::getImporterIgnorePaths()
1136 1141 {
1137 1142 return _p->_importIgnorePaths;
1138 1143 }
1139 1144
1140 1145 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
1141 1146 {
1142 1147 _p->_cppWrapperFactories.append(factory);
1143 1148 }
1144 1149
1145 1150 void PythonQt::addWrapperFactory( PythonQtForeignWrapperFactory* factory )
1146 1151 {
1147 1152 _p->_foreignWrapperFactories.append(factory);
1148 1153 }
1149 1154
1150 1155 //---------------------------------------------------------------------------------------------------
1151 1156 PythonQtPrivate::PythonQtPrivate()
1152 1157 {
1153 1158 _importInterface = NULL;
1154 1159 _defaultImporter = new PythonQtQFileImporter;
1155 1160 _noLongerWrappedCB = NULL;
1156 1161 _wrappedCB = NULL;
1157 1162 _currentClassInfoForClassWrapperCreation = NULL;
1158 1163 _profilingCB = NULL;
1164 _hadError = false;
1165 _systemExitExceptionHandlerEnabled = false;
1159 1166 }
1160 1167
1161 1168 void PythonQtPrivate::setupSharedLibrarySuffixes()
1162 1169 {
1163 1170 _sharedLibrarySuffixes.clear();
1164 1171 PythonQtObjectPtr imp;
1165 1172 imp.setNewRef(PyImport_ImportModule("imp"));
1166 1173 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
1167 1174 QVariant result = imp.call("get_suffixes");
1168 1175 #ifdef __linux
1169 1176 #ifdef _DEBUG
1170 1177 // First look for shared libraries with the '_d' suffix in debug mode on Linux.
1171 1178 // This is a workaround, because python does not append the '_d' suffix on Linux
1172 1179 // and would always load the release library otherwise.
1173 1180 _sharedLibrarySuffixes << "_d.so";
1174 1181 #endif
1175 1182 #endif
1176 1183 foreach (QVariant entry, result.toList()) {
1177 1184 QVariantList suffixEntry = entry.toList();
1178 1185 if (suffixEntry.count()==3) {
1179 1186 int code = suffixEntry.at(2).toInt();
1180 1187 if (code == cExtensionCode) {
1181 1188 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
1182 1189 }
1183 1190 }
1184 1191 }
1185 1192 }
1186 1193
1187 1194 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
1188 1195 {
1189 1196 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
1190 1197 _currentClassInfoForClassWrapperCreation = NULL;
1191 1198 return info;
1192 1199 }
1193 1200
1194 1201 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
1195 1202 {
1196 1203 o->setParent(this);
1197 1204 int numMethods = o->metaObject()->methodCount();
1198 1205 for (int i = 0; i < numMethods; i++) {
1199 1206 QMetaMethod m = o->metaObject()->method(i);
1200 1207 if ((m.methodType() == QMetaMethod::Method ||
1201 1208 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
1202 1209 if (qstrncmp(m.signature(), "new_", 4)==0) {
1203 1210 if ((decoTypes & ConstructorDecorator) == 0) continue;
1204 1211 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1205 1212 if (info->parameters().at(0).pointerCount == 1) {
1206 1213 QByteArray signature = m.signature();
1207 1214 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
1208 1215 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1209 1216 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1210 1217 classInfo->addConstructor(newSlot);
1211 1218 }
1212 1219 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
1213 1220 if ((decoTypes & DestructorDecorator) == 0) continue;
1214 1221 QByteArray signature = m.signature();
1215 1222 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
1216 1223 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1217 1224 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1218 1225 classInfo->setDestructor(newSlot);
1219 1226 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
1220 1227 if ((decoTypes & StaticDecorator) == 0) continue;
1221 1228 QByteArray signature = m.signature();
1222 1229 QByteArray nameOfClass = signature.mid(7);
1223 1230 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
1224 1231 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1225 1232 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1226 1233 classInfo->addDecoratorSlot(newSlot);
1227 1234 } else {
1228 1235 if ((decoTypes & InstanceDecorator) == 0) continue;
1229 1236 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1230 1237 if (info->parameters().count()>1) {
1231 1238 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
1232 1239 if (p.pointerCount==1) {
1233 1240 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
1234 1241 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
1235 1242 classInfo->addDecoratorSlot(newSlot);
1236 1243 }
1237 1244 }
1238 1245 }
1239 1246 }
1240 1247 }
1241 1248 }
1242 1249
1243 1250 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
1244 1251 {
1245 1252 foreach(QString name, names) {
1246 1253 _knownQObjectClassNames.insert(name.toLatin1(), true);
1247 1254 }
1248 1255 }
1249 1256
1250 1257 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1251 1258 {
1252 1259 _signalReceivers.remove(obj);
1253 1260 }
1254 1261
1262 namespace
1263 {
1264 //! adapted from python source file "pythonrun.c", function "handle_system_exit"
1265 //! return the exitcode instead of calling "Py_Exit".
1266 //! it gives the application an opportunity to properly terminate.
1267 int custom_system_exit_exception_handler()
1268 {
1269 PyObject *exception, *value, *tb;
1270 int exitcode = 0;
1271
1272 // if (Py_InspectFlag)
1273 // /* Don't exit if -i flag was given. This flag is set to 0
1274 // * when entering interactive mode for inspecting. */
1275 // return exitcode;
1276
1277 PyErr_Fetch(&exception, &value, &tb);
1278 if (Py_FlushLine())
1279 PyErr_Clear();
1280 fflush(stdout);
1281 if (value == NULL || value == Py_None)
1282 goto done;
1283 if (PyExceptionInstance_Check(value)) {
1284 /* The error code should be in the `code' attribute. */
1285 PyObject *code = PyObject_GetAttrString(value, "code");
1286 if (code) {
1287 Py_DECREF(value);
1288 value = code;
1289 if (value == Py_None)
1290 goto done;
1291 }
1292 /* If we failed to dig out the 'code' attribute,
1293 just let the else clause below print the error. */
1294 }
1295 if (PyInt_Check(value))
1296 exitcode = (int)PyInt_AsLong(value);
1297 else {
1298 PyObject *sys_stderr = PySys_GetObject(const_cast<char*>("stderr"));
1299 if (sys_stderr != NULL && sys_stderr != Py_None) {
1300 PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW);
1301 } else {
1302 PyObject_Print(value, stderr, Py_PRINT_RAW);
1303 fflush(stderr);
1304 }
1305 PySys_WriteStderr("\n");
1306 exitcode = 1;
1307 }
1308 done:
1309 /* Restore and clear the exception info, in order to properly decref
1310 * the exception, value, and traceback. If we just exit instead,
1311 * these leak, which confuses PYTHONDUMPREFS output, and may prevent
1312 * some finalizers from running.
1313 */
1314 PyErr_Restore(exception, value, tb);
1315 PyErr_Clear();
1316 return exitcode;
1317 //Py_Exit(exitcode);
1318 }
1319 }
1320
1255 1321 bool PythonQt::handleError()
1256 1322 {
1257 1323 bool flag = false;
1258 1324 if (PyErr_Occurred()) {
1259 1325
1260 // currently we just print the error and the stderr handler parses the errors
1261 PyErr_Print();
1262
1263 /*
1264 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1265 PyObject *ptype;
1266 PyObject *pvalue;
1267 PyObject *ptraceback;
1268 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1269
1270 Py_XDECREF(ptype);
1271 Py_XDECREF(pvalue);
1272 Py_XDECREF(ptraceback);
1273 */
1274 PyErr_Clear();
1326 if (_p->_systemExitExceptionHandlerEnabled &&
1327 PyErr_ExceptionMatches(PyExc_SystemExit)) {
1328 int exitcode = custom_system_exit_exception_handler();
1329 emit PythonQt::self()->systemExitExceptionRaised(exitcode);
1330 }
1331 else
1332 {
1333 // currently we just print the error and the stderr handler parses the errors
1334 PyErr_Print();
1335
1336 /*
1337 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1338 PyObject *ptype;
1339 PyObject *pvalue;
1340 PyObject *ptraceback;
1341 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1342
1343 Py_XDECREF(ptype);
1344 Py_XDECREF(pvalue);
1345 Py_XDECREF(ptraceback);
1346 */
1347 PyErr_Clear();
1348 }
1275 1349 flag = true;
1276 1350 }
1351 _p->_hadError = flag;
1277 1352 return flag;
1278 1353 }
1279 1354
1355 bool PythonQt::hadError()const
1356 {
1357 return _p->_hadError;
1358 }
1359
1360 void PythonQt::clearError()
1361 {
1362 _p->_hadError = false;
1363 }
1364
1365 void PythonQt::setSystemExitExceptionHandlerEnabled(bool value)
1366 {
1367 _p->_systemExitExceptionHandlerEnabled = value;
1368 }
1369
1370 bool PythonQt::systemExitExceptionHandlerEnabled() const
1371 {
1372 return _p->_systemExitExceptionHandlerEnabled;
1373 }
1374
1280 1375 void PythonQt::addSysPath(const QString& path)
1281 1376 {
1282 1377 PythonQtObjectPtr sys;
1283 1378 sys.setNewRef(PyImport_ImportModule("sys"));
1284 1379 PythonQtObjectPtr obj = lookupObject(sys, "path");
1285 1380 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1286 1381 }
1287 1382
1288 1383 void PythonQt::overwriteSysPath(const QStringList& paths)
1289 1384 {
1290 1385 PythonQtObjectPtr sys;
1291 1386 sys.setNewRef(PyImport_ImportModule("sys"));
1292 1387 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1293 1388 }
1294 1389
1295 1390 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1296 1391 {
1297 1392 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1298 1393 }
1299 1394
1300 1395 void PythonQt::stdOutRedirectCB(const QString& str)
1301 1396 {
1302 1397 if (!PythonQt::self()) {
1303 1398 std::cout << str.toLatin1().data() << std::endl;
1304 1399 return;
1305 1400 }
1306 1401 emit PythonQt::self()->pythonStdOut(str);
1307 1402 }
1308 1403
1309 1404 void PythonQt::stdErrRedirectCB(const QString& str)
1310 1405 {
1311 1406 if (!PythonQt::self()) {
1312 1407 std::cerr << str.toLatin1().data() << std::endl;
1313 1408 return;
1314 1409 }
1315 1410 emit PythonQt::self()->pythonStdErr(str);
1316 1411 }
1317 1412
1318 1413 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1319 1414 {
1320 1415 _p->_wrappedCB = cb;
1321 1416 }
1322 1417
1323 1418 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1324 1419 {
1325 1420 _p->_noLongerWrappedCB = cb;
1326 1421 }
1327 1422
1328 1423 void PythonQt::setProfilingCallback(ProfilingCB* cb)
1329 1424 {
1330 1425 _p->_profilingCB = cb;
1331 1426 }
1332 1427
1333 1428
1334 1429 static PyMethodDef PythonQtMethods[] = {
1335 1430 {NULL, NULL, 0, NULL}
1336 1431 };
1337 1432
1338 1433 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1339 1434 {
1340 1435 QByteArray name = "PythonQt";
1341 1436 if (!pythonQtModuleName.isEmpty()) {
1342 1437 name = pythonQtModuleName;
1343 1438 }
1344 1439 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1345 1440 _p->_pythonQtModuleName = name;
1346 1441
1347 1442 if (redirectStdOut) {
1348 1443 PythonQtObjectPtr sys;
1349 1444 PythonQtObjectPtr out;
1350 1445 PythonQtObjectPtr err;
1351 1446 sys.setNewRef(PyImport_ImportModule("sys"));
1352 1447 // create a redirection object for stdout and stderr
1353 1448 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1354 1449 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1355 1450 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1356 1451 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1357 1452 // replace the built in file objects with our own objects
1358 1453 PyModule_AddObject(sys, "stdout", out);
1359 1454 PyModule_AddObject(sys, "stderr", err);
1360 1455 }
1361 1456 }
1362 1457
1363 1458 QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString& name)
1364 1459 {
1365 1460 QStringList tmp = name.split(".");
1366 1461 QString methodName = tmp.takeLast();
1367 1462 QString variableName = tmp.join(".");
1368 1463 // TODO: the variableName may be a type name, this needs to be handled differently,
1369 1464 // because it is not necessarily known in the module context
1370 1465 PythonQtObjectPtr variableObject = lookupObject(module, variableName);
1371 1466 if (variableObject.isNull()) {
1372 1467 return "";
1373 1468 }
1374 1469
1375 1470 return getReturnTypeOfWrappedMethodHelper(variableObject, methodName, name);
1376 1471 }
1377 1472
1378 1473 QString PythonQt::getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName)
1379 1474 {
1380 1475 PythonQtObjectPtr typeObject = getObjectByType(typeName);
1381 1476 if (typeObject.isNull()) {
1382 1477 return "";
1383 1478 }
1384 1479 return getReturnTypeOfWrappedMethodHelper(typeObject, methodName, typeName + "." + methodName);
1385 1480 }
1386 1481
1387 1482 QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context)
1388 1483 {
1389 1484 PythonQtObjectPtr methodObject;
1390 1485 if (PyDict_Check(variableObject)) {
1391 1486 methodObject = PyDict_GetItemString(variableObject, methodName.toLatin1().constData());
1392 1487 } else {
1393 1488 methodObject.setNewRef(PyObject_GetAttrString(variableObject, methodName.toLatin1().constData()));
1394 1489 }
1395 1490 if (methodObject.isNull()) {
1396 1491 return "";
1397 1492 }
1398 1493
1399 1494 QString type;
1400 1495
1401 1496 if (methodObject->ob_type == &PyClass_Type || methodObject->ob_type == &PyType_Type) {
1402 1497 // the methodObject is not a method, but the name of a type/class. This means
1403 1498 // a constructor is called. Return the context.
1404 1499 type = context;
1405 1500 } else if (methodObject->ob_type == &PythonQtSlotFunction_Type) {
1406 1501 QString className;
1407 1502
1408 1503 if (PyObject_TypeCheck(variableObject, &PythonQtInstanceWrapper_Type)) {
1409 1504 // the type name of wrapped instance is the class name
1410 1505 className = variableObject->ob_type->tp_name;
1411 1506 } else {
1412 1507 PyObject* classNameObject = PyObject_GetAttrString(variableObject, "__name__");
1413 1508 if (classNameObject) {
1414 1509 Q_ASSERT(PyString_Check(classNameObject));
1415 1510 className = PyString_AsString(classNameObject);
1416 1511 Py_DECREF(classNameObject);
1417 1512 }
1418 1513 }
1419 1514
1420 1515 if (!className.isEmpty()) {
1421 1516 PythonQtClassInfo* info = _p->_knownClassInfos.value(className.toLatin1().constData());
1422 1517 if (info) {
1423 1518 PythonQtSlotInfo* slotInfo = info->member(methodName.toLatin1().constData())._slot;
1424 1519 if (slotInfo) {
1425 1520 if (slotInfo->metaMethod()) {
1426 1521 type = slotInfo->metaMethod()->typeName();
1427 1522 if (!type.isEmpty()) {
1428 1523 QChar c = type.at(type.length()-1);
1429 1524 while (c == '*' || c == '&') {
1430 1525 type.truncate(type.length()-1);
1431 1526 if (!type.isEmpty()) {
1432 1527 c = type.at(type.length()-1);
1433 1528 } else {
1434 1529 break;
1435 1530 }
1436 1531 }
1437 1532 // split away template arguments
1438 1533 type = type.split("<").first();
1439 1534 // split away const
1440 1535 type = type.split(" ").last().trimmed();
1441 1536
1442 1537 // if the type is a known class info, then create the full type name, i.e. include the
1443 1538 // module name. For example, the slot may return a QDate, then this looks up the
1444 1539 // name _PythonQt.QtCore.QDate.
1445 1540 PythonQtClassInfo* typeInfo = _p->_knownClassInfos.value(type.toLatin1().constData());
1446 1541 if (typeInfo && typeInfo->pythonQtClassWrapper()) {
1447 1542 PyObject* s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__module__");
1448 1543 Q_ASSERT(PyString_Check(s));
1449 1544 type = QString(PyString_AsString(s)) + "." + type;
1450 1545 Py_DECREF(s);
1451 1546 s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__name__");
1452 1547 Q_ASSERT(PyString_Check(s));
1453 1548 Py_DECREF(s);
1454 1549 }
1455 1550 }
1456 1551 }
1457 1552 }
1458 1553 }
1459 1554 }
1460 1555 }
1461 1556 return type;
1462 1557 }
1463 1558
1464 1559 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1465 1560 {
1466 1561 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1467 1562 }
1468 1563
1469 1564
1470 1565 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1471 1566 {
1472 1567 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1473 1568 if (!info) {
1474 1569 info = new PythonQtClassInfo();
1475 1570 info->setupCPPObject(typeName);
1476 1571 _knownClassInfos.insert(typeName, info);
1477 1572 }
1478 1573 return info;
1479 1574 }
1480 1575
1481 1576 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1482 1577 {
1483 1578 _p->addPolymorphicHandler(typeName, cb);
1484 1579 }
1485 1580
1486 1581 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1487 1582 {
1488 1583 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1489 1584 info->addPolymorphicHandler(cb);
1490 1585 }
1491 1586
1492 1587 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1493 1588 {
1494 1589 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1495 1590 }
1496 1591
1497 1592 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1498 1593 {
1499 1594 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1500 1595 if (info) {
1501 1596 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1502 1597 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1503 1598 return true;
1504 1599 } else {
1505 1600 return false;
1506 1601 }
1507 1602 }
1508 1603
1509 1604 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1510 1605 {
1511 1606 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1512 1607 if (!info->pythonQtClassWrapper()) {
1513 1608 info->setTypeSlots(typeSlots);
1514 1609 info->setupCPPObject(typeName);
1515 1610 createPythonQtClassWrapper(info, package, module);
1516 1611 }
1517 1612 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1518 1613 addParentClass(typeName, parentTypeName, 0);
1519 1614 }
1520 1615 if (wrapperCreator) {
1521 1616 info->setDecoratorProvider(wrapperCreator);
1522 1617 }
1523 1618 if (shell) {
1524 1619 info->setShellSetInstanceWrapperCB(shell);
1525 1620 }
1526 1621 }
1527 1622
1528 1623 PyObject* PythonQtPrivate::packageByName(const char* name)
1529 1624 {
1530 1625 if (name==NULL || name[0]==0) {
1531 1626 name = "private";
1532 1627 }
1533 1628 PyObject* v = _packages.value(name);
1534 1629 if (!v) {
1535 1630 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1536 1631 _packages.insert(name, v);
1537 1632 // AddObject steals the reference, so increment it!
1538 1633 Py_INCREF(v);
1539 1634 PyModule_AddObject(_pythonQtModule, name, v);
1540 1635 }
1541 1636 return v;
1542 1637 }
1543 1638
1544 1639 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1545 1640 {
1546 1641 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;
1547 1642 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1548 1643 PythonQt::self()->handleError();
1549 1644 }
1550 1645
1551 1646 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1552 1647 {
1553 1648 if (_p->_initFlags & ExternalHelp) {
1554 1649 emit pythonHelpRequest(QByteArray(info->className()));
1555 1650 return Py_BuildValue("");
1556 1651 } else {
1557 1652 return PyString_FromString(info->help().toLatin1().data());
1558 1653 }
1559 1654 }
1560 1655
1561 1656 void PythonQt::clearNotFoundCachedMembers()
1562 1657 {
1563 1658 foreach(PythonQtClassInfo* info, _p->_knownClassInfos) {
1564 1659 info->clearNotFoundCachedMembers();
1565 1660 }
1566 1661 }
1567 1662
1568 1663 void PythonQt::removeWrapperFactory( PythonQtCppWrapperFactory* factory )
1569 1664 {
1570 1665 _p->_cppWrapperFactories.removeAll(factory);
1571 1666 }
1572 1667
1573 1668 void PythonQt::removeWrapperFactory( PythonQtForeignWrapperFactory* factory )
1574 1669 {
1575 1670 _p->_foreignWrapperFactories.removeAll(factory);
1576 1671 }
1577 1672
1578 1673 void PythonQtPrivate::removeWrapperPointer(void* obj)
1579 1674 {
1580 1675 _wrappedObjects.remove(obj);
1581 1676 }
1582 1677
1583 1678 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1584 1679 {
1585 1680 _wrappedObjects.insert(obj, wrapper);
1586 1681 }
1587 1682
1588 1683 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1589 1684 {
1590 1685 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1591 1686 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1592 1687 // this is a wrapper whose QObject was already removed due to destruction
1593 1688 // so the obj pointer has to be a new QObject with the same address...
1594 1689 // we remove the old one and set the copy to NULL
1595 1690 wrap->_objPointerCopy = NULL;
1596 1691 removeWrapperPointer(obj);
1597 1692 wrap = NULL;
1598 1693 }
1599 1694 return wrap;
1600 1695 }
1601 1696
1602 1697 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1603 1698 {
1604 1699 PythonQtObjectPtr result;
1700 PythonQt::self()->clearError();
1605 1701 if (pycode) {
1606 1702 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1607 1703 } else {
1608 1704 PythonQt::self()->handleError();
1609 1705 }
1610 1706 return result;
1611 1707 }
1612 1708
1613 1709 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObject* obj )
1614 1710 {
1615 1711 void* foreignObject = NULL;
1616 1712 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
1617 1713 foreignObject = _foreignWrapperFactories.at(i)->unwrap(classname, obj);
1618 1714 if (foreignObject) {
1619 1715 return foreignObject;
1620 1716 }
1621 1717 }
1622 1718 return NULL;
1623 1719 }
1624 1720
1625 1721 bool PythonQtPrivate::isMethodDescriptor(PyObject* object) const
1626 1722 {
1627 1723 // This implementation is the same as in inspect.ismethoddescriptor(), inspect.py.
1628 1724 if (PyObject_HasAttrString(object, "__get__") &&
1629 1725 !PyObject_HasAttrString(object, "__set__") &&
1630 1726 !PyMethod_Check(object) &&
1631 1727 !PyFunction_Check(object) &&
1632 1728 !PyClass_Check(object)) {
1633 1729 return true;
1634 1730 }
1635 1731 return false;
1636 1732 }
1637 1733
1638 1734 QString PythonQtPrivate::getSignature(PyObject* object)
1639 1735 {
1640 1736 QString signature;
1641 1737
1642 1738 if (object) {
1643 1739 PyMethodObject* method = NULL;
1644 1740 PyFunctionObject* func = NULL;
1645 1741
1646 1742 bool decrefMethod = false;
1647 1743
1648 1744 if (object->ob_type == &PyClass_Type || object->ob_type == &PyType_Type) {
1649 1745 method = (PyMethodObject*)PyObject_GetAttrString(object, "__init__");
1650 1746 decrefMethod = true;
1651 1747 } else if (object->ob_type == &PyFunction_Type) {
1652 1748 func = (PyFunctionObject*)object;
1653 1749 } else if (object->ob_type == &PyMethod_Type) {
1654 1750 method = (PyMethodObject*)object;
1655 1751 }
1656 1752 if (method) {
1657 1753 if (PyFunction_Check(method->im_func)) {
1658 1754 func = (PyFunctionObject*)method->im_func;
1659 1755 } else if (isMethodDescriptor((PyObject*)method)) {
1660 1756 QString docstr;
1661 1757 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
1662 1758 if (doc) {
1663 1759 docstr = PyString_AsString(doc);
1664 1760 Py_DECREF(doc);
1665 1761 }
1666 1762
1667 1763 PyObject* s = PyObject_GetAttrString(object, "__name__");
1668 1764 if (s) {
1669 1765 Q_ASSERT(PyString_Check(s));
1670 1766 signature = PyString_AsString(s);
1671 1767 if (docstr.startsWith(signature + "(")) {
1672 1768 signature = docstr;
1673 1769 } else {
1674 1770 signature += "(...)";
1675 1771 if (!docstr.isEmpty()) {
1676 1772 signature += "\n\n" + docstr;
1677 1773 }
1678 1774 }
1679 1775 Py_DECREF(s);
1680 1776 }
1681 1777 }
1682 1778 }
1683 1779
1684 1780 if (func) {
1685 1781 QString funcName;
1686 1782 PyObject* s = PyObject_GetAttrString((PyObject*)func, "__name__");
1687 1783 if (s) {
1688 1784 Q_ASSERT(PyString_Check(s));
1689 1785 funcName = PyString_AsString(s);
1690 1786 Py_DECREF(s);
1691 1787 }
1692 1788 if (method && funcName == "__init__") {
1693 1789 PyObject* s = PyObject_GetAttrString(object, "__name__");
1694 1790 if (s) {
1695 1791 Q_ASSERT(PyString_Check(s));
1696 1792 funcName = PyString_AsString(s);
1697 1793 Py_DECREF(s);
1698 1794 }
1699 1795 }
1700 1796
1701 1797 QStringList arguments;
1702 1798 QStringList defaults;
1703 1799 QString varargs;
1704 1800 QString varkeywords;
1705 1801 // NOTE: This implementation is based on function getargs() in inspect.py.
1706 1802 // inspect.getargs() can handle anonymous (tuple) arguments, while this code does not.
1707 1803 // It can be implemented, but it may be rarely needed and not necessary.
1708 1804 PyCodeObject* code = (PyCodeObject*)func->func_code;
1709 1805 if (code->co_varnames) {
1710 1806 int nargs = code->co_argcount;
1711 1807 Q_ASSERT(PyTuple_Check(code->co_varnames));
1712 1808 for (int i=0; i<nargs; i++) {
1713 1809 PyObject* name = PyTuple_GetItem(code->co_varnames, i);
1714 1810 Q_ASSERT(PyString_Check(name));
1715 1811 arguments << PyString_AsString(name);
1716 1812 }
1717 1813 if (code->co_flags & CO_VARARGS) {
1718 1814 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1719 1815 Q_ASSERT(PyString_Check(s));
1720 1816 varargs = PyString_AsString(s);
1721 1817 nargs += 1;
1722 1818 }
1723 1819 if (code->co_flags & CO_VARKEYWORDS) {
1724 1820 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1725 1821 Q_ASSERT(PyString_Check(s));
1726 1822 varkeywords = PyString_AsString(s);
1727 1823 }
1728 1824 }
1729 1825
1730 1826 PyObject* defaultsTuple = func->func_defaults;
1731 1827 if (defaultsTuple) {
1732 1828 Q_ASSERT(PyTuple_Check(defaultsTuple));
1733 1829 for (Py_ssize_t i=0; i<PyTuple_Size(defaultsTuple); i++) {
1734 1830 PyObject* d = PyTuple_GetItem(defaultsTuple, i);
1735 1831 PyObject* s = PyObject_Repr(d);
1736 1832 Q_ASSERT(PyString_Check(s));
1737 1833 defaults << PyString_AsString(s);
1738 1834 Py_DECREF(s);
1739 1835 }
1740 1836 }
1741 1837
1742 1838 int firstdefault = arguments.size() - defaults.size();
1743 1839 for (int i=0; i<arguments.size(); i++) {
1744 1840 if (!signature.isEmpty()) { signature += ", "; }
1745 1841 if (!method || i>0 || arguments[i] != "self") {
1746 1842 signature += arguments[i];
1747 1843 if (i >= firstdefault) {
1748 1844 signature += "=" + defaults[i-firstdefault];
1749 1845 }
1750 1846 }
1751 1847 }
1752 1848 if (!varargs.isEmpty()) {
1753 1849 if (!signature.isEmpty()) { signature += ", "; }
1754 1850 signature += "*" + varargs;
1755 1851 }
1756 1852 if (!varkeywords.isEmpty()) {
1757 1853 if (!signature.isEmpty()) { signature += ", "; }
1758 1854 signature += "**" + varkeywords;
1759 1855 }
1760 1856 signature = funcName + "(" + signature + ")";
1761 1857 }
1762 1858
1763 1859 if (method && decrefMethod) {
1764 1860 Py_DECREF(method);
1765 1861 }
1766 1862 }
1767 1863
1768 1864 return signature;
1769 1865 }
1770 1866
1771 1867 void PythonQtPrivate::shellClassDeleted( void* shellClass )
1772 1868 {
1773 1869 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(shellClass);
1774 1870 if (wrap && wrap->_wrappedPtr) {
1775 1871 // this is a pure C++ wrapper and the shell has gone, so we need
1776 1872 // to set the _wrappedPtr to NULL on the wrapper
1777 1873 wrap->_wrappedPtr = NULL;
1778 1874 // and then we remove the wrapper, since the wrapped class is gone
1779 1875 _wrappedObjects.remove(shellClass);
1780 1876 }
1781 1877 // if the wrapper is a QObject, we do not handle this here,
1782 1878 // it will be handled by the QPointer<> to the QObject, which becomes NULL
1783 1879 // via the QObject destructor.
1784 1880 }
1785 1881
1786 1882 PyObject* PythonQtPrivate::wrapMemoryAsBuffer( const void* data, Py_ssize_t size )
1787 1883 {
1788 1884 // P3K port needed later on!
1789 1885 return PyBuffer_FromMemory((void*)data, size);
1790 1886 }
1791 1887
1792 1888 PyObject* PythonQtPrivate::wrapMemoryAsBuffer( void* data, Py_ssize_t size )
1793 1889 {
1794 1890 // P3K port needed later on!
1795 1891 return PyBuffer_FromReadWriteMemory(data, size);
1796 } No newline at end of file
1892 }
@@ -1,720 +1,743
1 1 #ifndef _PYTHONQT_H
2 2 #define _PYTHONQT_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQt.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include "PythonQtInstanceWrapper.h"
47 47 #include "PythonQtClassWrapper.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtObjectPtr.h"
50 50 #include "PythonQtStdIn.h"
51 51 #include <QObject>
52 52 #include <QVariant>
53 53 #include <QList>
54 54 #include <QHash>
55 55 #include <QByteArray>
56 56 #include <QStringList>
57 57 #include <QtDebug>
58 58 #include <iostream>
59 59
60 60
61 61 class PythonQtClassInfo;
62 62 class PythonQtPrivate;
63 63 class PythonQtMethodInfo;
64 64 class PythonQtSignalReceiver;
65 65 class PythonQtImportFileInterface;
66 66 class PythonQtCppWrapperFactory;
67 67 class PythonQtForeignWrapperFactory;
68 68 class PythonQtQFileImporter;
69 69
70 70 typedef void PythonQtQObjectWrappedCB(QObject* object);
71 71 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
72 72 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, const char **class_name);
73 73
74 74 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
75 75
76 76 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) {
77 77 (reinterpret_cast<T*>(object))->_wrapper = wrapper;
78 78 }
79 79
80 80 //! returns the offset that needs to be added to upcast an object of type T1 to T2
81 81 template<class T1, class T2> int PythonQtUpcastingOffset() {
82 82 return ((reinterpret_cast<char*>(static_cast<T2*>(reinterpret_cast<T1*>(0x100))))
83 83 - (reinterpret_cast<char*>(reinterpret_cast<T1*>(0x100))));
84 84 }
85 85
86 86 //! callback to create a QObject lazily
87 87 typedef QObject* PythonQtQObjectCreatorFunctionCB();
88 88
89 89 //! helper template to create a derived QObject class
90 90 template<class T> QObject* PythonQtCreateObject() { return new T(); };
91 91
92 92 //! The main interface to the Python Qt binding, realized as a singleton
93 93 /*!
94 94 Use PythonQt::init() to initialize the singleton and PythonQt::self() to access it.
95 95 While there can be only one PythonQt instance, you can have any number of Python context to do scripting in.
96 96 One possibility is to use createModuleFromFile(), createModuleFromScript() or createUniqueModule() to get a context
97 97 that is separated from the other contexts. Alternatively you can use Python dicts as contexts for script evaluation,
98 98 but you will need to populate the dict with the __builtins__ instance to have all Pythons available when running
99 99 code in the scope of a dict.
100 100 */
101 101 class PYTHONQT_EXPORT PythonQt : public QObject {
102 102
103 103 Q_OBJECT
104 104
105 105 public:
106 106
107 107 //! flags that can be passed to PythonQt::init()
108 108 enum InitFlags {
109 109 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
110 110 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
111 111 ExternalHelp = 4, //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
112 112 PythonAlreadyInitialized = 8 //!<< sets that PythonQt should not can PyInitialize, since it is already done
113 113 };
114 114
115 115 //! flags that tell PythonQt which operators to expect on the registered type
116 116 enum TypeSlots {
117 117 Type_Add = 1,
118 118 Type_Subtract = 1 << 1,
119 119 Type_Multiply = 1 << 2,
120 120 Type_Divide = 1 << 3,
121 121 Type_Mod = 1 << 4,
122 122 Type_And = 1 << 5,
123 123 Type_Or = 1 << 6,
124 124 Type_Xor = 1 << 7,
125 125 Type_LShift = 1 << 8,
126 126 Type_RShift = 1 << 9,
127 127
128 128 Type_InplaceAdd = 1 << 10,
129 129 Type_InplaceSubtract = 1 << 11,
130 130 Type_InplaceMultiply = 1 << 12,
131 131 Type_InplaceDivide = 1 << 13,
132 132 Type_InplaceMod = 1 << 14,
133 133 Type_InplaceAnd = 1 << 15,
134 134 Type_InplaceOr = 1 << 16,
135 135 Type_InplaceXor = 1 << 17,
136 136 Type_InplaceLShift = 1 << 18,
137 137 Type_InplaceRShift = 1 << 19,
138 138
139 139 // Not yet needed/nicely mappable/generated...
140 140 //Type_Positive = 1 << 29,
141 141 //Type_Negative = 1 << 29,
142 142 //Type_Abs = 1 << 29,
143 143 //Type_Hash = 1 << 29,
144 144
145 145 Type_Invert = 1 << 29,
146 146 Type_RichCompare = 1 << 30,
147 147 Type_NonZero = 1 << 31,
148 148
149 149 };
150 150
151 151 //! enum for profiling callback
152 152 enum ProfilingCallbackState {
153 153 Enter = 1,
154 154 Leave = 2
155 155 };
156 156
157 157 //! callback for profiling. className and methodName are only passed when state == Enter, otherwise
158 158 //! they are NULL.
159 159 typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName);
160 160
161 161 //---------------------------------------------------------------------------
162 162 //! \name Singleton Initialization
163 163 //@{
164 164
165 165 //! initialize the python qt binding (flags are a or combination of PythonQt::InitFlags), if \c pythonQtModuleName is given
166 166 //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
167 167 //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
168 168 static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray());
169 169
170 170 //! cleanup of the singleton
171 171 static void cleanup();
172 172
173 173 //! get the singleton instance
174 174 static PythonQt* self();
175 175
176 176 //@}
177 177
178 178 //! defines the object types for introspection
179 179 enum ObjectType {
180 180 Class,
181 181 Function,
182 182 Variable,
183 183 Module,
184 184 Anything,
185 185 CallOverloads
186 186 };
187 187
188 188
189 189 //---------------------------------------------------------------------------
190 190 //! \name Standard input handling
191 191 //@{
192 192
193 193 //! Overwrite default handling of stdin using a custom callback. It internally backup
194 194 //! the original 'sys.stdin' into 'sys.pythonqt_original_stdin'
195 195 void setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData = 0);
196 196
197 197 //! Enable or disable stdin custom callback. It resets 'sys.stdin' using either 'sys.pythonqt_stdin'
198 198 //! or 'sys.pythonqt_original_stdin'
199 199 void setRedirectStdInCallbackEnabled(bool enabled);
200 200
201 201 //@}
202 202
203 203 //---------------------------------------------------------------------------
204 204 //! \name Modules
205 205 //@{
206 206
207 207 //! get the __main__ module of python
208 208 PythonQtObjectPtr getMainModule();
209 209
210 210 //! import the given module and return a reference to it (useful to import e.g. "sys" and call something on it)
211 211 //! If a module is already imported, this returns the already imported module.
212 212 PythonQtObjectPtr importModule(const QString& name);
213 213
214 214 //! creates the new module \c name and evaluates the given file in the context of that module
215 215 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
216 216 //! to a module later on.
217 217 //! The user needs to make sure that the \c name is unique in the python module dictionary.
218 218 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
219 219
220 220 //! creates the new module \c name and evaluates the given script in the context of that module.
221 221 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
222 222 //! to a module later on.
223 223 //! The user needs to make sure that the \c name is unique in the python module dictionary.
224 224 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
225 225
226 226 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
227 227 //! script code
228 228 PythonQtObjectPtr createUniqueModule();
229 229
230 230 //@}
231 231
232 232 //---------------------------------------------------------------------------
233 233 //! \name Importing/Paths
234 234 //@{
235 235
236 236 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
237 237 void overwriteSysPath(const QStringList& paths);
238 238
239 239 //! prepend a path to sys.path to allow importing from it
240 240 void addSysPath(const QString& path);
241 241
242 242 //! sets the __path__ list of a module to the given list (important for local imports)
243 243 void setModuleImportPath(PyObject* module, const QStringList& paths);
244 244
245 245 //@}
246 246
247 247 //---------------------------------------------------------------------------
248 248 //! \name Registering Classes
249 249 //@{
250 250
251 251 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
252 252 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
253 253 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
254 254 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
255 255
256 256 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
257 257 //! (ownership of wrapper is passed to PythonQt)
258 258 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
259 259
260 260 This will add a wrapper object that is used to make calls to the given classname \c typeName.
261 261 All slots that take a pointer to typeName as the first argument will be callable from Python on
262 262 a variant object that contains such a type.
263 263 */
264 264 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
265 265
266 266 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
267 267 //! and it will register the classes when it first sees a pointer to such a derived class
268 268 void registerQObjectClassNames(const QStringList& names);
269 269
270 270 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
271 271 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
272 272 //! type is really derived from parentType.
273 273 //! Returns false if the typeName was not yet registered.
274 274 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
275 275
276 276 //! add a handler for polymorphic downcasting
277 277 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
278 278
279 279 //@}
280 280
281 281 //---------------------------------------------------------------------------
282 282 //! \name Script Parsing and Evaluation
283 283 //@{
284 284
285 285 //! parses the given file and returns the python code object, this can then be used to call evalCode()
286 286 PythonQtObjectPtr parseFile(const QString& filename);
287 287
288 288 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
289 289 //! If pycode is NULL, a python error is printed.
290 290 QVariant evalCode(PyObject* object, PyObject* pycode);
291 291
292 292 //! evaluates the given script code and returns the result value
293 293 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
294 294
295 295 //! evaluates the given script code from file
296 296 void evalFile(PyObject* object, const QString& filename);
297 297
298 298 //@}
299 299
300 300 //---------------------------------------------------------------------------
301 301 //! \name Signal Handlers
302 302 //@{
303 303
304 304 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
305 305 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
306 306
307 307 //! remove a signal handler from the given \c signal of \c obj
308 308 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
309 309
310 310 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
311 311 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
312 312
313 313 //! remove a signal handler from the given \c signal of \c obj
314 314 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
315 315
316 316 //@}
317 317
318 318 //---------------------------------------------------------------------------
319 319 //! \name Variable access
320 320 //@{
321 321
322 322 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
323 323 void addObject(PyObject* object, const QString& name, QObject* qObject);
324 324
325 325 //! add the given variable to the object
326 326 void addVariable(PyObject* object, const QString& name, const QVariant& v);
327 327
328 328 //! remove the given variable
329 329 void removeVariable(PyObject* module, const QString& name);
330 330
331 331 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
332 332 QVariant getVariable(PyObject* object, const QString& name);
333 333
334 334 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
335 335 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
336 336 //! read vars etc. in scope of the given \c object
337 337 QStringList introspectObject(PyObject* object, ObjectType type);
338 338 //! read vars etc. in scope of the type object called \c typename. First the typename
339 339 //! of the form module.type is split into module and type. Then the module is looked up
340 340 //! in sys.modules. If the module or type is not found there, then the type is looked up in
341 341 //! the __builtin__ module.
342 342 QStringList introspectType(const QString& typeName, ObjectType type);
343 343
344 344 //! returns the found callable object or NULL
345 345 //! @return new reference
346 346 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
347 347
348 348 //! returns the return type of the method of a wrapped c++ object referenced by \c objectname
349 349 QString getReturnTypeOfWrappedMethod(PyObject* module, const QString& objectname);
350 350 //! returns the return type of the method \c methodName of a wrapped c++ type referenced by \c typeName
351 351 QString getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName);
352 352 //@}
353 353
354 354 //---------------------------------------------------------------------------
355 355 //! \name Calling Python Objects
356 356 //@{
357 357
358 358 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
359 359 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList(), const QVariantMap& kwargs = QVariantMap());
360 360
361 361 //! call the given python object, returns the result converted to a QVariant
362 362 QVariant call(PyObject* callable, const QVariantList& args = QVariantList(), const QVariantMap& kwargs = QVariantMap());
363 363
364 364 //! call the given python object, returns the result as new PyObject
365 365 PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList(), const QVariantMap& kwargs = QVariantMap());
366 366
367 367 //@}
368 368
369 369 //---------------------------------------------------------------------------
370 370 //! \name Decorations, Constructors, Wrappers...
371 371 //@{
372 372
373 373 //! add an object whose slots will be used as decorator slots for
374 374 //! other QObjects or CPP classes. The slots need to follow the
375 375 //! convention that the first argument is a pointer to the wrapped object.
376 376 //! (ownership is passed to PythonQt)
377 377 /*!
378 378 Example:
379 379
380 380 A slot with the signature
381 381
382 382 \code
383 383 bool doSomething(QWidget* w, int a)
384 384 \endcode
385 385
386 386 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
387 387 that will be called with the concrete instance as first argument.
388 388 So in Python you can now e.g. call
389 389
390 390 \code
391 391 someWidget.doSomething(12)
392 392 \endcode
393 393
394 394 without QWidget really having this method. This allows to easily make normal methods
395 395 of Qt classes callable by forwarding them with such decorator slots
396 396 or to make CPP classes (which are not derived from QObject) callable from Python.
397 397 */
398 398 void addInstanceDecorators(QObject* o);
399 399
400 400 //! add an object whose slots will be used as decorator slots for
401 401 //! class objects (ownership is passed to PythonQt)
402 402 /*!
403 403 The slots need to follow the following convention:
404 404 - SomeClass* new_SomeClass(...)
405 405 - QVariant new_SomeClass(...)
406 406 - void delete_SomeClass(SomeClass*)
407 407 - ... static_SomeClass_someName(...)
408 408
409 409 This will add:
410 410 - a constructor
411 411 - a constructor which generates a QVariant
412 412 - a destructor (only useful for CPP objects)
413 413 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
414 414
415 415 */
416 416 void addClassDecorators(QObject* o);
417 417
418 418 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
419 419 void addDecorators(QObject* o);
420 420
421 421 //! add the given factory to PythonQt (ownership stays with caller)
422 422 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
423 423
424 424 //! add the given factory to PythonQt (ownership stays with caller)
425 425 void addWrapperFactory(PythonQtForeignWrapperFactory* factory);
426 426
427 427 //! remove the wrapper factory
428 428 void removeWrapperFactory(PythonQtCppWrapperFactory* factory);
429 429
430 430 //! remove the wrapper factory
431 431 void removeWrapperFactory(PythonQtForeignWrapperFactory* factory);
432 432
433 433 //@}
434 434
435 435 //---------------------------------------------------------------------------
436 436 //! \name Custom Importer
437 437 //@{
438 438
439 439 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
440 440 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
441 441 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
442 442 //! This is not reversible, so even setting setImporter(NULL) afterwards will
443 443 //! keep the custom PythonQt importer with a QFile default import interface.
444 444 //! Subsequent python import calls will make use of the passed importInterface
445 445 //! which forwards all import calls to the given \c importInterface.
446 446 //! Passing NULL will install a default QFile importer.
447 447 //! (\c importInterface ownership stays with caller)
448 448 void setImporter(PythonQtImportFileInterface* importInterface);
449 449
450 450 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
451 451 //! (without calling setImporter or installDefaultImporter at least once, the default python import
452 452 //! mechanism is in place)
453 453 //! the default importer allows to import files from anywhere QFile can read from,
454 454 //! including the Qt resource system using ":". Keep in mind that you need to extend
455 455 //! "sys.path" with ":" to be able to import from the Qt resources.
456 456 void installDefaultImporter() { setImporter(NULL); }
457 457
458 458 //! set paths that the importer should ignore
459 459 void setImporterIgnorePaths(const QStringList& paths);
460 460
461 461 //! get paths that the importer should ignore
462 462 const QStringList& getImporterIgnorePaths();
463 463
464 464 //! get access to the file importer (if set)
465 465 static PythonQtImportFileInterface* importInterface();
466 466
467 467 //@}
468 468
469 469 //---------------------------------------------------------------------------
470 470 //! \name Other Stuff
471 471 //@{
472 472
473 473 //! get access to internal data (should not be used on the public API, but is used by some C functions)
474 474 static PythonQtPrivate* priv() { return _self->_p; }
475 475
476 //! clear all NotFound entries on all class infos, to ensure that
477 //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded
478 void clearNotFoundCachedMembers();
479
476 480 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
477 481 //! The error is currently just output to the python stderr, future version might implement better trace printing
478 482 bool handleError();
479 483
480 //! clear all NotFound entries on all class infos, to ensure that
481 //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded
482 void clearNotFoundCachedMembers();
484 //! return \a true if \a handleError() has been called and an error occured.
485 bool hadError()const;
486
487 //! reset error flag. After calling this, hadError() will return false.
488 //! \sa hadError()
489 void clearError();
490
491 //! if set to true, the systemExitExceptionRaised signal will be emitted if exception SystemExit is caught
492 //! \sa handleError()
493 void setSystemExitExceptionHandlerEnabled(bool value);
483 494
484 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
495 //! return \a true if SystemExit exception is handled by PythonQt
496 //! \sa setSystemExitExceptionHandlerEnabled()
497 bool systemExitExceptionHandlerEnabled() const;
498
499 //! set a callback that is called when a QObject with parent == NULL is wrapped by PythonQt
485 500 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
486 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
501 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by PythonQt
487 502 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
488 503
489 504 //! call the callback if it is set
490 505 static void qObjectNoLongerWrappedCB(QObject* o);
491 506
492 507 //! called by internal help methods
493 508 PyObject* helpCalled(PythonQtClassInfo* info);
494 509
495 510 //! returns the found object or NULL
496 511 //! @return new reference
497 512 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
498 513
499 514 //! sets a callback that is called before and after function calls for profiling
500 515 void setProfilingCallback(ProfilingCB* cb);
501 516
502 517 //@}
503 518
504 519 signals:
505 520 //! emitted when python outputs something to stdout (and redirection is turned on)
506 521 void pythonStdOut(const QString& str);
507 522 //! emitted when python outputs something to stderr (and redirection is turned on)
508 523 void pythonStdErr(const QString& str);
509 524
510 525 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
511 526 void pythonHelpRequest(const QByteArray& cppClassName);
512 527
528 //! emitted when both custom SystemExit exception handler is enabled and a SystemExit
529 //! exception is raised.
530 //! \sa setSystemExitExceptionHandlerEnabled(bool)
531 void systemExitExceptionRaised(int exitCode);
532
513 533 private:
514 534 void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
515 535
516 536 QString getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context);
517 537
518 538 PyObject* getObjectByType(const QString& typeName);
519 539
520 540 //! callback for stdout redirection, emits pythonStdOut signal
521 541 static void stdOutRedirectCB(const QString& str);
522 542 //! callback for stderr redirection, emits pythonStdErr signal
523 543 static void stdErrRedirectCB(const QString& str);
524 544
525 545 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
526 546 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
527 547
528 548 PythonQt(int flags, const QByteArray& pythonQtModuleName);
529 549 ~PythonQt();
530 550
531 551 static PythonQt* _self;
532 552 static int _uniqueModuleCount;
533 553
534 554 PythonQtPrivate* _p;
535 555
536 556 };
537 557
538 558 //! internal PythonQt details
539 559 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
540 560
541 561 Q_OBJECT
542 562
543 563 public:
544 564 PythonQtPrivate();
545 565 ~PythonQtPrivate();
546 566
547 567 enum DecoratorTypes {
548 568 StaticDecorator = 1,
549 569 ConstructorDecorator = 2,
550 570 DestructorDecorator = 4,
551 571 InstanceDecorator = 8,
552 572 AllDecorators = 0xffff
553 573 };
554 574
555 575 //! get the suffixes that are used for shared libraries
556 576 const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
557 577
558 578 //! returns if the id is the id for PythonQtObjectPtr
559 579 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
560 580
561 581 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
562 582 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
563 583 //! remove the wrapper ptr again
564 584 void removeWrapperPointer(void* obj);
565 585
566 586 //! called by destructor of shells to allow invalidation of the Python wrapper
567 587 void shellClassDeleted(void* shellClass);
568 588
569 589 //! try to unwrap the given object to a C++ pointer using the foreign wrapper factories
570 590 void* unwrapForeignWrapper(const QByteArray& classname, PyObject* obj);
571 591
572 592 //! add parent class relation
573 593 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
574 594
575 595 //! add a handler for polymorphic downcasting
576 596 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
577 597
578 598 //! lookup existing classinfo and return new if not yet present
579 599 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
580 600
581 601 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
582 602 void removeSignalEmitter(QObject* obj);
583 603
584 604 //! wrap the given QObject into a Python object (or return existing wrapper!)
585 605 PyObject* wrapQObject(QObject* obj);
586 606
587 607 //! wrap the given ptr into a Python object (or return existing wrapper!) if there is a known QObject of that name or a known wrapper in the factory
588 608 PyObject* wrapPtr(void* ptr, const QByteArray& name);
589 609
590 610 //! create a read-only buffer object from the given memory
591 611 static PyObject* wrapMemoryAsBuffer(const void* data, Py_ssize_t size);
592 612
593 613 //! create a read-write buffer object from the given memory
594 614 static PyObject* wrapMemoryAsBuffer(void* data, Py_ssize_t size);
595 615
596 616 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
597 617 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
598 618 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
599 619 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
600 620
601 621 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
602 622 //! (ownership of wrapper is passed to PythonQt)
603 623 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
604 624
605 625 This will add a wrapper object that is used to make calls to the given classname \c typeName.
606 626 All slots that take a pointer to typeName as the first argument will be callable from Python on
607 627 a variant object that contains such a type.
608 628 */
609 629 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
610 630
611 631 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
612 632 //! and it will register the classes when it first sees a pointer to such a derived class
613 633 void registerQObjectClassNames(const QStringList& names);
614 634
615 635 //! add a decorator object
616 636 void addDecorators(QObject* o, int decoTypes);
617 637
618 638 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
619 639 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
620 640
621 641 //! create a new instance of the given enum type with given value (returns a new reference)
622 642 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
623 643
624 644 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
625 645 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
626 646
627 647 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
628 648 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
629 649
630 650 //! get the class info for a meta object (if available)
631 651 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
632 652
633 653 //! get the class info for a meta object (if available)
634 654 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
635 655
636 656 //! creates the new module from the given pycode
637 657 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
638 658
639 659 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
640 660 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
641 661
642 662 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
643 663 static PyObject* dummyTuple();
644 664
645 665 //! called by virtual overloads when a python return value can not be converted to the required Qt type
646 666 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
647 667
648 668 //! get access to the PythonQt module
649 669 PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
650 670
651 671 //! returns the profiling callback, which may be NULL
652 672 PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
653 673
654 674 //! determines the signature of the given callable object (similar as pydoc)
655 675 QString getSignature(PyObject* object);
656 676
657 677 //! returns true if the object is a method descriptor (same as inspect.ismethoddescriptor() in inspect.py)
658 678 bool isMethodDescriptor(PyObject* object) const;
659 679
660 680 private:
661 681 //! Setup the shared library suffixes by getting them from the "imp" module.
662 682 void setupSharedLibrarySuffixes();
663 683
664 684 //! create a new pythonqt class wrapper and place it in the pythonqt module
665 685 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
666 686
667 687 //! get/create new package module (the returned object is a borrowed reference)
668 688 PyObject* packageByName(const char* name);
669 689
670 690 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
671 691 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
672 692
673 693 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
674 694 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
675 695
676 696 //! stores the meta info of known Qt classes
677 697 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
678 698
679 699 //! names of qobject derived classes that can be casted to qobject savely
680 700 QHash<QByteArray, bool> _knownQObjectClassNames;
681 701
682 702 //! stores signal receivers for QObjects
683 703 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
684 704
685 705 //! the PythonQt python module
686 706 PythonQtObjectPtr _pythonQtModule;
687 707
688 708 //! the name of the PythonQt python module
689 709 QByteArray _pythonQtModuleName;
690 710
691 711 //! the importer interface (if set)
692 712 PythonQtImportFileInterface* _importInterface;
693 713
694 714 //! the default importer
695 715 PythonQtQFileImporter* _defaultImporter;
696 716
697 717 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
698 718 PythonQtQObjectWrappedCB* _wrappedCB;
699 719
700 720 QStringList _importIgnorePaths;
701 721 QStringList _sharedLibrarySuffixes;
702 722
703 723 //! the cpp object wrapper factories
704 724 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
705 725
706 726 QList<PythonQtForeignWrapperFactory*> _foreignWrapperFactories;
707 727
708 728 QHash<QByteArray, PyObject*> _packages;
709 729
710 730 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
711 731
712 732 PythonQt::ProfilingCB* _profilingCB;
713 733
714 734 int _initFlags;
715 735 int _PythonQtObjectPtr_metaId;
716 736
737 bool _hadError;
738 bool _systemExitExceptionHandlerEnabled;
739
717 740 friend class PythonQt;
718 741 };
719 742
720 743 #endif
@@ -1,55 +1,56
1 1 /*
2 2 *
3 3 * Copyright (C) 2011 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 #ifndef __PythonQtPythonInclude_h
34 34 #define __PythonQtPythonInclude_h
35 35
36 36 // Undefine macros that Python.h defines to avoid redefinition warning.
37 37 #undef _POSIX_C_SOURCE
38 38 #undef _POSIX_THREADS
39 39 #undef _XOPEN_SOURCE
40 40
41 41 // If PYTHONQT_USE_RELEASE_PYTHON_FALLBACK is enabled, try to link
42 42 // release Python DLL if it is available by undefining _DEBUG while
43 43 // including Python.h
44 44 #if defined(PYTHONQT_USE_RELEASE_PYTHON_FALLBACK) && defined(_DEBUG)
45 45 #undef _DEBUG
46 46 #if defined(_MSC_VER) && _MSC_VER >= 1400
47 47 #define _CRT_NOFORCE_MANIFEST 1
48 #define _STL_NOFORCE_MANIFEST 1
48 49 #endif
49 50 #include <Python.h>
50 51 #define _DEBUG
51 52 #else
52 53 #include <Python.h>
53 54 #endif
54 55
55 56 #endif
@@ -1,152 +1,159
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 59 QString output;
60 60 if (PyTuple_GET_SIZE(args)>=1) {
61 61 PyObject* obj = PyTuple_GET_ITEM(args,0);
62 62 if (PyUnicode_Check(obj)) {
63 63 PyObject *tmp = PyUnicode_AsUTF8String(obj);
64 64 if(tmp) {
65 65 output = QString::fromUtf8(PyString_AS_STRING(tmp));
66 66 Py_DECREF(tmp);
67 67 } else {
68 68 return NULL;
69 69 }
70 70 } else {
71 71 char *string;
72 72 if (!PyArg_ParseTuple(args, "s", &string)) {
73 73 return NULL;
74 74 }
75 75 output = QString::fromLatin1(string);
76 76 }
77 77 }
78 78
79 79 if (s->softspace > 0) {
80 80 (*s->_cb)(QString(""));
81 81 s->softspace = 0;
82 82 }
83 83
84 84 (*s->_cb)(output);
85 85 }
86 86 return Py_BuildValue("");
87 87 }
88 88
89 89 static PyObject *PythonQtStdOutRedirect_flush(PyObject * /*self*/, PyObject * /*args*/)
90 90 {
91 91 return Py_BuildValue("");
92 92 }
93 93
94
94 static PyObject *PythonQtStdOutRedirect_isatty(PyObject * /*self*/, PyObject * /*args*/)
95 {
96 Py_INCREF(Py_False);
97 return Py_False;
98 }
95 99
96 100 static PyMethodDef PythonQtStdOutRedirect_methods[] = {
97 101 {"write", (PyCFunction)PythonQtStdOutRedirect_write, METH_VARARGS,
98 102 "redirect the writing to a callback"},
99 103 {"flush", (PyCFunction)PythonQtStdOutRedirect_flush, METH_VARARGS,
100 104 "flush the output, currently not implemented but needed for logging framework"
101 105 },
106 {"isatty", (PyCFunction)PythonQtStdOutRedirect_isatty, METH_NOARGS,
107 "return False since this object is not a tty-like device. Needed for logging framework"
108 },
102 109 {NULL, NULL, 0 , NULL} /* sentinel */
103 110 };
104 111
105 112 static PyMemberDef PythonQtStdOutRedirect_members[] = {
106 113 {const_cast<char*>("softspace"), T_INT, offsetof(PythonQtStdOutRedirect, softspace), 0,
107 114 const_cast<char*>("soft space flag")
108 115 },
109 116 {NULL} /* Sentinel */
110 117 };
111 118
112 119 PyTypeObject PythonQtStdOutRedirectType = {
113 120 PyObject_HEAD_INIT(NULL)
114 121 0, /*ob_size*/
115 122 "PythonQtStdOutRedirect", /*tp_name*/
116 123 sizeof(PythonQtStdOutRedirect), /*tp_basicsize*/
117 124 0, /*tp_itemsize*/
118 125 0, /*tp_dealloc*/
119 126 0, /*tp_print*/
120 127 0, /*tp_getattr*/
121 128 0, /*tp_setattr*/
122 129 0, /*tp_compare*/
123 130 0, /*tp_repr*/
124 131 0, /*tp_as_number*/
125 132 0, /*tp_as_sequence*/
126 133 0, /*tp_as_mapping*/
127 134 0, /*tp_hash */
128 135 0, /*tp_call*/
129 136 0, /*tp_str*/
130 137 0, /*tp_getattro*/
131 138 0, /*tp_setattro*/
132 139 0, /*tp_as_buffer*/
133 140 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
134 141 "PythonQtStdOutRedirect", /* tp_doc */
135 142 0, /* tp_traverse */
136 143 0, /* tp_clear */
137 144 0, /* tp_richcompare */
138 145 0, /* tp_weaklistoffset */
139 146 0, /* tp_iter */
140 147 0, /* tp_iternext */
141 148 PythonQtStdOutRedirect_methods, /* tp_methods */
142 149 PythonQtStdOutRedirect_members, /* tp_members */
143 150 0, /* tp_getset */
144 151 0, /* tp_base */
145 152 0, /* tp_dict */
146 153 0, /* tp_descr_get */
147 154 0, /* tp_descr_set */
148 155 0, /* tp_dictoffset */
149 156 0, /* tp_init */
150 157 0, /* tp_alloc */
151 158 PythonQtStdOutRedirect_new, /* tp_new */
152 159 };
General Comments 0
You need to be logged in to leave comments. Login now