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)
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)
844
869
{
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
+ }
0 commit comments