##// END OF EJS Templates
added remove method for wrapper factories...
florianlink -
r168:215258552523
parent child
Show More
@@ -1,1342 +1,1352
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignalReceiver.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtStdIn.h"
49 49 #include "PythonQtStdOut.h"
50 50 #include "PythonQtCppWrapperFactory.h"
51 51 #include "PythonQtVariants.h"
52 52 #include "PythonQtStdDecorators.h"
53 53 #include "PythonQtQFileImporter.h"
54 54 #include <pydebug.h>
55 55 #include <vector>
56 56
57 57 PythonQt* PythonQt::_self = NULL;
58 58 int PythonQt::_uniqueModuleCount = 0;
59 59
60 60 void PythonQt_init_QtGuiBuiltin(PyObject*);
61 61 void PythonQt_init_QtCoreBuiltin(PyObject*);
62 62
63 63 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
64 64 {
65 65 if (!_self) {
66 66 _self = new PythonQt(flags, pythonQtModuleName);
67 67
68 68 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
69 69 qRegisterMetaType<QList<QObject*> >("QList<void*>");
70 70
71 71 PythonQtRegisterToolClassesTemplateConverter(int);
72 72 PythonQtRegisterToolClassesTemplateConverter(float);
73 73 PythonQtRegisterToolClassesTemplateConverter(double);
74 74 PythonQtRegisterToolClassesTemplateConverter(qint32);
75 75 PythonQtRegisterToolClassesTemplateConverter(quint32);
76 76 PythonQtRegisterToolClassesTemplateConverter(qint64);
77 77 PythonQtRegisterToolClassesTemplateConverter(quint64);
78 78 // TODO: which other POD types should be available for QList etc.
79 79
80 80 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
81 81
82 82 PythonQt_init_QtCoreBuiltin(NULL);
83 83 PythonQt_init_QtGuiBuiltin(NULL);
84 84
85 85 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
86 86 PythonQtRegisterToolClassesTemplateConverter(QDate);
87 87 PythonQtRegisterToolClassesTemplateConverter(QTime);
88 88 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
89 89 PythonQtRegisterToolClassesTemplateConverter(QUrl);
90 90 PythonQtRegisterToolClassesTemplateConverter(QLocale);
91 91 PythonQtRegisterToolClassesTemplateConverter(QRect);
92 92 PythonQtRegisterToolClassesTemplateConverter(QRectF);
93 93 PythonQtRegisterToolClassesTemplateConverter(QSize);
94 94 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
95 95 PythonQtRegisterToolClassesTemplateConverter(QLine);
96 96 PythonQtRegisterToolClassesTemplateConverter(QLineF);
97 97 PythonQtRegisterToolClassesTemplateConverter(QPoint);
98 98 PythonQtRegisterToolClassesTemplateConverter(QPointF);
99 99 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
100 100
101 101 PythonQtRegisterToolClassesTemplateConverter(QFont);
102 102 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
103 103 PythonQtRegisterToolClassesTemplateConverter(QBrush);
104 104 PythonQtRegisterToolClassesTemplateConverter(QColor);
105 105 PythonQtRegisterToolClassesTemplateConverter(QPalette);
106 106 PythonQtRegisterToolClassesTemplateConverter(QIcon);
107 107 PythonQtRegisterToolClassesTemplateConverter(QImage);
108 108 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
109 109 PythonQtRegisterToolClassesTemplateConverter(QRegion);
110 110 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
111 111 PythonQtRegisterToolClassesTemplateConverter(QCursor);
112 112 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
113 113 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
114 114 PythonQtRegisterToolClassesTemplateConverter(QPen);
115 115 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
116 116 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
117 117 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
118 118
119 119
120 120 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
121 121 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
122 122 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
123 123 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
124 124 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
125 125 for (unsigned int i = 0;i<16; i++) {
126 126 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
127 127 if (obj) {
128 128 PyModule_AddObject(pack, names[i], obj);
129 129 Py_INCREF(obj);
130 130 PyModule_AddObject(pack2, names[i], obj);
131 131 } else {
132 132 std::cerr << "method not found " << names[i];
133 133 }
134 134 }
135 135 }
136 136 }
137 137
138 138 void PythonQt::cleanup()
139 139 {
140 140 if (_self) {
141 141 delete _self;
142 142 _self = NULL;
143 143 }
144 144 }
145 145
146 146 PythonQt* PythonQt::self() { return _self; }
147 147
148 148 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
149 149 {
150 150 _p = new PythonQtPrivate;
151 151 _p->_initFlags = flags;
152 152
153 153 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
154 154
155 155 if ((flags & PythonAlreadyInitialized) == 0) {
156 156 Py_SetProgramName(const_cast<char*>("PythonQt"));
157 157 if (flags & IgnoreSiteModule) {
158 158 // this prevents the automatic importing of Python site files
159 159 Py_NoSiteFlag = 1;
160 160 }
161 161 Py_Initialize();
162 162 }
163 163
164 164 // add our own python object types for qt object slots
165 165 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
166 166 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
167 167 }
168 168 Py_INCREF(&PythonQtSlotFunction_Type);
169 169
170 170 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
171 171 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
172 172 // add our own python object types for classes
173 173 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
174 174 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
175 175 }
176 176 Py_INCREF(&PythonQtClassWrapper_Type);
177 177
178 178 // add our own python object types for CPP instances
179 179 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
180 180 PythonQt::handleError();
181 181 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
182 182 }
183 183 Py_INCREF(&PythonQtInstanceWrapper_Type);
184 184
185 185 // add our own python object types for redirection of stdout
186 186 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
187 187 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
188 188 }
189 189 Py_INCREF(&PythonQtStdOutRedirectType);
190 190
191 191 // add our own python object types for redirection of stdin
192 192 if (PyType_Ready(&PythonQtStdInRedirectType) < 0) {
193 193 std::cerr << "could not initialize PythonQtStdInRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
194 194 }
195 195 Py_INCREF(&PythonQtStdInRedirectType);
196 196
197 197 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
198 198
199 199 _p->setupSharedLibrarySuffixes();
200 200
201 201 }
202 202
203 203 PythonQt::~PythonQt() {
204 204 delete _p;
205 205 _p = NULL;
206 206 }
207 207
208 208 PythonQtPrivate::~PythonQtPrivate() {
209 209 delete _defaultImporter;
210 210 _defaultImporter = NULL;
211 211
212 212 {
213 213 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
214 214 while (i.hasNext()) {
215 215 delete i.next().value();
216 216 }
217 217 }
218 218 PythonQtConv::global_valueStorage.clear();
219 219 PythonQtConv::global_ptrStorage.clear();
220 220 PythonQtConv::global_variantStorage.clear();
221 221
222 222 PythonQtMethodInfo::cleanupCachedMethodInfos();
223 223 }
224 224
225 225 void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData)
226 226 {
227 227 if (!callback)
228 228 {
229 229 std::cerr << "PythonQt::setRedirectStdInCallback - callback parameter is NULL !" << std::endl;
230 230 return;
231 231 }
232 232
233 233 PythonQtObjectPtr sys;
234 234 PythonQtObjectPtr in;
235 235 sys.setNewRef(PyImport_ImportModule("sys"));
236 236
237 237 // Backup original 'sys.stdin' if not yet done
238 238 PyRun_SimpleString("if not hasattr(sys, 'pythonqt_original_stdin'):"
239 239 "sys.pythonqt_original_stdin = sys.stdin");
240 240
241 241 in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, NULL, NULL);
242 242 ((PythonQtStdInRedirect*)in.object())->_cb = callback;
243 243 ((PythonQtStdInRedirect*)in.object())->_callData = callbackData;
244 244 // replace the built in file objects with our own objects
245 245 PyModule_AddObject(sys, "stdin", in);
246 246
247 247 // Backup custom 'stdin' into 'pythonqt_stdin'
248 248 PyRun_SimpleString("sys.pythonqt_stdin = sys.stdin");
249 249 }
250 250
251 251 void PythonQt::setRedirectStdInCallbackEnabled(bool enabled)
252 252 {
253 253 if (enabled)
254 254 {
255 255 PyRun_SimpleString("if hasattr(sys, 'pythonqt_stdin'):"
256 256 "sys.stdin = sys.pythonqt_stdin");
257 257 }
258 258 else
259 259 {
260 260 PyRun_SimpleString("if hasattr(sys,'pythonqt_original_stdin'):"
261 261 "sys.stdin = sys.pythonqt_original_stdin");
262 262 }
263 263 }
264 264
265 265 PythonQtImportFileInterface* PythonQt::importInterface()
266 266 {
267 267 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
268 268 }
269 269
270 270 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
271 271 {
272 272 if (_self->_p->_noLongerWrappedCB) {
273 273 (*_self->_p->_noLongerWrappedCB)(o);
274 274 };
275 275 }
276 276
277 277 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
278 278 {
279 279 _p->registerClass(metaobject, package, wrapperCreator, shell);
280 280 }
281 281
282 282 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
283 283 {
284 284 // we register all classes in the hierarchy
285 285 const QMetaObject* m = metaobject;
286 286 bool first = true;
287 287 while (m) {
288 288 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
289 289 if (!info->pythonQtClassWrapper()) {
290 290 info->setTypeSlots(typeSlots);
291 291 info->setupQObject(m);
292 292 createPythonQtClassWrapper(info, package, module);
293 293 if (m->superClass()) {
294 294 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
295 295 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
296 296 }
297 297 } else if (first && module) {
298 298 // There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
299 299 // since it might have been placed into "private" earlier on.
300 300 // If the wrapper was already added to module before, it is just readded, which does no harm.
301 301 PyObject* classWrapper = info->pythonQtClassWrapper();
302 302 // AddObject steals a reference, so we need to INCREF
303 303 Py_INCREF(classWrapper);
304 304 PyModule_AddObject(module, info->className(), classWrapper);
305 305 }
306 306 if (first) {
307 307 first = false;
308 308 if (wrapperCreator) {
309 309 info->setDecoratorProvider(wrapperCreator);
310 310 }
311 311 if (shell) {
312 312 info->setShellSetInstanceWrapperCB(shell);
313 313 }
314 314 }
315 315 m = m->superClass();
316 316 }
317 317 }
318 318
319 319 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
320 320 {
321 321 PyObject* pack = module?module:packageByName(package);
322 322 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
323 323 PyModule_AddObject(pack, info->className(), pyobj);
324 324 if (!module && package && strncmp(package,"Qt",2)==0) {
325 325 // since PyModule_AddObject steals the reference, we need a incref once more...
326 326 Py_INCREF(pyobj);
327 327 // put all qt objects into Qt as well
328 328 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
329 329 }
330 330 info->setPythonQtClassWrapper(pyobj);
331 331 }
332 332
333 333 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
334 334 {
335 335 if (!obj) {
336 336 Py_INCREF(Py_None);
337 337 return Py_None;
338 338 }
339 339 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
340 340 if (!wrap) {
341 341 // smuggling it in...
342 342 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
343 343 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
344 344 registerClass(obj->metaObject());
345 345 classInfo = _knownClassInfos.value(obj->metaObject()->className());
346 346 }
347 347 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
348 348 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
349 349 } else {
350 350 Py_INCREF(wrap);
351 351 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
352 352 }
353 353 return (PyObject*)wrap;
354 354 }
355 355
356 356 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
357 357 {
358 358 if (!ptr) {
359 359 Py_INCREF(Py_None);
360 360 return Py_None;
361 361 }
362 362
363 363 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
364 364 if (!wrap) {
365 365 PythonQtClassInfo* info = _knownClassInfos.value(name);
366 366 if (!info) {
367 367 // maybe it is a PyObject, which we can return directly
368 368 if (name == "PyObject") {
369 369 PyObject* p = (PyObject*)ptr;
370 370 Py_INCREF(p);
371 371 return p;
372 372 }
373 373
374 374 // we do not know the metaobject yet, but we might know it by it's name:
375 375 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
376 376 // yes, we know it, so we can convert to QObject
377 377 QObject* qptr = (QObject*)ptr;
378 378 registerClass(qptr->metaObject());
379 379 info = _knownClassInfos.value(qptr->metaObject()->className());
380 380 }
381 381 }
382 382 if (info && info->isQObject()) {
383 383 QObject* qptr = (QObject*)ptr;
384 384 // if the object is a derived object, we want to switch the class info to the one of the derived class:
385 385 if (name!=(qptr->metaObject()->className())) {
386 386 registerClass(qptr->metaObject());
387 387 info = _knownClassInfos.value(qptr->metaObject()->className());
388 388 }
389 389 wrap = createNewPythonQtInstanceWrapper(qptr, info);
390 390 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
391 391 return (PyObject*)wrap;
392 392 }
393 393
394 394 // not a known QObject, try to wrap via foreign wrapper factories
395 395 PyObject* foreignWrapper = NULL;
396 396 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
397 397 foreignWrapper = _foreignWrapperFactories.at(i)->wrap(name, ptr);
398 398 if (foreignWrapper) {
399 399 return foreignWrapper;
400 400 }
401 401 }
402 402
403 403 // not a known QObject, so try our wrapper factory:
404 404 QObject* wrapper = NULL;
405 405 for (int i=0; i<_cppWrapperFactories.size(); i++) {
406 406 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
407 407 if (wrapper) {
408 408 break;
409 409 }
410 410 }
411 411
412 412 if (info) {
413 413 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
414 414 ptr = info->castDownIfPossible(ptr, &info);
415 415 }
416 416
417 417 if (!info || info->pythonQtClassWrapper()==NULL) {
418 418 // still unknown, register as CPP class
419 419 registerCPPClass(name.constData());
420 420 info = _knownClassInfos.value(name);
421 421 }
422 422 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
423 423 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
424 424 info->setMetaObject(wrapper->metaObject());
425 425 }
426 426
427 427 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
428 428 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
429 429 } else {
430 430 Py_INCREF(wrap);
431 431 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
432 432 }
433 433 return (PyObject*)wrap;
434 434 }
435 435
436 436 PyObject* PythonQtPrivate::dummyTuple() {
437 437 static PyObject* dummyTuple = NULL;
438 438 if (dummyTuple==NULL) {
439 439 dummyTuple = PyTuple_New(1);
440 440 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
441 441 }
442 442 return dummyTuple;
443 443 }
444 444
445 445
446 446 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
447 447 // call the associated class type to create a new instance...
448 448 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
449 449
450 450 result->setQObject(obj);
451 451 result->_wrappedPtr = wrappedPtr;
452 452 result->_ownedByPythonQt = false;
453 453 result->_useQMetaTypeDestroy = false;
454 454
455 455 if (wrappedPtr) {
456 456 _wrappedObjects.insert(wrappedPtr, result);
457 457 } else {
458 458 _wrappedObjects.insert(obj, result);
459 459 if (obj->parent()== NULL && _wrappedCB) {
460 460 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
461 461 (*_wrappedCB)(obj);
462 462 }
463 463 }
464 464 return result;
465 465 }
466 466
467 467 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
468 468 PythonQtClassWrapper* result;
469 469
470 470 PyObject* className = PyString_FromString(info->className());
471 471
472 472 PyObject* baseClasses = PyTuple_New(1);
473 473 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
474 474
475 475 PyObject* typeDict = PyDict_New();
476 476 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
477 477 PyDict_SetItemString(typeDict, "__module__", moduleName);
478 478
479 479 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
480 480
481 481 // set the class info so that PythonQtClassWrapper_new can read it
482 482 _currentClassInfoForClassWrapperCreation = info;
483 483 // create the new type object by calling the type
484 484 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
485 485
486 486 Py_DECREF(baseClasses);
487 487 Py_DECREF(typeDict);
488 488 Py_DECREF(args);
489 489 Py_DECREF(className);
490 490
491 491 return result;
492 492 }
493 493
494 494 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
495 495 {
496 496 PyObject* args = Py_BuildValue("(i)", enumValue);
497 497 PyObject* result = PyObject_Call(enumType, args, NULL);
498 498 Py_DECREF(args);
499 499 return result;
500 500 }
501 501
502 502 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
503 503 PyObject* result;
504 504
505 505 PyObject* className = PyString_FromString(enumName);
506 506
507 507 PyObject* baseClasses = PyTuple_New(1);
508 508 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
509 509
510 510 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
511 511 PyObject* typeDict = PyDict_New();
512 512 PyDict_SetItemString(typeDict, "__module__", module);
513 513
514 514 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
515 515
516 516 // create the new int derived type object by calling the core type
517 517 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
518 518
519 519 Py_DECREF(baseClasses);
520 520 Py_DECREF(typeDict);
521 521 Py_DECREF(args);
522 522 Py_DECREF(className);
523 523
524 524 return result;
525 525 }
526 526
527 527 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
528 528 {
529 529 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
530 530 if (!r) {
531 531 r = new PythonQtSignalReceiver(obj);
532 532 _p->_signalReceivers.insert(obj, r);
533 533 }
534 534 return r;
535 535 }
536 536
537 537 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
538 538 {
539 539 bool flag = false;
540 540 PythonQtObjectPtr callable = lookupCallable(module, objectname);
541 541 if (callable) {
542 542 PythonQtSignalReceiver* r = getSignalReceiver(obj);
543 543 flag = r->addSignalHandler(signal, callable);
544 544 if (!flag) {
545 545 // signal not found
546 546 }
547 547 } else {
548 548 // callable not found
549 549 }
550 550 return flag;
551 551 }
552 552
553 553 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
554 554 {
555 555 bool flag = false;
556 556 PythonQtSignalReceiver* r = getSignalReceiver(obj);
557 557 if (r) {
558 558 flag = r->addSignalHandler(signal, receiver);
559 559 }
560 560 return flag;
561 561 }
562 562
563 563 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
564 564 {
565 565 bool flag = false;
566 566 PythonQtObjectPtr callable = lookupCallable(module, objectname);
567 567 if (callable) {
568 568 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
569 569 if (r) {
570 570 flag = r->removeSignalHandler(signal, callable);
571 571 }
572 572 } else {
573 573 // callable not found
574 574 }
575 575 return flag;
576 576 }
577 577
578 578 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
579 579 {
580 580 bool flag = false;
581 581 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
582 582 if (r) {
583 583 flag = r->removeSignalHandler(signal, receiver);
584 584 }
585 585 return flag;
586 586 }
587 587
588 588 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
589 589 {
590 590 PythonQtObjectPtr p = lookupObject(module, name);
591 591 if (p) {
592 592 if (PyCallable_Check(p)) {
593 593 return p;
594 594 }
595 595 }
596 596 PyErr_Clear();
597 597 return NULL;
598 598 }
599 599
600 600 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
601 601 {
602 602 QStringList l = name.split('.');
603 603 PythonQtObjectPtr p = module;
604 604 PythonQtObjectPtr prev;
605 605 QString s;
606 606 QByteArray b;
607 607 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
608 608 prev = p;
609 609 b = (*i).toLatin1();
610 610 if (PyDict_Check(p)) {
611 611 p = PyDict_GetItemString(p, b.data());
612 612 } else {
613 613 p.setNewRef(PyObject_GetAttrString(p, b.data()));
614 614 }
615 615 }
616 616 PyErr_Clear();
617 617 return p;
618 618 }
619 619
620 620 PythonQtObjectPtr PythonQt::getMainModule() {
621 621 //both borrowed
622 622 PythonQtObjectPtr dict = PyImport_GetModuleDict();
623 623 return PyDict_GetItemString(dict, "__main__");
624 624 }
625 625
626 626 PythonQtObjectPtr PythonQt::importModule(const QString& name)
627 627 {
628 628 PythonQtObjectPtr mod;
629 629 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
630 630 return mod;
631 631 }
632 632
633 633
634 634 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
635 635 QVariant result;
636 636 if (pycode) {
637 637 PyObject* dict = NULL;
638 638 if (PyModule_Check(object)) {
639 639 dict = PyModule_GetDict(object);
640 640 } else if (PyDict_Check(object)) {
641 641 dict = object;
642 642 }
643 643 PyObject* r = NULL;
644 644 if (dict) {
645 645 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
646 646 }
647 647 if (r) {
648 648 result = PythonQtConv::PyObjToQVariant(r);
649 649 Py_DECREF(r);
650 650 } else {
651 651 handleError();
652 652 }
653 653 } else {
654 654 handleError();
655 655 }
656 656 return result;
657 657 }
658 658
659 659 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
660 660 {
661 661 QVariant result;
662 662 PythonQtObjectPtr p;
663 663 PyObject* dict = NULL;
664 664 if (PyModule_Check(object)) {
665 665 dict = PyModule_GetDict(object);
666 666 } else if (PyDict_Check(object)) {
667 667 dict = object;
668 668 }
669 669 if (dict) {
670 670 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
671 671 }
672 672 if (p) {
673 673 result = PythonQtConv::PyObjToQVariant(p);
674 674 } else {
675 675 handleError();
676 676 }
677 677 return result;
678 678 }
679 679
680 680 void PythonQt::evalFile(PyObject* module, const QString& filename)
681 681 {
682 682 PythonQtObjectPtr code = parseFile(filename);
683 683 if (code) {
684 684 evalCode(module, code);
685 685 } else {
686 686 handleError();
687 687 }
688 688 }
689 689
690 690 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
691 691 {
692 692 PythonQtObjectPtr p;
693 693 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
694 694 if (!p) {
695 695 handleError();
696 696 }
697 697 return p;
698 698 }
699 699
700 700 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
701 701 {
702 702 PythonQtObjectPtr code = parseFile(filename);
703 703 PythonQtObjectPtr module = _p->createModule(name, code);
704 704 return module;
705 705 }
706 706
707 707 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
708 708 {
709 709 PyErr_Clear();
710 710 QString scriptCode = script;
711 711 if (scriptCode.isEmpty()) {
712 712 // we always need at least a linefeed
713 713 scriptCode = "\n";
714 714 }
715 715 PythonQtObjectPtr pycode;
716 716 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
717 717 PythonQtObjectPtr module = _p->createModule(name, pycode);
718 718 return module;
719 719 }
720 720
721 721 PythonQtObjectPtr PythonQt::createUniqueModule()
722 722 {
723 723 static QString pyQtStr("PythonQt_module");
724 724 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
725 725 return createModuleFromScript(moduleName);
726 726 }
727 727
728 728 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
729 729 {
730 730 if (PyModule_Check(object)) {
731 731 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
732 732 } else if (PyDict_Check(object)) {
733 733 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
734 734 } else {
735 735 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
736 736 }
737 737 }
738 738
739 739 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
740 740 {
741 741 if (PyModule_Check(object)) {
742 742 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
743 743 } else if (PyDict_Check(object)) {
744 744 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
745 745 } else {
746 746 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
747 747 }
748 748 }
749 749
750 750 void PythonQt::removeVariable(PyObject* object, const QString& name)
751 751 {
752 752 if (PyDict_Check(object)) {
753 753 PyDict_DelItemString(object, name.toLatin1().data());
754 754 } else {
755 755 PyObject_DelAttrString(object, name.toLatin1().data());
756 756 }
757 757 }
758 758
759 759 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
760 760 {
761 761 QVariant result;
762 762 PythonQtObjectPtr obj = lookupObject(object, objectname);
763 763 if (obj) {
764 764 result = PythonQtConv::PyObjToQVariant(obj);
765 765 }
766 766 return result;
767 767 }
768 768
769 769 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
770 770 {
771 771 QStringList results;
772 772
773 773 PythonQtObjectPtr object;
774 774 if (objectname.isEmpty()) {
775 775 object = module;
776 776 } else {
777 777 object = lookupObject(module, objectname);
778 778 if (!object && type == CallOverloads) {
779 779 PyObject* dict = lookupObject(module, "__builtins__");
780 780 if (dict) {
781 781 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
782 782 }
783 783 }
784 784 }
785 785
786 786 if (object) {
787 787 if (type == CallOverloads) {
788 788 if (PythonQtSlotFunction_Check(object)) {
789 789 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
790 790 PythonQtSlotInfo* info = o->m_ml;
791 791
792 792 while (info) {
793 793 results << info->fullSignature();
794 794 info = info->nextInfo();
795 795 }
796 796 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
797 797 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
798 798 PythonQtSlotInfo* info = o->classInfo()->constructors();
799 799
800 800 while (info) {
801 801 results << info->fullSignature();
802 802 info = info->nextInfo();
803 803 }
804 804 } else {
805 805 //TODO: use pydoc!
806 806 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
807 807 if (doc) {
808 808 results << PyString_AsString(doc);
809 809 Py_DECREF(doc);
810 810 }
811 811 }
812 812 } else {
813 813 PyObject* keys = NULL;
814 814 bool isDict = false;
815 815 if (PyDict_Check(object)) {
816 816 keys = PyDict_Keys(object);
817 817 isDict = true;
818 818 } else {
819 819 keys = PyObject_Dir(object);
820 820 }
821 821 if (keys) {
822 822 int count = PyList_Size(keys);
823 823 PyObject* key;
824 824 PyObject* value;
825 825 QString keystr;
826 826 for (int i = 0;i<count;i++) {
827 827 key = PyList_GetItem(keys,i);
828 828 if (isDict) {
829 829 value = PyDict_GetItem(object, key);
830 830 Py_INCREF(value);
831 831 } else {
832 832 value = PyObject_GetAttr(object, key);
833 833 }
834 834 if (!value) continue;
835 835 keystr = PyString_AsString(key);
836 836 static const QString underscoreStr("__tmp");
837 837 if (!keystr.startsWith(underscoreStr)) {
838 838 switch (type) {
839 839 case Anything:
840 840 results << keystr;
841 841 break;
842 842 case Class:
843 843 if (value->ob_type == &PyClass_Type) {
844 844 results << keystr;
845 845 }
846 846 break;
847 847 case Variable:
848 848 if (value->ob_type != &PyClass_Type
849 849 && value->ob_type != &PyCFunction_Type
850 850 && value->ob_type != &PyFunction_Type
851 851 && value->ob_type != &PyModule_Type
852 852 ) {
853 853 results << keystr;
854 854 }
855 855 break;
856 856 case Function:
857 857 if (value->ob_type == &PyFunction_Type ||
858 858 value->ob_type == &PyMethod_Type
859 859 ) {
860 860 results << keystr;
861 861 }
862 862 break;
863 863 case Module:
864 864 if (value->ob_type == &PyModule_Type) {
865 865 results << keystr;
866 866 }
867 867 break;
868 868 default:
869 869 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
870 870 }
871 871 }
872 872 Py_DECREF(value);
873 873 }
874 874 Py_DECREF(keys);
875 875 }
876 876 }
877 877 }
878 878 return results;
879 879 }
880 880
881 881 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
882 882 {
883 883 PythonQtObjectPtr callable = lookupCallable(object, name);
884 884 if (callable) {
885 885 return call(callable, args);
886 886 } else {
887 887 return QVariant();
888 888 }
889 889 }
890 890
891 891 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
892 892 {
893 893 QVariant r;
894 894 PythonQtObjectPtr result;
895 895 result.setNewRef(callAndReturnPyObject(callable, args));
896 896 if (result) {
897 897 r = PythonQtConv::PyObjToQVariant(result);
898 898 } else {
899 899 PythonQt::self()->handleError();
900 900 }
901 901 return r;
902 902 }
903 903
904 904 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
905 905 {
906 906 PyObject* result = NULL;
907 907 if (callable) {
908 908 PythonQtObjectPtr pargs;
909 909 int count = args.size();
910 910 if (count>0) {
911 911 pargs.setNewRef(PyTuple_New(count));
912 912 }
913 913 bool err = false;
914 914 // transform QVariants to Python
915 915 for (int i = 0; i < count; i++) {
916 916 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
917 917 if (arg) {
918 918 // steals reference, no unref
919 919 PyTuple_SetItem(pargs, i,arg);
920 920 } else {
921 921 err = true;
922 922 break;
923 923 }
924 924 }
925 925
926 926 if (!err) {
927 927 PyErr_Clear();
928 928 result = PyObject_CallObject(callable, pargs);
929 929 }
930 930 }
931 931 return result;
932 932 }
933 933
934 934 void PythonQt::addInstanceDecorators(QObject* o)
935 935 {
936 936 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
937 937 }
938 938
939 939 void PythonQt::addClassDecorators(QObject* o)
940 940 {
941 941 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
942 942 }
943 943
944 944 void PythonQt::addDecorators(QObject* o)
945 945 {
946 946 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
947 947 }
948 948
949 949 void PythonQt::registerQObjectClassNames(const QStringList& names)
950 950 {
951 951 _p->registerQObjectClassNames(names);
952 952 }
953 953
954 954 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
955 955 {
956 956 _p->_importInterface = importInterface;
957 957 PythonQtImport::init();
958 958 }
959 959
960 960 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
961 961 {
962 962 _p->_importIgnorePaths = paths;
963 963 }
964 964
965 965 const QStringList& PythonQt::getImporterIgnorePaths()
966 966 {
967 967 return _p->_importIgnorePaths;
968 968 }
969 969
970 970 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
971 971 {
972 972 _p->_cppWrapperFactories.append(factory);
973 973 }
974 974
975 975 void PythonQt::addWrapperFactory( PythonQtForeignWrapperFactory* factory )
976 976 {
977 977 _p->_foreignWrapperFactories.append(factory);
978 978 }
979 979
980 980 //---------------------------------------------------------------------------------------------------
981 981 PythonQtPrivate::PythonQtPrivate()
982 982 {
983 983 _importInterface = NULL;
984 984 _defaultImporter = new PythonQtQFileImporter;
985 985 _noLongerWrappedCB = NULL;
986 986 _wrappedCB = NULL;
987 987 _currentClassInfoForClassWrapperCreation = NULL;
988 988 _profilingCB = NULL;
989 989 }
990 990
991 991 void PythonQtPrivate::setupSharedLibrarySuffixes()
992 992 {
993 993 _sharedLibrarySuffixes.clear();
994 994 PythonQtObjectPtr imp;
995 995 imp.setNewRef(PyImport_ImportModule("imp"));
996 996 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
997 997 QVariant result = imp.call("get_suffixes");
998 998 #ifdef __linux
999 999 #ifdef _DEBUG
1000 1000 // First look for shared libraries with the '_d' suffix in debug mode on Linux.
1001 1001 // This is a workaround, because python does not append the '_d' suffix on Linux
1002 1002 // and would always load the release library otherwise.
1003 1003 _sharedLibrarySuffixes << "_d.so";
1004 1004 #endif
1005 1005 #endif
1006 1006 foreach (QVariant entry, result.toList()) {
1007 1007 QVariantList suffixEntry = entry.toList();
1008 1008 if (suffixEntry.count()==3) {
1009 1009 int code = suffixEntry.at(2).toInt();
1010 1010 if (code == cExtensionCode) {
1011 1011 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
1012 1012 }
1013 1013 }
1014 1014 }
1015 1015 }
1016 1016
1017 1017 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
1018 1018 {
1019 1019 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
1020 1020 _currentClassInfoForClassWrapperCreation = NULL;
1021 1021 return info;
1022 1022 }
1023 1023
1024 1024 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
1025 1025 {
1026 1026 o->setParent(this);
1027 1027 int numMethods = o->metaObject()->methodCount();
1028 1028 for (int i = 0; i < numMethods; i++) {
1029 1029 QMetaMethod m = o->metaObject()->method(i);
1030 1030 if ((m.methodType() == QMetaMethod::Method ||
1031 1031 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
1032 1032 if (qstrncmp(m.signature(), "new_", 4)==0) {
1033 1033 if ((decoTypes & ConstructorDecorator) == 0) continue;
1034 1034 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1035 1035 if (info->parameters().at(0).pointerCount == 1) {
1036 1036 QByteArray signature = m.signature();
1037 1037 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
1038 1038 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1039 1039 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1040 1040 classInfo->addConstructor(newSlot);
1041 1041 }
1042 1042 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
1043 1043 if ((decoTypes & DestructorDecorator) == 0) continue;
1044 1044 QByteArray signature = m.signature();
1045 1045 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
1046 1046 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1047 1047 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1048 1048 classInfo->setDestructor(newSlot);
1049 1049 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
1050 1050 if ((decoTypes & StaticDecorator) == 0) continue;
1051 1051 QByteArray signature = m.signature();
1052 1052 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
1053 1053 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
1054 1054 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1055 1055 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1056 1056 classInfo->addDecoratorSlot(newSlot);
1057 1057 } else {
1058 1058 if ((decoTypes & InstanceDecorator) == 0) continue;
1059 1059 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1060 1060 if (info->parameters().count()>1) {
1061 1061 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
1062 1062 if (p.pointerCount==1) {
1063 1063 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
1064 1064 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
1065 1065 classInfo->addDecoratorSlot(newSlot);
1066 1066 }
1067 1067 }
1068 1068 }
1069 1069 }
1070 1070 }
1071 1071 }
1072 1072
1073 1073 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
1074 1074 {
1075 1075 foreach(QString name, names) {
1076 1076 _knownQObjectClassNames.insert(name.toLatin1(), true);
1077 1077 }
1078 1078 }
1079 1079
1080 1080 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1081 1081 {
1082 1082 _signalReceivers.remove(obj);
1083 1083 }
1084 1084
1085 1085 bool PythonQt::handleError()
1086 1086 {
1087 1087 bool flag = false;
1088 1088 if (PyErr_Occurred()) {
1089 1089
1090 1090 // currently we just print the error and the stderr handler parses the errors
1091 1091 PyErr_Print();
1092 1092
1093 1093 /*
1094 1094 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1095 1095 PyObject *ptype;
1096 1096 PyObject *pvalue;
1097 1097 PyObject *ptraceback;
1098 1098 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1099 1099
1100 1100 Py_XDECREF(ptype);
1101 1101 Py_XDECREF(pvalue);
1102 1102 Py_XDECREF(ptraceback);
1103 1103 */
1104 1104 PyErr_Clear();
1105 1105 flag = true;
1106 1106 }
1107 1107 return flag;
1108 1108 }
1109 1109
1110 1110 void PythonQt::addSysPath(const QString& path)
1111 1111 {
1112 1112 PythonQtObjectPtr sys;
1113 1113 sys.setNewRef(PyImport_ImportModule("sys"));
1114 1114 PythonQtObjectPtr obj = lookupObject(sys, "path");
1115 1115 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1116 1116 }
1117 1117
1118 1118 void PythonQt::overwriteSysPath(const QStringList& paths)
1119 1119 {
1120 1120 PythonQtObjectPtr sys;
1121 1121 sys.setNewRef(PyImport_ImportModule("sys"));
1122 1122 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1123 1123 }
1124 1124
1125 1125 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1126 1126 {
1127 1127 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1128 1128 }
1129 1129
1130 1130 void PythonQt::stdOutRedirectCB(const QString& str)
1131 1131 {
1132 1132 if (!PythonQt::self()) {
1133 1133 std::cout << str.toLatin1().data() << std::endl;
1134 1134 return;
1135 1135 }
1136 1136 emit PythonQt::self()->pythonStdOut(str);
1137 1137 }
1138 1138
1139 1139 void PythonQt::stdErrRedirectCB(const QString& str)
1140 1140 {
1141 1141 if (!PythonQt::self()) {
1142 1142 std::cerr << str.toLatin1().data() << std::endl;
1143 1143 return;
1144 1144 }
1145 1145 emit PythonQt::self()->pythonStdErr(str);
1146 1146 }
1147 1147
1148 1148 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1149 1149 {
1150 1150 _p->_wrappedCB = cb;
1151 1151 }
1152 1152
1153 1153 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1154 1154 {
1155 1155 _p->_noLongerWrappedCB = cb;
1156 1156 }
1157 1157
1158 1158 void PythonQt::setProfilingCallback(ProfilingCB* cb)
1159 1159 {
1160 1160 _p->_profilingCB = cb;
1161 1161 }
1162 1162
1163 1163
1164 1164 static PyMethodDef PythonQtMethods[] = {
1165 1165 {NULL, NULL, 0, NULL}
1166 1166 };
1167 1167
1168 1168 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1169 1169 {
1170 1170 QByteArray name = "PythonQt";
1171 1171 if (!pythonQtModuleName.isEmpty()) {
1172 1172 name = pythonQtModuleName;
1173 1173 }
1174 1174 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1175 1175 _p->_pythonQtModuleName = name;
1176 1176
1177 1177 if (redirectStdOut) {
1178 1178 PythonQtObjectPtr sys;
1179 1179 PythonQtObjectPtr out;
1180 1180 PythonQtObjectPtr err;
1181 1181 sys.setNewRef(PyImport_ImportModule("sys"));
1182 1182 // create a redirection object for stdout and stderr
1183 1183 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1184 1184 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1185 1185 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1186 1186 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1187 1187 // replace the built in file objects with our own objects
1188 1188 PyModule_AddObject(sys, "stdout", out);
1189 1189 PyModule_AddObject(sys, "stderr", err);
1190 1190 }
1191 1191 }
1192 1192
1193 1193 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1194 1194 {
1195 1195 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1196 1196 }
1197 1197
1198 1198
1199 1199 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1200 1200 {
1201 1201 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1202 1202 if (!info) {
1203 1203 info = new PythonQtClassInfo();
1204 1204 info->setupCPPObject(typeName);
1205 1205 _knownClassInfos.insert(typeName, info);
1206 1206 }
1207 1207 return info;
1208 1208 }
1209 1209
1210 1210 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1211 1211 {
1212 1212 _p->addPolymorphicHandler(typeName, cb);
1213 1213 }
1214 1214
1215 1215 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1216 1216 {
1217 1217 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1218 1218 info->addPolymorphicHandler(cb);
1219 1219 }
1220 1220
1221 1221 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1222 1222 {
1223 1223 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1224 1224 }
1225 1225
1226 1226 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1227 1227 {
1228 1228 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1229 1229 if (info) {
1230 1230 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1231 1231 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1232 1232 return true;
1233 1233 } else {
1234 1234 return false;
1235 1235 }
1236 1236 }
1237 1237
1238 1238 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1239 1239 {
1240 1240 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1241 1241 if (!info->pythonQtClassWrapper()) {
1242 1242 info->setTypeSlots(typeSlots);
1243 1243 info->setupCPPObject(typeName);
1244 1244 createPythonQtClassWrapper(info, package, module);
1245 1245 }
1246 1246 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1247 1247 addParentClass(typeName, parentTypeName, 0);
1248 1248 }
1249 1249 if (wrapperCreator) {
1250 1250 info->setDecoratorProvider(wrapperCreator);
1251 1251 }
1252 1252 if (shell) {
1253 1253 info->setShellSetInstanceWrapperCB(shell);
1254 1254 }
1255 1255 }
1256 1256
1257 1257 PyObject* PythonQtPrivate::packageByName(const char* name)
1258 1258 {
1259 1259 if (name==NULL || name[0]==0) {
1260 1260 name = "private";
1261 1261 }
1262 1262 PyObject* v = _packages.value(name);
1263 1263 if (!v) {
1264 1264 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1265 1265 _packages.insert(name, v);
1266 1266 // AddObject steals the reference, so increment it!
1267 1267 Py_INCREF(v);
1268 1268 PyModule_AddObject(_pythonQtModule, name, v);
1269 1269 }
1270 1270 return v;
1271 1271 }
1272 1272
1273 1273 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1274 1274 {
1275 1275 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;
1276 1276 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1277 1277 PythonQt::self()->handleError();
1278 1278 }
1279 1279
1280 1280 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1281 1281 {
1282 1282 if (_p->_initFlags & ExternalHelp) {
1283 1283 emit pythonHelpRequest(QByteArray(info->className()));
1284 1284 return Py_BuildValue("");
1285 1285 } else {
1286 1286 return PyString_FromString(info->help().toLatin1().data());
1287 1287 }
1288 1288 }
1289 1289
1290 1290 void PythonQt::clearNotFoundCachedMembers()
1291 1291 {
1292 1292 foreach(PythonQtClassInfo* info, _p->_knownClassInfos) {
1293 1293 info->clearNotFoundCachedMembers();
1294 1294 }
1295 1295 }
1296 1296
1297 void PythonQt::removeWrapperFactory( PythonQtCppWrapperFactory* factory )
1298 {
1299 _p->_cppWrapperFactories.removeAll(factory);
1300 }
1301
1302 void PythonQt::removeWrapperFactory( PythonQtForeignWrapperFactory* factory )
1303 {
1304 _p->_foreignWrapperFactories.removeAll(factory);
1305 }
1306
1297 1307 void PythonQtPrivate::removeWrapperPointer(void* obj)
1298 1308 {
1299 1309 _wrappedObjects.remove(obj);
1300 1310 }
1301 1311
1302 1312 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1303 1313 {
1304 1314 _wrappedObjects.insert(obj, wrapper);
1305 1315 }
1306 1316
1307 1317 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1308 1318 {
1309 1319 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1310 1320 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1311 1321 // this is a wrapper whose QObject was already removed due to destruction
1312 1322 // so the obj pointer has to be a new QObject with the same address...
1313 1323 // we remove the old one and set the copy to NULL
1314 1324 wrap->_objPointerCopy = NULL;
1315 1325 removeWrapperPointer(obj);
1316 1326 wrap = NULL;
1317 1327 }
1318 1328 return wrap;
1319 1329 }
1320 1330
1321 1331 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1322 1332 {
1323 1333 PythonQtObjectPtr result;
1324 1334 if (pycode) {
1325 1335 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1326 1336 } else {
1327 1337 PythonQt::self()->handleError();
1328 1338 }
1329 1339 return result;
1330 1340 }
1331 1341
1332 1342 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObject* obj )
1333 1343 {
1334 1344 void* foreignObject = NULL;
1335 1345 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
1336 1346 foreignObject = _foreignWrapperFactories.at(i)->unwrap(classname, obj);
1337 1347 if (foreignObject) {
1338 1348 return foreignObject;
1339 1349 }
1340 1350 }
1341 1351 return NULL;
1342 1352 } No newline at end of file
@@ -1,684 +1,690
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
337 337 //! returns the found callable object or NULL
338 338 //! @return new reference
339 339 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
340 340
341 341 //@}
342 342
343 343 //---------------------------------------------------------------------------
344 344 //! \name Calling Python Objects
345 345 //@{
346 346
347 347 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
348 348 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
349 349
350 350 //! call the given python object, returns the result converted to a QVariant
351 351 QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
352 352
353 353 //! call the given python object, returns the result as new PyObject
354 354 PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList());
355 355
356 356 //@}
357 357
358 358 //---------------------------------------------------------------------------
359 359 //! \name Decorations, Constructors, Wrappers...
360 360 //@{
361 361
362 362 //! add an object whose slots will be used as decorator slots for
363 363 //! other QObjects or CPP classes. The slots need to follow the
364 364 //! convention that the first argument is a pointer to the wrapped object.
365 365 //! (ownership is passed to PythonQt)
366 366 /*!
367 367 Example:
368 368
369 369 A slot with the signature
370 370
371 371 \code
372 372 bool doSomething(QWidget* w, int a)
373 373 \endcode
374 374
375 375 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
376 376 that will be called with the concrete instance as first argument.
377 377 So in Python you can now e.g. call
378 378
379 379 \code
380 380 someWidget.doSomething(12)
381 381 \endcode
382 382
383 383 without QWidget really having this method. This allows to easily make normal methods
384 384 of Qt classes callable by forwarding them with such decorator slots
385 385 or to make CPP classes (which are not derived from QObject) callable from Python.
386 386 */
387 387 void addInstanceDecorators(QObject* o);
388 388
389 389 //! add an object whose slots will be used as decorator slots for
390 390 //! class objects (ownership is passed to PythonQt)
391 391 /*!
392 392 The slots need to follow the following convention:
393 393 - SomeClass* new_SomeClass(...)
394 394 - QVariant new_SomeClass(...)
395 395 - void delete_SomeClass(SomeClass*)
396 396 - ... static_SomeClass_someName(...)
397 397
398 398 This will add:
399 399 - a constructor
400 400 - a constructor which generates a QVariant
401 401 - a destructor (only useful for CPP objects)
402 402 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
403 403
404 404 */
405 405 void addClassDecorators(QObject* o);
406 406
407 407 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
408 408 void addDecorators(QObject* o);
409 409
410 410 //! add the given factory to PythonQt (ownership stays with caller)
411 411 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
412 412
413 413 //! add the given factory to PythonQt (ownership stays with caller)
414 414 void addWrapperFactory(PythonQtForeignWrapperFactory* factory);
415 415
416 //! remove the wrapper factory
417 void removeWrapperFactory(PythonQtCppWrapperFactory* factory);
418
419 //! remove the wrapper factory
420 void removeWrapperFactory(PythonQtForeignWrapperFactory* factory);
421
416 422 //@}
417 423
418 424 //---------------------------------------------------------------------------
419 425 //! \name Custom Importer
420 426 //@{
421 427
422 428 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
423 429 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
424 430 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
425 431 //! This is not reversible, so even setting setImporter(NULL) afterwards will
426 432 //! keep the custom PythonQt importer with a QFile default import interface.
427 433 //! Subsequent python import calls will make use of the passed importInterface
428 434 //! which forwards all import calls to the given \c importInterface.
429 435 //! Passing NULL will install a default QFile importer.
430 436 //! (\c importInterface ownership stays with caller)
431 437 void setImporter(PythonQtImportFileInterface* importInterface);
432 438
433 439 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
434 440 //! (without calling setImporter or installDefaultImporter at least once, the default python import
435 441 //! mechanism is in place)
436 442 //! the default importer allows to import files from anywhere QFile can read from,
437 443 //! including the Qt resource system using ":". Keep in mind that you need to extend
438 444 //! "sys.path" with ":" to be able to import from the Qt resources.
439 445 void installDefaultImporter() { setImporter(NULL); }
440 446
441 447 //! set paths that the importer should ignore
442 448 void setImporterIgnorePaths(const QStringList& paths);
443 449
444 450 //! get paths that the importer should ignore
445 451 const QStringList& getImporterIgnorePaths();
446 452
447 453 //! get access to the file importer (if set)
448 454 static PythonQtImportFileInterface* importInterface();
449 455
450 456 //@}
451 457
452 458 //---------------------------------------------------------------------------
453 459 //! \name Other Stuff
454 460 //@{
455 461
456 462 //! get access to internal data (should not be used on the public API, but is used by some C functions)
457 463 static PythonQtPrivate* priv() { return _self->_p; }
458 464
459 465 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
460 466 //! The error is currently just output to the python stderr, future version might implement better trace printing
461 467 bool handleError();
462 468
463 469 //! clear all NotFound entries on all class infos, to ensure that
464 470 //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded
465 471 void clearNotFoundCachedMembers();
466 472
467 473 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
468 474 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
469 475 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
470 476 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
471 477
472 478 //! call the callback if it is set
473 479 static void qObjectNoLongerWrappedCB(QObject* o);
474 480
475 481 //! called by internal help methods
476 482 PyObject* helpCalled(PythonQtClassInfo* info);
477 483
478 484 //! returns the found object or NULL
479 485 //! @return new reference
480 486 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
481 487
482 488 //! sets a callback that is called before and after function calls for profiling
483 489 void setProfilingCallback(ProfilingCB* cb);
484 490
485 491 //@}
486 492
487 493 signals:
488 494 //! emitted when python outputs something to stdout (and redirection is turned on)
489 495 void pythonStdOut(const QString& str);
490 496 //! emitted when python outputs something to stderr (and redirection is turned on)
491 497 void pythonStdErr(const QString& str);
492 498
493 499 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
494 500 void pythonHelpRequest(const QByteArray& cppClassName);
495 501
496 502 private:
497 503 void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
498 504
499 505 //! callback for stdout redirection, emits pythonStdOut signal
500 506 static void stdOutRedirectCB(const QString& str);
501 507 //! callback for stderr redirection, emits pythonStdErr signal
502 508 static void stdErrRedirectCB(const QString& str);
503 509
504 510 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
505 511 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
506 512
507 513 PythonQt(int flags, const QByteArray& pythonQtModuleName);
508 514 ~PythonQt();
509 515
510 516 static PythonQt* _self;
511 517 static int _uniqueModuleCount;
512 518
513 519 PythonQtPrivate* _p;
514 520
515 521 };
516 522
517 523 //! internal PythonQt details
518 524 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
519 525
520 526 Q_OBJECT
521 527
522 528 public:
523 529 PythonQtPrivate();
524 530 ~PythonQtPrivate();
525 531
526 532 enum DecoratorTypes {
527 533 StaticDecorator = 1,
528 534 ConstructorDecorator = 2,
529 535 DestructorDecorator = 4,
530 536 InstanceDecorator = 8,
531 537 AllDecorators = 0xffff
532 538 };
533 539
534 540 //! get the suffixes that are used for shared libraries
535 541 const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
536 542
537 543 //! returns if the id is the id for PythonQtObjectPtr
538 544 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
539 545
540 546 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
541 547 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
542 548 //! remove the wrapper ptr again
543 549 void removeWrapperPointer(void* obj);
544 550
545 551 //! try to unwrap the given object to a C++ pointer using the foreign wrapper factories
546 552 void* unwrapForeignWrapper(const QByteArray& classname, PyObject* obj);
547 553
548 554 //! add parent class relation
549 555 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
550 556
551 557 //! add a handler for polymorphic downcasting
552 558 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
553 559
554 560 //! lookup existing classinfo and return new if not yet present
555 561 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
556 562
557 563 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
558 564 void removeSignalEmitter(QObject* obj);
559 565
560 566 //! wrap the given QObject into a Python object (or return existing wrapper!)
561 567 PyObject* wrapQObject(QObject* obj);
562 568
563 569 //! 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
564 570 PyObject* wrapPtr(void* ptr, const QByteArray& name);
565 571
566 572 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
567 573 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
568 574 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
569 575 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
570 576
571 577 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
572 578 //! (ownership of wrapper is passed to PythonQt)
573 579 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
574 580
575 581 This will add a wrapper object that is used to make calls to the given classname \c typeName.
576 582 All slots that take a pointer to typeName as the first argument will be callable from Python on
577 583 a variant object that contains such a type.
578 584 */
579 585 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);
580 586
581 587 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
582 588 //! and it will register the classes when it first sees a pointer to such a derived class
583 589 void registerQObjectClassNames(const QStringList& names);
584 590
585 591 //! add a decorator object
586 592 void addDecorators(QObject* o, int decoTypes);
587 593
588 594 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
589 595 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
590 596
591 597 //! create a new instance of the given enum type with given value (returns a new reference)
592 598 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
593 599
594 600 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
595 601 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
596 602
597 603 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
598 604 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
599 605
600 606 //! get the class info for a meta object (if available)
601 607 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
602 608
603 609 //! get the class info for a meta object (if available)
604 610 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
605 611
606 612 //! creates the new module from the given pycode
607 613 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
608 614
609 615 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
610 616 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
611 617
612 618 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
613 619 static PyObject* dummyTuple();
614 620
615 621 //! called by virtual overloads when a python return value can not be converted to the required Qt type
616 622 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
617 623
618 624 //! get access to the PythonQt module
619 625 PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
620 626
621 627 //! returns the profiling callback, which may be NULL
622 628 PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
623 629
624 630 private:
625 631 //! Setup the shared library suffixes by getting them from the "imp" module.
626 632 void setupSharedLibrarySuffixes();
627 633
628 634 //! create a new pythonqt class wrapper and place it in the pythonqt module
629 635 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
630 636
631 637 //! get/create new package module (the returned object is a borrowed reference)
632 638 PyObject* packageByName(const char* name);
633 639
634 640 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
635 641 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
636 642
637 643 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
638 644 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
639 645
640 646 //! stores the meta info of known Qt classes
641 647 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
642 648
643 649 //! names of qobject derived classes that can be casted to qobject savely
644 650 QHash<QByteArray, bool> _knownQObjectClassNames;
645 651
646 652 //! stores signal receivers for QObjects
647 653 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
648 654
649 655 //! the PythonQt python module
650 656 PythonQtObjectPtr _pythonQtModule;
651 657
652 658 //! the name of the PythonQt python module
653 659 QByteArray _pythonQtModuleName;
654 660
655 661 //! the importer interface (if set)
656 662 PythonQtImportFileInterface* _importInterface;
657 663
658 664 //! the default importer
659 665 PythonQtQFileImporter* _defaultImporter;
660 666
661 667 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
662 668 PythonQtQObjectWrappedCB* _wrappedCB;
663 669
664 670 QStringList _importIgnorePaths;
665 671 QStringList _sharedLibrarySuffixes;
666 672
667 673 //! the cpp object wrapper factories
668 674 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
669 675
670 676 QList<PythonQtForeignWrapperFactory*> _foreignWrapperFactories;
671 677
672 678 QHash<QByteArray, PyObject*> _packages;
673 679
674 680 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
675 681
676 682 PythonQt::ProfilingCB* _profilingCB;
677 683
678 684 int _initFlags;
679 685 int _PythonQtObjectPtr_metaId;
680 686
681 687 friend class PythonQt;
682 688 };
683 689
684 690 #endif
@@ -1,80 +1,86
1 1 #ifndef _PYTHONQTCPPWRAPPERFACTORY_H
2 2 #define _PYTHONQTCPPWRAPPERFACTORY_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 PythonQtCppWrapperFactory.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-06
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 #include "PythonQtPythonInclude.h"
46
47 #include "PythonQtSystem.h"
48 #include <QObject>
49 #include <QByteArray>
50
45 51 //! Factory interface for C++ classes that can be wrapped by QObject objects
46 52 /*! To create your own factory, derive PythonQtCppWrapperFactory and implement
47 53 the create() method.
48 54 A factory can be added to PythonQt by PythonQt::addCppWrapperFactory().
49 55 */
50 56 class PYTHONQT_EXPORT PythonQtCppWrapperFactory
51 57 {
52 58 public:
53 59 PythonQtCppWrapperFactory() {};
54 60 virtual ~PythonQtCppWrapperFactory() {};
55 61
56 62 //! create a wrapper for the given object
57 63 virtual QObject* create(const QByteArray& classname, void *ptr) = 0;
58 64
59 65 };
60 66
61 67 //! Factory interface for C++ classes that can be mapped directly from/to
62 68 //! Python with other means than PythonQt/QObjects.
63 69 class PYTHONQT_EXPORT PythonQtForeignWrapperFactory
64 70 {
65 71 public:
66 72 PythonQtForeignWrapperFactory() {};
67 73 virtual ~PythonQtForeignWrapperFactory() {};
68 74
69 75 //! create a Python object (with new reference count), wrapping the given \p ptr as class of type \p classname
70 76 //! Return NULL (and not Py_None) if the object could not be wrapped.
71 77 virtual PyObject* wrap(const QByteArray& classname, void *ptr) = 0;
72 78
73 79 //! unwrap the given object to a C++ object of type \p classname if possible
74 80 //! Return NULL otherwise.
75 81 virtual void* unwrap(const QByteArray& classname, PyObject* object) = 0;
76 82
77 83 };
78 84
79 85 #endif
80 86
General Comments 0
You need to be logged in to leave comments. Login now