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