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