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