##// END OF EJS Templates
merged in features from the MeVisLab repository...
florianlink -
r4:41816e302524
parent child
Show More
@@ -52,6 +52,7
52 52 #include <pydebug.h>
53 53
54 54 PythonQt* PythonQt::_self = NULL;
55 int PythonQt::_uniqueModuleCount = 0;
55 56
56 57
57 58 void PythonQt::init(int flags)
@@ -211,6 +212,13 void PythonQt::registerClass(const QMetaObject* metaobject)
211 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 222 void PythonQtPrivate::registerClass(const QMetaObject* metaobject)
215 223 {
216 224 // we register all classes in the hierarchy
@@ -259,7 +267,7 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
259 267 Py_INCREF(Py_None);
260 268 return Py_None;
261 269 }
262 PythonQtWrapper* wrap = _wrappedObjects.value(obj);
270 PythonQtWrapper* wrap = findWrapperAndRemoveUnused(obj);
263 271 if (!wrap) {
264 272 // smuggling it in...
265 273 PythonQtClassInfo* classInfo = _knownQtClasses.value(obj->metaObject()->className());
@@ -268,8 +276,6 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
268 276 classInfo = _knownQtClasses.value(obj->metaObject()->className());
269 277 }
270 278 wrap = createNewPythonQtWrapper(obj, classInfo);
271 // insert destroyed handler
272 connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(wrappedObjectDestroyed(QObject*)));
273 279 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
274 280 } else {
275 281 Py_INCREF(wrap);
@@ -284,7 +290,7 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
284 290 Py_INCREF(Py_None);
285 291 return Py_None;
286 292 }
287 PythonQtWrapper* wrap = _wrappedObjects.value(ptr);
293 PythonQtWrapper* wrap = findWrapperAndRemoveUnused(ptr);
288 294 if (!wrap) {
289 295 PythonQtClassInfo* info = _knownQtClasses.value(name);
290 296 if (!info) {
@@ -304,8 +310,6 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
304 310 info = _knownQtClasses.value(qptr->metaObject()->className());
305 311 }
306 312 wrap = createNewPythonQtWrapper(qptr, info);
307 // insert destroyed handler
308 connect(qptr, SIGNAL(destroyed(QObject*)), this, SLOT(wrappedObjectDestroyed(QObject*)));
309 313 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
310 314 } else {
311 315 // maybe it is a PyObject, which we can return directly
@@ -360,7 +364,7 PythonQtWrapper* PythonQtPrivate::createNewPythonQtWrapper(QObject* obj, PythonQ
360 364 result = (PythonQtWrapper *)PythonQtWrapper_Type.tp_new(&PythonQtWrapper_Type,
361 365 NULL, NULL);
362 366
363 result->_obj = obj;
367 result->setQObject(obj);
364 368 result->_info = info;
365 369 result->_wrappedPtr = wrappedPtr;
366 370 result->_ownedByPythonQt = false;
@@ -369,6 +373,10 PythonQtWrapper* PythonQtPrivate::createNewPythonQtWrapper(QObject* obj, PythonQ
369 373 _wrappedObjects.insert(wrappedPtr, result);
370 374 } else {
371 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 381 return result;
374 382 }
@@ -400,8 +408,6 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
400 408 if (!r) {
401 409 r = new PythonQtSignalReceiver(obj);
402 410 _p->_signalReceivers.insert(obj, r);
403 // insert destroyed handler
404 connect(obj, SIGNAL(destroyed(QObject*)), _p ,SLOT(destroyedSignalEmitter(QObject*)));
405 411 }
406 412 return r;
407 413 }
@@ -540,6 +546,34 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
540 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 577 void PythonQt::addObject(PyObject* module, const QString& name, QObject* object)
544 578 {
545 579 PyModule_AddObject(module, name.toLatin1().data(), _p->wrapQObject(object));
@@ -763,6 +797,8 const QList<PythonQtConstructorHandler*>& PythonQt::constructorHandlers()
763 797 PythonQtPrivate::PythonQtPrivate()
764 798 {
765 799 _importInterface = NULL;
800 _noLongerWrappedCB = NULL;
801 _wrappedCB = NULL;
766 802 }
767 803
768 804 void PythonQtPrivate::addDecorators(QObject* o, bool instanceDeco, bool classDeco)
@@ -829,20 +865,9 QList<PythonQtSlotInfo*> PythonQtPrivate::getDecoratorSlots(const QByteArray& cl
829 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());
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);
870 _signalReceivers.remove(obj);
846 871 }
847 872
848 873 bool PythonQt::handleError()
@@ -892,6 +917,16 void PythonQt::stdErrRedirectCB(const QString& str)
892 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 932 static PyMethodDef PythonQtMethods[] = {
@@ -944,3 +979,33 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
944 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 66 class PythonQtCppWrapperFactory;
67 67 class PythonQtConstructorHandler;
68 68
69 typedef void PythonQtQObjectWrappedCB(QObject* object);
70 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
71
69 72 //! the main interface to the Python Qt binding, realized as a singleton
70 73 class PYTHONQT_EXPORT PythonQt : public QObject {
71 74
@@ -137,6 +140,22 public:
137 140 //! evaluates the given script code from file
138 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 159 //@{ Signal handlers
141 160
142 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 299 //! The error is currently just output to the python stderr, future version might implement better trace printing
281 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 310 signals:
284 311 //! emitted when python outputs something to stdout (and redirection is turned on)
285 312 void pythonStdOut(const QString& str);
@@ -313,6 +340,7 private:
313 340 ~PythonQt();
314 341
315 342 static PythonQt* _self;
343 static int _uniqueModuleCount;
316 344
317 345 PythonQtPrivate* _p;
318 346
@@ -331,7 +359,10 public:
331 359 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
332 360
333 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 367 //! wrap the given QObject into a Python object (or return existing wrapper!)
337 368 PyObject* wrapQObject(QObject* obj);
@@ -379,15 +410,14 public:
379 410 //! get the destructor slot for the given classname
380 411 PythonQtSlotInfo* getDestructorSlot(const QByteArray& className) { return _destructorSlots.value(className); }
381 412
382 protected slots:
383 //! called when a wrapped QObject is destroyed
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);
413 //! creates the new module from the given pycode
414 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
388 415
389 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 421 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
392 422 QHash<void* , PythonQtWrapper *> _wrappedObjects;
393 423
@@ -412,6 +442,9 private:
412 442 //! the importer interface (if set)
413 443 PythonQtImportFileInterface* _importInterface;
414 444
445 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
446 PythonQtQObjectWrappedCB* _wrappedCB;
447
415 448 QStringList _importIgnorePaths;
416 449
417 450 //! the cpp object wrapper factories
@@ -296,7 +296,8 return Py_None;
296 296 }
297 297 } else {
298 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 301 } else {
301 302 // not matching
302 303 }
@@ -487,6 +488,8 return Py_None;
487 488 if (ok) {
488 489 PythonQtValueStorage_ADD_VALUE(global_valueStorage, unsigned int, val, ptr);
489 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 733 // is this worth anything? we loose the knowledge of the cpp object type
731 734 v = qVariantFromValue(wrap->_wrappedPtr);
732 735 } else {
733 v = qVariantFromValue(wrap->_obj);
736 QObject* myObject = wrap->_obj;
737 v = qVariantFromValue(myObject);
734 738 }
735 739 return v;
736 740 } else if (val->ob_type==&PyDict_Type) {
@@ -998,7 +1002,8 bool PythonQtConv::ConvertPythonListToQListOfType(PyObject* obj, QList<void*>* l
998 1002 }
999 1003 } else {
1000 1004 if (wrap->_info->inherits(type)) {
1001 list->append((void*)wrap->_obj);
1005 QObject* myObject = wrap->_obj;
1006 list->append((void*)myObject);
1002 1007 } else {
1003 1008 result = false;
1004 1009 break;
@@ -620,11 +620,13 PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int ispackag
620 620 else {
621 621 // mlabDebugConst("MLABPython", "compiling source " << path);
622 622 code = compileSource(path, qdata);
623 if (code) {
623 624 // save a pyc file if possible
624 625 QDateTime time;
625 626 time = hasImporter?PythonQt::importInterface()->lastModifiedDate(path):QFileInfo(path).lastModified();
626 627 writeCompiledModule((PyCodeObject*)code, path+"c", time.toTime_t());
627 628 }
629 }
628 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 202 PyTypeObject PythonQtMetaObjectWrapper_Type = {
198 203 PyObject_HEAD_INIT(NULL)
199 204 0, /*ob_size*/
@@ -209,7 +214,7 PyTypeObject PythonQtMetaObjectWrapper_Type = {
209 214 0, /*tp_as_number*/
210 215 0, /*tp_as_sequence*/
211 216 0, /*tp_as_mapping*/
212 0, /*tp_hash */
217 (hashfunc)PythonQtMetaObjectWrapper_hash, /*tp_hash */
213 218 PythonQtMetaObjectWrapper_call, /*tp_call*/
214 219 0, /*tp_str*/
215 220 PythonQtMetaObjectWrapper_getattro, /*tp_getattro*/
@@ -45,12 +45,46
45 45 #include "PythonQtConversion.h"
46 46 #include <QMetaObject>
47 47 #include <QMetaMethod>
48 #include "funcobject.h"
48 49
49 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 79 const PythonQtMethodInfo* m = methodInfo();
52 // paramterCount includes return value:
80 // parameterCount includes return value:
53 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 89 PyObject* pargs = NULL;
56 90 if (count>1) {
@@ -97,6 +131,7 PythonQtSignalReceiver::PythonQtSignalReceiver(QObject* obj):PythonQtSignalRecei
97 131
98 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 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 80 static PyMethodDef PythonQtStdOutRedirect_methods[] = {
75 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 86 {NULL} /* Sentinel */
79 87 };
@@ -171,6 +171,18 QString qVariantToString(const QVariant& v) {
171 171 case QVariant::Time:
172 172 r = v.toTime().toString(Qt::ISODate);
173 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 186 //TODO: add more printing for other variant types
175 187 default:
176 188 r = v.toString();
@@ -182,6 +194,9 static PyObject * PythonQtVariantWrapper_str(PyObject * obj)
182 194 {
183 195 PythonQtVariantWrapper* wt = (PythonQtVariantWrapper*)obj;
184 196 QString val = qVariantToString(*wt->_variant);
197 if (val.isEmpty()) {
198 val = wt->_variant->typeName();
199 }
185 200 return PyString_FromFormat("%s", val.toLatin1().constData());
186 201 }
187 202
@@ -68,16 +68,26 static void PythonQtWrapper_dealloc(PythonQtWrapper* self)
68 68 // TODO: print a warning? we can not destroy that object
69 69 }
70 70 }
71 } else if (self->_obj) {
71 } else {
72 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 77 if (self->_ownedByPythonQt) {
75 78 if (!self->_obj->parent()) {
76 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 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 98 self = (PythonQtWrapper *)type->tp_alloc(type, 0);
89 99 if (self != NULL) {
90 100 self->_info = NULL;
91 self->_obj = NULL;
101 new (&self->_obj) QPointer<QObject>();
92 102 self->_wrappedPtr = NULL;
93 103 self->_ownedByPythonQt = false;
94 104 }
@@ -248,14 +258,15 static int PythonQtWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value
248 258 static PyObject * PythonQtWrapper_repr(PyObject * obj)
249 259 {
250 260 PythonQtWrapper* wt = (PythonQtWrapper*)obj;
261 QObject *qobj = wt->_obj;
251 262 if (wt->_wrappedPtr) {
252 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 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 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 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 315 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
292 316 static PyNumberMethods PythonQtWrapper_as_number = {
293 317 0, /* nb_add */
@@ -345,7 +369,7 PyTypeObject PythonQtWrapper_Type = {
345 369 &PythonQtWrapper_as_number, /*tp_as_number*/
346 370 0, /*tp_as_sequence*/
347 371 0, /*tp_as_mapping*/
348 0, /*tp_hash */
372 (hashfunc)PythonQtWrapper_hash, /*tp_hash */
349 373 0, /*tp_call*/
350 374 0, /*tp_str*/
351 375 PythonQtWrapper_getattro, /*tp_getattro*/
@@ -45,6 +45,7
45 45 #include <Python.h>
46 46
47 47 #include "PythonQtSystem.h"
48 #include <QPointer>
48 49
49 50 #include "structmember.h"
50 51 #include "methodobject.h"
@@ -61,8 +62,18 extern PYTHONQT_EXPORT PyTypeObject PythonQtWrapper_Type;
61 62 typedef struct {
62 63 PyObject_HEAD
63 64
65 //! set the QObject pointer
66 void setQObject(QObject* object) {
67 _obj = object;
68 _objPointerCopy = object;
69 }
70
64 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 77 //! optional C++ object Ptr that is wrapped by the above _obj
67 78 void* _wrappedPtr;
68 79
General Comments 0
You need to be logged in to leave comments. Login now