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