##// END OF EJS Templates
merged in features from the MeVisLab repository...
florianlink -
r4:41816e302524
parent child
Show More
@@ -52,6 +52,7
52 #include <pydebug.h>
52 #include <pydebug.h>
53
53
54 PythonQt* PythonQt::_self = NULL;
54 PythonQt* PythonQt::_self = NULL;
55 int PythonQt::_uniqueModuleCount = 0;
55
56
56
57
57 void PythonQt::init(int flags)
58 void PythonQt::init(int flags)
@@ -211,6 +212,13 void PythonQt::registerClass(const QMetaObject* metaobject)
211 _p->registerClass(metaobject);
212 _p->registerClass(metaobject);
212 }
213 }
213
214
215 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
216 {
217 if (_self->_p->_noLongerWrappedCB) {
218 (*_self->_p->_noLongerWrappedCB)(o);
219 };
220 }
221
214 void PythonQtPrivate::registerClass(const QMetaObject* metaobject)
222 void PythonQtPrivate::registerClass(const QMetaObject* metaobject)
215 {
223 {
216 // we register all classes in the hierarchy
224 // we register all classes in the hierarchy
@@ -259,7 +267,7 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
259 Py_INCREF(Py_None);
267 Py_INCREF(Py_None);
260 return Py_None;
268 return Py_None;
261 }
269 }
262 PythonQtWrapper* wrap = _wrappedObjects.value(obj);
270 PythonQtWrapper* wrap = findWrapperAndRemoveUnused(obj);
263 if (!wrap) {
271 if (!wrap) {
264 // smuggling it in...
272 // smuggling it in...
265 PythonQtClassInfo* classInfo = _knownQtClasses.value(obj->metaObject()->className());
273 PythonQtClassInfo* classInfo = _knownQtClasses.value(obj->metaObject()->className());
@@ -268,8 +276,6 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
268 classInfo = _knownQtClasses.value(obj->metaObject()->className());
276 classInfo = _knownQtClasses.value(obj->metaObject()->className());
269 }
277 }
270 wrap = createNewPythonQtWrapper(obj, classInfo);
278 wrap = createNewPythonQtWrapper(obj, classInfo);
271 // insert destroyed handler
272 connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(wrappedObjectDestroyed(QObject*)));
273 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
279 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
274 } else {
280 } else {
275 Py_INCREF(wrap);
281 Py_INCREF(wrap);
@@ -284,7 +290,7 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
284 Py_INCREF(Py_None);
290 Py_INCREF(Py_None);
285 return Py_None;
291 return Py_None;
286 }
292 }
287 PythonQtWrapper* wrap = _wrappedObjects.value(ptr);
293 PythonQtWrapper* wrap = findWrapperAndRemoveUnused(ptr);
288 if (!wrap) {
294 if (!wrap) {
289 PythonQtClassInfo* info = _knownQtClasses.value(name);
295 PythonQtClassInfo* info = _knownQtClasses.value(name);
290 if (!info) {
296 if (!info) {
@@ -304,8 +310,6 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
304 info = _knownQtClasses.value(qptr->metaObject()->className());
310 info = _knownQtClasses.value(qptr->metaObject()->className());
305 }
311 }
306 wrap = createNewPythonQtWrapper(qptr, info);
312 wrap = createNewPythonQtWrapper(qptr, info);
307 // insert destroyed handler
308 connect(qptr, SIGNAL(destroyed(QObject*)), this, SLOT(wrappedObjectDestroyed(QObject*)));
309 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
313 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
310 } else {
314 } else {
311 // maybe it is a PyObject, which we can return directly
315 // maybe it is a PyObject, which we can return directly
@@ -360,7 +364,7 PythonQtWrapper* PythonQtPrivate::createNewPythonQtWrapper(QObject* obj, PythonQ
360 result = (PythonQtWrapper *)PythonQtWrapper_Type.tp_new(&PythonQtWrapper_Type,
364 result = (PythonQtWrapper *)PythonQtWrapper_Type.tp_new(&PythonQtWrapper_Type,
361 NULL, NULL);
365 NULL, NULL);
362
366
363 result->_obj = obj;
367 result->setQObject(obj);
364 result->_info = info;
368 result->_info = info;
365 result->_wrappedPtr = wrappedPtr;
369 result->_wrappedPtr = wrappedPtr;
366 result->_ownedByPythonQt = false;
370 result->_ownedByPythonQt = false;
@@ -369,6 +373,10 PythonQtWrapper* PythonQtPrivate::createNewPythonQtWrapper(QObject* obj, PythonQ
369 _wrappedObjects.insert(wrappedPtr, result);
373 _wrappedObjects.insert(wrappedPtr, result);
370 } else {
374 } else {
371 _wrappedObjects.insert(obj, result);
375 _wrappedObjects.insert(obj, result);
376 if (obj->parent()== NULL && _wrappedCB) {
377 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
378 (*_wrappedCB)(obj);
379 }
372 }
380 }
373 return result;
381 return result;
374 }
382 }
@@ -400,8 +408,6 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
400 if (!r) {
408 if (!r) {
401 r = new PythonQtSignalReceiver(obj);
409 r = new PythonQtSignalReceiver(obj);
402 _p->_signalReceivers.insert(obj, r);
410 _p->_signalReceivers.insert(obj, r);
403 // insert destroyed handler
404 connect(obj, SIGNAL(destroyed(QObject*)), _p ,SLOT(destroyedSignalEmitter(QObject*)));
405 }
411 }
406 return r;
412 return r;
407 }
413 }
@@ -540,6 +546,34 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
540 return p;
546 return p;
541 }
547 }
542
548
549 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
550 {
551 PythonQtObjectPtr code = parseFile(filename);
552 PythonQtObjectPtr module = _p->createModule(name, code);
553 return module;
554 }
555
556 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
557 {
558 PyErr_Clear();
559 QString scriptCode = script;
560 if (scriptCode.isEmpty()) {
561 // we always need at least a linefeed
562 scriptCode = "\n";
563 }
564 PythonQtObjectPtr pycode;
565 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
566 PythonQtObjectPtr module = _p->createModule(name, pycode);
567 return module;
568 }
569
570 PythonQtObjectPtr PythonQt::createUniqueModule()
571 {
572 static QString pyQtStr("PythonQt_module");
573 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
574 return createModuleFromScript(moduleName);
575 }
576
543 void PythonQt::addObject(PyObject* module, const QString& name, QObject* object)
577 void PythonQt::addObject(PyObject* module, const QString& name, QObject* object)
544 {
578 {
545 PyModule_AddObject(module, name.toLatin1().data(), _p->wrapQObject(object));
579 PyModule_AddObject(module, name.toLatin1().data(), _p->wrapQObject(object));
@@ -763,6 +797,8 const QList<PythonQtConstructorHandler*>& PythonQt::constructorHandlers()
763 PythonQtPrivate::PythonQtPrivate()
797 PythonQtPrivate::PythonQtPrivate()
764 {
798 {
765 _importInterface = NULL;
799 _importInterface = NULL;
800 _noLongerWrappedCB = NULL;
801 _wrappedCB = NULL;
766 }
802 }
767
803
768 void PythonQtPrivate::addDecorators(QObject* o, bool instanceDeco, bool classDeco)
804 void PythonQtPrivate::addDecorators(QObject* o, bool instanceDeco, bool classDeco)
@@ -829,20 +865,9 QList<PythonQtSlotInfo*> PythonQtPrivate::getDecoratorSlots(const QByteArray& cl
829 return _knownQtDecoratorSlots.values(className);
865 return _knownQtDecoratorSlots.values(className);
830 }
866 }
831
867
832 void PythonQtPrivate::wrappedObjectDestroyed(QObject* obj)
868 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
833 {
869 {
834 // mlabDebugConst("MLABPython","PyWrapper QObject destroyed " << o << " " << o->name() << " " << o->className());
870 _signalReceivers.remove(obj);
835 PythonQtWrapper* wrap = _wrappedObjects[obj];
836 if (wrap) {
837 _wrappedObjects.remove(obj);
838 // remove the pointer but keep the wrapper alive in python
839 wrap->_obj = NULL;
840 }
841 }
842
843 void PythonQtPrivate::destroyedSignalEmitter(QObject* obj)
844 {
845 _signalReceivers.take(obj);
846 }
871 }
847
872
848 bool PythonQt::handleError()
873 bool PythonQt::handleError()
@@ -892,6 +917,16 void PythonQt::stdErrRedirectCB(const QString& str)
892 emit PythonQt::self()->pythonStdErr(str);
917 emit PythonQt::self()->pythonStdErr(str);
893 }
918 }
894
919
920 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
921 {
922 _p->_wrappedCB = cb;
923 }
924
925 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
926 {
927 _p->_noLongerWrappedCB = cb;
928 }
929
895
930
896
931
897 static PyMethodDef PythonQtMethods[] = {
932 static PyMethodDef PythonQtMethods[] = {
@@ -944,3 +979,33 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
944 return PyString_FromString(info->help().toLatin1().data());
979 return PyString_FromString(info->help().toLatin1().data());
945 }
980 }
946 }
981 }
982
983 void PythonQtPrivate::removeWrapperPointer(void* obj)
984 {
985 _wrappedObjects.remove(obj);
986 }
987
988 PythonQtWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
989 {
990 PythonQtWrapper* wrap = _wrappedObjects.value(obj);
991 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
992 // this is a wrapper whose QObject was already removed due to destruction
993 // so the obj pointer has to be a new QObject with the same address...
994 // we remove the old one and set the copy to NULL
995 wrap->_objPointerCopy = NULL;
996 removeWrapperPointer(obj);
997 wrap = NULL;
998 }
999 return wrap;
1000 }
1001
1002 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1003 {
1004 PythonQtObjectPtr result;
1005 if (pycode) {
1006 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1007 } else {
1008 PythonQt::self()->handleError();
1009 }
1010 return result;
1011 }
@@ -66,6 +66,9 class PythonQtImportFileInterface;
66 class PythonQtCppWrapperFactory;
66 class PythonQtCppWrapperFactory;
67 class PythonQtConstructorHandler;
67 class PythonQtConstructorHandler;
68
68
69 typedef void PythonQtQObjectWrappedCB(QObject* object);
70 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
71
69 //! the main interface to the Python Qt binding, realized as a singleton
72 //! the main interface to the Python Qt binding, realized as a singleton
70 class PYTHONQT_EXPORT PythonQt : public QObject {
73 class PYTHONQT_EXPORT PythonQt : public QObject {
71
74
@@ -137,6 +140,22 public:
137 //! evaluates the given script code from file
140 //! evaluates the given script code from file
138 void evalFile(PyObject* module, const QString& filename);
141 void evalFile(PyObject* module, const QString& filename);
139
142
143 //! creates the new module \c name and evaluates the given file in the context of that module
144 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
145 //! to a module later on.
146 //! The user needs to make sure that the \c name is unique in the python module dictionary.
147 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
148
149 //! creates the new module \c name and evaluates the given script in the context of that module.
150 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
151 //! to a module later on.
152 //! The user needs to make sure that the \c name is unique in the python module dictionary.
153 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
154
155 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
156 //! script code
157 PythonQtObjectPtr createUniqueModule();
158
140 //@{ Signal handlers
159 //@{ Signal handlers
141
160
142 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
161 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
@@ -280,6 +299,14 public:
280 //! The error is currently just output to the python stderr, future version might implement better trace printing
299 //! The error is currently just output to the python stderr, future version might implement better trace printing
281 bool handleError();
300 bool handleError();
282
301
302 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
303 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
304 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
305 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
306
307 //! call the callback if it is set
308 static void qObjectNoLongerWrappedCB(QObject* o);
309
283 signals:
310 signals:
284 //! emitted when python outputs something to stdout (and redirection is turned on)
311 //! emitted when python outputs something to stdout (and redirection is turned on)
285 void pythonStdOut(const QString& str);
312 void pythonStdOut(const QString& str);
@@ -313,6 +340,7 private:
313 ~PythonQt();
340 ~PythonQt();
314
341
315 static PythonQt* _self;
342 static PythonQt* _self;
343 static int _uniqueModuleCount;
316
344
317 PythonQtPrivate* _p;
345 PythonQtPrivate* _p;
318
346
@@ -331,7 +359,10 public:
331 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
359 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
332
360
333 //! remove the wrapper ptr again
361 //! remove the wrapper ptr again
334 void removeWrapperPointer(void* obj) { _wrappedObjects.take(obj); }
362 void removeWrapperPointer(void* obj);
363
364 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
365 void removeSignalEmitter(QObject* obj);
335
366
336 //! wrap the given QObject into a Python object (or return existing wrapper!)
367 //! wrap the given QObject into a Python object (or return existing wrapper!)
337 PyObject* wrapQObject(QObject* obj);
368 PyObject* wrapQObject(QObject* obj);
@@ -379,15 +410,14 public:
379 //! get the destructor slot for the given classname
410 //! get the destructor slot for the given classname
380 PythonQtSlotInfo* getDestructorSlot(const QByteArray& className) { return _destructorSlots.value(className); }
411 PythonQtSlotInfo* getDestructorSlot(const QByteArray& className) { return _destructorSlots.value(className); }
381
412
382 protected slots:
413 //! creates the new module from the given pycode
383 //! called when a wrapped QObject is destroyed
414 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
384 void wrappedObjectDestroyed(QObject* obj);
385
386 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
387 void destroyedSignalEmitter(QObject* obj);
388
415
389 private:
416 private:
390
417
418 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
419 PythonQtWrapper* findWrapperAndRemoveUnused(void* obj);
420
391 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
421 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
392 QHash<void* , PythonQtWrapper *> _wrappedObjects;
422 QHash<void* , PythonQtWrapper *> _wrappedObjects;
393
423
@@ -412,6 +442,9 private:
412 //! the importer interface (if set)
442 //! the importer interface (if set)
413 PythonQtImportFileInterface* _importInterface;
443 PythonQtImportFileInterface* _importInterface;
414
444
445 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
446 PythonQtQObjectWrappedCB* _wrappedCB;
447
415 QStringList _importIgnorePaths;
448 QStringList _importIgnorePaths;
416
449
417 //! the cpp object wrapper factories
450 //! the cpp object wrapper factories
@@ -296,7 +296,8 return Py_None;
296 }
296 }
297 } else {
297 } else {
298 if (wrap->_info->inherits(info.name)) {
298 if (wrap->_info->inherits(info.name)) {
299 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, wrap->_obj, ptr);
299 QObject* myObject = wrap->_obj;
300 PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, myObject, ptr);
300 } else {
301 } else {
301 // not matching
302 // not matching
302 }
303 }
@@ -487,6 +488,8 return Py_None;
487 if (ok) {
488 if (ok) {
488 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned int, val, ptr);
489 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned int, val, ptr);
489 return ptr;
490 return ptr;
491 } else {
492 return NULL;
490 }
493 }
491 }
494 }
492 }
495 }
@@ -730,7 +733,8 QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
730 // is this worth anything? we loose the knowledge of the cpp object type
733 // is this worth anything? we loose the knowledge of the cpp object type
731 v = qVariantFromValue(wrap->_wrappedPtr);
734 v = qVariantFromValue(wrap->_wrappedPtr);
732 } else {
735 } else {
733 v = qVariantFromValue(wrap->_obj);
736 QObject* myObject = wrap->_obj;
737 v = qVariantFromValue(myObject);
734 }
738 }
735 return v;
739 return v;
736 } else if (val->ob_type==&PyDict_Type) {
740 } else if (val->ob_type==&PyDict_Type) {
@@ -998,7 +1002,8 bool PythonQtConv::ConvertPythonListToQListOfType(PyObject* obj, QList<void*>* l
998 }
1002 }
999 } else {
1003 } else {
1000 if (wrap->_info->inherits(type)) {
1004 if (wrap->_info->inherits(type)) {
1001 list->append((void*)wrap->_obj);
1005 QObject* myObject = wrap->_obj;
1006 list->append((void*)myObject);
1002 } else {
1007 } else {
1003 result = false;
1008 result = false;
1004 break;
1009 break;
@@ -620,11 +620,13 PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int ispackag
620 else {
620 else {
621 // mlabDebugConst("MLABPython", "compiling source " << path);
621 // mlabDebugConst("MLABPython", "compiling source " << path);
622 code = compileSource(path, qdata);
622 code = compileSource(path, qdata);
623 if (code) {
623 // save a pyc file if possible
624 // save a pyc file if possible
624 QDateTime time;
625 QDateTime time;
625 time = hasImporter?PythonQt::importInterface()->lastModifiedDate(path):QFileInfo(path).lastModified();
626 time = hasImporter?PythonQt::importInterface()->lastModifiedDate(path):QFileInfo(path).lastModified();
626 writeCompiledModule((PyCodeObject*)code, path+"c", time.toTime_t());
627 writeCompiledModule((PyCodeObject*)code, path+"c", time.toTime_t());
627 }
628 }
629 }
628 return code;
630 return code;
629 }
631 }
630
632
@@ -194,6 +194,11 static int PythonQtMetaObjectWrapper_compare(PyObject * obj1, PyObject * obj2)
194 }
194 }
195 }
195 }
196
196
197 static long PythonQtMetaObjectWrapper_hash(PythonQtMetaObjectWrapper *obj)
198 {
199 return reinterpret_cast<long>(obj->_info);
200 }
201
197 PyTypeObject PythonQtMetaObjectWrapper_Type = {
202 PyTypeObject PythonQtMetaObjectWrapper_Type = {
198 PyObject_HEAD_INIT(NULL)
203 PyObject_HEAD_INIT(NULL)
199 0, /*ob_size*/
204 0, /*ob_size*/
@@ -209,7 +214,7 PyTypeObject PythonQtMetaObjectWrapper_Type = {
209 0, /*tp_as_number*/
214 0, /*tp_as_number*/
210 0, /*tp_as_sequence*/
215 0, /*tp_as_sequence*/
211 0, /*tp_as_mapping*/
216 0, /*tp_as_mapping*/
212 0, /*tp_hash */
217 (hashfunc)PythonQtMetaObjectWrapper_hash, /*tp_hash */
213 PythonQtMetaObjectWrapper_call, /*tp_call*/
218 PythonQtMetaObjectWrapper_call, /*tp_call*/
214 0, /*tp_str*/
219 0, /*tp_str*/
215 PythonQtMetaObjectWrapper_getattro, /*tp_getattro*/
220 PythonQtMetaObjectWrapper_getattro, /*tp_getattro*/
@@ -45,12 +45,46
45 #include "PythonQtConversion.h"
45 #include "PythonQtConversion.h"
46 #include <QMetaObject>
46 #include <QMetaObject>
47 #include <QMetaMethod>
47 #include <QMetaMethod>
48 #include "funcobject.h"
48
49
49 void PythonQtSignalTarget::call(void **arguments) const
50 void PythonQtSignalTarget::call(void **arguments) const
50 {
51 {
52 // Note: we check if the callable is a PyFunctionObject and has a fixed number of arguments
53 // if that is the case, we only pass these arguments to python and skip the additional arguments from the signal
54
55 int numPythonArgs = -1;
56 if (PyFunction_Check(_callable)) {
57 PyObject* o = _callable;
58 PyFunctionObject* func = (PyFunctionObject*)o;
59 PyCodeObject* code = (PyCodeObject*)func->func_code;
60 if (!(code->co_flags & 0x04)) {
61 numPythonArgs = code->co_argcount;
62 } else {
63 // variable numbers of arguments allowed
64 }
65 } else if (PyMethod_Check(_callable)) {
66 PyObject* o = _callable;
67 PyMethodObject* method = (PyMethodObject*)o;
68 if (PyFunction_Check(method->im_func)) {
69 PyFunctionObject* func = (PyFunctionObject*)method->im_func;
70 PyCodeObject* code = (PyCodeObject*)func->func_code;
71 if (!(code->co_flags & 0x04)) {
72 numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self"
73 } else {
74 // variable numbers of arguments allowed
75 }
76 }
77 }
78
51 const PythonQtMethodInfo* m = methodInfo();
79 const PythonQtMethodInfo* m = methodInfo();
52 // paramterCount includes return value:
80 // parameterCount includes return value:
53 int count = m->parameterCount();
81 int count = m->parameterCount();
82 if (numPythonArgs!=-1) {
83 if (count>numPythonArgs+1) {
84 // take less arguments
85 count = numPythonArgs+1;
86 }
87 }
54
88
55 PyObject* pargs = NULL;
89 PyObject* pargs = NULL;
56 if (count>1) {
90 if (count>1) {
@@ -97,6 +131,7 PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalRecei
97
131
98 PythonQtSignalReceiver::~PythonQtSignalReceiver()
132 PythonQtSignalReceiver::~PythonQtSignalReceiver()
99 {
133 {
134 PythonQt::priv()->removeSignalEmitter(_obj);
100 }
135 }
101
136
102
137
@@ -70,10 +70,18 static PyObject *PythonQtStdOutRedirect_write(PyObject *self, PyObject *args)
70 return Py_BuildValue("");
70 return Py_BuildValue("");
71 }
71 }
72
72
73 static PyObject *PythonQtStdOutRedirect_flush(PyObject *self, PyObject *args)
74 {
75 return Py_BuildValue("");
76 }
77
78
73
79
74 static PyMethodDef PythonQtStdOutRedirect_methods[] = {
80 static PyMethodDef PythonQtStdOutRedirect_methods[] = {
75 {"write", (PyCFunction)PythonQtStdOutRedirect_write, METH_VARARGS,
81 {"write", (PyCFunction)PythonQtStdOutRedirect_write, METH_VARARGS,
76 "redirect the writing to a callback"
82 "redirect the writing to a callback"},
83 {"flush", (PyCFunction)PythonQtStdOutRedirect_flush, METH_VARARGS,
84 "flush the output, currently not implemented but needed for logging framework"
77 },
85 },
78 {NULL} /* Sentinel */
86 {NULL} /* Sentinel */
79 };
87 };
@@ -171,6 +171,18 QString qVariantToString(const QVariant& v) {
171 case QVariant::Time:
171 case QVariant::Time:
172 r = v.toTime().toString(Qt::ISODate);
172 r = v.toTime().toString(Qt::ISODate);
173 break;
173 break;
174 case QVariant::Pixmap:
175 {
176 QPixmap p = qvariant_cast<QPixmap>(v);
177 r = QString("Pixmap ") + QString::number(p.width()) + ", " + QString::number(p.height());
178 }
179 break;
180 case QVariant::Image:
181 {
182 QImage img = qvariant_cast<QImage>(v);
183 r = QString("Image ") + QString::number(img.width()) + ", " + QString::number(img.height());
184 }
185 break;
174 //TODO: add more printing for other variant types
186 //TODO: add more printing for other variant types
175 default:
187 default:
176 r = v.toString();
188 r = v.toString();
@@ -182,6 +194,9 static PyObject * PythonQtVariantWrapper_str(PyObject * obj)
182 {
194 {
183 PythonQtVariantWrapper* wt = (PythonQtVariantWrapper*)obj;
195 PythonQtVariantWrapper* wt = (PythonQtVariantWrapper*)obj;
184 QString val = qVariantToString(*wt->_variant);
196 QString val = qVariantToString(*wt->_variant);
197 if (val.isEmpty()) {
198 val = wt->_variant->typeName();
199 }
185 return PyString_FromFormat("%s", val.toLatin1().constData());
200 return PyString_FromFormat("%s", val.toLatin1().constData());
186 }
201 }
187
202
@@ -68,16 +68,26 static void PythonQtWrapper_dealloc(PythonQtWrapper* self)
68 // TODO: print a warning? we can not destroy that object
68 // TODO: print a warning? we can not destroy that object
69 }
69 }
70 }
70 }
71 } else if (self->_obj) {
71 } else {
72 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->_info->wrappedClassName().latin1());
72 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->_info->wrappedClassName().latin1());
73 PythonQt::priv()->removeWrapperPointer(self->_obj);
73 if (self->_objPointerCopy) {
74 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
75 }
76 if (self->_obj) {
74 if (self->_ownedByPythonQt) {
77 if (self->_ownedByPythonQt) {
75 if (!self->_obj->parent()) {
78 if (!self->_obj->parent()) {
76 delete self->_obj;
79 delete self->_obj;
77 self->_obj = NULL;
80 }
81 } else {
82 if (self->_obj->parent()==NULL) {
83 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
84 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
85 }
78 }
86 }
79 }
87 }
80 }
88 }
89 self->_obj = NULL;
90 self->_obj.~QPointer<QObject>();
81 self->ob_type->tp_free((PyObject*)self);
91 self->ob_type->tp_free((PyObject*)self);
82 }
92 }
83
93
@@ -88,7 +98,7 static PyObject* PythonQtWrapper_new(PyTypeObject *type, PyObject *args, PyObjec
88 self = (PythonQtWrapper *)type->tp_alloc(type, 0);
98 self = (PythonQtWrapper *)type->tp_alloc(type, 0);
89 if (self != NULL) {
99 if (self != NULL) {
90 self->_info = NULL;
100 self->_info = NULL;
91 self->_obj = NULL;
101 new (&self->_obj) QPointer<QObject>();
92 self->_wrappedPtr = NULL;
102 self->_wrappedPtr = NULL;
93 self->_ownedByPythonQt = false;
103 self->_ownedByPythonQt = false;
94 }
104 }
@@ -248,14 +258,15 static int PythonQtWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value
248 static PyObject * PythonQtWrapper_repr(PyObject * obj)
258 static PyObject * PythonQtWrapper_repr(PyObject * obj)
249 {
259 {
250 PythonQtWrapper* wt = (PythonQtWrapper*)obj;
260 PythonQtWrapper* wt = (PythonQtWrapper*)obj;
261 QObject *qobj = wt->_obj;
251 if (wt->_wrappedPtr) {
262 if (wt->_wrappedPtr) {
252 if (wt->_obj) {
263 if (wt->_obj) {
253 return PyString_FromFormat("%s (C++ Object 0x%x wrapped by %s 0x%x))", wt->_info->className(), wt->_wrappedPtr, wt->_obj->metaObject()->className(), wt->_obj);
264 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wt->_info->className(), wt->_wrappedPtr, wt->_obj->metaObject()->className(), qobj);
254 } else {
265 } else {
255 return PyString_FromFormat("%s (C++ Object 0x%x unwrapped)", wt->_info->className(), wt->_wrappedPtr);
266 return PyString_FromFormat("%s (C++ Object %p unwrapped)", wt->_info->className(), wt->_wrappedPtr);
256 }
267 }
257 } else {
268 } else {
258 return PyString_FromFormat("%s (QObject 0x%x)", wt->_info->className(), wt->_obj, wt->_wrappedPtr);
269 return PyString_FromFormat("%s (QObject %p)", wt->_info->className(), qobj);
259 }
270 }
260 }
271 }
261
272
@@ -288,6 +299,19 static int PythonQtWrapper_nonzero(PyObject *obj)
288 return (wt->_wrappedPtr == NULL && wt->_obj == NULL)?0:1;
299 return (wt->_wrappedPtr == NULL && wt->_obj == NULL)?0:1;
289 }
300 }
290
301
302
303 static long PythonQtWrapper_hash(PythonQtWrapper *obj)
304 {
305 if (obj->_wrappedPtr != NULL) {
306 return reinterpret_cast<long>(obj->_wrappedPtr);
307 } else {
308 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
309 return reinterpret_cast<long>(qobj);
310 }
311 }
312
313
314
291 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
315 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
292 static PyNumberMethods PythonQtWrapper_as_number = {
316 static PyNumberMethods PythonQtWrapper_as_number = {
293 0, /* nb_add */
317 0, /* nb_add */
@@ -345,7 +369,7 PyTypeObject PythonQtWrapper_Type = {
345 &PythonQtWrapper_as_number, /*tp_as_number*/
369 &PythonQtWrapper_as_number, /*tp_as_number*/
346 0, /*tp_as_sequence*/
370 0, /*tp_as_sequence*/
347 0, /*tp_as_mapping*/
371 0, /*tp_as_mapping*/
348 0, /*tp_hash */
372 (hashfunc)PythonQtWrapper_hash, /*tp_hash */
349 0, /*tp_call*/
373 0, /*tp_call*/
350 0, /*tp_str*/
374 0, /*tp_str*/
351 PythonQtWrapper_getattro, /*tp_getattro*/
375 PythonQtWrapper_getattro, /*tp_getattro*/
@@ -45,6 +45,7
45 #include <Python.h>
45 #include <Python.h>
46
46
47 #include "PythonQtSystem.h"
47 #include "PythonQtSystem.h"
48 #include <QPointer>
48
49
49 #include "structmember.h"
50 #include "structmember.h"
50 #include "methodobject.h"
51 #include "methodobject.h"
@@ -61,8 +62,18 extern PYTHONQT_EXPORT PyTypeObject PythonQtWrapper_Type;
61 typedef struct {
62 typedef struct {
62 PyObject_HEAD
63 PyObject_HEAD
63
64
65 //! set the QObject pointer
66 void setQObject(QObject* object) {
67 _obj = object;
68 _objPointerCopy = object;
69 }
70
64 //! pointer to the wrapped Qt object or if _wrappedPtr is set, the Qt object that wraps the C++ Ptr
71 //! pointer to the wrapped Qt object or if _wrappedPtr is set, the Qt object that wraps the C++ Ptr
65 QObject* _obj;
72 QPointer<QObject> _obj;
73 //! a copy of the _obj pointer, which is required because the wrapper needs to
74 //! deregister itself via the _obj pointer, even when the QPointer<QObject> object was destroyed
75 void* _objPointerCopy;
76
66 //! optional C++ object Ptr that is wrapped by the above _obj
77 //! optional C++ object Ptr that is wrapped by the above _obj
67 void* _wrappedPtr;
78 void* _wrappedPtr;
68
79
General Comments 0
You need to be logged in to leave comments. Login now