@@ -170,17 +170,20 PythonQt::PythonQt(int flags) | |||
|
170 | 170 | } |
|
171 | 171 | Py_INCREF(&PythonQtSlotFunction_Type); |
|
172 | 172 | |
|
173 | // add our own python object types for qt objects | |
|
174 | if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) { | |
|
175 | std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl; | |
|
176 | } | |
|
177 | Py_INCREF(&PythonQtInstanceWrapper_Type); | |
|
178 | ||
|
179 | // add our own python object types for qt objects | |
|
173 | // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it | |
|
174 | PythonQtClassWrapper_Type.tp_base = &PyType_Type; | |
|
175 | // add our own python object types for classes | |
|
180 | 176 | if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) { |
|
181 | 177 | std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl; |
|
182 | 178 | } |
|
183 | 179 | Py_INCREF(&PythonQtClassWrapper_Type); |
|
180 | ||
|
181 | // add our own python object types for CPP instances | |
|
182 | if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) { | |
|
183 | PythonQt::handleError(); | |
|
184 | std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl; | |
|
185 | } | |
|
186 | Py_INCREF(&PythonQtInstanceWrapper_Type); | |
|
184 | 187 | |
|
185 | 188 | // add our own python object types for redirection of stdout |
|
186 | 189 | if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) { |
@@ -274,16 +277,8 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* p | |||
|
274 | 277 | while (m) { |
|
275 | 278 | PythonQtClassInfo* info = _knownQtClasses.value(m->className()); |
|
276 | 279 | if (!info) { |
|
277 |
info = |
|
|
280 | info = createPythonQtClassInfo(m, NULL, package); | |
|
278 | 281 | _knownQtClasses.insert(m->className(), info); |
|
279 | PythonQtObjectPtr pack = packageByName(package); | |
|
280 | PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info); | |
|
281 | PyModule_AddObject(pack, m->className(), pyobj); | |
|
282 | if (package && strncmp(package,"Qt",2)==0) { | |
|
283 | // put all qt objects into Qt as well | |
|
284 | PythonQtObjectPtr pack = packageByName("Qt"); | |
|
285 | PyModule_AddObject(pack, m->className(), pyobj); | |
|
286 | } | |
|
287 | 282 | } |
|
288 | 283 | if (first) { |
|
289 | 284 | first = false; |
@@ -295,6 +290,21 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* p | |||
|
295 | 290 | } |
|
296 | 291 | } |
|
297 | 292 | |
|
293 | PythonQtClassInfo* PythonQtPrivate::createPythonQtClassInfo(const QMetaObject* meta, const char* cppClassName, const char* package) | |
|
294 | { | |
|
295 | PythonQtClassInfo* info = new PythonQtClassInfo(meta, cppClassName); | |
|
296 | PythonQtObjectPtr pack = packageByName(package); | |
|
297 | PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, package); | |
|
298 | PyModule_AddObject(pack, meta?meta->className():cppClassName, pyobj); | |
|
299 | if (package && strncmp(package,"Qt",2)==0) { | |
|
300 | // put all qt objects into Qt as well | |
|
301 | PythonQtObjectPtr pack = packageByName("Qt"); | |
|
302 | PyModule_AddObject(pack, meta?meta->className():cppClassName, pyobj); | |
|
303 | } | |
|
304 | info->setPythonQtClassWrapper(pyobj); | |
|
305 | return info; | |
|
306 | } | |
|
307 | ||
|
298 | 308 | bool PythonQtPrivate::isEnumType(const QMetaObject* meta, const QByteArray& name) { |
|
299 | 309 | int i = meta?meta->indexOfEnumerator(name.constData()):-1; |
|
300 | 310 | if (i!=-1) { |
@@ -337,10 +347,10 PyObject* PythonQtPrivate::wrapQObject(QObject* obj) | |||
|
337 | 347 | classInfo = _knownQtClasses.value(obj->metaObject()->className()); |
|
338 | 348 | } |
|
339 | 349 | wrap = createNewPythonQtInstanceWrapper(obj, classInfo); |
|
340 |
// mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap-> |
|
|
350 | // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1()); | |
|
341 | 351 | } else { |
|
342 | 352 | Py_INCREF(wrap); |
|
343 |
// mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap-> |
|
|
353 | // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1()); | |
|
344 | 354 | } |
|
345 | 355 | return (PyObject*)wrap; |
|
346 | 356 | } |
@@ -371,7 +381,7 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name) | |||
|
371 | 381 | info = _knownQtClasses.value(qptr->metaObject()->className()); |
|
372 | 382 | } |
|
373 | 383 | wrap = createNewPythonQtInstanceWrapper(qptr, info); |
|
374 |
// mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap-> |
|
|
384 | // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1()); | |
|
375 | 385 | } else { |
|
376 | 386 | // maybe it is a PyObject, which we can return directly |
|
377 | 387 | if (name == "PyObject") { |
@@ -389,32 +399,37 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name) | |||
|
389 | 399 | } |
|
390 | 400 | PythonQtClassInfo* info = _knownQtWrapperClasses.value(name); |
|
391 | 401 | if (!info) { |
|
392 | info = new PythonQtClassInfo(wrapper?wrapper->metaObject():NULL, name); | |
|
393 |
_knownQtWrapperClasses. |
|
|
394 | PyModule_AddObject(_pythonQtModule, name, (PyObject*)createNewPythonQtClassWrapper(info)); | |
|
395 | } else { | |
|
396 |
|
|
|
397 | info->setMetaObject(wrapper->metaObject()); | |
|
398 | } | |
|
402 | registerCPPClass(name.constData()); | |
|
403 | info = _knownQtWrapperClasses.value(name); | |
|
404 | } | |
|
405 | if (wrapper && (info->metaObject() != wrapper->metaObject())) { | |
|
406 | info->setMetaObject(wrapper->metaObject()); | |
|
399 | 407 | } |
|
400 | 408 | wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr); |
|
401 |
// mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap-> |
|
|
409 | // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1()); | |
|
402 | 410 | } |
|
403 | 411 | } else { |
|
404 | 412 | Py_INCREF(wrap); |
|
405 |
//mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap-> |
|
|
413 | //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1()); | |
|
406 | 414 | } |
|
407 | 415 | return (PyObject*)wrap; |
|
408 | 416 | } |
|
409 | 417 | |
|
418 | PyObject* PythonQtPrivate::dummyTuple() { | |
|
419 | static PyObject* dummyTuple = NULL; | |
|
420 | if (dummyTuple==NULL) { | |
|
421 | dummyTuple = PyTuple_New(1); | |
|
422 | PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy")); | |
|
423 | } | |
|
424 | return dummyTuple; | |
|
425 | } | |
|
426 | ||
|
410 | 427 | |
|
411 | 428 | PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) { |
|
412 | PythonQtInstanceWrapper* result; | |
|
413 | result = (PythonQtInstanceWrapper *)PythonQtInstanceWrapper_Type.tp_new(&PythonQtInstanceWrapper_Type, | |
|
414 | NULL, NULL); | |
|
429 | // call the associated class type to create a new instance... | |
|
430 | PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL); | |
|
415 | 431 | |
|
416 | 432 | result->setQObject(obj); |
|
417 | result->_info = info; | |
|
418 | 433 | result->_wrappedPtr = wrappedPtr; |
|
419 | 434 | result->_ownedByPythonQt = false; |
|
420 | 435 | result->_useQMetaTypeDestroy = false; |
@@ -431,11 +446,36 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObje | |||
|
431 | 446 | return result; |
|
432 | 447 | } |
|
433 | 448 | |
|
434 | PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info) { | |
|
449 | PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) { | |
|
435 | 450 | PythonQtClassWrapper* result; |
|
436 | result = (PythonQtClassWrapper *)PythonQtClassWrapper_Type.tp_new(&PythonQtClassWrapper_Type, | |
|
437 | NULL, NULL); | |
|
438 | result->_info = info; | |
|
451 | ||
|
452 | PyObject* className = PyString_FromString(info->className()); | |
|
453 | ||
|
454 | PyObject* baseClasses = PyTuple_New(1); | |
|
455 | PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type); | |
|
456 | ||
|
457 | PyObject* typeDict = PyDict_New(); | |
|
458 | QByteArray moduleName("PythonQt"); | |
|
459 | if (package && strcmp(package, "")!=0) { | |
|
460 | moduleName += "."; | |
|
461 | moduleName += package; | |
|
462 | } | |
|
463 | PyDict_SetItemString(typeDict, "__module__", PyString_FromString(moduleName.constData())); | |
|
464 | ||
|
465 | PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict); | |
|
466 | ||
|
467 | // set the class info so that PythonQtClassWrapper_new can read it | |
|
468 | _currentClassInfoForClassWrapperCreation = info; | |
|
469 | // create the new type object by calling the type | |
|
470 | result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL); | |
|
471 | ||
|
472 | Py_DECREF(baseClasses); | |
|
473 | Py_DECREF(typeDict); | |
|
474 | Py_DECREF(args); | |
|
475 | Py_DECREF(className); | |
|
476 | ||
|
477 | //TODO XXX why is this incref needed? It looks like the types get garbage collected somehow?! | |
|
478 | Py_INCREF((PyObject*)result); | |
|
439 | 479 | return result; |
|
440 | 480 | } |
|
441 | 481 | |
@@ -666,7 +706,7 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, | |||
|
666 | 706 | } |
|
667 | 707 | } else if (object->ob_type == &PythonQtClassWrapper_Type) { |
|
668 | 708 | PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object(); |
|
669 |
PythonQtSlotInfo* info = o-> |
|
|
709 | PythonQtSlotInfo* info = o->classInfo()->constructors(); | |
|
670 | 710 | |
|
671 | 711 | while (info) { |
|
672 | 712 | results << info->fullSignature(false); |
@@ -817,16 +857,6 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory) | |||
|
817 | 857 | _p->_cppWrapperFactories.append(factory); |
|
818 | 858 | } |
|
819 | 859 | |
|
820 | void PythonQt::addConstructorHandler(PythonQtConstructorHandler* factory) | |
|
821 | { | |
|
822 | _p->_constructorHandlers.append(factory); | |
|
823 | } | |
|
824 | ||
|
825 | const QList<PythonQtConstructorHandler*>& PythonQt::constructorHandlers() | |
|
826 | { | |
|
827 | return _p->_constructorHandlers; | |
|
828 | }; | |
|
829 | ||
|
830 | 860 | //--------------------------------------------------------------------------------------------------- |
|
831 | 861 | PythonQtPrivate::PythonQtPrivate() |
|
832 | 862 | { |
@@ -834,6 +864,14 PythonQtPrivate::PythonQtPrivate() | |||
|
834 | 864 | _defaultImporter = new PythonQtQFileImporter; |
|
835 | 865 | _noLongerWrappedCB = NULL; |
|
836 | 866 | _wrappedCB = NULL; |
|
867 | _currentClassInfoForClassWrapperCreation = NULL; | |
|
868 | } | |
|
869 | ||
|
870 | PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation() | |
|
871 | { | |
|
872 | PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation; | |
|
873 | _currentClassInfoForClassWrapperCreation = NULL; | |
|
874 | return info; | |
|
837 | 875 | } |
|
838 | 876 | |
|
839 | 877 | void PythonQtPrivate::addDecorators(QObject* o, int decoTypes) |
@@ -1006,16 +1044,8 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentT | |||
|
1006 | 1044 | { |
|
1007 | 1045 | PythonQtClassInfo* info = _knownQtWrapperClasses.value(typeName); |
|
1008 | 1046 | if (!info) { |
|
1009 |
info = |
|
|
1047 | info = createPythonQtClassInfo(NULL, typeName, package); | |
|
1010 | 1048 | _knownQtWrapperClasses.insert(typeName, info); |
|
1011 | PythonQtObjectPtr pack = packageByName(package); | |
|
1012 | PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info); | |
|
1013 | PyModule_AddObject(pack, typeName, pyobj); | |
|
1014 | if (package && strncmp(package,"Qt",2)==0) { | |
|
1015 | // put all qt objects into Qt as well | |
|
1016 | PythonQtObjectPtr pack = packageByName("Qt"); | |
|
1017 | PyModule_AddObject(pack, typeName, pyobj); | |
|
1018 | } | |
|
1019 | 1049 | } |
|
1020 | 1050 | if (parentTypeName) { |
|
1021 | 1051 | info->setWrappedParentClassName(parentTypeName); |
@@ -1055,6 +1085,11 void PythonQtPrivate::removeWrapperPointer(void* obj) | |||
|
1055 | 1085 | _wrappedObjects.remove(obj); |
|
1056 | 1086 | } |
|
1057 | 1087 | |
|
1088 | void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper) | |
|
1089 | { | |
|
1090 | _wrappedObjects.insert(obj, wrapper); | |
|
1091 | } | |
|
1092 | ||
|
1058 | 1093 | PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj) |
|
1059 | 1094 | { |
|
1060 | 1095 | PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj); |
@@ -63,7 +63,6 class PythonQtMethodInfo; | |||
|
63 | 63 | class PythonQtSignalReceiver; |
|
64 | 64 | class PythonQtImportFileInterface; |
|
65 | 65 | class PythonQtCppWrapperFactory; |
|
66 | class PythonQtConstructorHandler; | |
|
67 | 66 | class PythonQtQFileImporter; |
|
68 | 67 | |
|
69 | 68 | typedef void PythonQtQObjectWrappedCB(QObject* object); |
@@ -269,12 +268,6 public: | |||
|
269 | 268 | //! add the given factory to PythonQt (ownership stays with caller) |
|
270 | 269 | void addWrapperFactory(PythonQtCppWrapperFactory* factory); |
|
271 | 270 | |
|
272 | //! add the given constructor handler to PythonQt (ownership stays with caller) | |
|
273 | void addConstructorHandler(PythonQtConstructorHandler* handler); | |
|
274 | ||
|
275 | //! get list of constructor handlers | |
|
276 | const QList<PythonQtConstructorHandler*>& constructorHandlers(); | |
|
277 | ||
|
278 | 271 | //@} |
|
279 | 272 | |
|
280 | 273 | //@{ Custom importer (to replace internal import implementation of python) |
@@ -383,6 +376,8 public: | |||
|
383 | 376 | //! returns if the id is the id for PythonQtObjectPtr |
|
384 | 377 | bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; } |
|
385 | 378 | |
|
379 | //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists) | |
|
380 | void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper); | |
|
386 | 381 | //! remove the wrapper ptr again |
|
387 | 382 | void removeWrapperPointer(void* obj); |
|
388 | 383 | |
@@ -425,7 +420,7 public: | |||
|
425 | 420 | bool isEnumType(const QMetaObject* meta, const QByteArray& name); |
|
426 | 421 | |
|
427 | 422 | //! helper method that creates a PythonQtClassWrapper object |
|
428 | PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info); | |
|
423 | PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package = NULL); | |
|
429 | 424 | |
|
430 | 425 | //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map |
|
431 | 426 | PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL); |
@@ -445,7 +440,17 public: | |||
|
445 | 440 | //! creates the new module from the given pycode |
|
446 | 441 | PythonQtObjectPtr createModule(const QString& name, PyObject* pycode); |
|
447 | 442 | |
|
443 | //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again | |
|
444 | PythonQtClassInfo* currentClassInfoForClassWrapperCreation(); | |
|
445 | ||
|
446 | //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation | |
|
447 | static PyObject* dummyTuple(); | |
|
448 | ||
|
448 | 449 | private: |
|
450 | ||
|
451 | //! create a new class info and python wrapper type | |
|
452 | PythonQtClassInfo* createPythonQtClassInfo(const QMetaObject* meta, const char* cppClassName, const char* package); | |
|
453 | ||
|
449 | 454 | //! get/create new package module |
|
450 | 455 | PythonQtObjectPtr packageByName(const char* name); |
|
451 | 456 | |
@@ -487,14 +492,13 private: | |||
|
487 | 492 | //! the cpp object wrapper factories |
|
488 | 493 | QList<PythonQtCppWrapperFactory*> _cppWrapperFactories; |
|
489 | 494 | |
|
490 | //! the cpp object wrapper factories | |
|
491 | QList<PythonQtConstructorHandler*> _constructorHandlers; | |
|
492 | ||
|
493 | 495 | QHash<QByteArray , PythonQtSlotInfo *> _constructorSlots; |
|
494 | 496 | QHash<QByteArray , PythonQtSlotInfo *> _destructorSlots; |
|
495 | 497 | |
|
496 | 498 | QHash<QByteArray, PythonQtObjectPtr> _packages; |
|
497 | 499 | |
|
500 | PythonQtClassInfo* _currentClassInfoForClassWrapperCreation; | |
|
501 | ||
|
498 | 502 | int _initFlags; |
|
499 | 503 | int _PythonQtObjectPtr_metaId; |
|
500 | 504 |
@@ -54,6 +54,7 PythonQtClassInfo::PythonQtClassInfo(const QMetaObject* meta, const QByteArray& | |||
|
54 | 54 | _parentClassInfoResolved = false; |
|
55 | 55 | _decoratorProvider = NULL; |
|
56 | 56 | _decoratorProviderCB = NULL; |
|
57 | _pythonQtClassWrapper = NULL; | |
|
57 | 58 | if (wrappedClassName.isEmpty()) { |
|
58 | 59 | _metaTypeId = -1; |
|
59 | 60 | } else { |
@@ -125,6 +125,12 public: | |||
|
125 | 125 | //! check if the special method "hasOwner" is implemented and if it returns false, which means that the object may be destroyed |
|
126 | 126 | bool hasOwnerMethodButNoOwner(void* object); |
|
127 | 127 | |
|
128 | //! set the associated PythonQtClassWrapper (which handles instance creation of this type) | |
|
129 | void setPythonQtClassWrapper(PyObject* obj) { _pythonQtClassWrapper = obj; } | |
|
130 | ||
|
131 | //! get the associated PythonQtClassWrapper (which handles instance creation of this type) | |
|
132 | PyObject* pythonQtClassWrapper() { return _pythonQtClassWrapper; } | |
|
133 | ||
|
128 | 134 | private: |
|
129 | 135 | //! resolve the parent class from either meta object or cpp parent class name |
|
130 | 136 | void resolveParentClassInfo(); |
@@ -150,6 +156,8 private: | |||
|
150 | 156 | PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB; |
|
151 | 157 | PythonQtClassInfo* _parentClassInfo; |
|
152 | 158 | |
|
159 | PyObject* _pythonQtClassWrapper; | |
|
160 | ||
|
153 | 161 | bool _parentClassInfoResolved; |
|
154 | 162 | int _metaTypeId; |
|
155 | 163 |
@@ -47,72 +47,50 | |||
|
47 | 47 | #include "PythonQtClassInfo.h" |
|
48 | 48 | #include "PythonQtConversion.h" |
|
49 | 49 | |
|
50 |
static |
|
|
50 | static PyObject* PythonQtClassWrapper_alloc(PyTypeObject *self, Py_ssize_t nitems) | |
|
51 | 51 | { |
|
52 | self->ob_type->tp_free((PyObject*)self); | |
|
53 | } | |
|
52 | // call the default type alloc | |
|
53 | PyObject* obj = PyType_Type.tp_alloc(self, nitems); | |
|
54 | 54 | |
|
55 | static PyObject* PythonQtClassWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/) | |
|
56 | { | |
|
57 | PythonQtClassWrapper *self; | |
|
55 | // take current class type, if we are called via newPythonQtClassWrapper() | |
|
56 | PythonQtClassWrapper* wrap = (PythonQtClassWrapper*)obj; | |
|
57 | wrap->_classInfo = PythonQt::priv()->currentClassInfoForClassWrapperCreation(); | |
|
58 | 58 | |
|
59 | self = (PythonQtClassWrapper *)type->tp_alloc(type, 0); | |
|
60 | if (self != NULL) { | |
|
61 | self->_info = NULL; | |
|
62 | } | |
|
63 | return (PyObject *)self; | |
|
59 | return obj; | |
|
64 | 60 | } |
|
65 | 61 | |
|
66 | static int PythonQtClassWrapper_init(PythonQtClassWrapper * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/) | |
|
67 | { | |
|
68 | return 0; | |
|
69 | } | |
|
70 | 62 | |
|
71 |
|
|
|
72 | PythonQtClassWrapper* wrapper = (PythonQtClassWrapper*)func; | |
|
73 | PyObject* result = NULL; | |
|
74 | QString error; | |
|
75 | PyObject* err = NULL; | |
|
76 | if (wrapper->_info->constructors()) { | |
|
77 | result = PythonQtSlotFunction_CallImpl(NULL, wrapper->_info->constructors(), args, kw); | |
|
78 | err = PyErr_Occurred(); | |
|
79 | } | |
|
80 | if (!result) { | |
|
81 | QObject* v = NULL; | |
|
82 | QListIterator<PythonQtConstructorHandler*> it(PythonQt::self()->constructorHandlers()); | |
|
83 | while (!v && it.hasNext()) { | |
|
84 | v = it.next()->create(wrapper->_info->metaObject(), args, kw, error); | |
|
85 | } | |
|
86 | if (v) { | |
|
87 | result = PythonQt::priv()->wrapQObject(v); | |
|
88 | } | |
|
63 | static int PythonQtClassWrapper_init(PythonQtClassWrapper* self, PyObject* args, PyObject* kwds) | |
|
64 | { | |
|
65 | // call the default type init | |
|
66 | if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0) { | |
|
67 | return -1; | |
|
89 | 68 | } |
|
90 | if (result) { | |
|
91 | // change ownershipflag to be owned by PythonQt | |
|
92 | if (result->ob_type == &PythonQtInstanceWrapper_Type) { | |
|
93 | ((PythonQtInstanceWrapper*)result)->_ownedByPythonQt = true; | |
|
94 | } | |
|
95 | } else { | |
|
96 | if (!wrapper->_info->constructors()) { | |
|
97 | if (!err) { | |
|
98 | if (error.isEmpty()) { | |
|
99 | error = QString("No constructors available for ") + wrapper->_info->className(); | |
|
100 | } | |
|
101 | PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); | |
|
102 | } | |
|
69 | ||
|
70 | // if we have no CPP class information, try our base class | |
|
71 | if (!self->classInfo()) { | |
|
72 | PyTypeObject* superType = ((PyTypeObject *)self)->tp_base; | |
|
73 | ||
|
74 | if (!superType || (superType->ob_type != &PythonQtClassWrapper_Type)) { | |
|
75 | PyErr_Format(PyExc_TypeError, "type %s is not derived from PythonQtClassWrapper", ((PyTypeObject*)self)->tp_name); | |
|
76 | return -1; | |
|
103 | 77 | } |
|
78 | ||
|
79 | // take the class info from the superType | |
|
80 | self->_classInfo = ((PythonQtClassWrapper*)superType)->classInfo(); | |
|
104 | 81 | } |
|
105 | return result; | |
|
82 | ||
|
83 | return 0; | |
|
106 | 84 | } |
|
107 | 85 | |
|
108 | 86 | static PyObject *PythonQtClassWrapper_classname(PythonQtClassWrapper* type) |
|
109 | 87 | { |
|
110 |
return PyString_FromString((QString(" |
|
|
88 | return PyString_FromString((QString("Class_") + type->classInfo()->className()).toLatin1().data()); | |
|
111 | 89 | } |
|
112 | 90 | |
|
113 | 91 | static PyObject *PythonQtClassWrapper_help(PythonQtClassWrapper* type) |
|
114 | 92 | { |
|
115 |
return PythonQt::self()->helpCalled(type-> |
|
|
93 | return PythonQt::self()->helpCalled(type->classInfo()); | |
|
116 | 94 | } |
|
117 | 95 | |
|
118 | 96 | |
@@ -127,7 +105,7 static PyMethodDef PythonQtClassWrapper_methods[] = { | |||
|
127 | 105 | }; |
|
128 | 106 | |
|
129 | 107 | |
|
130 | static PyObject *PythonQtClassWrapper_getattro(PyObject *obj,PyObject *name) | |
|
108 | static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) | |
|
131 | 109 | { |
|
132 | 110 | const char *attributeName; |
|
133 | 111 | PythonQtClassWrapper *wrapper = (PythonQtClassWrapper *)obj; |
@@ -136,7 +114,7 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj,PyObject *name) | |||
|
136 | 114 | return NULL; |
|
137 | 115 | } |
|
138 | 116 | |
|
139 |
PythonQtMemberInfo member = wrapper-> |
|
|
117 | PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName); | |
|
140 | 118 | if (member._type == PythonQtMemberInfo::EnumValue) { |
|
141 | 119 | return PyInt_FromLong(member._enumValue); |
|
142 | 120 | } |
@@ -152,7 +130,7 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj,PyObject *name) | |||
|
152 | 130 | PyErr_Clear(); |
|
153 | 131 | |
|
154 | 132 | if (qstrcmp(attributeName, "__dict__")==0) { |
|
155 |
QStringList l = wrapper-> |
|
|
133 | QStringList l = wrapper->classInfo()->memberList(true); | |
|
156 | 134 | PyObject* dict = PyDict_New(); |
|
157 | 135 | foreach (QString name, l) { |
|
158 | 136 | //PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data()); |
@@ -162,53 +140,47 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj,PyObject *name) | |||
|
162 | 140 | return dict; |
|
163 | 141 | } |
|
164 | 142 | |
|
165 |
QString error = QString(wrapper-> |
|
|
143 | QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'"; | |
|
166 | 144 | PyErr_SetString(PyExc_AttributeError, error.toLatin1().data()); |
|
167 | 145 | return NULL; |
|
168 | 146 | } |
|
169 | 147 | |
|
148 | static int PythonQtClassWrapper_setattro(PyObject *obj,PyObject *name,PyObject * /*value*/) | |
|
149 | { | |
|
150 | QString error; | |
|
151 | char *attributeName; | |
|
152 | if ((attributeName = PyString_AsString(name)) == NULL) { | |
|
153 | return -1; | |
|
154 | } | |
|
155 | PythonQtClassWrapper *wrapper = (PythonQtClassWrapper *)obj; | |
|
156 | ||
|
157 | // TODO | |
|
158 | return -1; | |
|
159 | } | |
|
160 | ||
|
161 | /* | |
|
170 | 162 | static PyObject * PythonQtClassWrapper_repr(PyObject * obj) |
|
171 | 163 |
|
|
172 | 164 | PythonQtClassWrapper* wrapper = (PythonQtClassWrapper*)obj; |
|
173 |
if (wrapper-> |
|
|
174 |
const QMetaObject* meta = wrapper-> |
|
|
165 | if (wrapper->classInfo()->isCPPWrapper()) { | |
|
166 | const QMetaObject* meta = wrapper->classInfo()->metaObject(); | |
|
175 | 167 | if (!meta) { |
|
176 |
QObject* decorator = wrapper-> |
|
|
168 | QObject* decorator = wrapper->classInfo()->decorator(); | |
|
177 | 169 | if (decorator) { |
|
178 | 170 | meta = decorator->metaObject(); |
|
179 | 171 | } |
|
180 | 172 | } |
|
181 | 173 | if (meta) { |
|
182 |
return PyString_FromFormat("%s Class (C++ wrapped by %s)", wrapper-> |
|
|
183 | } else { | |
|
184 | return PyString_FromFormat("%s Class (C++ unwrapped)", wrapper->_info->className()); | |
|
185 | } | |
|
186 | } else { | |
|
187 | return PyString_FromFormat("%s Class", wrapper->_info->className()); | |
|
188 | } | |
|
189 | } | |
|
190 | ||
|
191 | static int PythonQtClassWrapper_compare(PyObject * obj1, PyObject * obj2) | |
|
192 | { | |
|
193 | if (obj1->ob_type == &PythonQtClassWrapper_Type && | |
|
194 | obj2->ob_type == &PythonQtClassWrapper_Type) { | |
|
195 | ||
|
196 | PythonQtClassWrapper* w1 = (PythonQtClassWrapper*)obj1; | |
|
197 | PythonQtClassWrapper* w2 = (PythonQtClassWrapper*)obj2; | |
|
198 | if (w1->_info == w2->_info) { | |
|
199 | return 0; | |
|
174 | return PyString_FromFormat("%s Class (C++ wrapped by %s)", wrapper->classInfo()->className(), meta->className()); | |
|
200 | 175 | } else { |
|
201 | return -1; | |
|
176 | return PyString_FromFormat("%s Class (C++ unwrapped)", wrapper->classInfo()->className()); | |
|
202 | 177 | } |
|
203 | 178 | } else { |
|
204 | return -1; | |
|
179 | return PyString_FromFormat("%s Class", wrapper->classInfo()->className()); | |
|
205 | 180 | } |
|
206 | 181 |
|
|
207 | 182 |
|
|
208 | static long PythonQtClassWrapper_hash(PythonQtClassWrapper *obj) | |
|
209 | { | |
|
210 | return reinterpret_cast<long>(obj->_info); | |
|
211 | } | |
|
183 | */ | |
|
212 | 184 | |
|
213 | 185 | PyTypeObject PythonQtClassWrapper_Type = { |
|
214 | 186 | PyObject_HEAD_INIT(NULL) |
@@ -216,23 +188,23 PyTypeObject PythonQtClassWrapper_Type = { | |||
|
216 | 188 | "PythonQt.PythonQtClassWrapper", /*tp_name*/ |
|
217 | 189 | sizeof(PythonQtClassWrapper), /*tp_basicsize*/ |
|
218 | 190 | 0, /*tp_itemsize*/ |
|
219 | (destructor)PythonQtClassWrapper_dealloc, /*tp_dealloc*/ | |
|
191 | 0, /*tp_dealloc*/ | |
|
220 | 192 | 0, /*tp_print*/ |
|
221 | 193 | 0, /*tp_getattr*/ |
|
222 | 194 | 0, /*tp_setattr*/ |
|
223 | PythonQtClassWrapper_compare, /*tp_compare*/ | |
|
224 |
|
|
|
195 | 0, /*tp_compare*/ | |
|
196 | 0, //PythonQtClassWrapper_repr, /*tp_repr*/ | |
|
225 | 197 | 0, /*tp_as_number*/ |
|
226 | 198 | 0, /*tp_as_sequence*/ |
|
227 | 199 | 0, /*tp_as_mapping*/ |
|
228 |
|
|
|
229 |
|
|
|
200 | 0, /*tp_hash */ | |
|
201 | 0, /*tp_call*/ | |
|
230 | 202 | 0, /*tp_str*/ |
|
231 | 203 | PythonQtClassWrapper_getattro, /*tp_getattro*/ |
|
232 |
|
|
|
204 | PythonQtClassWrapper_setattro, /*tp_setattro*/ | |
|
233 | 205 | 0, /*tp_as_buffer*/ |
|
234 | 206 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
|
235 |
|
|
|
207 | 0, /* tp_doc */ | |
|
236 | 208 | 0, /* tp_traverse */ |
|
237 | 209 | 0, /* tp_clear */ |
|
238 | 210 | 0, /* tp_richcompare */ |
@@ -248,8 +220,9 PyTypeObject PythonQtClassWrapper_Type = { | |||
|
248 | 220 | 0, /* tp_descr_set */ |
|
249 | 221 | 0, /* tp_dictoffset */ |
|
250 | 222 | (initproc)PythonQtClassWrapper_init, /* tp_init */ |
|
251 |
|
|
|
252 |
|
|
|
223 | PythonQtClassWrapper_alloc, /* tp_alloc */ | |
|
224 | 0, /* tp_new */ | |
|
225 | 0, /* tp_free */ | |
|
253 | 226 | }; |
|
254 | 227 | |
|
255 | 228 | //------------------------------------------------------- |
@@ -51,29 +51,25 | |||
|
51 | 51 | #include <QString> |
|
52 | 52 | |
|
53 | 53 | class PythonQtClassInfo; |
|
54 | class QObject; | |
|
55 | struct QMetaObject; | |
|
56 | 54 | |
|
55 | //! the type of the PythonQt class wrapper objects | |
|
57 | 56 | extern PyTypeObject PythonQtClassWrapper_Type; |
|
58 | 57 | |
|
59 | 58 | //--------------------------------------------------------------- |
|
60 |
//! a Python wrapper object for |
|
|
59 | //! a Python wrapper object for PythonQt wrapped classes | |
|
60 | //! which inherits from the Python type object to allow | |
|
61 | //! deriving of wrapped CPP classes from Python. | |
|
61 | 62 | typedef struct { |
|
62 | PyObject_HEAD | |
|
63 | PyHeapTypeObject _base; | |
|
63 | 64 | |
|
64 | //! the class information (which contains the meta object as well) | |
|
65 |
PythonQtClassInfo* _ |
|
|
65 | //! the additional class information that PythonQt stores for the CPP class | |
|
66 | PythonQtClassInfo* _classInfo; | |
|
67 | ||
|
68 | //! get the class info | |
|
69 | PythonQtClassInfo* classInfo() { return _classInfo; } | |
|
66 | 70 | |
|
67 | 71 | } PythonQtClassWrapper; |
|
68 | 72 | |
|
69 | 73 | //--------------------------------------------------------------- |
|
70 | // an abstact class for handling construction of objects | |
|
71 | class PythonQtConstructorHandler { | |
|
72 | public: | |
|
73 | //! get rid of warnings | |
|
74 | virtual ~PythonQtConstructorHandler() {} | |
|
75 | ||
|
76 | virtual QObject* create(const QMetaObject* meta, PyObject *args, PyObject *kw, QString& error) = 0; | |
|
77 | }; | |
|
78 | 74 | |
|
79 | #endif No newline at end of file | |
|
75 | #endif |
@@ -224,15 +224,15 return Py_None; | |||
|
224 | 224 | { |
|
225 | 225 | bool ok; |
|
226 | 226 | void* ptr = NULL; |
|
227 |
if (obj |
|
|
227 | if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) { | |
|
228 | 228 | // if we have a Qt wrapper object and if we do not need a QVariant, we do the following: |
|
229 | 229 | // (the Variant case is handled below in a switch) |
|
230 | 230 | |
|
231 | 231 | // a C++ wrapper (can be passed as pointer or reference) |
|
232 | 232 | PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)obj; |
|
233 |
if (wrap-> |
|
|
233 | if (wrap->classInfo()->inherits(info.name)) { | |
|
234 | 234 | void* object; |
|
235 |
if (wrap-> |
|
|
235 | if (wrap->classInfo()->isCPPWrapper()) { | |
|
236 | 236 | object = wrap->_wrappedPtr; |
|
237 | 237 | } else { |
|
238 | 238 | QObject* tmp = wrap->_obj; |
@@ -690,13 +690,13 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) | |||
|
690 | 690 | type = QVariant::Double; |
|
691 | 691 | } else if (val == Py_False || val == Py_True) { |
|
692 | 692 | type = QVariant::Bool; |
|
693 |
} else if (val |
|
|
693 | } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) { | |
|
694 | 694 | PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val; |
|
695 | 695 | // c++ wrapper, check if the class names of the c++ objects match |
|
696 |
if (wrap-> |
|
|
697 |
if (wrap-> |
|
|
696 | if (wrap->classInfo()->isCPPWrapper()) { | |
|
697 | if (wrap->classInfo()->metaTypeId()>0) { | |
|
698 | 698 | // construct a new variant from the C++ object if it has a meta type |
|
699 |
v = QVariant(wrap-> |
|
|
699 | v = QVariant(wrap->classInfo()->metaTypeId(), wrap->_wrappedPtr); | |
|
700 | 700 | } else { |
|
701 | 701 | // is this worth anything? we loose the knowledge of the cpp object type |
|
702 | 702 | v = qVariantFromValue(wrap->_wrappedPtr); |
@@ -849,9 +849,9 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) | |||
|
849 | 849 | break; |
|
850 | 850 | |
|
851 | 851 | default: |
|
852 |
if (val |
|
|
852 | if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) { | |
|
853 | 853 | PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val; |
|
854 |
if (wrap-> |
|
|
854 | if (wrap->classInfo()->isCPPWrapper() && wrap->classInfo()->metaTypeId() == type) { | |
|
855 | 855 | // construct a new variant from the C++ object if it has the same meta type |
|
856 | 856 | v = QVariant(type, wrap->_wrappedPtr); |
|
857 | 857 | } else { |
@@ -956,11 +956,11 bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList<vo | |||
|
956 | 956 | PyObject* value; |
|
957 | 957 | for (int i = 0;i<count;i++) { |
|
958 | 958 | value = PySequence_GetItem(obj,i); |
|
959 |
if (value |
|
|
959 | if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) { | |
|
960 | 960 | PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)value; |
|
961 | 961 | // both QObjects and CPP wrappers support inherits, so we use that to check of we match |
|
962 |
if (wrap-> |
|
|
963 |
if (wrap-> |
|
|
962 | if (wrap->classInfo()->inherits(type)) { | |
|
963 | if (wrap->classInfo()->isCPPWrapper()) { | |
|
964 | 964 | list->append(wrap->_wrappedPtr); |
|
965 | 965 | } else { |
|
966 | 966 | QObject* myObject = wrap->_obj; |
@@ -45,24 +45,31 | |||
|
45 | 45 | #include "PythonQtSlot.h" |
|
46 | 46 | #include "PythonQtClassInfo.h" |
|
47 | 47 | #include "PythonQtConversion.h" |
|
48 | #include "PythonQtClassWrapper.h" | |
|
49 | ||
|
50 | PythonQtClassInfo* PythonQtInstanceWrapper::classInfo() | |
|
51 | { | |
|
52 | // take the class info from our type object | |
|
53 | return ((PythonQtClassWrapper*)ob_type)->_classInfo; | |
|
54 | } | |
|
48 | 55 | |
|
49 | 56 | static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) { |
|
50 | 57 | |
|
51 | 58 | // is this a C++ wrapper? |
|
52 | 59 | if (self->_wrappedPtr) { |
|
53 |
//mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self-> |
|
|
60 | //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1()); | |
|
54 | 61 | |
|
55 | 62 | PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr); |
|
56 | 63 | // we own our qobject, so we delete it now: |
|
57 | 64 | delete self->_obj; |
|
58 | 65 | self->_obj = NULL; |
|
59 |
if (force || self-> |
|
|
60 |
int type = self-> |
|
|
66 | if (force || self->classInfo()->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) { | |
|
67 | int type = self->classInfo()->metaTypeId(); | |
|
61 | 68 | if (self->_useQMetaTypeDestroy && type>=0) { |
|
62 | 69 | // use QMetaType to destroy the object |
|
63 | 70 | QMetaType::destroy(type, self->_wrappedPtr); |
|
64 | 71 | } else { |
|
65 |
PythonQtSlotInfo* slot = PythonQt::priv()->getDestructorSlot(self-> |
|
|
72 | PythonQtSlotInfo* slot = PythonQt::priv()->getDestructorSlot(self->classInfo()->className()); | |
|
66 | 73 | if (slot) { |
|
67 | 74 | void* args[2]; |
|
68 | 75 | args[0] = NULL; |
@@ -80,7 +87,7 static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, | |||
|
80 | 87 | } |
|
81 | 88 | } |
|
82 | 89 | } else { |
|
83 |
//mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self-> |
|
|
90 | //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1()); | |
|
84 | 91 | if (self->_objPointerCopy) { |
|
85 | 92 | PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy); |
|
86 | 93 | } |
@@ -107,13 +114,18 static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self) | |||
|
107 | 114 | self->ob_type->tp_free((PyObject*)self); |
|
108 | 115 | } |
|
109 | 116 | |
|
110 |
static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * |
|
|
117 | static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * args, PyObject * /*kwds*/) | |
|
111 | 118 | { |
|
119 | PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type; | |
|
112 | 120 | PythonQtInstanceWrapper *self; |
|
121 | static PyObject* emptyTuple = NULL; | |
|
122 | if (emptyTuple==NULL) { | |
|
123 | emptyTuple = PyTuple_New(0); | |
|
124 | } | |
|
125 | ||
|
126 | self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL); | |
|
113 | 127 | |
|
114 | self = (PythonQtInstanceWrapper *)type->tp_alloc(type, 0); | |
|
115 | 128 | if (self != NULL) { |
|
116 | self->_info = NULL; | |
|
117 | 129 | new (&self->_obj) QPointer<QObject>(); |
|
118 | 130 | self->_wrappedPtr = NULL; |
|
119 | 131 | self->_ownedByPythonQt = false; |
@@ -122,19 +134,51 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*ar | |||
|
122 | 134 | return (PyObject *)self; |
|
123 | 135 | } |
|
124 | 136 | |
|
125 |
static int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * |
|
|
137 | static int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds) | |
|
126 | 138 | { |
|
139 | PyObject* result = NULL; | |
|
140 | ||
|
141 | if (args == PythonQtPrivate::dummyTuple()) { | |
|
142 | // we are called from the internal PythonQt API, so our data will be filled later on... | |
|
143 | return 0; | |
|
144 | } | |
|
145 | ||
|
146 | // we are called from python, try to construct our object | |
|
147 | if (self->classInfo()->constructors()) { | |
|
148 | void* directCPPPointer = NULL; | |
|
149 | PythonQtSlotFunction_CallImpl(NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer); | |
|
150 | if (PyErr_Occurred()) { | |
|
151 | return -1; | |
|
152 | } | |
|
153 | if (directCPPPointer) { | |
|
154 | // change ownershipflag to be owned by PythonQt | |
|
155 | self->_ownedByPythonQt = true; | |
|
156 | self->_useQMetaTypeDestroy = false; | |
|
157 | if (self->classInfo()->isCPPWrapper()) { | |
|
158 | self->_wrappedPtr = directCPPPointer; | |
|
159 | // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?! | |
|
160 | } else { | |
|
161 | self->setQObject((QObject*)directCPPPointer); | |
|
162 | } | |
|
163 | // register with PythonQt | |
|
164 | PythonQt::priv()->addWrapperPointer(directCPPPointer, self); | |
|
165 | } | |
|
166 | } else { | |
|
167 | QString error = QString("No constructors available for ") + self->classInfo()->className(); | |
|
168 | PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); | |
|
169 | return -1; | |
|
170 | } | |
|
127 | 171 | return 0; |
|
128 | 172 | } |
|
129 | 173 | |
|
130 | 174 | static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* type) |
|
131 | 175 | { |
|
132 |
return PyString_FromString(type-> |
|
|
176 | return PyString_FromString(type->classInfo()->className()); | |
|
133 | 177 | } |
|
134 | 178 | |
|
135 | 179 | static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* type) |
|
136 | 180 | { |
|
137 |
return PythonQt::self()->helpCalled(type-> |
|
|
181 | return PythonQt::self()->helpCalled(type->classInfo()); | |
|
138 | 182 | } |
|
139 | 183 | |
|
140 | 184 | static PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self) |
@@ -169,7 +213,7 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) | |||
|
169 | 213 | } |
|
170 | 214 | |
|
171 | 215 | if (!wrapper->_obj && !wrapper->_wrappedPtr) { |
|
172 |
QString error = QString("Trying to read attribute '") + attributeName + "' from a destroyed " + wrapper-> |
|
|
216 | QString error = QString("Trying to read attribute '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object"; | |
|
173 | 217 | PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); |
|
174 | 218 | return NULL; |
|
175 | 219 | } |
@@ -178,7 +222,7 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) | |||
|
178 | 222 | |
|
179 | 223 | // TODO: dynamic properties are missing |
|
180 | 224 | |
|
181 |
PythonQtMemberInfo member = wrapper-> |
|
|
225 | PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName); | |
|
182 | 226 | switch (member._type) { |
|
183 | 227 | case PythonQtMemberInfo::Property: |
|
184 | 228 | if (wrapper->_obj) { |
@@ -215,7 +259,7 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) | |||
|
215 | 259 | } |
|
216 | 260 | |
|
217 | 261 | if (qstrcmp(attributeName, "__dict__")==0) { |
|
218 |
QStringList l = wrapper-> |
|
|
262 | QStringList l = wrapper->classInfo()->memberList(false); | |
|
219 | 263 | PyObject* dict = PyDict_New(); |
|
220 | 264 | foreach (QString name, l) { |
|
221 | 265 | //PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data()); |
@@ -227,7 +271,7 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) | |||
|
227 | 271 | } |
|
228 | 272 | |
|
229 | 273 | |
|
230 |
QString error = QString(wrapper-> |
|
|
274 | QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'"; | |
|
231 | 275 | PyErr_SetString(PyExc_AttributeError, error.toLatin1().data()); |
|
232 | 276 | return NULL; |
|
233 | 277 | } |
@@ -242,12 +286,12 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec | |||
|
242 | 286 | return -1; |
|
243 | 287 | |
|
244 | 288 | if (!wrapper->_obj) { |
|
245 |
error = QString("Trying to set attribute '") + attributeName + "' on a destroyed " + wrapper-> |
|
|
289 | error = QString("Trying to set attribute '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object"; | |
|
246 | 290 | PyErr_SetString(PyExc_AttributeError, error.toLatin1().data()); |
|
247 | 291 | return -1; |
|
248 | 292 | } |
|
249 | 293 | |
|
250 |
PythonQtMemberInfo member = wrapper-> |
|
|
294 | PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName); | |
|
251 | 295 | if (member._type == PythonQtMemberInfo::Property) { |
|
252 | 296 | QMetaProperty prop = member._property; |
|
253 | 297 | if (prop.isWritable()) { |
@@ -271,13 +315,13 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec | |||
|
271 | 315 | + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")"; |
|
272 | 316 | } |
|
273 | 317 | } else { |
|
274 |
error = QString("Property '") + attributeName + "' of " + wrapper-> |
|
|
318 | error = QString("Property '") + attributeName + "' of " + wrapper->classInfo()->className() + " object is not writable"; | |
|
275 | 319 | } |
|
276 | 320 | } else { |
|
277 | 321 | if (member._type == PythonQtMemberInfo::Slot) { |
|
278 |
error = QString("Slot '") + attributeName + "' can not be overwritten on " + wrapper-> |
|
|
322 | error = QString("Slot '") + attributeName + "' can not be overwritten on " + wrapper->classInfo()->className() + " object"; | |
|
279 | 323 | } else if (member._type == PythonQtMemberInfo::EnumValue) { |
|
280 |
error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + wrapper-> |
|
|
324 | error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + wrapper->classInfo()->className() + " object"; | |
|
281 | 325 | } |
|
282 | 326 | } |
|
283 | 327 | |
@@ -290,17 +334,17 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj) | |||
|
290 | 334 | PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj; |
|
291 | 335 | QObject *qobj = wrapper->_obj; |
|
292 | 336 | if (wrapper->_wrappedPtr) { |
|
293 |
QString str = PythonQtConv::CPPObjectToString(wrapper-> |
|
|
337 | QString str = PythonQtConv::CPPObjectToString(wrapper->classInfo()->metaTypeId(), wrapper->_wrappedPtr); | |
|
294 | 338 | if (!str.isEmpty()) { |
|
295 | 339 | return PyString_FromFormat("%s", str.toLatin1().constData()); |
|
296 | 340 | } else |
|
297 | 341 | if (wrapper->_obj) { |
|
298 |
return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wrapper-> |
|
|
342 | return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wrapper->classInfo()->className(), wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj); | |
|
299 | 343 | } else { |
|
300 |
return PyString_FromFormat("%s (C++ Object %p)", wrapper-> |
|
|
344 | return PyString_FromFormat("%s (C++ Object %p)", wrapper->classInfo()->className(), wrapper->_wrappedPtr); | |
|
301 | 345 | } |
|
302 | 346 | } else { |
|
303 |
return PyString_FromFormat("%s (QObject %p)", wrapper-> |
|
|
347 | return PyString_FromFormat("%s (QObject %p)", wrapper->classInfo()->className(), qobj); | |
|
304 | 348 | } |
|
305 | 349 | } |
|
306 | 350 | |
@@ -309,24 +353,24 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj) | |||
|
309 | 353 | PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj; |
|
310 | 354 | QObject *qobj = wrapper->_obj; |
|
311 | 355 | if (wrapper->_wrappedPtr) { |
|
312 |
QString str = PythonQtConv::CPPObjectToString(wrapper-> |
|
|
356 | QString str = PythonQtConv::CPPObjectToString(wrapper->classInfo()->metaTypeId(), wrapper->_wrappedPtr); | |
|
313 | 357 | if (!str.isEmpty()) { |
|
314 |
return PyString_FromFormat("%s(%s, %p)", QMetaType::typeName(wrapper-> |
|
|
358 | return PyString_FromFormat("%s(%s, %p)", QMetaType::typeName(wrapper->classInfo()->metaTypeId()), str.toLatin1().constData(), wrapper->_wrappedPtr); | |
|
315 | 359 | } else |
|
316 | 360 | if (wrapper->_obj) { |
|
317 |
return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wrapper-> |
|
|
361 | return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wrapper->classInfo()->className(), wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj); | |
|
318 | 362 | } else { |
|
319 |
return PyString_FromFormat("%s (C++ Object %p)", wrapper-> |
|
|
363 | return PyString_FromFormat("%s (C++ Object %p)", wrapper->classInfo()->className(), wrapper->_wrappedPtr); | |
|
320 | 364 | } |
|
321 | 365 | } else { |
|
322 |
return PyString_FromFormat("%s (QObject %p)", wrapper-> |
|
|
366 | return PyString_FromFormat("%s (QObject %p)", wrapper->classInfo()->className(), qobj); | |
|
323 | 367 | } |
|
324 | 368 | } |
|
325 | 369 | |
|
326 | 370 | static int PythonQtInstanceWrapper_compare(PyObject * obj1, PyObject * obj2) |
|
327 | 371 | { |
|
328 |
if (obj1 |
|
|
329 |
obj2 |
|
|
372 | if (PyObject_TypeCheck(obj1, &PythonQtInstanceWrapper_Type) && | |
|
373 | PyObject_TypeCheck(obj2, &PythonQtInstanceWrapper_Type)) { | |
|
330 | 374 | |
|
331 | 375 | PythonQtInstanceWrapper* w1 = (PythonQtInstanceWrapper*)obj1; |
|
332 | 376 | PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)obj2; |
@@ -338,11 +382,11 static int PythonQtInstanceWrapper_compare(PyObject * obj1, PyObject * obj2) | |||
|
338 | 382 | } else if (w1->_obj == w2->_obj) { |
|
339 | 383 | return 0; |
|
340 | 384 | } |
|
341 |
const char* class1 = w1-> |
|
|
342 |
const char* class2 = w2-> |
|
|
385 | const char* class1 = w1->classInfo()->className(); | |
|
386 | const char* class2 = w2->classInfo()->className(); | |
|
343 | 387 | if (strcmp(class1, class2) == 0) { |
|
344 | 388 | // same class names, so we can try the operator_equal |
|
345 |
PythonQtMemberInfo info = w1-> |
|
|
389 | PythonQtMemberInfo info = w1->classInfo()->member("operator_equal"); | |
|
346 | 390 | if (info._type == PythonQtMemberInfo::Slot) { |
|
347 | 391 | bool result = false; |
|
348 | 392 | void* obj1 = w1->_wrappedPtr; |
@@ -440,7 +484,7 static PyNumberMethods PythonQtInstanceWrapper_as_number = { | |||
|
440 | 484 | }; |
|
441 | 485 | |
|
442 | 486 | PyTypeObject PythonQtInstanceWrapper_Type = { |
|
443 | PyObject_HEAD_INIT(NULL) | |
|
487 | PyObject_HEAD_INIT(&PythonQtClassWrapper_Type) | |
|
444 | 488 | 0, /*ob_size*/ |
|
445 | 489 | "PythonQt.PythonQtInstanceWrapper", /*tp_name*/ |
|
446 | 490 | sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/ |
@@ -62,6 +62,9 extern PYTHONQT_EXPORT PyTypeObject PythonQtInstanceWrapper_Type; | |||
|
62 | 62 | typedef struct { |
|
63 | 63 | PyObject_HEAD |
|
64 | 64 | |
|
65 | //! the class information, this is set even if the _obj or _wrappedPtr is NULL to support typed NULL pointers | |
|
66 | PythonQtClassInfo* classInfo(); | |
|
67 | ||
|
65 | 68 | //! set the QObject pointer |
|
66 | 69 | void setQObject(QObject* object) { |
|
67 | 70 | _obj = object; |
@@ -77,9 +80,6 typedef struct { | |||
|
77 | 80 | //! optional C++ object Ptr that is wrapped by the above _obj |
|
78 | 81 | void* _wrappedPtr; |
|
79 | 82 | |
|
80 | //! the class information, this is set even if the _obj or _wrappedPtr is NULL to support typed NULL pointers | |
|
81 | PythonQtClassInfo* _info; | |
|
82 | ||
|
83 | 83 | //! flag that stores if the object is owned by pythonQt |
|
84 | 84 | bool _ownedByPythonQt; |
|
85 | 85 |
@@ -50,10 +50,13 | |||
|
50 | 50 | #define PYTHONQT_MAX_ARGS 32 |
|
51 | 51 | |
|
52 | 52 | |
|
53 |
|
|
|
53 | bool PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer) | |
|
54 | 54 | { |
|
55 | 55 | static unsigned int recursiveEntry = 0; |
|
56 | 56 | |
|
57 | if (directReturnValuePointer) { | |
|
58 | *directReturnValuePointer = NULL; | |
|
59 | } | |
|
57 | 60 | // store the current storage position, so that we can get back to this state after a slot is called |
|
58 | 61 | // (do this locally, so that we have all positions on the stack |
|
59 | 62 | PythonQtValueStoragePosition globalValueStoragePos; |
@@ -87,7 +90,13 PyObject* PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, P | |||
|
87 | 90 | } |
|
88 | 91 | if (argList[0]==NULL) { |
|
89 | 92 | // create empty default value for the return value |
|
90 | argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam); | |
|
93 | if (!directReturnValuePointer) { | |
|
94 | // create empty default value for the return value | |
|
95 | argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam); | |
|
96 | } else { | |
|
97 | // we can use our pointer directly! | |
|
98 | argList[0] = directReturnValuePointer; | |
|
99 | } | |
|
91 | 100 | } |
|
92 | 101 | } |
|
93 | 102 | |
@@ -129,10 +138,14 PyObject* PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, P | |||
|
129 | 138 | (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList); |
|
130 | 139 | |
|
131 | 140 | if (argList[0] || returnValueParam.typeId == QMetaType::Void) { |
|
132 |
if ( |
|
|
133 | result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]); | |
|
141 | if (directReturnValuePointer) { | |
|
142 | result = NULL; | |
|
134 | 143 | } else { |
|
135 | result = PyInt_FromLong(*((unsigned int*)argList[0])); | |
|
144 | if (!returnValueIsEnum) { | |
|
145 | result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]); | |
|
146 | } else { | |
|
147 | result = PyInt_FromLong(*((unsigned int*)argList[0])); | |
|
148 | } | |
|
136 | 149 | } |
|
137 | 150 | } else { |
|
138 | 151 | QString e = QString("Called ") + info->fullSignature(skipFirst) + ", return type is ignored because it is unknown to PythonQt."; |
@@ -147,8 +160,9 PyObject* PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, P | |||
|
147 | 160 | PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos); |
|
148 | 161 | PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos); |
|
149 | 162 | |
|
163 | *pythonReturnValue = result; | |
|
150 | 164 | // NOTE: it is important to only return here, otherwise the stack will not be popped!!! |
|
151 | return result; | |
|
165 | return result || (directReturnValuePointer && *directReturnValuePointer); | |
|
152 | 166 | } |
|
153 | 167 | |
|
154 | 168 | //----------------------------------------------------------------------------------- |
@@ -159,7 +173,7 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw | |||
|
159 | 173 | { |
|
160 | 174 | PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func; |
|
161 | 175 | PythonQtSlotInfo* info = f->m_ml; |
|
162 |
if (f->m_self |
|
|
176 | if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) { | |
|
163 | 177 | PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self; |
|
164 | 178 | return PythonQtSlotFunction_CallImpl(self->_obj, info, args, kw, self->_wrappedPtr); |
|
165 | 179 | } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) { |
@@ -169,7 +183,7 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw | |||
|
169 | 183 | } |
|
170 | 184 | } |
|
171 | 185 | |
|
172 | PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg) | |
|
186 | PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer) | |
|
173 | 187 | { |
|
174 | 188 | int argc = PyTuple_Size(args); |
|
175 | 189 | |
@@ -178,33 +192,32 PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* | |||
|
178 | 192 | #endif |
|
179 | 193 | |
|
180 | 194 | PyObject* r = NULL; |
|
181 | ||
|
195 | bool ok = false; | |
|
196 | if (directReturnValuePointer) { | |
|
197 | *directReturnValuePointer = NULL; | |
|
198 | } | |
|
199 | ||
|
182 | 200 | if (info->nextInfo()) { |
|
183 | 201 | // overloaded slot call, try on all slots with strict conversion first |
|
202 | bool strict = true; | |
|
184 | 203 | PythonQtSlotInfo* i = info; |
|
185 |
while (i |
|
|
204 | while (i) { | |
|
186 | 205 | bool skipFirst = i->isInstanceDecorator(); |
|
187 | 206 | if (i->parameterCount()-1-(skipFirst?1:0) == argc) { |
|
188 | 207 | PyErr_Clear(); |
|
189 |
|
|
|
190 | if (PyErr_Occurred()) break; | |
|
208 | ok = PythonQtCallSlot(objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer); | |
|
209 | if (PyErr_Occurred() || ok) break; | |
|
191 | 210 | } |
|
192 | 211 | i = i->nextInfo(); |
|
193 | } | |
|
194 |
if ( |
|
|
195 | // try on all slots with non-strict conversion | |
|
196 |
i = |
|
|
197 | while (i && r==NULL) { | |
|
198 | bool skipFirst = i->isInstanceDecorator(); | |
|
199 | if (i->parameterCount()-1-(skipFirst?1:0) == argc) { | |
|
200 | PyErr_Clear(); | |
|
201 | r = PythonQtCallSlot(objectToCall, args, false, i, firstArg); | |
|
202 | if (PyErr_Occurred()) break; | |
|
212 | if (!i) { | |
|
213 | if (strict) { | |
|
214 | // one more run without being strict | |
|
215 | strict = false; | |
|
216 | i = info; | |
|
203 | 217 | } |
|
204 | i = i->nextInfo(); | |
|
205 | 218 | } |
|
206 | 219 | } |
|
207 |
if ( |
|
|
220 | if (!ok && !PyErr_Occurred()) { | |
|
208 | 221 | QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n"); |
|
209 | 222 | PythonQtSlotInfo* i = info; |
|
210 | 223 | while (i) { |
@@ -219,8 +232,8 PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* | |||
|
219 | 232 | bool skipFirst = info->isInstanceDecorator(); |
|
220 | 233 | if (info->parameterCount()-1-(skipFirst?1:0) == argc) { |
|
221 | 234 | PyErr_Clear(); |
|
222 |
|
|
|
223 |
if ( |
|
|
235 | ok = PythonQtCallSlot(objectToCall, args, false, info, firstArg, &r, directReturnValuePointer); | |
|
236 | if (!ok && !PyErr_Occurred()) { | |
|
224 | 237 | QString e = QString("Called ") + info->fullSignature(skipFirst) + " with wrong arguments: " + PythonQtConv::PyObjGetString(args); |
|
225 | 238 | PyErr_SetString(PyExc_ValueError, e.toLatin1().data()); |
|
226 | 239 | } |
@@ -61,7 +61,7 PyObject* PythonQtSlotFunction_GetSelf(PyObject *); | |||
|
61 | 61 | |
|
62 | 62 | PyObject* PythonQtSlotFunction_Call(PyObject *, PyObject *, PyObject *); |
|
63 | 63 | |
|
64 | PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL); | |
|
64 | PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL, void** directReturnValuePointer=NULL); | |
|
65 | 65 | |
|
66 | 66 | |
|
67 | 67 | PyObject* PythonQtSlotFunction_New(PythonQtSlotInfo *, PyObject *, |
General Comments 0
You need to be logged in to leave comments.
Login now