@@ -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 = |
|
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 = |
|
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:: |
|
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) |
|
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 |
|
|
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 |
|
|
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 |
|
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 |
|
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 |
|
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 |
|
|
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 |
|
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