5252#include < pydebug.h>
5353
5454PythonQt* PythonQt::_self = NULL ;
55+ int PythonQt::_uniqueModuleCount = 0 ;
5556
5657
5758void PythonQt::init (int flags)
@@ -211,6 +212,13 @@ void PythonQt::registerClass(const QMetaObject* metaobject)
211212 _p->registerClass (metaobject);
212213}
213214
215+ void PythonQt::qObjectNoLongerWrappedCB (QObject* o)
216+ {
217+ if (_self->_p ->_noLongerWrappedCB ) {
218+ (*_self->_p ->_noLongerWrappedCB )(o);
219+ };
220+ }
221+
214222void PythonQtPrivate::registerClass (const QMetaObject* metaobject)
215223{
216224 // we register all classes in the hierarchy
@@ -259,7 +267,7 @@ PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
259267 Py_INCREF (Py_None);
260268 return Py_None;
261269 }
262- PythonQtWrapper* wrap = _wrappedObjects. value (obj);
270+ PythonQtWrapper* wrap = findWrapperAndRemoveUnused (obj);
263271 if (!wrap) {
264272 // smuggling it in...
265273 PythonQtClassInfo* classInfo = _knownQtClasses.value (obj->metaObject ()->className ());
@@ -268,8 +276,6 @@ PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
268276 classInfo = _knownQtClasses.value (obj->metaObject ()->className ());
269277 }
270278 wrap = createNewPythonQtWrapper (obj, classInfo);
271- // insert destroyed handler
272- connect (obj, SIGNAL (destroyed (QObject*)), this , SLOT (wrappedObjectDestroyed (QObject*)));
273279 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
274280 } else {
275281 Py_INCREF (wrap);
@@ -284,7 +290,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
284290 Py_INCREF (Py_None);
285291 return Py_None;
286292 }
287- PythonQtWrapper* wrap = _wrappedObjects. value (ptr);
293+ PythonQtWrapper* wrap = findWrapperAndRemoveUnused (ptr);
288294 if (!wrap) {
289295 PythonQtClassInfo* info = _knownQtClasses.value (name);
290296 if (!info) {
@@ -304,8 +310,6 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
304310 info = _knownQtClasses.value (qptr->metaObject ()->className ());
305311 }
306312 wrap = createNewPythonQtWrapper (qptr, info);
307- // insert destroyed handler
308- connect (qptr, SIGNAL (destroyed (QObject*)), this , SLOT (wrappedObjectDestroyed (QObject*)));
309313 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->_info->wrappedClassName().latin1());
310314 } else {
311315 // maybe it is a PyObject, which we can return directly
@@ -360,7 +364,7 @@ PythonQtWrapper* PythonQtPrivate::createNewPythonQtWrapper(QObject* obj, PythonQ
360364 result = (PythonQtWrapper *)PythonQtWrapper_Type.tp_new (&PythonQtWrapper_Type,
361365 NULL , NULL );
362366
363- result->_obj = obj;
367+ result->setQObject ( obj) ;
364368 result->_info = info;
365369 result->_wrappedPtr = wrappedPtr;
366370 result->_ownedByPythonQt = false ;
@@ -369,6 +373,10 @@ PythonQtWrapper* PythonQtPrivate::createNewPythonQtWrapper(QObject* obj, PythonQ
369373 _wrappedObjects.insert (wrappedPtr, result);
370374 } else {
371375 _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+ }
372380 }
373381 return result;
374382}
@@ -400,8 +408,6 @@ PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
400408 if (!r) {
401409 r = new PythonQtSignalReceiver (obj);
402410 _p->_signalReceivers .insert (obj, r);
403- // insert destroyed handler
404- connect (obj, SIGNAL (destroyed (QObject*)), _p ,SLOT (destroyedSignalEmitter (QObject*)));
405411 }
406412 return r;
407413}
@@ -540,6 +546,34 @@ PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
540546 return p;
541547}
542548
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+
543577void PythonQt::addObject (PyObject* module , const QString& name, QObject* object)
544578{
545579 PyModule_AddObject (module , name.toLatin1 ().data (), _p->wrapQObject (object));
@@ -763,6 +797,8 @@ const QList<PythonQtConstructorHandler*>& PythonQt::constructorHandlers()
763797PythonQtPrivate::PythonQtPrivate ()
764798{
765799 _importInterface = NULL ;
800+ _noLongerWrappedCB = NULL ;
801+ _wrappedCB = NULL ;
766802}
767803
768804void PythonQtPrivate::addDecorators (QObject* o, bool instanceDeco, bool classDeco)
@@ -829,20 +865,9 @@ QList<PythonQtSlotInfo*> PythonQtPrivate::getDecoratorSlots(const QByteArray& cl
829865 return _knownQtDecoratorSlots.values (className);
830866}
831867
832- void PythonQtPrivate::wrappedObjectDestroyed (QObject* obj)
833- {
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)
868+ void PythonQtPrivate::removeSignalEmitter (QObject* obj)
844869{
845- _signalReceivers.take (obj);
870+ _signalReceivers.remove (obj);
846871}
847872
848873bool PythonQt::handleError ()
@@ -892,6 +917,16 @@ void PythonQt::stdErrRedirectCB(const QString& str)
892917 emit PythonQt::self ()->pythonStdErr (str);
893918}
894919
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+
895930
896931
897932static PyMethodDef PythonQtMethods[] = {
@@ -944,3 +979,33 @@ PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
944979 return PyString_FromString (info->help ().toLatin1 ().data ());
945980 }
946981}
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+ }
0 commit comments