##// END OF EJS Templates
adapted to new generator files...
florianlink -
r193:65af4461ce48
parent child
Show More
@@ -1,1781 +1,1793
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQt.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignal.h"
47 47 #include "PythonQtSignalReceiver.h"
48 48 #include "PythonQtConversion.h"
49 49 #include "PythonQtStdIn.h"
50 50 #include "PythonQtStdOut.h"
51 51 #include "PythonQtCppWrapperFactory.h"
52 52 #include "PythonQtVariants.h"
53 53 #include "PythonQtStdDecorators.h"
54 54 #include "PythonQtQFileImporter.h"
55 55 #include <pydebug.h>
56 56 #include <vector>
57 57
58 58 PythonQt* PythonQt::_self = NULL;
59 59 int PythonQt::_uniqueModuleCount = 0;
60 60
61 61 void PythonQt_init_QtGuiBuiltin(PyObject*);
62 62 void PythonQt_init_QtCoreBuiltin(PyObject*);
63 63
64 64
65 65 PyObject* PythonQtConvertFromStringRef(const void* inObject, int /*metaTypeId*/)
66 66 {
67 67 return PythonQtConv::QStringToPyObject(((QStringRef*)inObject)->toString());
68 68 }
69 69
70 70 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
71 71 {
72 72 if (!_self) {
73 73 _self = new PythonQt(flags, pythonQtModuleName);
74 74
75 75 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
76 76 qRegisterMetaType<QList<QObject*> >("QList<void*>");
77 77
78 78 int stringRefId = qRegisterMetaType<QStringRef>("QStringRef");
79 79 PythonQtConv::registerMetaTypeToPythonConverter(stringRefId, PythonQtConvertFromStringRef);
80 80
81 81 PythonQtRegisterToolClassesTemplateConverter(int);
82 82 PythonQtRegisterToolClassesTemplateConverter(float);
83 83 PythonQtRegisterToolClassesTemplateConverter(double);
84 84 PythonQtRegisterToolClassesTemplateConverter(qint32);
85 85 PythonQtRegisterToolClassesTemplateConverter(quint32);
86 86 PythonQtRegisterToolClassesTemplateConverter(qint64);
87 87 PythonQtRegisterToolClassesTemplateConverter(quint64);
88 88 // TODO: which other POD types should be available for QList etc.
89 89
90 90 PythonQt_init_QtCoreBuiltin(NULL);
91 91 PythonQt_init_QtGuiBuiltin(NULL);
92 92
93 93 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
94 94 PythonQt::self()->registerCPPClass("QMetaObject",0, "QtCore", PythonQtCreateObject<PythonQtWrapper_QMetaObject>);
95 95
96 96 PythonQtRegisterToolClassesTemplateConverter(QByteArray);
97 97 PythonQtRegisterToolClassesTemplateConverter(QDate);
98 98 PythonQtRegisterToolClassesTemplateConverter(QTime);
99 99 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
100 100 PythonQtRegisterToolClassesTemplateConverter(QUrl);
101 101 PythonQtRegisterToolClassesTemplateConverter(QLocale);
102 102 PythonQtRegisterToolClassesTemplateConverter(QRect);
103 103 PythonQtRegisterToolClassesTemplateConverter(QRectF);
104 104 PythonQtRegisterToolClassesTemplateConverter(QSize);
105 105 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
106 106 PythonQtRegisterToolClassesTemplateConverter(QLine);
107 107 PythonQtRegisterToolClassesTemplateConverter(QLineF);
108 108 PythonQtRegisterToolClassesTemplateConverter(QPoint);
109 109 PythonQtRegisterToolClassesTemplateConverter(QPointF);
110 110 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
111 111
112 112 PythonQtRegisterToolClassesTemplateConverter(QFont);
113 113 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
114 114 PythonQtRegisterToolClassesTemplateConverter(QBrush);
115 115 PythonQtRegisterToolClassesTemplateConverter(QColor);
116 116 PythonQtRegisterToolClassesTemplateConverter(QPalette);
117 117 PythonQtRegisterToolClassesTemplateConverter(QIcon);
118 118 PythonQtRegisterToolClassesTemplateConverter(QImage);
119 119 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
120 120 PythonQtRegisterToolClassesTemplateConverter(QRegion);
121 121 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
122 122 PythonQtRegisterToolClassesTemplateConverter(QCursor);
123 123 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
124 124 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
125 125 PythonQtRegisterToolClassesTemplateConverter(QPen);
126 126 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
127 127 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
128 128 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
129 129
130 130
131 131 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
132 132 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
133 133 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
134 134 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
135 135 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
136 136 for (unsigned int i = 0;i<16; i++) {
137 137 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
138 138 if (obj) {
139 139 PyModule_AddObject(pack, names[i], obj);
140 140 Py_INCREF(obj);
141 141 PyModule_AddObject(pack2, names[i], obj);
142 142 } else {
143 143 std::cerr << "method not found " << names[i];
144 144 }
145 145 }
146 146 }
147 147 }
148 148
149 149 void PythonQt::cleanup()
150 150 {
151 151 if (_self) {
152 152 delete _self;
153 153 _self = NULL;
154 154 }
155 155 }
156 156
157 157 PythonQt* PythonQt::self() { return _self; }
158 158
159 159 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
160 160 {
161 161 _p = new PythonQtPrivate;
162 162 _p->_initFlags = flags;
163 163
164 164 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
165 165
166 166 if ((flags & PythonAlreadyInitialized) == 0) {
167 167 Py_SetProgramName(const_cast<char*>("PythonQt"));
168 168 if (flags & IgnoreSiteModule) {
169 169 // this prevents the automatic importing of Python site files
170 170 Py_NoSiteFlag = 1;
171 171 }
172 172 Py_Initialize();
173 173 }
174 174
175 175 // add our own python object types for qt object slots
176 176 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
177 177 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
178 178 }
179 179 Py_INCREF(&PythonQtSlotFunction_Type);
180 180
181 181 if (PyType_Ready(&PythonQtSignalFunction_Type) < 0) {
182 182 std::cerr << "could not initialize PythonQtSignalFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
183 183 }
184 184 Py_INCREF(&PythonQtSignalFunction_Type);
185 185
186 186 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
187 187 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
188 188 // add our own python object types for classes
189 189 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
190 190 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
191 191 }
192 192 Py_INCREF(&PythonQtClassWrapper_Type);
193 193
194 194 // add our own python object types for CPP instances
195 195 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
196 196 PythonQt::handleError();
197 197 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
198 198 }
199 199 Py_INCREF(&PythonQtInstanceWrapper_Type);
200 200
201 201 // add our own python object types for redirection of stdout
202 202 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
203 203 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
204 204 }
205 205 Py_INCREF(&PythonQtStdOutRedirectType);
206 206
207 207 // add our own python object types for redirection of stdin
208 208 if (PyType_Ready(&PythonQtStdInRedirectType) < 0) {
209 209 std::cerr << "could not initialize PythonQtStdInRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
210 210 }
211 211 Py_INCREF(&PythonQtStdInRedirectType);
212 212
213 213 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
214 214
215 215 _p->setupSharedLibrarySuffixes();
216 216
217 217 }
218 218
219 219 PythonQt::~PythonQt() {
220 220 delete _p;
221 221 _p = NULL;
222 222 }
223 223
224 224 PythonQtPrivate::~PythonQtPrivate() {
225 225 delete _defaultImporter;
226 226 _defaultImporter = NULL;
227 227
228 228 {
229 229 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
230 230 while (i.hasNext()) {
231 231 delete i.next().value();
232 232 }
233 233 }
234 234 PythonQtConv::global_valueStorage.clear();
235 235 PythonQtConv::global_ptrStorage.clear();
236 236 PythonQtConv::global_variantStorage.clear();
237 237
238 238 PythonQtMethodInfo::cleanupCachedMethodInfos();
239 239 }
240 240
241 241 void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData)
242 242 {
243 243 if (!callback)
244 244 {
245 245 std::cerr << "PythonQt::setRedirectStdInCallback - callback parameter is NULL !" << std::endl;
246 246 return;
247 247 }
248 248
249 249 PythonQtObjectPtr sys;
250 250 PythonQtObjectPtr in;
251 251 sys.setNewRef(PyImport_ImportModule("sys"));
252 252
253 253 // Backup original 'sys.stdin' if not yet done
254 254 PyRun_SimpleString("if not hasattr(sys, 'pythonqt_original_stdin'):"
255 255 "sys.pythonqt_original_stdin = sys.stdin");
256 256
257 257 in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, NULL, NULL);
258 258 ((PythonQtStdInRedirect*)in.object())->_cb = callback;
259 259 ((PythonQtStdInRedirect*)in.object())->_callData = callbackData;
260 260 // replace the built in file objects with our own objects
261 261 PyModule_AddObject(sys, "stdin", in);
262 262
263 263 // Backup custom 'stdin' into 'pythonqt_stdin'
264 264 PyRun_SimpleString("sys.pythonqt_stdin = sys.stdin");
265 265 }
266 266
267 267 void PythonQt::setRedirectStdInCallbackEnabled(bool enabled)
268 268 {
269 269 if (enabled)
270 270 {
271 271 PyRun_SimpleString("if hasattr(sys, 'pythonqt_stdin'):"
272 272 "sys.stdin = sys.pythonqt_stdin");
273 273 }
274 274 else
275 275 {
276 276 PyRun_SimpleString("if hasattr(sys,'pythonqt_original_stdin'):"
277 277 "sys.stdin = sys.pythonqt_original_stdin");
278 278 }
279 279 }
280 280
281 281 PythonQtImportFileInterface* PythonQt::importInterface()
282 282 {
283 283 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
284 284 }
285 285
286 286 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
287 287 {
288 288 if (_self->_p->_noLongerWrappedCB) {
289 289 (*_self->_p->_noLongerWrappedCB)(o);
290 290 };
291 291 }
292 292
293 293 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
294 294 {
295 295 _p->registerClass(metaobject, package, wrapperCreator, shell);
296 296 }
297 297
298 298 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
299 299 {
300 300 // we register all classes in the hierarchy
301 301 const QMetaObject* m = metaobject;
302 302 bool first = true;
303 303 while (m) {
304 304 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
305 305 if (!info->pythonQtClassWrapper()) {
306 306 info->setTypeSlots(typeSlots);
307 307 info->setupQObject(m);
308 308 createPythonQtClassWrapper(info, package, module);
309 309 if (m->superClass()) {
310 310 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
311 311 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
312 312 }
313 313 } else if (first && module) {
314 314 // There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
315 315 // since it might have been placed into "private" earlier on.
316 316 // If the wrapper was already added to module before, it is just readded, which does no harm.
317 317 PyObject* classWrapper = info->pythonQtClassWrapper();
318 318 // AddObject steals a reference, so we need to INCREF
319 319 Py_INCREF(classWrapper);
320 320 PyModule_AddObject(module, info->className(), classWrapper);
321 321 }
322 322 if (first) {
323 323 first = false;
324 324 if (wrapperCreator) {
325 325 info->setDecoratorProvider(wrapperCreator);
326 326 }
327 327 if (shell) {
328 328 info->setShellSetInstanceWrapperCB(shell);
329 329 }
330 330 }
331 331 m = m->superClass();
332 332 }
333 333 }
334 334
335 335 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
336 336 {
337 337 PyObject* pack = module?module:packageByName(package);
338 338 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
339 339 PyModule_AddObject(pack, info->className(), pyobj);
340 340 if (!module && package && strncmp(package,"Qt",2)==0) {
341 341 // since PyModule_AddObject steals the reference, we need a incref once more...
342 342 Py_INCREF(pyobj);
343 343 // put all qt objects into Qt as well
344 344 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
345 345 }
346 346 info->setPythonQtClassWrapper(pyobj);
347 347 }
348 348
349 349 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
350 350 {
351 351 if (!obj) {
352 352 Py_INCREF(Py_None);
353 353 return Py_None;
354 354 }
355 355 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
356 356 if (wrap && wrap->_wrappedPtr) {
357 357 // uh oh, we want to wrap a QObject, but have a C++ wrapper at that
358 358 // address, so probably that C++ wrapper has been deleted earlier and
359 359 // now we see a QObject with the same address.
360 360 // Do not use the old wrapper anymore.
361 361 wrap = NULL;
362 362 }
363 363 if (!wrap) {
364 364 // smuggling it in...
365 365 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
366 366 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
367 367 registerClass(obj->metaObject());
368 368 classInfo = _knownClassInfos.value(obj->metaObject()->className());
369 369 }
370 370 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
371 371 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
372 372 } else {
373 373 Py_INCREF(wrap);
374 374 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
375 375 }
376 376 return (PyObject*)wrap;
377 377 }
378 378
379 379 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
380 380 {
381 381 if (!ptr) {
382 382 Py_INCREF(Py_None);
383 383 return Py_None;
384 384 }
385 385
386 386 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
387 387 PythonQtInstanceWrapper* possibleStillAliveWrapper = NULL;
388 388 if (wrap && wrap->_wrappedPtr) {
389 389 // we have a previous C++ wrapper... if the wrapper is for a C++ object,
390 390 // we are not sure if it may have been deleted earlier and we just see the same C++
391 391 // pointer once again. To make sure that we do not reuse a wrapper of the wrong type,
392 392 // we compare the classInfo() pointer and only reuse the wrapper if it has the same
393 393 // info. This is only needed for non-QObjects, since we know it when a QObject gets deleted.
394 394 possibleStillAliveWrapper = wrap;
395 395 wrap = NULL;
396 396 }
397 397 if (!wrap) {
398 398 PythonQtClassInfo* info = _knownClassInfos.value(name);
399 399 if (!info) {
400 400 // maybe it is a PyObject, which we can return directly
401 401 if (name == "PyObject") {
402 402 PyObject* p = (PyObject*)ptr;
403 403 Py_INCREF(p);
404 404 return p;
405 405 }
406 406
407 407 // we do not know the metaobject yet, but we might know it by its name:
408 408 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
409 409 // yes, we know it, so we can convert to QObject
410 410 QObject* qptr = (QObject*)ptr;
411 411 registerClass(qptr->metaObject());
412 412 info = _knownClassInfos.value(qptr->metaObject()->className());
413 413 }
414 414 }
415 415 if (info && info->isQObject()) {
416 416 QObject* qptr = (QObject*)ptr;
417 417 // if the object is a derived object, we want to switch the class info to the one of the derived class:
418 418 if (name!=(qptr->metaObject()->className())) {
419 419 registerClass(qptr->metaObject());
420 420 info = _knownClassInfos.value(qptr->metaObject()->className());
421 421 }
422 422 wrap = createNewPythonQtInstanceWrapper(qptr, info);
423 423 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
424 424 return (PyObject*)wrap;
425 425 }
426 426
427 427 // not a known QObject, try to wrap via foreign wrapper factories
428 428 PyObject* foreignWrapper = NULL;
429 429 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
430 430 foreignWrapper = _foreignWrapperFactories.at(i)->wrap(name, ptr);
431 431 if (foreignWrapper) {
432 432 return foreignWrapper;
433 433 }
434 434 }
435 435
436 436 // not a known QObject, so try our wrapper factory:
437 437 QObject* wrapper = NULL;
438 438 for (int i=0; i<_cppWrapperFactories.size(); i++) {
439 439 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
440 440 if (wrapper) {
441 441 break;
442 442 }
443 443 }
444 444
445 445 if (info) {
446 446 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
447 447 ptr = info->castDownIfPossible(ptr, &info);
448 448
449 449 // if downcasting found out that the object is a QObject,
450 450 // handle it like one:
451 451 if (info && info->isQObject()) {
452 452 QObject* qptr = (QObject*)ptr;
453 453 // if the object is a derived object, we want to switch the class info to the one of the derived class:
454 454 if (name!=(qptr->metaObject()->className())) {
455 455 registerClass(qptr->metaObject());
456 456 info = _knownClassInfos.value(qptr->metaObject()->className());
457 457 }
458 458 wrap = createNewPythonQtInstanceWrapper(qptr, info);
459 459 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
460 460 return (PyObject*)wrap;
461 461 }
462 462 }
463 463
464 464 if (!info || info->pythonQtClassWrapper()==NULL) {
465 465 // still unknown, register as CPP class
466 466 registerCPPClass(name.constData());
467 467 info = _knownClassInfos.value(name);
468 468 }
469 469 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
470 470 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
471 471 info->setMetaObject(wrapper->metaObject());
472 472 }
473 473
474 474 if (possibleStillAliveWrapper && possibleStillAliveWrapper->classInfo() == info) {
475 475 wrap = possibleStillAliveWrapper;
476 476 Py_INCREF(wrap);
477 477 } else {
478 478 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
479 479 }
480 480 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
481 481 } else {
482 482 Py_INCREF(wrap);
483 483 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
484 484 }
485 485 return (PyObject*)wrap;
486 486 }
487 487
488 488 PyObject* PythonQtPrivate::dummyTuple() {
489 489 static PyObject* dummyTuple = NULL;
490 490 if (dummyTuple==NULL) {
491 491 dummyTuple = PyTuple_New(1);
492 492 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
493 493 }
494 494 return dummyTuple;
495 495 }
496 496
497 497
498 498 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
499 499 // call the associated class type to create a new instance...
500 500 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
501 501
502 502 result->setQObject(obj);
503 503 result->_wrappedPtr = wrappedPtr;
504 504 result->_ownedByPythonQt = false;
505 505 result->_useQMetaTypeDestroy = false;
506 506
507 507 if (wrappedPtr) {
508 508 _wrappedObjects.insert(wrappedPtr, result);
509 509 } else {
510 510 _wrappedObjects.insert(obj, result);
511 511 if (obj->parent()== NULL && _wrappedCB) {
512 512 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
513 513 (*_wrappedCB)(obj);
514 514 }
515 515 }
516 516 return result;
517 517 }
518 518
519 519 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
520 520 PythonQtClassWrapper* result;
521 521
522 522 PyObject* className = PyString_FromString(info->className());
523 523
524 524 PyObject* baseClasses = PyTuple_New(1);
525 525 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
526 526
527 527 PyObject* typeDict = PyDict_New();
528 528 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
529 529 PyDict_SetItemString(typeDict, "__module__", moduleName);
530 530
531 531 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
532 532
533 533 // set the class info so that PythonQtClassWrapper_new can read it
534 534 _currentClassInfoForClassWrapperCreation = info;
535 535 // create the new type object by calling the type
536 536 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
537 537
538 538 Py_DECREF(baseClasses);
539 539 Py_DECREF(typeDict);
540 540 Py_DECREF(args);
541 541 Py_DECREF(className);
542 542
543 543 return result;
544 544 }
545 545
546 546 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
547 547 {
548 548 PyObject* args = Py_BuildValue("(i)", enumValue);
549 549 PyObject* result = PyObject_Call(enumType, args, NULL);
550 550 Py_DECREF(args);
551 551 return result;
552 552 }
553 553
554 554 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
555 555 PyObject* result;
556 556
557 557 PyObject* className = PyString_FromString(enumName);
558 558
559 559 PyObject* baseClasses = PyTuple_New(1);
560 560 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
561 561
562 562 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
563 563 PyObject* typeDict = PyDict_New();
564 564 PyDict_SetItemString(typeDict, "__module__", module);
565 565
566 566 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
567 567
568 568 // create the new int derived type object by calling the core type
569 569 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
570 570
571 571 Py_DECREF(baseClasses);
572 572 Py_DECREF(typeDict);
573 573 Py_DECREF(args);
574 574 Py_DECREF(className);
575 575
576 576 return result;
577 577 }
578 578
579 579 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
580 580 {
581 581 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
582 582 if (!r) {
583 583 r = new PythonQtSignalReceiver(obj);
584 584 _p->_signalReceivers.insert(obj, r);
585 585 }
586 586 return r;
587 587 }
588 588
589 589 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
590 590 {
591 591 bool flag = false;
592 592 PythonQtObjectPtr callable = lookupCallable(module, objectname);
593 593 if (callable) {
594 594 PythonQtSignalReceiver* r = getSignalReceiver(obj);
595 595 flag = r->addSignalHandler(signal, callable);
596 596 if (!flag) {
597 597 // signal not found
598 598 }
599 599 } else {
600 600 // callable not found
601 601 }
602 602 return flag;
603 603 }
604 604
605 605 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
606 606 {
607 607 bool flag = false;
608 608 PythonQtSignalReceiver* r = getSignalReceiver(obj);
609 609 if (r) {
610 610 flag = r->addSignalHandler(signal, receiver);
611 611 }
612 612 return flag;
613 613 }
614 614
615 615 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
616 616 {
617 617 bool flag = false;
618 618 PythonQtObjectPtr callable = lookupCallable(module, objectname);
619 619 if (callable) {
620 620 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
621 621 if (r) {
622 622 flag = r->removeSignalHandler(signal, callable);
623 623 }
624 624 } else {
625 625 // callable not found
626 626 }
627 627 return flag;
628 628 }
629 629
630 630 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
631 631 {
632 632 bool flag = false;
633 633 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
634 634 if (r) {
635 635 flag = r->removeSignalHandler(signal, receiver);
636 636 }
637 637 return flag;
638 638 }
639 639
640 640 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
641 641 {
642 642 PythonQtObjectPtr p = lookupObject(module, name);
643 643 if (p) {
644 644 if (PyCallable_Check(p)) {
645 645 return p;
646 646 }
647 647 }
648 648 PyErr_Clear();
649 649 return NULL;
650 650 }
651 651
652 652 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
653 653 {
654 654 QStringList l = name.split('.');
655 655 PythonQtObjectPtr p = module;
656 656 PythonQtObjectPtr prev;
657 657 QByteArray b;
658 658 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
659 659 prev = p;
660 660 b = (*i).toLatin1();
661 661 if (PyDict_Check(p)) {
662 662 p = PyDict_GetItemString(p, b.data());
663 663 } else {
664 664 p.setNewRef(PyObject_GetAttrString(p, b.data()));
665 665 }
666 666 }
667 667 PyErr_Clear();
668 668 return p;
669 669 }
670 670
671 671 PythonQtObjectPtr PythonQt::getMainModule() {
672 672 //both borrowed
673 673 PythonQtObjectPtr dict = PyImport_GetModuleDict();
674 674 return PyDict_GetItemString(dict, "__main__");
675 675 }
676 676
677 677 PythonQtObjectPtr PythonQt::importModule(const QString& name)
678 678 {
679 679 PythonQtObjectPtr mod;
680 680 mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
681 681 return mod;
682 682 }
683 683
684 684
685 685 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
686 686 QVariant result;
687 687 if (pycode) {
688 688 PyObject* dict = NULL;
689 689 PyObject* globals = NULL;
690 690 if (PyModule_Check(object)) {
691 691 dict = PyModule_GetDict(object);
692 692 globals = dict;
693 693 } else if (PyDict_Check(object)) {
694 694 dict = object;
695 695 globals = dict;
696 696 } else {
697 697 dict = PyObject_GetAttrString(object, "__dict__");
698 698 globals = PyObject_GetAttrString(PyImport_ImportModule(PyString_AS_STRING(PyObject_GetAttrString(object, "__module__"))),"__dict__");
699 699 }
700 700 PyObject* r = NULL;
701 701 if (dict) {
702 702 r = PyEval_EvalCode((PyCodeObject*)pycode, globals , dict);
703 703 }
704 704 if (r) {
705 705 result = PythonQtConv::PyObjToQVariant(r);
706 706 Py_DECREF(r);
707 707 } else {
708 708 handleError();
709 709 }
710 710 } else {
711 711 handleError();
712 712 }
713 713 return result;
714 714 }
715 715
716 716 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
717 717 {
718 718 QVariant result;
719 719 PythonQtObjectPtr p;
720 720 PyObject* dict = NULL;
721 721 if (PyModule_Check(object)) {
722 722 dict = PyModule_GetDict(object);
723 723 } else if (PyDict_Check(object)) {
724 724 dict = object;
725 725 }
726 726 if (dict) {
727 727 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
728 728 }
729 729 if (p) {
730 730 result = PythonQtConv::PyObjToQVariant(p);
731 731 } else {
732 732 handleError();
733 733 }
734 734 return result;
735 735 }
736 736
737 737 void PythonQt::evalFile(PyObject* module, const QString& filename)
738 738 {
739 739 PythonQtObjectPtr code = parseFile(filename);
740 740 if (code) {
741 741 evalCode(module, code);
742 742 } else {
743 743 handleError();
744 744 }
745 745 }
746 746
747 747 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
748 748 {
749 749 PythonQtObjectPtr p;
750 750 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
751 751 if (!p) {
752 752 handleError();
753 753 }
754 754 return p;
755 755 }
756 756
757 757 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
758 758 {
759 759 PythonQtObjectPtr code = parseFile(filename);
760 760 PythonQtObjectPtr module = _p->createModule(name, code);
761 761 return module;
762 762 }
763 763
764 764 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
765 765 {
766 766 PyErr_Clear();
767 767 QString scriptCode = script;
768 768 if (scriptCode.isEmpty()) {
769 769 // we always need at least a linefeed
770 770 scriptCode = "\n";
771 771 }
772 772 PythonQtObjectPtr pycode;
773 773 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
774 774 PythonQtObjectPtr module = _p->createModule(name, pycode);
775 775 return module;
776 776 }
777 777
778 778 PythonQtObjectPtr PythonQt::createUniqueModule()
779 779 {
780 780 static QString pyQtStr("PythonQt_module");
781 781 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
782 782 return createModuleFromScript(moduleName);
783 783 }
784 784
785 785 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
786 786 {
787 787 if (PyModule_Check(object)) {
788 788 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
789 789 } else if (PyDict_Check(object)) {
790 790 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
791 791 } else {
792 792 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
793 793 }
794 794 }
795 795
796 796 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
797 797 {
798 798 if (PyModule_Check(object)) {
799 799 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
800 800 } else if (PyDict_Check(object)) {
801 801 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
802 802 } else {
803 803 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
804 804 }
805 805 }
806 806
807 807 void PythonQt::removeVariable(PyObject* object, const QString& name)
808 808 {
809 809 if (PyDict_Check(object)) {
810 810 PyDict_DelItemString(object, name.toLatin1().data());
811 811 } else {
812 812 PyObject_DelAttrString(object, name.toLatin1().data());
813 813 }
814 814 }
815 815
816 816 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
817 817 {
818 818 QVariant result;
819 819 PythonQtObjectPtr obj = lookupObject(object, objectname);
820 820 if (obj) {
821 821 result = PythonQtConv::PyObjToQVariant(obj);
822 822 }
823 823 return result;
824 824 }
825 825
826 826 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
827 827 {
828 828 QStringList results;
829 829
830 830 PythonQtObjectPtr object;
831 831 if (objectname.isEmpty()) {
832 832 object = module;
833 833 } else {
834 834 object = lookupObject(module, objectname);
835 835 if (!object && type == CallOverloads) {
836 836 PyObject* dict = lookupObject(module, "__builtins__");
837 837 if (dict) {
838 838 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
839 839 }
840 840 }
841 841 }
842 842
843 843 if (object) {
844 844 results = introspectObject(object, type);
845 845 }
846 846
847 847 return results;
848 848 }
849 849
850 850 QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
851 851 {
852 852 QStringList results;
853 853
854 854 if (type == CallOverloads) {
855 855 if (PythonQtSlotFunction_Check(object)) {
856 856 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object;
857 857 PythonQtSlotInfo* info = o->m_ml;
858 858
859 859 while (info) {
860 860 results << info->fullSignature();
861 861 info = info->nextInfo();
862 862 }
863 863 } else if (PythonQtSignalFunction_Check(object)) {
864 864 PythonQtSignalFunctionObject* o = (PythonQtSignalFunctionObject*)object;
865 865 PythonQtSlotInfo* info = o->m_ml;
866 866
867 867 while (info) {
868 868 results << info->fullSignature();
869 869 info = info->nextInfo();
870 870 }
871 871 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
872 872 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
873 873 PythonQtSlotInfo* info = o->classInfo()->constructors();
874 874
875 875 while (info) {
876 876 results << info->fullSignature();
877 877 info = info->nextInfo();
878 878 }
879 879 } else {
880 880 QString signature = _p->getSignature(object);
881 881 if (!signature.isEmpty()) {
882 882 results << signature;
883 883 } else {
884 884 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
885 885 if (doc) {
886 886 results << PyString_AsString(doc);
887 887 Py_DECREF(doc);
888 888 }
889 889 }
890 890 }
891 891 } else {
892 892 PyObject* keys = NULL;
893 893 bool isDict = false;
894 894 if (PyDict_Check(object)) {
895 895 keys = PyDict_Keys(object);
896 896 isDict = true;
897 897 } else {
898 898 keys = PyObject_Dir(object);
899 899 }
900 900 if (keys) {
901 901 int count = PyList_Size(keys);
902 902 PyObject* key;
903 903 PyObject* value;
904 904 QString keystr;
905 905 for (int i = 0;i<count;i++) {
906 906 key = PyList_GetItem(keys,i);
907 907 if (isDict) {
908 908 value = PyDict_GetItem(object, key);
909 909 Py_INCREF(value);
910 910 } else {
911 911 value = PyObject_GetAttr(object, key);
912 912 }
913 913 if (!value) continue;
914 914 keystr = PyString_AsString(key);
915 915 static const QString underscoreStr("__tmp");
916 916 if (!keystr.startsWith(underscoreStr)) {
917 917 switch (type) {
918 918 case Anything:
919 919 results << keystr;
920 920 break;
921 921 case Class:
922 922 if (value->ob_type == &PyClass_Type || value->ob_type == &PyType_Type) {
923 923 results << keystr;
924 924 }
925 925 break;
926 926 case Variable:
927 927 if (value->ob_type != &PyClass_Type
928 928 && value->ob_type != &PyCFunction_Type
929 929 && value->ob_type != &PyFunction_Type
930 930 && value->ob_type != &PyMethod_Type
931 931 && value->ob_type != &PyModule_Type
932 932 && value->ob_type != &PyType_Type
933 933 && value->ob_type != &PythonQtSlotFunction_Type
934 934 ) {
935 935 results << keystr;
936 936 }
937 937 break;
938 938 case Function:
939 939 if (value->ob_type == &PyCFunction_Type ||
940 940 value->ob_type == &PyFunction_Type ||
941 941 value->ob_type == &PyMethod_Type ||
942 942 value->ob_type == &PythonQtSlotFunction_Type
943 943 ) {
944 944 results << keystr;
945 945 }
946 946 break;
947 947 case Module:
948 948 if (value->ob_type == &PyModule_Type) {
949 949 results << keystr;
950 950 }
951 951 break;
952 952 default:
953 953 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
954 954 }
955 955 }
956 956 Py_DECREF(value);
957 957 }
958 958 Py_DECREF(keys);
959 959 }
960 960 if ((type == Anything) || (type == Variable)) {
961 961 if (object->ob_type == &PythonQtClassWrapper_Type) {
962 962 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
963 963 PythonQtClassInfo* info = o->classInfo();
964 964 results += info->propertyList();
965 965 }
966 966 }
967 967 }
968 968 return results;
969 969 }
970 970
971 971 PyObject* PythonQt::getObjectByType(const QString& typeName)
972 972 {
973 973 PythonQtObjectPtr sys;
974 974 sys.setNewRef(PyImport_ImportModule("sys"));
975 975 PythonQtObjectPtr modules = lookupObject(sys, "modules");
976 976 Q_ASSERT(PyDict_Check(modules));
977 977
978 978 QStringList tmp = typeName.split(".");
979 979 QString simpleTypeName = tmp.takeLast();
980 980 QString moduleName = tmp.join(".");
981 981
982 982 PyObject* object = NULL;
983 983 PyObject* moduleObject = PyDict_GetItemString(modules, moduleName.toLatin1().constData());
984 984 if (moduleObject) {
985 985 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
986 986 }
987 987
988 988 if (!object) {
989 989 moduleObject = PyDict_GetItemString(modules, "__builtin__");
990 990 if (moduleObject) {
991 991 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
992 992 }
993 993 }
994 994
995 995 return object;
996 996 }
997 997
998 998 QStringList PythonQt::introspectType(const QString& typeName, ObjectType type)
999 999 {
1000 1000 QStringList results;
1001 1001 PyObject* object = getObjectByType(typeName);
1002 1002 if (!object) {
1003 1003 // the last item may be a member, split it away and try again
1004 1004 QStringList tmp = typeName.split(".");
1005 1005 QString memberName = tmp.takeLast();
1006 1006 QString typeName;
1007 1007 if (tmp.isEmpty()) {
1008 1008 typeName = memberName;
1009 1009 memberName.clear();
1010 1010 } else {
1011 1011 typeName = tmp.takeLast();
1012 1012 }
1013 1013 PyObject* typeObject = getObjectByType(typeName);
1014 1014 if (typeObject) {
1015 1015 object = PyObject_GetAttrString(typeObject, memberName.toLatin1().constData());
1016 1016 }
1017 1017 }
1018 1018 if (object) {
1019 1019 results = introspectObject(object, type);
1020 1020 Py_DECREF(object);
1021 1021 }
1022 1022 return results;
1023 1023 }
1024 1024
1025 1025 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args, const QVariantMap& kwargs)
1026 1026 {
1027 1027 PythonQtObjectPtr callable = lookupCallable(object, name);
1028 1028 if (callable) {
1029 1029 return call(callable, args, kwargs);
1030 1030 } else {
1031 1031 return QVariant();
1032 1032 }
1033 1033 }
1034 1034
1035 1035 QVariant PythonQt::call(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
1036 1036 {
1037 1037 QVariant r;
1038 1038 PythonQtObjectPtr result;
1039 1039 result.setNewRef(callAndReturnPyObject(callable, args, kwargs));
1040 1040 if (result) {
1041 1041 r = PythonQtConv::PyObjToQVariant(result);
1042 1042 } else {
1043 1043 PythonQt::self()->handleError();
1044 1044 }
1045 1045 return r;
1046 1046 }
1047 1047
1048 1048 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
1049 1049 {
1050 1050 PyObject* result = NULL;
1051 1051 if (callable) {
1052 1052 bool err = false;
1053 1053 PythonQtObjectPtr pargs;
1054 1054 int count = args.size();
1055 1055 if ((count > 0) || (kwargs.count() > 0)) { // create empty tuple if kwargs are given
1056 1056 pargs.setNewRef(PyTuple_New(count));
1057 1057
1058 1058 // transform QVariant arguments to Python
1059 1059 for (int i = 0; i < count; i++) {
1060 1060 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
1061 1061 if (arg) {
1062 1062 // steals reference, no unref
1063 1063 PyTuple_SetItem(pargs, i,arg);
1064 1064 } else {
1065 1065 err = true;
1066 1066 break;
1067 1067 }
1068 1068 }
1069 1069 }
1070 1070 if (!err) {
1071 1071 if (kwargs.isEmpty()) {
1072 1072 // do a direct call if we have no keyword arguments
1073 1073 PyErr_Clear();
1074 1074 result = PyObject_CallObject(callable, pargs);
1075 1075 } else {
1076 1076 // convert keyword arguments to Python
1077 1077 PythonQtObjectPtr pkwargs;
1078 1078 pkwargs.setNewRef(PyDict_New());
1079 1079 QMapIterator<QString, QVariant> it(kwargs);
1080 1080 while (it.hasNext()) {
1081 1081 it.next();
1082 1082 PyObject* arg = PythonQtConv::QVariantToPyObject(it.value());
1083 1083 if (arg) {
1084 1084 PyDict_SetItemString(pkwargs, it.key().toLatin1().constData(), arg);
1085 1085 } else {
1086 1086 err = true;
1087 1087 break;
1088 1088 }
1089 1089 }
1090 1090 if (!err) {
1091 1091 // call with arguments and keyword arguments
1092 1092 PyErr_Clear();
1093 1093 result = PyObject_Call(callable, pargs, pkwargs);
1094 1094 }
1095 1095 }
1096 1096 }
1097 1097 }
1098 1098 return result;
1099 1099 }
1100 1100
1101 1101 void PythonQt::addInstanceDecorators(QObject* o)
1102 1102 {
1103 1103 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
1104 1104 }
1105 1105
1106 1106 void PythonQt::addClassDecorators(QObject* o)
1107 1107 {
1108 1108 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
1109 1109 }
1110 1110
1111 1111 void PythonQt::addDecorators(QObject* o)
1112 1112 {
1113 1113 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
1114 1114 }
1115 1115
1116 1116 void PythonQt::registerQObjectClassNames(const QStringList& names)
1117 1117 {
1118 1118 _p->registerQObjectClassNames(names);
1119 1119 }
1120 1120
1121 1121 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
1122 1122 {
1123 1123 _p->_importInterface = importInterface;
1124 1124 PythonQtImport::init();
1125 1125 }
1126 1126
1127 1127 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
1128 1128 {
1129 1129 _p->_importIgnorePaths = paths;
1130 1130 }
1131 1131
1132 1132 const QStringList& PythonQt::getImporterIgnorePaths()
1133 1133 {
1134 1134 return _p->_importIgnorePaths;
1135 1135 }
1136 1136
1137 1137 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
1138 1138 {
1139 1139 _p->_cppWrapperFactories.append(factory);
1140 1140 }
1141 1141
1142 1142 void PythonQt::addWrapperFactory( PythonQtForeignWrapperFactory* factory )
1143 1143 {
1144 1144 _p->_foreignWrapperFactories.append(factory);
1145 1145 }
1146 1146
1147 1147 //---------------------------------------------------------------------------------------------------
1148 1148 PythonQtPrivate::PythonQtPrivate()
1149 1149 {
1150 1150 _importInterface = NULL;
1151 1151 _defaultImporter = new PythonQtQFileImporter;
1152 1152 _noLongerWrappedCB = NULL;
1153 1153 _wrappedCB = NULL;
1154 1154 _currentClassInfoForClassWrapperCreation = NULL;
1155 1155 _profilingCB = NULL;
1156 1156 }
1157 1157
1158 1158 void PythonQtPrivate::setupSharedLibrarySuffixes()
1159 1159 {
1160 1160 _sharedLibrarySuffixes.clear();
1161 1161 PythonQtObjectPtr imp;
1162 1162 imp.setNewRef(PyImport_ImportModule("imp"));
1163 1163 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
1164 1164 QVariant result = imp.call("get_suffixes");
1165 1165 #ifdef __linux
1166 1166 #ifdef _DEBUG
1167 1167 // First look for shared libraries with the '_d' suffix in debug mode on Linux.
1168 1168 // This is a workaround, because python does not append the '_d' suffix on Linux
1169 1169 // and would always load the release library otherwise.
1170 1170 _sharedLibrarySuffixes << "_d.so";
1171 1171 #endif
1172 1172 #endif
1173 1173 foreach (QVariant entry, result.toList()) {
1174 1174 QVariantList suffixEntry = entry.toList();
1175 1175 if (suffixEntry.count()==3) {
1176 1176 int code = suffixEntry.at(2).toInt();
1177 1177 if (code == cExtensionCode) {
1178 1178 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
1179 1179 }
1180 1180 }
1181 1181 }
1182 1182 }
1183 1183
1184 1184 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
1185 1185 {
1186 1186 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
1187 1187 _currentClassInfoForClassWrapperCreation = NULL;
1188 1188 return info;
1189 1189 }
1190 1190
1191 1191 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
1192 1192 {
1193 1193 o->setParent(this);
1194 1194 int numMethods = o->metaObject()->methodCount();
1195 1195 for (int i = 0; i < numMethods; i++) {
1196 1196 QMetaMethod m = o->metaObject()->method(i);
1197 1197 if ((m.methodType() == QMetaMethod::Method ||
1198 1198 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
1199 1199 if (qstrncmp(m.signature(), "new_", 4)==0) {
1200 1200 if ((decoTypes & ConstructorDecorator) == 0) continue;
1201 1201 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1202 1202 if (info->parameters().at(0).pointerCount == 1) {
1203 1203 QByteArray signature = m.signature();
1204 1204 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
1205 1205 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1206 1206 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1207 1207 classInfo->addConstructor(newSlot);
1208 1208 }
1209 1209 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
1210 1210 if ((decoTypes & DestructorDecorator) == 0) continue;
1211 1211 QByteArray signature = m.signature();
1212 1212 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
1213 1213 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1214 1214 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1215 1215 classInfo->setDestructor(newSlot);
1216 1216 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
1217 1217 if ((decoTypes & StaticDecorator) == 0) continue;
1218 1218 QByteArray signature = m.signature();
1219 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
1219 QByteArray nameOfClass = signature.mid(7);
1220 1220 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
1221 1221 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
1222 1222 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
1223 1223 classInfo->addDecoratorSlot(newSlot);
1224 1224 } else {
1225 1225 if ((decoTypes & InstanceDecorator) == 0) continue;
1226 1226 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
1227 1227 if (info->parameters().count()>1) {
1228 1228 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
1229 1229 if (p.pointerCount==1) {
1230 1230 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
1231 1231 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
1232 1232 classInfo->addDecoratorSlot(newSlot);
1233 1233 }
1234 1234 }
1235 1235 }
1236 1236 }
1237 1237 }
1238 1238 }
1239 1239
1240 1240 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
1241 1241 {
1242 1242 foreach(QString name, names) {
1243 1243 _knownQObjectClassNames.insert(name.toLatin1(), true);
1244 1244 }
1245 1245 }
1246 1246
1247 1247 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1248 1248 {
1249 1249 _signalReceivers.remove(obj);
1250 1250 }
1251 1251
1252 1252 bool PythonQt::handleError()
1253 1253 {
1254 1254 bool flag = false;
1255 1255 if (PyErr_Occurred()) {
1256 1256
1257 1257 // currently we just print the error and the stderr handler parses the errors
1258 1258 PyErr_Print();
1259 1259
1260 1260 /*
1261 1261 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1262 1262 PyObject *ptype;
1263 1263 PyObject *pvalue;
1264 1264 PyObject *ptraceback;
1265 1265 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1266 1266
1267 1267 Py_XDECREF(ptype);
1268 1268 Py_XDECREF(pvalue);
1269 1269 Py_XDECREF(ptraceback);
1270 1270 */
1271 1271 PyErr_Clear();
1272 1272 flag = true;
1273 1273 }
1274 1274 return flag;
1275 1275 }
1276 1276
1277 1277 void PythonQt::addSysPath(const QString& path)
1278 1278 {
1279 1279 PythonQtObjectPtr sys;
1280 1280 sys.setNewRef(PyImport_ImportModule("sys"));
1281 1281 PythonQtObjectPtr obj = lookupObject(sys, "path");
1282 1282 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1283 1283 }
1284 1284
1285 1285 void PythonQt::overwriteSysPath(const QStringList& paths)
1286 1286 {
1287 1287 PythonQtObjectPtr sys;
1288 1288 sys.setNewRef(PyImport_ImportModule("sys"));
1289 1289 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1290 1290 }
1291 1291
1292 1292 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1293 1293 {
1294 1294 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1295 1295 }
1296 1296
1297 1297 void PythonQt::stdOutRedirectCB(const QString& str)
1298 1298 {
1299 1299 if (!PythonQt::self()) {
1300 1300 std::cout << str.toLatin1().data() << std::endl;
1301 1301 return;
1302 1302 }
1303 1303 emit PythonQt::self()->pythonStdOut(str);
1304 1304 }
1305 1305
1306 1306 void PythonQt::stdErrRedirectCB(const QString& str)
1307 1307 {
1308 1308 if (!PythonQt::self()) {
1309 1309 std::cerr << str.toLatin1().data() << std::endl;
1310 1310 return;
1311 1311 }
1312 1312 emit PythonQt::self()->pythonStdErr(str);
1313 1313 }
1314 1314
1315 1315 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1316 1316 {
1317 1317 _p->_wrappedCB = cb;
1318 1318 }
1319 1319
1320 1320 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1321 1321 {
1322 1322 _p->_noLongerWrappedCB = cb;
1323 1323 }
1324 1324
1325 1325 void PythonQt::setProfilingCallback(ProfilingCB* cb)
1326 1326 {
1327 1327 _p->_profilingCB = cb;
1328 1328 }
1329 1329
1330 1330
1331 1331 static PyMethodDef PythonQtMethods[] = {
1332 1332 {NULL, NULL, 0, NULL}
1333 1333 };
1334 1334
1335 1335 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1336 1336 {
1337 1337 QByteArray name = "PythonQt";
1338 1338 if (!pythonQtModuleName.isEmpty()) {
1339 1339 name = pythonQtModuleName;
1340 1340 }
1341 1341 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1342 1342 _p->_pythonQtModuleName = name;
1343 1343
1344 1344 if (redirectStdOut) {
1345 1345 PythonQtObjectPtr sys;
1346 1346 PythonQtObjectPtr out;
1347 1347 PythonQtObjectPtr err;
1348 1348 sys.setNewRef(PyImport_ImportModule("sys"));
1349 1349 // create a redirection object for stdout and stderr
1350 1350 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1351 1351 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1352 1352 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1353 1353 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1354 1354 // replace the built in file objects with our own objects
1355 1355 PyModule_AddObject(sys, "stdout", out);
1356 1356 PyModule_AddObject(sys, "stderr", err);
1357 1357 }
1358 1358 }
1359 1359
1360 1360 QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString& name)
1361 1361 {
1362 1362 QStringList tmp = name.split(".");
1363 1363 QString methodName = tmp.takeLast();
1364 1364 QString variableName = tmp.join(".");
1365 1365 // TODO: the variableName may be a type name, this needs to be handled differently,
1366 1366 // because it is not necessarily known in the module context
1367 1367 PythonQtObjectPtr variableObject = lookupObject(module, variableName);
1368 1368 if (variableObject.isNull()) {
1369 1369 return "";
1370 1370 }
1371 1371
1372 1372 return getReturnTypeOfWrappedMethodHelper(variableObject, methodName, name);
1373 1373 }
1374 1374
1375 1375 QString PythonQt::getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName)
1376 1376 {
1377 1377 PythonQtObjectPtr typeObject = getObjectByType(typeName);
1378 1378 if (typeObject.isNull()) {
1379 1379 return "";
1380 1380 }
1381 1381 return getReturnTypeOfWrappedMethodHelper(typeObject, methodName, typeName + "." + methodName);
1382 1382 }
1383 1383
1384 1384 QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context)
1385 1385 {
1386 1386 PythonQtObjectPtr methodObject;
1387 1387 if (PyDict_Check(variableObject)) {
1388 1388 methodObject = PyDict_GetItemString(variableObject, methodName.toLatin1().constData());
1389 1389 } else {
1390 1390 methodObject.setNewRef(PyObject_GetAttrString(variableObject, methodName.toLatin1().constData()));
1391 1391 }
1392 1392 if (methodObject.isNull()) {
1393 1393 return "";
1394 1394 }
1395 1395
1396 1396 QString type;
1397 1397
1398 1398 if (methodObject->ob_type == &PyClass_Type || methodObject->ob_type == &PyType_Type) {
1399 1399 // the methodObject is not a method, but the name of a type/class. This means
1400 1400 // a constructor is called. Return the context.
1401 1401 type = context;
1402 1402 } else if (methodObject->ob_type == &PythonQtSlotFunction_Type) {
1403 1403 QString className;
1404 1404
1405 1405 if (PyObject_TypeCheck(variableObject, &PythonQtInstanceWrapper_Type)) {
1406 1406 // the type name of wrapped instance is the class name
1407 1407 className = variableObject->ob_type->tp_name;
1408 1408 } else {
1409 1409 PyObject* classNameObject = PyObject_GetAttrString(variableObject, "__name__");
1410 1410 if (classNameObject) {
1411 1411 Q_ASSERT(PyString_Check(classNameObject));
1412 1412 className = PyString_AsString(classNameObject);
1413 1413 Py_DECREF(classNameObject);
1414 1414 }
1415 1415 }
1416 1416
1417 1417 if (!className.isEmpty()) {
1418 1418 PythonQtClassInfo* info = _p->_knownClassInfos.value(className.toLatin1().constData());
1419 1419 if (info) {
1420 1420 PythonQtSlotInfo* slotInfo = info->member(methodName.toLatin1().constData())._slot;
1421 1421 if (slotInfo) {
1422 1422 if (slotInfo->metaMethod()) {
1423 1423 type = slotInfo->metaMethod()->typeName();
1424 1424 if (!type.isEmpty()) {
1425 1425 QChar c = type.at(type.length()-1);
1426 1426 while (c == '*' || c == '&') {
1427 1427 type.truncate(type.length()-1);
1428 1428 if (!type.isEmpty()) {
1429 1429 c = type.at(type.length()-1);
1430 1430 } else {
1431 1431 break;
1432 1432 }
1433 1433 }
1434 1434 // split away template arguments
1435 1435 type = type.split("<").first();
1436 1436 // split away const
1437 1437 type = type.split(" ").last().trimmed();
1438 1438
1439 1439 // if the type is a known class info, then create the full type name, i.e. include the
1440 1440 // module name. For example, the slot may return a QDate, then this looks up the
1441 1441 // name _PythonQt.QtCore.QDate.
1442 1442 PythonQtClassInfo* typeInfo = _p->_knownClassInfos.value(type.toLatin1().constData());
1443 1443 if (typeInfo && typeInfo->pythonQtClassWrapper()) {
1444 1444 PyObject* s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__module__");
1445 1445 Q_ASSERT(PyString_Check(s));
1446 1446 type = QString(PyString_AsString(s)) + "." + type;
1447 1447 Py_DECREF(s);
1448 1448 s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__name__");
1449 1449 Q_ASSERT(PyString_Check(s));
1450 1450 Py_DECREF(s);
1451 1451 }
1452 1452 }
1453 1453 }
1454 1454 }
1455 1455 }
1456 1456 }
1457 1457 }
1458 1458 return type;
1459 1459 }
1460 1460
1461 1461 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1462 1462 {
1463 1463 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1464 1464 }
1465 1465
1466 1466
1467 1467 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1468 1468 {
1469 1469 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1470 1470 if (!info) {
1471 1471 info = new PythonQtClassInfo();
1472 1472 info->setupCPPObject(typeName);
1473 1473 _knownClassInfos.insert(typeName, info);
1474 1474 }
1475 1475 return info;
1476 1476 }
1477 1477
1478 1478 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1479 1479 {
1480 1480 _p->addPolymorphicHandler(typeName, cb);
1481 1481 }
1482 1482
1483 1483 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1484 1484 {
1485 1485 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1486 1486 info->addPolymorphicHandler(cb);
1487 1487 }
1488 1488
1489 1489 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1490 1490 {
1491 1491 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1492 1492 }
1493 1493
1494 1494 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1495 1495 {
1496 1496 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1497 1497 if (info) {
1498 1498 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1499 1499 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1500 1500 return true;
1501 1501 } else {
1502 1502 return false;
1503 1503 }
1504 1504 }
1505 1505
1506 1506 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1507 1507 {
1508 1508 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1509 1509 if (!info->pythonQtClassWrapper()) {
1510 1510 info->setTypeSlots(typeSlots);
1511 1511 info->setupCPPObject(typeName);
1512 1512 createPythonQtClassWrapper(info, package, module);
1513 1513 }
1514 1514 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1515 1515 addParentClass(typeName, parentTypeName, 0);
1516 1516 }
1517 1517 if (wrapperCreator) {
1518 1518 info->setDecoratorProvider(wrapperCreator);
1519 1519 }
1520 1520 if (shell) {
1521 1521 info->setShellSetInstanceWrapperCB(shell);
1522 1522 }
1523 1523 }
1524 1524
1525 1525 PyObject* PythonQtPrivate::packageByName(const char* name)
1526 1526 {
1527 1527 if (name==NULL || name[0]==0) {
1528 1528 name = "private";
1529 1529 }
1530 1530 PyObject* v = _packages.value(name);
1531 1531 if (!v) {
1532 1532 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1533 1533 _packages.insert(name, v);
1534 1534 // AddObject steals the reference, so increment it!
1535 1535 Py_INCREF(v);
1536 1536 PyModule_AddObject(_pythonQtModule, name, v);
1537 1537 }
1538 1538 return v;
1539 1539 }
1540 1540
1541 1541 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1542 1542 {
1543 1543 QString error = "Return value '" + PythonQtConv::PyObjGetString(result) + "' can not be converted to expected C++ type '" + methodInfo->parameters().at(0).name + "' as return value of virtual method " + signature;
1544 1544 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1545 1545 PythonQt::self()->handleError();
1546 1546 }
1547 1547
1548 1548 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1549 1549 {
1550 1550 if (_p->_initFlags & ExternalHelp) {
1551 1551 emit pythonHelpRequest(QByteArray(info->className()));
1552 1552 return Py_BuildValue("");
1553 1553 } else {
1554 1554 return PyString_FromString(info->help().toLatin1().data());
1555 1555 }
1556 1556 }
1557 1557
1558 1558 void PythonQt::clearNotFoundCachedMembers()
1559 1559 {
1560 1560 foreach(PythonQtClassInfo* info, _p->_knownClassInfos) {
1561 1561 info->clearNotFoundCachedMembers();
1562 1562 }
1563 1563 }
1564 1564
1565 1565 void PythonQt::removeWrapperFactory( PythonQtCppWrapperFactory* factory )
1566 1566 {
1567 1567 _p->_cppWrapperFactories.removeAll(factory);
1568 1568 }
1569 1569
1570 1570 void PythonQt::removeWrapperFactory( PythonQtForeignWrapperFactory* factory )
1571 1571 {
1572 1572 _p->_foreignWrapperFactories.removeAll(factory);
1573 1573 }
1574 1574
1575 1575 void PythonQtPrivate::removeWrapperPointer(void* obj)
1576 1576 {
1577 1577 _wrappedObjects.remove(obj);
1578 1578 }
1579 1579
1580 1580 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1581 1581 {
1582 1582 _wrappedObjects.insert(obj, wrapper);
1583 1583 }
1584 1584
1585 1585 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1586 1586 {
1587 1587 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1588 1588 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1589 1589 // this is a wrapper whose QObject was already removed due to destruction
1590 1590 // so the obj pointer has to be a new QObject with the same address...
1591 1591 // we remove the old one and set the copy to NULL
1592 1592 wrap->_objPointerCopy = NULL;
1593 1593 removeWrapperPointer(obj);
1594 1594 wrap = NULL;
1595 1595 }
1596 1596 return wrap;
1597 1597 }
1598 1598
1599 1599 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1600 1600 {
1601 1601 PythonQtObjectPtr result;
1602 1602 if (pycode) {
1603 1603 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1604 1604 } else {
1605 1605 PythonQt::self()->handleError();
1606 1606 }
1607 1607 return result;
1608 1608 }
1609 1609
1610 1610 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObject* obj )
1611 1611 {
1612 1612 void* foreignObject = NULL;
1613 1613 for (int i=0; i<_foreignWrapperFactories.size(); i++) {
1614 1614 foreignObject = _foreignWrapperFactories.at(i)->unwrap(classname, obj);
1615 1615 if (foreignObject) {
1616 1616 return foreignObject;
1617 1617 }
1618 1618 }
1619 1619 return NULL;
1620 1620 }
1621 1621
1622 1622 bool PythonQtPrivate::isMethodDescriptor(PyObject* object) const
1623 1623 {
1624 1624 // This implementation is the same as in inspect.ismethoddescriptor(), inspect.py.
1625 1625 if (PyObject_HasAttrString(object, "__get__") &&
1626 1626 !PyObject_HasAttrString(object, "__set__") &&
1627 1627 !PyMethod_Check(object) &&
1628 1628 !PyFunction_Check(object) &&
1629 1629 !PyClass_Check(object)) {
1630 1630 return true;
1631 1631 }
1632 1632 return false;
1633 1633 }
1634 1634
1635 1635 QString PythonQtPrivate::getSignature(PyObject* object)
1636 1636 {
1637 1637 QString signature;
1638 1638
1639 1639 if (object) {
1640 1640 PyMethodObject* method = NULL;
1641 1641 PyFunctionObject* func = NULL;
1642 1642
1643 1643 bool decrefMethod = false;
1644 1644
1645 1645 if (object->ob_type == &PyClass_Type || object->ob_type == &PyType_Type) {
1646 1646 method = (PyMethodObject*)PyObject_GetAttrString(object, "__init__");
1647 1647 decrefMethod = true;
1648 1648 } else if (object->ob_type == &PyFunction_Type) {
1649 1649 func = (PyFunctionObject*)object;
1650 1650 } else if (object->ob_type == &PyMethod_Type) {
1651 1651 method = (PyMethodObject*)object;
1652 1652 }
1653 1653 if (method) {
1654 1654 if (PyFunction_Check(method->im_func)) {
1655 1655 func = (PyFunctionObject*)method->im_func;
1656 1656 } else if (isMethodDescriptor((PyObject*)method)) {
1657 1657 QString docstr;
1658 1658 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
1659 1659 if (doc) {
1660 1660 docstr = PyString_AsString(doc);
1661 1661 Py_DECREF(doc);
1662 1662 }
1663 1663
1664 1664 PyObject* s = PyObject_GetAttrString(object, "__name__");
1665 1665 if (s) {
1666 1666 Q_ASSERT(PyString_Check(s));
1667 1667 signature = PyString_AsString(s);
1668 1668 if (docstr.startsWith(signature + "(")) {
1669 1669 signature = docstr;
1670 1670 } else {
1671 1671 signature += "(...)";
1672 1672 if (!docstr.isEmpty()) {
1673 1673 signature += "\n\n" + docstr;
1674 1674 }
1675 1675 }
1676 1676 Py_DECREF(s);
1677 1677 }
1678 1678 }
1679 1679 }
1680 1680
1681 1681 if (func) {
1682 1682 QString funcName;
1683 1683 PyObject* s = PyObject_GetAttrString((PyObject*)func, "__name__");
1684 1684 if (s) {
1685 1685 Q_ASSERT(PyString_Check(s));
1686 1686 funcName = PyString_AsString(s);
1687 1687 Py_DECREF(s);
1688 1688 }
1689 1689 if (method && funcName == "__init__") {
1690 1690 PyObject* s = PyObject_GetAttrString(object, "__name__");
1691 1691 if (s) {
1692 1692 Q_ASSERT(PyString_Check(s));
1693 1693 funcName = PyString_AsString(s);
1694 1694 Py_DECREF(s);
1695 1695 }
1696 1696 }
1697 1697
1698 1698 QStringList arguments;
1699 1699 QStringList defaults;
1700 1700 QString varargs;
1701 1701 QString varkeywords;
1702 1702 // NOTE: This implementation is based on function getargs() in inspect.py.
1703 1703 // inspect.getargs() can handle anonymous (tuple) arguments, while this code does not.
1704 1704 // It can be implemented, but it may be rarely needed and not necessary.
1705 1705 PyCodeObject* code = (PyCodeObject*)func->func_code;
1706 1706 if (code->co_varnames) {
1707 1707 int nargs = code->co_argcount;
1708 1708 Q_ASSERT(PyTuple_Check(code->co_varnames));
1709 1709 for (int i=0; i<nargs; i++) {
1710 1710 PyObject* name = PyTuple_GetItem(code->co_varnames, i);
1711 1711 Q_ASSERT(PyString_Check(name));
1712 1712 arguments << PyString_AsString(name);
1713 1713 }
1714 1714 if (code->co_flags & CO_VARARGS) {
1715 1715 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1716 1716 Q_ASSERT(PyString_Check(s));
1717 1717 varargs = PyString_AsString(s);
1718 1718 nargs += 1;
1719 1719 }
1720 1720 if (code->co_flags & CO_VARKEYWORDS) {
1721 1721 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1722 1722 Q_ASSERT(PyString_Check(s));
1723 1723 varkeywords = PyString_AsString(s);
1724 1724 }
1725 1725 }
1726 1726
1727 1727 PyObject* defaultsTuple = func->func_defaults;
1728 1728 if (defaultsTuple) {
1729 1729 Q_ASSERT(PyTuple_Check(defaultsTuple));
1730 1730 for (Py_ssize_t i=0; i<PyTuple_Size(defaultsTuple); i++) {
1731 1731 PyObject* d = PyTuple_GetItem(defaultsTuple, i);
1732 1732 PyObject* s = PyObject_Repr(d);
1733 1733 Q_ASSERT(PyString_Check(s));
1734 1734 defaults << PyString_AsString(s);
1735 1735 Py_DECREF(s);
1736 1736 }
1737 1737 }
1738 1738
1739 1739 int firstdefault = arguments.size() - defaults.size();
1740 1740 for (int i=0; i<arguments.size(); i++) {
1741 1741 if (!signature.isEmpty()) { signature += ", "; }
1742 1742 if (!method || i>0 || arguments[i] != "self") {
1743 1743 signature += arguments[i];
1744 1744 if (i >= firstdefault) {
1745 1745 signature += "=" + defaults[i-firstdefault];
1746 1746 }
1747 1747 }
1748 1748 }
1749 1749 if (!varargs.isEmpty()) {
1750 1750 if (!signature.isEmpty()) { signature += ", "; }
1751 1751 signature += "*" + varargs;
1752 1752 }
1753 1753 if (!varkeywords.isEmpty()) {
1754 1754 if (!signature.isEmpty()) { signature += ", "; }
1755 1755 signature += "**" + varkeywords;
1756 1756 }
1757 1757 signature = funcName + "(" + signature + ")";
1758 1758 }
1759 1759
1760 1760 if (method && decrefMethod) {
1761 1761 Py_DECREF(method);
1762 1762 }
1763 1763 }
1764 1764
1765 1765 return signature;
1766 1766 }
1767 1767
1768 1768 void PythonQtPrivate::shellClassDeleted( void* shellClass )
1769 1769 {
1770 1770 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(shellClass);
1771 1771 if (wrap && wrap->_wrappedPtr) {
1772 1772 // this is a pure C++ wrapper and the shell has gone, so we need
1773 1773 // to set the _wrappedPtr to NULL on the wrapper
1774 1774 wrap->_wrappedPtr = NULL;
1775 1775 // and then we remove the wrapper, since the wrapped class is gone
1776 1776 _wrappedObjects.remove(shellClass);
1777 1777 }
1778 1778 // if the wrapper is a QObject, we do not handle this here,
1779 1779 // it will be handled by the QPointer<> to the QObject, which becomes NULL
1780 1780 // via the QObject destructor.
1781 }
1782
1783 PyObject* PythonQtPrivate::wrapMemoryAsBuffer( const void* data, Py_ssize_t size )
1784 {
1785 // P3K port needed later on!
1786 return PyBuffer_FromMemory((void*)data, size);
1787 }
1788
1789 PyObject* PythonQtPrivate::wrapMemoryAsBuffer( void* data, Py_ssize_t size )
1790 {
1791 // P3K port needed later on!
1792 return PyBuffer_FromReadWriteMemory(data, size);
1781 1793 } No newline at end of file
@@ -1,714 +1,720
1 1 #ifndef _PYTHONQT_H
2 2 #define _PYTHONQT_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQt.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include "PythonQtInstanceWrapper.h"
47 47 #include "PythonQtClassWrapper.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtObjectPtr.h"
50 50 #include "PythonQtStdIn.h"
51 51 #include <QObject>
52 52 #include <QVariant>
53 53 #include <QList>
54 54 #include <QHash>
55 55 #include <QByteArray>
56 56 #include <QStringList>
57 57 #include <QtDebug>
58 58 #include <iostream>
59 59
60 60
61 61 class PythonQtClassInfo;
62 62 class PythonQtPrivate;
63 63 class PythonQtMethodInfo;
64 64 class PythonQtSignalReceiver;
65 65 class PythonQtImportFileInterface;
66 66 class PythonQtCppWrapperFactory;
67 67 class PythonQtForeignWrapperFactory;
68 68 class PythonQtQFileImporter;
69 69
70 70 typedef void PythonQtQObjectWrappedCB(QObject* object);
71 71 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
72 72 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, const char **class_name);
73 73
74 74 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
75 75
76 76 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) {
77 77 (reinterpret_cast<T*>(object))->_wrapper = wrapper;
78 78 }
79 79
80 80 //! returns the offset that needs to be added to upcast an object of type T1 to T2
81 81 template<class T1, class T2> int PythonQtUpcastingOffset() {
82 82 return ((reinterpret_cast<char*>(static_cast<T2*>(reinterpret_cast<T1*>(0x100))))
83 83 - (reinterpret_cast<char*>(reinterpret_cast<T1*>(0x100))));
84 84 }
85 85
86 86 //! callback to create a QObject lazily
87 87 typedef QObject* PythonQtQObjectCreatorFunctionCB();
88 88
89 89 //! helper template to create a derived QObject class
90 90 template<class T> QObject* PythonQtCreateObject() { return new T(); };
91 91
92 92 //! The main interface to the Python Qt binding, realized as a singleton
93 93 /*!
94 94 Use PythonQt::init() to initialize the singleton and PythonQt::self() to access it.
95 95 While there can be only one PythonQt instance, you can have any number of Python context to do scripting in.
96 96 One possibility is to use createModuleFromFile(), createModuleFromScript() or createUniqueModule() to get a context
97 97 that is separated from the other contexts. Alternatively you can use Python dicts as contexts for script evaluation,
98 98 but you will need to populate the dict with the __builtins__ instance to have all Pythons available when running
99 99 code in the scope of a dict.
100 100 */
101 101 class PYTHONQT_EXPORT PythonQt : public QObject {
102 102
103 103 Q_OBJECT
104 104
105 105 public:
106 106
107 107 //! flags that can be passed to PythonQt::init()
108 108 enum InitFlags {
109 109 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
110 110 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
111 111 ExternalHelp = 4, //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
112 112 PythonAlreadyInitialized = 8 //!<< sets that PythonQt should not can PyInitialize, since it is already done
113 113 };
114 114
115 115 //! flags that tell PythonQt which operators to expect on the registered type
116 116 enum TypeSlots {
117 117 Type_Add = 1,
118 118 Type_Subtract = 1 << 1,
119 119 Type_Multiply = 1 << 2,
120 120 Type_Divide = 1 << 3,
121 121 Type_Mod = 1 << 4,
122 122 Type_And = 1 << 5,
123 123 Type_Or = 1 << 6,
124 124 Type_Xor = 1 << 7,
125 125 Type_LShift = 1 << 8,
126 126 Type_RShift = 1 << 9,
127 127
128 128 Type_InplaceAdd = 1 << 10,
129 129 Type_InplaceSubtract = 1 << 11,
130 130 Type_InplaceMultiply = 1 << 12,
131 131 Type_InplaceDivide = 1 << 13,
132 132 Type_InplaceMod = 1 << 14,
133 133 Type_InplaceAnd = 1 << 15,
134 134 Type_InplaceOr = 1 << 16,
135 135 Type_InplaceXor = 1 << 17,
136 136 Type_InplaceLShift = 1 << 18,
137 137 Type_InplaceRShift = 1 << 19,
138 138
139 139 // Not yet needed/nicely mappable/generated...
140 140 //Type_Positive = 1 << 29,
141 141 //Type_Negative = 1 << 29,
142 142 //Type_Abs = 1 << 29,
143 143 //Type_Hash = 1 << 29,
144 144
145 145 Type_Invert = 1 << 29,
146 146 Type_RichCompare = 1 << 30,
147 147 Type_NonZero = 1 << 31,
148 148
149 149 };
150 150
151 151 //! enum for profiling callback
152 152 enum ProfilingCallbackState {
153 153 Enter = 1,
154 154 Leave = 2
155 155 };
156 156
157 157 //! callback for profiling. className and methodName are only passed when state == Enter, otherwise
158 158 //! they are NULL.
159 159 typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName);
160 160
161 161 //---------------------------------------------------------------------------
162 162 //! \name Singleton Initialization
163 163 //@{
164 164
165 165 //! initialize the python qt binding (flags are a or combination of PythonQt::InitFlags), if \c pythonQtModuleName is given
166 166 //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
167 167 //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
168 168 static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray());
169 169
170 170 //! cleanup of the singleton
171 171 static void cleanup();
172 172
173 173 //! get the singleton instance
174 174 static PythonQt* self();
175 175
176 176 //@}
177 177
178 178 //! defines the object types for introspection
179 179 enum ObjectType {
180 180 Class,
181 181 Function,
182 182 Variable,
183 183 Module,
184 184 Anything,
185 185 CallOverloads
186 186 };
187 187
188 188
189 189 //---------------------------------------------------------------------------
190 190 //! \name Standard input handling
191 191 //@{
192 192
193 193 //! Overwrite default handling of stdin using a custom callback. It internally backup
194 194 //! the original 'sys.stdin' into 'sys.pythonqt_original_stdin'
195 195 void setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData = 0);
196 196
197 197 //! Enable or disable stdin custom callback. It resets 'sys.stdin' using either 'sys.pythonqt_stdin'
198 198 //! or 'sys.pythonqt_original_stdin'
199 199 void setRedirectStdInCallbackEnabled(bool enabled);
200 200
201 201 //@}
202 202
203 203 //---------------------------------------------------------------------------
204 204 //! \name Modules
205 205 //@{
206 206
207 207 //! get the __main__ module of python
208 208 PythonQtObjectPtr getMainModule();
209 209
210 210 //! import the given module and return a reference to it (useful to import e.g. "sys" and call something on it)
211 211 //! If a module is already imported, this returns the already imported module.
212 212 PythonQtObjectPtr importModule(const QString& name);
213 213
214 214 //! creates the new module \c name and evaluates the given file in the context of that module
215 215 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
216 216 //! to a module later on.
217 217 //! The user needs to make sure that the \c name is unique in the python module dictionary.
218 218 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
219 219
220 220 //! creates the new module \c name and evaluates the given script in the context of that module.
221 221 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
222 222 //! to a module later on.
223 223 //! The user needs to make sure that the \c name is unique in the python module dictionary.
224 224 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
225 225
226 226 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
227 227 //! script code
228 228 PythonQtObjectPtr createUniqueModule();
229 229
230 230 //@}
231 231
232 232 //---------------------------------------------------------------------------
233 233 //! \name Importing/Paths
234 234 //@{
235 235
236 236 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
237 237 void overwriteSysPath(const QStringList& paths);
238 238
239 239 //! prepend a path to sys.path to allow importing from it
240 240 void addSysPath(const QString& path);
241 241
242 242 //! sets the __path__ list of a module to the given list (important for local imports)
243 243 void setModuleImportPath(PyObject* module, const QStringList& paths);
244 244
245 245 //@}
246 246
247 247 //---------------------------------------------------------------------------
248 248 //! \name Registering Classes
249 249 //@{
250 250
251 251 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
252 252 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
253 253 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
254 254 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
255 255
256 256 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
257 257 //! (ownership of wrapper is passed to PythonQt)
258 258 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
259 259
260 260 This will add a wrapper object that is used to make calls to the given classname \c typeName.
261 261 All slots that take a pointer to typeName as the first argument will be callable from Python on
262 262 a variant object that contains such a type.
263 263 */
264 264 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
265 265
266 266 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
267 267 //! and it will register the classes when it first sees a pointer to such a derived class
268 268 void registerQObjectClassNames(const QStringList& names);
269 269
270 270 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
271 271 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
272 272 //! type is really derived from parentType.
273 273 //! Returns false if the typeName was not yet registered.
274 274 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
275 275
276 276 //! add a handler for polymorphic downcasting
277 277 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
278 278
279 279 //@}
280 280
281 281 //---------------------------------------------------------------------------
282 282 //! \name Script Parsing and Evaluation
283 283 //@{
284 284
285 285 //! parses the given file and returns the python code object, this can then be used to call evalCode()
286 286 PythonQtObjectPtr parseFile(const QString& filename);
287 287
288 288 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
289 289 //! If pycode is NULL, a python error is printed.
290 290 QVariant evalCode(PyObject* object, PyObject* pycode);
291 291
292 292 //! evaluates the given script code and returns the result value
293 293 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
294 294
295 295 //! evaluates the given script code from file
296 296 void evalFile(PyObject* object, const QString& filename);
297 297
298 298 //@}
299 299
300 300 //---------------------------------------------------------------------------
301 301 //! \name Signal Handlers
302 302 //@{
303 303
304 304 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
305 305 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
306 306
307 307 //! remove a signal handler from the given \c signal of \c obj
308 308 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
309 309
310 310 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
311 311 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
312 312
313 313 //! remove a signal handler from the given \c signal of \c obj
314 314 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
315 315
316 316 //@}
317 317
318 318 //---------------------------------------------------------------------------
319 319 //! \name Variable access
320 320 //@{
321 321
322 322 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
323 323 void addObject(PyObject* object, const QString& name, QObject* qObject);
324 324
325 325 //! add the given variable to the object
326 326 void addVariable(PyObject* object, const QString& name, const QVariant& v);
327 327
328 328 //! remove the given variable
329 329 void removeVariable(PyObject* module, const QString& name);
330 330
331 331 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
332 332 QVariant getVariable(PyObject* object, const QString& name);
333 333
334 334 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
335 335 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
336 336 //! read vars etc. in scope of the given \c object
337 337 QStringList introspectObject(PyObject* object, ObjectType type);
338 338 //! read vars etc. in scope of the type object called \c typename. First the typename
339 339 //! of the form module.type is split into module and type. Then the module is looked up
340 340 //! in sys.modules. If the module or type is not found there, then the type is looked up in
341 341 //! the __builtin__ module.
342 342 QStringList introspectType(const QString& typeName, ObjectType type);
343 343
344 344 //! returns the found callable object or NULL
345 345 //! @return new reference
346 346 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
347 347
348 348 //! returns the return type of the method of a wrapped c++ object referenced by \c objectname
349 349 QString getReturnTypeOfWrappedMethod(PyObject* module, const QString& objectname);
350 350 //! returns the return type of the method \c methodName of a wrapped c++ type referenced by \c typeName
351 351 QString getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName);
352 352 //@}
353 353
354 354 //---------------------------------------------------------------------------
355 355 //! \name Calling Python Objects
356 356 //@{
357 357
358 358 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
359 359 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList(), const QVariantMap& kwargs = QVariantMap());
360 360
361 361 //! call the given python object, returns the result converted to a QVariant
362 362 QVariant call(PyObject* callable, const QVariantList& args = QVariantList(), const QVariantMap& kwargs = QVariantMap());
363 363
364 364 //! call the given python object, returns the result as new PyObject
365 365 PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList(), const QVariantMap& kwargs = QVariantMap());
366 366
367 367 //@}
368 368
369 369 //---------------------------------------------------------------------------
370 370 //! \name Decorations, Constructors, Wrappers...
371 371 //@{
372 372
373 373 //! add an object whose slots will be used as decorator slots for
374 374 //! other QObjects or CPP classes. The slots need to follow the
375 375 //! convention that the first argument is a pointer to the wrapped object.
376 376 //! (ownership is passed to PythonQt)
377 377 /*!
378 378 Example:
379 379
380 380 A slot with the signature
381 381
382 382 \code
383 383 bool doSomething(QWidget* w, int a)
384 384 \endcode
385 385
386 386 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
387 387 that will be called with the concrete instance as first argument.
388 388 So in Python you can now e.g. call
389 389
390 390 \code
391 391 someWidget.doSomething(12)
392 392 \endcode
393 393
394 394 without QWidget really having this method. This allows to easily make normal methods
395 395 of Qt classes callable by forwarding them with such decorator slots
396 396 or to make CPP classes (which are not derived from QObject) callable from Python.
397 397 */
398 398 void addInstanceDecorators(QObject* o);
399 399
400 400 //! add an object whose slots will be used as decorator slots for
401 401 //! class objects (ownership is passed to PythonQt)
402 402 /*!
403 403 The slots need to follow the following convention:
404 404 - SomeClass* new_SomeClass(...)
405 405 - QVariant new_SomeClass(...)
406 406 - void delete_SomeClass(SomeClass*)
407 407 - ... static_SomeClass_someName(...)
408 408
409 409 This will add:
410 410 - a constructor
411 411 - a constructor which generates a QVariant
412 412 - a destructor (only useful for CPP objects)
413 413 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
414 414
415 415 */
416 416 void addClassDecorators(QObject* o);
417 417
418 418 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
419 419 void addDecorators(QObject* o);
420 420
421 421 //! add the given factory to PythonQt (ownership stays with caller)
422 422 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
423 423
424 424 //! add the given factory to PythonQt (ownership stays with caller)
425 425 void addWrapperFactory(PythonQtForeignWrapperFactory* factory);
426 426
427 427 //! remove the wrapper factory
428 428 void removeWrapperFactory(PythonQtCppWrapperFactory* factory);
429 429
430 430 //! remove the wrapper factory
431 431 void removeWrapperFactory(PythonQtForeignWrapperFactory* factory);
432 432
433 433 //@}
434 434
435 435 //---------------------------------------------------------------------------
436 436 //! \name Custom Importer
437 437 //@{
438 438
439 439 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
440 440 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
441 441 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
442 442 //! This is not reversible, so even setting setImporter(NULL) afterwards will
443 443 //! keep the custom PythonQt importer with a QFile default import interface.
444 444 //! Subsequent python import calls will make use of the passed importInterface
445 445 //! which forwards all import calls to the given \c importInterface.
446 446 //! Passing NULL will install a default QFile importer.
447 447 //! (\c importInterface ownership stays with caller)
448 448 void setImporter(PythonQtImportFileInterface* importInterface);
449 449
450 450 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
451 451 //! (without calling setImporter or installDefaultImporter at least once, the default python import
452 452 //! mechanism is in place)
453 453 //! the default importer allows to import files from anywhere QFile can read from,
454 454 //! including the Qt resource system using ":". Keep in mind that you need to extend
455 455 //! "sys.path" with ":" to be able to import from the Qt resources.
456 456 void installDefaultImporter() { setImporter(NULL); }
457 457
458 458 //! set paths that the importer should ignore
459 459 void setImporterIgnorePaths(const QStringList& paths);
460 460
461 461 //! get paths that the importer should ignore
462 462 const QStringList& getImporterIgnorePaths();
463 463
464 464 //! get access to the file importer (if set)
465 465 static PythonQtImportFileInterface* importInterface();
466 466
467 467 //@}
468 468
469 469 //---------------------------------------------------------------------------
470 470 //! \name Other Stuff
471 471 //@{
472 472
473 473 //! get access to internal data (should not be used on the public API, but is used by some C functions)
474 474 static PythonQtPrivate* priv() { return _self->_p; }
475 475
476 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 //! create a read-only buffer object from the given memory
591 static PyObject* wrapMemoryAsBuffer(const void* data, Py_ssize_t size);
592
593 //! create a read-write buffer object from the given memory
594 static PyObject* wrapMemoryAsBuffer(void* data, Py_ssize_t size);
595
590 596 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
591 597 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
592 598 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
593 599 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
594 600
595 601 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
596 602 //! (ownership of wrapper is passed to PythonQt)
597 603 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
598 604
599 605 This will add a wrapper object that is used to make calls to the given classname \c typeName.
600 606 All slots that take a pointer to typeName as the first argument will be callable from Python on
601 607 a variant object that contains such a type.
602 608 */
603 609 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 610
605 611 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
606 612 //! and it will register the classes when it first sees a pointer to such a derived class
607 613 void registerQObjectClassNames(const QStringList& names);
608 614
609 615 //! add a decorator object
610 616 void addDecorators(QObject* o, int decoTypes);
611 617
612 618 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
613 619 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
614 620
615 621 //! create a new instance of the given enum type with given value (returns a new reference)
616 622 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
617 623
618 624 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
619 625 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
620 626
621 627 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
622 628 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
623 629
624 630 //! get the class info for a meta object (if available)
625 631 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
626 632
627 633 //! get the class info for a meta object (if available)
628 634 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
629 635
630 636 //! creates the new module from the given pycode
631 637 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
632 638
633 639 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
634 640 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
635 641
636 642 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
637 643 static PyObject* dummyTuple();
638 644
639 645 //! called by virtual overloads when a python return value can not be converted to the required Qt type
640 646 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
641 647
642 648 //! get access to the PythonQt module
643 649 PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
644 650
645 651 //! returns the profiling callback, which may be NULL
646 652 PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
647 653
648 654 //! determines the signature of the given callable object (similar as pydoc)
649 655 QString getSignature(PyObject* object);
650 656
651 657 //! returns true if the object is a method descriptor (same as inspect.ismethoddescriptor() in inspect.py)
652 658 bool isMethodDescriptor(PyObject* object) const;
653 659
654 660 private:
655 661 //! Setup the shared library suffixes by getting them from the "imp" module.
656 662 void setupSharedLibrarySuffixes();
657 663
658 664 //! create a new pythonqt class wrapper and place it in the pythonqt module
659 665 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
660 666
661 667 //! get/create new package module (the returned object is a borrowed reference)
662 668 PyObject* packageByName(const char* name);
663 669
664 670 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
665 671 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
666 672
667 673 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
668 674 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
669 675
670 676 //! stores the meta info of known Qt classes
671 677 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
672 678
673 679 //! names of qobject derived classes that can be casted to qobject savely
674 680 QHash<QByteArray, bool> _knownQObjectClassNames;
675 681
676 682 //! stores signal receivers for QObjects
677 683 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
678 684
679 685 //! the PythonQt python module
680 686 PythonQtObjectPtr _pythonQtModule;
681 687
682 688 //! the name of the PythonQt python module
683 689 QByteArray _pythonQtModuleName;
684 690
685 691 //! the importer interface (if set)
686 692 PythonQtImportFileInterface* _importInterface;
687 693
688 694 //! the default importer
689 695 PythonQtQFileImporter* _defaultImporter;
690 696
691 697 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
692 698 PythonQtQObjectWrappedCB* _wrappedCB;
693 699
694 700 QStringList _importIgnorePaths;
695 701 QStringList _sharedLibrarySuffixes;
696 702
697 703 //! the cpp object wrapper factories
698 704 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
699 705
700 706 QList<PythonQtForeignWrapperFactory*> _foreignWrapperFactories;
701 707
702 708 QHash<QByteArray, PyObject*> _packages;
703 709
704 710 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
705 711
706 712 PythonQt::ProfilingCB* _profilingCB;
707 713
708 714 int _initFlags;
709 715 int _PythonQtObjectPtr_metaId;
710 716
711 717 friend class PythonQt;
712 718 };
713 719
714 720 #endif
@@ -1,535 +1,532
1 1 #ifndef _PYTHONQTDOC_H
2 2 #define _PYTHONQTDOC_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 PythonQtDoc.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-10
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 /*!
46 46 \if USE_GLOBAL_DOXYGEN_DOC
47 47 \page PythonQtPage PythonQt Overview
48 48 \else
49 49 \mainpage notitle
50 50 \endif
51 51
52 52 \image html PythonQt.jpg
53 53
54 54 \section Introduction
55 55
56 56 \b PythonQt is a dynamic <a href="http://www.python.org" target="_blank">
57 57 Python</a> binding for the <a href="http://qt.nokia.com" target="_blank">
58 58 Qt framework</a>.
59 59 It offers an easy way to embed the Python scripting language into
60 60 your C++ Qt applications. It makes heavy use of the QMetaObject system and thus requires Qt 4.x.
61 61
62 62 The focus of PythonQt is on embedding Python into an existing C++ application, not on writing the whole
63 63 application completely in Python. If you want to write your whole application in Python,
64 64 you should use <a href="http://www.riverbankcomputing.co.uk/pyqt/" target="_blank">PyQt</a> or <a href="http://www.pyside.org" target="_blank">PySide</a> instead.
65 65
66 66 If you are looking for a simple way to embed Python objects into your C++/Qt Application
67 67 and to script parts of your application via Python, PythonQt is the way to go!
68 68
69 69 PythonQt is a stable library that was developed to make the
70 70 Image Processing and Visualization platform <a href="http://www.mevislab.de" target="_blank">MeVisLab</a>
71 71 scriptable from Python.
72 72
73 73 - \ref Features
74 74 - \ref Download
75 75 - \ref License
76 76 - \ref Developer
77 77 - \ref Building
78 78 - \ref Examples
79 79
80 80 \page Features Features
81 81
82 82 \section Builtin Built-in Features
83 83
84 84 The following are the built-in features of the PythonQt library:
85 85
86 86 - Access all \b slots, \b properties, children and registered enums of any QObject derived class from Python
87 87 - Connecting Qt Signals to Python functions (both from within Python and from C++)
88 88 - Easy wrapping of Python objects from C++ with smart, reference-counting PythonQtObjectPtr.
89 89 - Convenient conversions to/from QVariant for PythonQtObjectPtr.
90 90 - Wrapping of C++ objects (which are not derived from QObject) via PythonQtCppWrapperFactory
91 91 - Extending C++ and QObject derived classes with additional slots, static methods and constructors (see Decorators)
92 92 - StdOut/Err redirection to Qt signals instead of cout
93 93 - Interface for creating your own \c import replacement, so that Python scripts can be e.g. signed/verified before they are executed (PythonQtImportFileInterface)
94 94 - Mapping of plain-old-datatypes and ALL QVariant types to and from Python
95 95 - Support for wrapping of user QVariant types which are registerd via QMetaType
96 96 - Support for Qt namespace (with all enumerators)
97 97 - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has
98 98 - No preprocessing/wrapping tool needs to be started, PythonQt can script any QObject without prior knowledge about it (except for the MetaObject information from the \b moc)
99 99 - Multiple inheritance for C++ objects (e.g. a QWidget is derived from QObject and QPaintDevice, PythonQt will automatically cast a QWidget to a QPaintDevice when needed)
100 100 - Polymorphic downcasting (if e.g. PythonQt sees a QEvent, it can downcast it depending on the type(), so the Python e.g. sees a QPaintEvent instead of a plain QEvent)
101 101 - Deriving C++ objects from Python and overwriting virtual method with a Python implementation (requires usage of wrapper generator or manual work!)
102 102 - Extensible handler for Python/C++ conversion of complex types, e.g. mapping of QVector<SomeObject> to/from a Python array
103 103 - Setting of dynamic QObject properties via setProperty(), dynamic properties can be accessed for reading and writing like normal Python attributes (but creating a new property needs to be done with setProperty(), to distinguish from normal Python attributes)
104 104
105 105 \section FeaturesQtAll Features with wrapper generator
106 106
107 107 Thanks to the new wrapper generator, PythonQt now offers the additional PythonQt_QtAll library which wraps the complete Qt API, including all C++ classes and all non-slots on QObject derived classes.
108 108 This offers the following features:
109 109
110 110 - Complete Qt API wrapped and accessible
111 111 - The following modules are available as submodules of the PythonQt module:
112 112 - QtCore
113 113 - QtGui
114 114 - QtNetwork
115 115 - QtOpenGL
116 116 - QtSql
117 117 - QtSvg
118 118 - QtUiTools
119 119 - QtWebKit
120 120 - QtXml
121 121 - (QtXmlPatterns, QtScript, QtHelp, phonon, assistant, designer are currently not supported, this would require some additional effort on the code generator)
122 122 - For convenience, all classes are also available in the PythonQt.Qt module, for people who do not care in which module a class is located
123 123 - Any Qt class that has virtual methods can be easily derived from Python and the virtual methods can be reimplemented in Python (this feature is considered experimental!)
124 124 - Polymorphic downcasting on QEvent, QGraphicsItem, QStyleOption, ...
125 125 - Multiple inheritance support (e.g., QGraphicsTextItem is a QObject AND a QGraphicsItem, PythonQt will handle this well)
126 126
127 127 \section Comparison Comparison with PyQt/PySide
128 128
129 129 - PythonQt is not as pythonic as PyQt in many details (e.g. buffer protocol, pickling, translation support, ...) and it is mainly thought for embedding and intercommunication between Qt/Cpp and Python
130 130 - PythonQt allows to communicate in both directions, e.g., calling a Python object from C++ AND calling a C++ method from Python, while PyQt only handles the Python->C++ direction
131 131 - PythonQt offers properties as Python attributes, while PyQt offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PyQt)
132 132 - PythonQt currently does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
133 133 - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it like a normal slot
134 134 - PythonQt does not (yet) offer to add new signals to Python/C++ objects and it does not yet support the newstyle PyQt signals (so you need to connect via C++ string signatures)
135 135 - Ownership of objects is a bit different in PythonQt, currently Python classes derived from a C++ class need to be manually referenced in Python to not get deleted too early (this will be fixed in a future version)
136 136 - QStrings are always converted to unicode Python objects, QByteArray always stays a QByteArray and can be converted using str()
137 137 - There are many details in the generated wrappers that could need some polishing, e.g., methods that use pointer arguments for additional return values could return a results tuple.
138 138 - Not all types of QList/QVector/QHash templates are supported, some Qt methods use those as arguments/return values (but you can add your own handlers to handle them if you need them).
139 139 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
140 140 - In the long run, PythonQt will consider using/extending PySide with the features of PythonQt to get rid of its own generator and typesystem files, alternatively the KDE Smoke generator might be used in the future (this has not yet been decided, the current PythonQt generator works well and there is no hurry to switch).
141 141
142 142 \page Download Download
143 143
144 144 PythonQt is hosted on <a href="http://sourceforge.net/projects/pythonqt/" target="_blank">SourceForge</a>.
145 145
146 146 You can download the source code as a tarball at http://sourceforge.net/projects/pythonqt/files/.
147 147 Alternatively you can get the latest version from the svn repository.
148 148
149 149 You can also browse the source code online via ViewVC: http://pythonqt.svn.sourceforge.net/viewvc/pythonqt/trunk/
150 150
151 151 \note We do not offer prebuilt binaries, since there are so many possible combinations of
152 152 platforms (Windows/Linux/MacOs), architectures (32/64 bit) and Python versions.
153 153
154 154 \page License License
155 155
156 156 PythonQt is distributed under the LGPL license, so it pairs well with the LGPL of the Qt 4.5 release and allows
157 157 to be used in commercial applications when following the LGPL 2.1 obligations.
158 158
159 159 The build system of PythonQt makes use of a modified version of the LGPL'ed QtScript generator,
160 160 located in the "generator" directory.
161 161
162 162 See http://qt.gitorious.org/qt-labs/qtscriptgenerator for details on the original project.
163 163 Thanks a lot to the QtJambi guys and the QtScript Generator project for the C++ parser and
164 164 Qt typesystem files!
165 165
166 166 The PythonQt wrappers generated by the generator located in the "generated_cpp" directory are free to be used without any licensing restrictions.
167 167
168 The generated wrappers are pre-generated and checked-in for Qt 4.8, so you only need to build and run the
168 The generated wrappers are pre-generated and checked-in for Qt 4.6.1, so you only need to build and run the
169 169 generator when you want to build additional wrappers or you want to upgrade/downgrade to another Qt version.
170 170 You may use the generator to generate C++ bindings for your own C++ classes (e.g., to make them inheritable in Python),
171 171 but this is currently not documented and involves creating your own typesystem files (although the Qt Jambi examples might help you).
172 172
173 173
174 174 \page Developer Developer
175 175
176 176 \section Interface Interface
177 177
178 178 The main interface to PythonQt is the PythonQt singleton.
179 179 PythonQt needs to be initialized via PythonQt::init() once.
180 180 Afterwards you communicate with the singleton via PythonQt::self().
181 181 PythonQt offers a complete Qt binding, which
182 182 needs to be enabled via PythonQt_QtAll::init().
183 183
184 184
185 185 \section Datatype Datatype Mapping
186 186
187 187 The following table shows the mapping between Python and Qt objects:
188 188 <table>
189 189 <tr><th>Qt/C++</th><th>Python</th></tr>
190 190 <tr><td>bool</td><td>bool</td></tr>
191 191 <tr><td>double</td><td>float</td></tr>
192 192 <tr><td>float</td><td>float</td></tr>
193 193 <tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
194 194 <tr><td>long</td><td>integer</td></tr>
195 195 <tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
196 196 <tr><td>QString</td><td>unicode string</td></tr>
197 197 <tr><td>QByteArray</td><td>QByteArray wrapper</td></tr>
198 198 <tr><td>char*</td><td>str</td></tr>
199 199 <tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
200 200 <tr><td>QVariantList</td><td>tuple of objects</td></tr>
201 201 <tr><td>QVariantMap</td><td>dict of objects</td></tr>
202 202 <tr><td>QVariant</td><td>depends on type, see below</td></tr>
203 203 <tr><td>QSize, QRect and all other standard Qt QVariants</td><td>variant wrapper that supports complete API of the respective Qt classes</td></tr>
204 204 <tr><td>OwnRegisteredMetaType</td><td>C++ wrapper, optionally with additional information/wrapping provided by registerCPPClass()</td></tr>
205 205 <tr><td>QList<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
206 206 <tr><td>QVector<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
207 207 <tr><td>EnumType</td><td>Enum wrapper derived from python integer</td></tr>
208 208 <tr><td>QObject (and derived classes)</td><td>QObject wrapper</td></tr>
209 209 <tr><td>C++ object</td><td>CPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
210 210 <tr><td>PyObject</td><td>PyObject</td></tr>
211 211 </table>
212 212
213 213 PyObject is passed as direct pointer, which allows to pass/return any Python object directly to/from
214 214 a Qt slot that uses PyObject* as its argument/return value.
215 215 QVariants are mapped recursively as given above, e.g. a dictionary can
216 216 contain lists of dictionaries of doubles.
217 217 All Qt QVariant types are implemented, PythonQt supports the complete Qt API for these object.
218 218
219 219 \section QObject QObject Wrapping
220 220
221 221 All classes derived from QObject are automatically wrapped with a python wrapper class
222 222 when they become visible to the Python interpreter. This can happen via
223 223 - the PythonQt::addObject() method
224 224 - when a Qt \b slot returns a QObject derived object to python
225 225 - when a Qt \b signal contains a QObject and is connected to a python function
226 226
227 227 It is important that you call PythonQt::registerClass() for any QObject derived class
228 228 that may become visible to Python, except when you add it via PythonQt::addObject().
229 229 This will register the complete parent hierachy of the registered class, so that
230 230 when you register e.g. a QPushButton, QWidget will be registered as well (and all intermediate
231 231 parents).
232 232
233 233 From Python, you can talk to the returned QObjects in a natural way by calling
234 234 their slots and receiving the return values. You can also read/write all
235 235 properties of the objects as if they where normal python properties.
236 236
237 237 In addition to this, the wrapped objects support
238 238 - className() - returns a string that reprents the classname of the QObject
239 239 - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form
240 240 - delete() - deletes the object (use with care, especially if you passed the ownership to C++)
241 241 - connect(signal, function) - connect the signal of the given object to a python function
242 242 - connect(signal, qobject, slot) - connect the signal of the given object to a slot of another QObject
243 243 - disconnect(signal, function) - disconnect the signal of the given object from a python function
244 244 - disconnect(signal, qobject, slot) - disconnect the signal of the given object from a slot of another QObject
245 245 - children() - returns the children of the object
246 246 - setParent(QObject) - set the parent
247 247 - QObject* parent() - get the parent
248 248
249 249 The below example shows how to connect signals in Python:
250 250
251 251 \code
252 252 # define a signal handler function
253 253 def someFunction(flag):
254 254 print flag
255 255
256 256 # button1 is a QPushButton that has been added to Python via addObject()
257 257 # connect the clicked signal to a python function:
258 258 button1.connect("clicked(bool)", someFunction)
259 259
260 260 \endcode
261 261
262 262 \section CPP CPP Wrapping
263 263
264 264 You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory
265 265 and adding your factory via addWrapperFactory().
266 266 Whenever PythonQt encounters a CPP pointer (e.g. on a slot or signal)
267 267 and it does not known it as a QObject derived class, it will create a generic CPP wrapper. So even unknown C++ objects
268 268 can be passed through Python. If the wrapper factory supports the CPP class, a QObject wrapper will be created for each
269 269 instance that enters Python. An alternative to a complete wrapper via the wrapper factory are decorators, see \ref Decorators
270 270
271 271 \section MetaObject Meta Object/Class access
272 272
273 273 For each known C++ class, PythonQt provides a Python class. These classes are visible
274 274 inside of the "PythonQt" python module or in subpackages if a package is given when the class is registered.
275 275
276 276 A Meta class supports:
277 277
278 278 - access to all declared enum values
279 279 - constructors
280 280 - static methods
281 281 - unbound non-static methods
282 282 - help() and className()
283 283
284 284 From within Python, you can import the module "PythonQt" to access these classes and the Qt namespace.
285 285
286 286 \code
287 287 from PythonQt import QtCore
288 288
289 289 # namespace access:
290 290 print QtCore.Qt.AlignLeft
291 291
292 292 # constructors
293 293 a = QtCore.QSize(12,13)
294 294 b = QtCore.QFont()
295 295
296 296 # static method
297 297 QtCore.QDate.currentDate()
298 298
299 299 # enum value
300 300 QtCore.QFont.UltraCondensed
301 301
302 302 \endcode
303 303
304 304 \section Decorators Decorator slots
305 305
306 306 PythonQt introduces a new generic approach to extend any wrapped QObject or CPP object with
307 307
308 308 - constructors
309 309 - destructors (for CPP objects)
310 310 - additional slots
311 311 - static slots (callable on both the Meta object and the instances)
312 312
313 313 The idea behind decorators is that we wanted to make it as easy as possible to extend
314 314 wrapped objects. Since we already have an implementation for invoking any Qt Slot from
315 315 Python, it looked promising to use this approach for the extension of wrapped objects as well.
316 316 This avoids that the PythonQt user needs to care about how Python arguments are mapped from/to
317 317 Qt when he wants to create static methods, constructors and additional member functions.
318 318
319 319 The basic idea about decorators is to create a QObject derived class that implements slots
320 320 which take one of the above roles (e.g. constructor, destructor etc.) via a naming convention.
321 321 These slots are then assigned to other classes via the naming convention.
322 322
323 323 - SomeClassName* new_SomeClassName(...) - defines a constructor for "SomeClassName" that returns a new object of type SomeClassName (where SomeClassName can be any CPP class, not just QObject classes)
324 324 - void delete_SomeClassName(SomeClassName* o) - defines a destructor, which should delete the passed in object o
325 325 - anything static_SomeClassName_someMethodName(...) - defines a static method that is callable on instances and the meta class
326 326 - anything someMethodName(SomeClassName* o, ...) - defines a slot that will be available on SomeClassName instances (and derived instances). When such a slot is called the first argument is the pointer to the instance and the rest of the arguments can be used to make a call on the instance.
327 327
328 328 The below example shows all kinds of decorators in action:
329 329
330 330 \code
331 331
332 332 // an example CPP object
333 333 class YourCPPObject {
334 334 public:
335 335 YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
336 336
337 337 float doSomething(int arg1) { return arg1*a*b; };
338 338
339 339 private:
340 340
341 341 int a;
342 342 float b;
343 343 };
344 344
345 345 // an example decorator
346 346 class ExampleDecorator : public QObject
347 347 {
348 348 Q_OBJECT
349 349
350 350 public slots:
351 351 // add a constructor to QSize that takes a QPoint
352 352 QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
353 353
354 354 // add a constructor for QPushButton that takes a text and a parent widget
355 355 QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) { return new QPushButton(text, parent); }
356 356
357 357 // add a constructor for a CPP object
358 358 YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new YourCPPObject(arg1, arg2); }
359 359
360 360 // add a destructor for a CPP object
361 361 void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
362 362
363 363 // add a static method to QWidget
364 364 QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
365 365
366 366 // add an additional slot to QWidget (make move() callable, which is not declared as a slot in QWidget)
367 367 void move(QWidget* w, const QPoint& p) { w->move(p); }
368 368
369 369 // add an additional slot to QWidget, overloading the above move method
370 370 void move(QWidget* w, int x, int y) { w->move(x,y); }
371 371
372 372 // add a method to your own CPP object
373 373 int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1); }
374 374 };
375 375
376 376 ...
377 377
378 378 PythonQt::self()->addDecorators(new ExampleDecorator());
379 379 PythonQt::self()->registerCPPClass("YourCPPObject");
380 380
381 381 \endcode
382 382
383 383 After you have registered an instance of the above ExampleDecorator, you can do the following from Python
384 384 (all these calls are mapped to the above decorator slots):
385 385
386 386 \code
387 387 from PythonQt import QtCore, QtGui, YourCPPObject
388 388
389 389 # call our new constructor of QSize
390 390 size = QtCore.QSize(QPoint(1,2));
391 391
392 392 # call our new QPushButton constructor
393 393 button = QtGui.QPushButton("sometext");
394 394
395 395 # call the move slot (overload1)
396 396 button.move(QPoint(0,0))
397 397
398 398 # call the move slot (overload2)
399 399 button.move(0,0)
400 400
401 401 # call the static method
402 402 grabber = QtGui.QWidget.mouseWrapper();
403 403
404 404 # create a CPP object via constructor
405 405 yourCpp = YourCPPObject(1,11.5)
406 406
407 407 # call the wrapped method on CPP object
408 408 print yourCpp.doSomething(1);
409 409
410 410 # destructor will be called:
411 411 yourCpp = None
412 412
413 413 \endcode
414 414
415 415 \page Building Building
416 416
417 417 PythonQt requires at least Qt 4.6.1 (for earlier Qt versions, you will need to run the pythonqt_gerenator, Qt 4.3 is the absolute minimum) and Python 2.5.x or 2.6.x on Windows, Linux and MacOS X. It has not yet been tested with Python 3.x, but it should only require minor changes.
418 418 To compile PythonQt, you will need a python developer installation which includes Python's header files and
419 419 the python2x.[lib | dll | so | dynlib].
420 420 The build scripts a currently set to use Python 2.6.
421 421 You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system.
422 422
423 \note In addition to the qmake profiles, PythonQt now offers building via Cmake. Just use the provided
424 CMakeLists.txt in the root directory of the project. This build option has not been well tested yet.
425
426 \section Windows
423 \subsection Windows
427 424
428 425 On Windows, the (non-source) Python Windows installer can be used.
429 426 Make sure that you use the same compiler, the current Python distribution is built
430 427 with Visual Studio 2003. If you want to use another compiler, you will need to build
431 428 Python yourself, using your compiler.
432 429
433 430 To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root
434 431 dir of the python installation and \b PYTHON_LIB to point to
435 432 the directory where the python lib file is located.
436 433
437 434 When using the prebuild Python installer, this will be:
438 435
439 436 \code
440 437 > set PYTHON_PATH = c:\Python26
441 438 > set PYTHON_LIB = c:\Python26\libs
442 439 \endcode
443 440
444 441 When using the python sources, this will be something like:
445 442
446 443 \code
447 444 > set PYTHON_PATH = c:\yourDir\Python-2.6.1\
448 445 > set PYTHON_LIB = c:\yourDir\Python-2.6.1\PCbuild8\Win32
449 446 \endcode
450 447
451 448 To build all, do the following (after setting the above variables):
452 449
453 450 \code
454 451 > cd PythonQtRoot
455 452 > vcvars32
456 453 > qmake
457 454 > nmake
458 455 \endcode
459 456
460 457 This should build everything. If Python can not be linked or include files can not be found,
461 458 you probably need to tweak \b build/python.prf
462 459
463 460 The tests and examples are located in PythonQt/lib.
464 461
465 \section Linux
462 \subsection Linux
466 463
467 464 On Linux, you need to install a Python-dev package.
468 465 If Python can not be linked or include files can not be found,
469 466 you probably need to tweak \b build/python.prf
470 467
471 468 To build PythonQt, just do a:
472 469
473 470 \code
474 471 > cd PythonQtRoot
475 472 > qmake
476 473 > make all
477 474 \endcode
478 475
479 476 The tests and examples are located in PythonQt/lib.
480 477 You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
481 478 linker can find the *.so files.
482 479
483 \section MacOSX
480 \subsection MacOsX
484 481
485 482 On Mac, Python is installed as a Framework, so you should not need to install it.
486 483 To build PythonQt, just do a:
487 484
488 485 \code
489 486 > cd PythonQtRoot
490 487 > qmake
491 488 > make all
492 489 \endcode
493 490
494 491 \section Tests
495 492
496 493 There is a unit test that tests most features of PythonQt, see the \b tests subdirectory for details.
497 494
498 495 \page Examples Examples
499 496
500 497 Examples are available in the \b examples directory. The PyScriptingConsole implements a simple
501 498 interactive scripting console that shows how to script a simple application. The PyLauncher application can be used to run arbitrary PythonQt scripts given on the commandline.
502 499
503 500 The following shows a simple example on how to integrate PythonQt into your Qt application:
504 501
505 502 \code
506 503 #include "PythonQt.h"
507 504 #include <QApplication>
508 505 ...
509 506
510 507 int main( int argc, char **argv )
511 508 {
512 509
513 510 QApplication qapp(argc, argv);
514 511
515 512 // init PythonQt and Python itself
516 513 PythonQt::init();
517 514
518 515 // get a smart pointer to the __main__ module of the Python interpreter
519 516 PythonQtObjectPtr context = PythonQt::self()->getMainModule();
520 517
521 518 // add a QObject as variable of name "example" to the namespace of the __main__ module
522 519 PyExampleObject example;
523 520 context.addObject("example", &example);
524 521
525 522 // do something
526 523 context.evalScript("print example");
527 524 context.evalScript("def multiply(a,b):\n return a*b;\n");
528 525 QVariantList args;
529 526 args << 42 << 47;
530 527 QVariant result = context.call("multiply", args);
531 528 ...
532 529 \endcode
533 530
534 531
535 532 */
General Comments 0
You need to be logged in to leave comments. Login now