##// END OF EJS Templates
- wrapped instances are now wrapped by class specific subtypes to facilitate future deriving from python...
florianlink -
r18:44e5ff2700cb
parent child
Show More
@@ -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 = new PythonQtClassInfo(m);
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->_info->wrappedClassName().latin1());
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->_info->wrappedClassName().latin1());
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->_info->wrappedClassName().latin1());
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.insert(name, info);
394 PyModule_AddObject(_pythonQtModule, name, (PyObject*)createNewPythonQtClassWrapper(info));
395 } else {
396 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
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->_info->wrappedClassName().latin1());
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->_info->wrappedClassName().latin1());
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->_info->constructors();
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 = new PythonQtClassInfo(NULL, typeName);
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 void PythonQtClassWrapper_dealloc(PythonQtClassWrapper* self)
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 PyObject *PythonQtClassWrapper_call(PyObject *func, PyObject *args, PyObject *kw) {
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("Meta_") + type->_info->className()).toLatin1().data());
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->_info);
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->_info->member(attributeName);
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->_info->memberList(true);
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->_info->className()) + " has no attribute named '" + QString(attributeName) + "'";
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->_info->isCPPWrapper()) {
174 const QMetaObject* meta = wrapper->_info->metaObject();
165 if (wrapper->classInfo()->isCPPWrapper()) {
166 const QMetaObject* meta = wrapper->classInfo()->metaObject();
175 167 if (!meta) {
176 QObject* decorator = wrapper->_info->decorator();
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->_info->className(), meta->className());
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 PythonQtClassWrapper_repr, /*tp_repr*/
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 (hashfunc)PythonQtClassWrapper_hash, /*tp_hash */
229 PythonQtClassWrapper_call, /*tp_call*/
200 0, /*tp_hash */
201 0, /*tp_call*/
230 202 0, /*tp_str*/
231 203 PythonQtClassWrapper_getattro, /*tp_getattro*/
232 0, /*tp_setattro*/
204 PythonQtClassWrapper_setattro, /*tp_setattro*/
233 205 0, /*tp_as_buffer*/
234 206 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
235 "PythonQtClassWrapper object", /* tp_doc */
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 0, /* tp_alloc */
252 PythonQtClassWrapper_new, /* tp_new */
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 Qt meta objects
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* _info;
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->ob_type == &PythonQtInstanceWrapper_Type && info.typeId != PythonQtMethodInfo::Variant) {
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->_info->inherits(info.name)) {
233 if (wrap->classInfo()->inherits(info.name)) {
234 234 void* object;
235 if (wrap->_info->isCPPWrapper()) {
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->ob_type == &PythonQtInstanceWrapper_Type) {
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->_info->isCPPWrapper()) {
697 if (wrap->_info->metaTypeId()>0) {
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->_info->metaTypeId(), wrap->_wrappedPtr);
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->ob_type == &PythonQtInstanceWrapper_Type) {
852 if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {
853 853 PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val;
854 if (wrap->_info->isCPPWrapper() && wrap->_info->metaTypeId() == type) {
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->ob_type == &PythonQtInstanceWrapper_Type) {
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->_info->inherits(type)) {
963 if (wrap->_info->isCPPWrapper()) {
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->_info->wrappedClassName().latin1());
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->_info->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) {
60 int type = self->_info->metaTypeId();
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->_info->className());
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->_info->wrappedClassName().latin1());
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 * /*args*/, PyObject * /*kwds*/)
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 * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/)
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->_info->className());
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->_info);
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->_info->className() + " object";
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->_info->member(attributeName);
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->_info->memberList(false);
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->_info->className()) + " has no attribute named '" + QString(attributeName) + "'";
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->_info->className() + " object";
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->_info->member(attributeName);
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->_info->className() + " object is not writable";
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->_info->className() + " object";
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->_info->className() + " object";
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->_info->metaTypeId(), wrapper->_wrappedPtr);
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->_info->className(), wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
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->_info->className(), wrapper->_wrappedPtr);
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->_info->className(), qobj);
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->_info->metaTypeId(), wrapper->_wrappedPtr);
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->_info->metaTypeId()), str.toLatin1().constData(), wrapper->_wrappedPtr);
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->_info->className(), wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
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->_info->className(), wrapper->_wrappedPtr);
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->_info->className(), qobj);
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->ob_type == &PythonQtInstanceWrapper_Type &&
329 obj2->ob_type == &PythonQtInstanceWrapper_Type) {
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->_info->className();
342 const char* class2 = w2->_info->className();
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->_info->member("operator_equal");
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 PyObject* PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument)
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 (!returnValueIsEnum) {
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->ob_type == &PythonQtInstanceWrapper_Type) {
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 && r==NULL) {
204 while (i) {
186 205 bool skipFirst = i->isInstanceDecorator();
187 206 if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
188 207 PyErr_Clear();
189 r = PythonQtCallSlot(objectToCall, args, true, i, firstArg);
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 (!r) {
195 // try on all slots with non-strict conversion
196 i = info;
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 (r==NULL && !PyErr_Occurred()) {
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 r = PythonQtCallSlot(objectToCall, args, false, info, firstArg);
223 if (r==NULL && !PyErr_Occurred()) {
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