PythonQt.cpp
1193 lines
| 39.9 KiB
| text/x-c
|
CppLexer
/ src / PythonQt.cpp
ezust
|
r0 | /* | ||
* | ||||
* Copyright (C) 2006 MeVis Research GmbH All Rights Reserved. | ||||
* | ||||
* This library is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU Lesser General Public | ||||
* License as published by the Free Software Foundation; either | ||||
* version 2.1 of the License, or (at your option) any later version. | ||||
* | ||||
* This library is distributed in the hope that it will be useful, | ||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
* Lesser General Public License for more details. | ||||
* | ||||
* Further, this software is distributed without any warranty that it is | ||||
* free of the rightful claim of any third person regarding infringement | ||||
* or the like. Any license provided herein, whether implied or | ||||
* otherwise, applies only to this software file. Patent licenses, if | ||||
* any, provided herein do not apply to combinations of this program with | ||||
* other software, or any other product whatsoever. | ||||
* | ||||
* You should have received a copy of the GNU Lesser General Public | ||||
* License along with this library; if not, write to the Free Software | ||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
* | ||||
* Contact information: MeVis Research GmbH, Universitaetsallee 29, | ||||
* 28359 Bremen, Germany or: | ||||
* | ||||
* http://www.mevis.de | ||||
* | ||||
*/ | ||||
//---------------------------------------------------------------------------------- | ||||
/*! | ||||
// \file PythonQt.cpp | ||||
// \author Florian Link | ||||
// \author Last changed by $Author: florian $ | ||||
// \date 2006-05 | ||||
*/ | ||||
//---------------------------------------------------------------------------------- | ||||
#include "PythonQt.h" | ||||
#include "PythonQtImporter.h" | ||||
#include "PythonQtClassInfo.h" | ||||
#include "PythonQtMethodInfo.h" | ||||
#include "PythonQtSignalReceiver.h" | ||||
#include "PythonQtConversion.h" | ||||
#include "PythonQtStdOut.h" | ||||
#include "PythonQtCppWrapperFactory.h" | ||||
#include "PythonQtVariants.h" | ||||
#include "PythonQtStdDecorators.h" | ||||
florianlink
|
r8 | #include "PythonQtQFileImporter.h" | ||
ezust
|
r0 | #include <pydebug.h> | ||
florianlink
|
r10 | #include <vector> | ||
ezust
|
r0 | |||
PythonQt* PythonQt::_self = NULL; | ||||
florianlink
|
r4 | int PythonQt::_uniqueModuleCount = 0; | ||
ezust
|
r0 | |||
void PythonQt::init(int flags) | ||||
{ | ||||
if (!_self) { | ||||
_self = new PythonQt(flags); | ||||
} | ||||
PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>"); | ||||
qRegisterMetaType<QList<QObject*> >("QList<void*>"); | ||||
florianlink
|
r10 | |||
PythonQtRegisterToolClassesTemplateConverter(int); | ||||
PythonQtRegisterToolClassesTemplateConverter(float); | ||||
PythonQtRegisterToolClassesTemplateConverter(double); | ||||
// TODO: which other POD types should be available for QList etc. | ||||
ezust
|
r0 | |||
PythonQt::self()->addDecorators(new PythonQtStdDecorators()); | ||||
florianlink
|
r10 | |||
PythonQt::self()->registerCPPClass("Qt", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_Qt>); | ||||
PythonQt::self()->registerCPPClass("QBitArray", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QBitArray>); | ||||
PythonQt::self()->registerCPPClass("QDate", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDate>); | ||||
PythonQt::self()->registerCPPClass("QTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QTime>); | ||||
PythonQt::self()->registerCPPClass("QDateTime", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QDateTime>); | ||||
PythonQt::self()->registerCPPClass("QUrl", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QUrl>); | ||||
PythonQt::self()->registerCPPClass("QLocale", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLocale>); | ||||
PythonQt::self()->registerCPPClass("QRect", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRect>); | ||||
PythonQt::self()->registerCPPClass("QRectF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRectF>); | ||||
PythonQt::self()->registerCPPClass("QSize", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSize>); | ||||
PythonQt::self()->registerCPPClass("QSizeF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QSizeF>); | ||||
PythonQt::self()->registerCPPClass("QLine", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLine>); | ||||
PythonQt::self()->registerCPPClass("QLineF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QLineF>); | ||||
PythonQt::self()->registerCPPClass("QPoint", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPoint>); | ||||
PythonQt::self()->registerCPPClass("QPointF", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QPointF>); | ||||
PythonQt::self()->registerCPPClass("QRegExp", "", "QtCore", PythonQtCreateObject<PythonQtWrapper_QRegExp>); | ||||
PythonQtRegisterToolClassesTemplateConverter(QDate); | ||||
PythonQtRegisterToolClassesTemplateConverter(QTime); | ||||
PythonQtRegisterToolClassesTemplateConverter(QDateTime); | ||||
PythonQtRegisterToolClassesTemplateConverter(QUrl); | ||||
PythonQtRegisterToolClassesTemplateConverter(QLocale); | ||||
PythonQtRegisterToolClassesTemplateConverter(QRect); | ||||
PythonQtRegisterToolClassesTemplateConverter(QRectF); | ||||
PythonQtRegisterToolClassesTemplateConverter(QSize); | ||||
PythonQtRegisterToolClassesTemplateConverter(QSizeF); | ||||
PythonQtRegisterToolClassesTemplateConverter(QLine); | ||||
PythonQtRegisterToolClassesTemplateConverter(QLineF); | ||||
PythonQtRegisterToolClassesTemplateConverter(QPoint); | ||||
PythonQtRegisterToolClassesTemplateConverter(QPointF); | ||||
PythonQtRegisterToolClassesTemplateConverter(QRegExp); | ||||
ezust
|
r0 | |||
florianlink
|
r10 | PythonQt::self()->registerCPPClass("QFont", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QFont>); | ||
PythonQt::self()->registerCPPClass("QPixmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPixmap>); | ||||
PythonQt::self()->registerCPPClass("QBrush", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBrush>); | ||||
PythonQt::self()->registerCPPClass("QColor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QColor>); | ||||
PythonQt::self()->registerCPPClass("QPalette", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPalette>); | ||||
PythonQt::self()->registerCPPClass("QIcon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QIcon>); | ||||
PythonQt::self()->registerCPPClass("QImage", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QImage>); | ||||
PythonQt::self()->registerCPPClass("QPolygon", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPolygon>); | ||||
PythonQt::self()->registerCPPClass("QRegion", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QRegion>); | ||||
PythonQt::self()->registerCPPClass("QBitmap", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QBitmap>); | ||||
PythonQt::self()->registerCPPClass("QCursor", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QCursor>); | ||||
PythonQt::self()->registerCPPClass("QSizePolicy", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QSizePolicy>); | ||||
PythonQt::self()->registerCPPClass("QKeySequence", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QKeySequence>); | ||||
PythonQt::self()->registerCPPClass("QPen", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QPen>); | ||||
PythonQt::self()->registerCPPClass("QTextLength", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextLength>); | ||||
PythonQt::self()->registerCPPClass("QTextFormat", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QTextFormat>); | ||||
PythonQt::self()->registerCPPClass("QMatrix", "", "QtGui", PythonQtCreateObject<PythonQtWrapper_QMatrix>); | ||||
PythonQtRegisterToolClassesTemplateConverter(QFont); | ||||
PythonQtRegisterToolClassesTemplateConverter(QPixmap); | ||||
PythonQtRegisterToolClassesTemplateConverter(QBrush); | ||||
PythonQtRegisterToolClassesTemplateConverter(QColor); | ||||
PythonQtRegisterToolClassesTemplateConverter(QPalette); | ||||
PythonQtRegisterToolClassesTemplateConverter(QIcon); | ||||
PythonQtRegisterToolClassesTemplateConverter(QImage); | ||||
PythonQtRegisterToolClassesTemplateConverter(QPolygon); | ||||
PythonQtRegisterToolClassesTemplateConverter(QRegion); | ||||
PythonQtRegisterToolClassesTemplateConverter(QBitmap); | ||||
PythonQtRegisterToolClassesTemplateConverter(QCursor); | ||||
PythonQtRegisterToolClassesTemplateConverter(QSizePolicy); | ||||
PythonQtRegisterToolClassesTemplateConverter(QKeySequence); | ||||
PythonQtRegisterToolClassesTemplateConverter(QPen); | ||||
PythonQtRegisterToolClassesTemplateConverter(QTextLength); | ||||
PythonQtRegisterToolClassesTemplateConverter(QTextFormat); | ||||
PythonQtRegisterToolClassesTemplateConverter(QMatrix); | ||||
ezust
|
r0 | } | ||
void PythonQt::cleanup() | ||||
{ | ||||
if (_self) { | ||||
delete _self; | ||||
_self = NULL; | ||||
} | ||||
} | ||||
PythonQt::PythonQt(int flags) | ||||
{ | ||||
_p = new PythonQtPrivate; | ||||
_p->_initFlags = flags; | ||||
_p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr"); | ||||
Py_SetProgramName("PythonQt"); | ||||
if (flags & IgnoreSiteModule) { | ||||
// this prevents the automatic importing of Python site files | ||||
Py_NoSiteFlag = 1; | ||||
} | ||||
Py_Initialize(); | ||||
// add our own python object types for qt object slots | ||||
if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) { | ||||
std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl; | ||||
} | ||||
Py_INCREF(&PythonQtSlotFunction_Type); | ||||
florianlink
|
r18 | // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it | ||
PythonQtClassWrapper_Type.tp_base = &PyType_Type; | ||||
// add our own python object types for classes | ||||
florianlink
|
r16 | if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) { | ||
std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl; | ||||
ezust
|
r0 | } | ||
florianlink
|
r16 | Py_INCREF(&PythonQtClassWrapper_Type); | ||
florianlink
|
r18 | |||
// add our own python object types for CPP instances | ||||
if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) { | ||||
PythonQt::handleError(); | ||||
std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl; | ||||
} | ||||
Py_INCREF(&PythonQtInstanceWrapper_Type); | ||||
ezust
|
r0 | |||
// add our own python object types for redirection of stdout | ||||
if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) { | ||||
std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl; | ||||
} | ||||
Py_INCREF(&PythonQtStdOutRedirectType); | ||||
initPythonQtModule(flags & RedirectStdOut); | ||||
} | ||||
PythonQt::~PythonQt() { | ||||
delete _p; | ||||
_p = NULL; | ||||
} | ||||
PythonQtPrivate::~PythonQtPrivate() { | ||||
florianlink
|
r8 | delete _defaultImporter; | ||
_defaultImporter = NULL; | ||||
florianlink
|
r24 | |||
florianlink
|
r8 | { | ||
florianlink
|
r24 | QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos); | ||
ezust
|
r0 | while (i.hasNext()) { | ||
delete i.next().value(); | ||||
} | ||||
} | ||||
PythonQtConv::global_valueStorage.clear(); | ||||
PythonQtConv::global_ptrStorage.clear(); | ||||
PythonQtConv::global_variantStorage.clear(); | ||||
PythonQtMethodInfo::cleanupCachedMethodInfos(); | ||||
} | ||||
PythonQtImportFileInterface* PythonQt::importInterface() | ||||
{ | ||||
florianlink
|
r8 | return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter; | ||
ezust
|
r0 | } | ||
florianlink
|
r4 | void PythonQt::qObjectNoLongerWrappedCB(QObject* o) | ||
{ | ||||
if (_self->_p->_noLongerWrappedCB) { | ||||
(*_self->_p->_noLongerWrappedCB)(o); | ||||
}; | ||||
} | ||||
florianlink
|
r24 | void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell) | ||
florianlink
|
r10 | { | ||
florianlink
|
r24 | _p->registerClass(metaobject, package, wrapperCreator, shell); | ||
florianlink
|
r10 | } | ||
florianlink
|
r24 | void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell) | ||
ezust
|
r0 | { | ||
// we register all classes in the hierarchy | ||||
const QMetaObject* m = metaobject; | ||||
florianlink
|
r10 | bool first = true; | ||
ezust
|
r0 | while (m) { | ||
florianlink
|
r24 | PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className()); | ||
if (!info->pythonQtClassWrapper()) { | ||||
info->setupQObject(m); | ||||
createPythonQtClassWrapper(info, package); | ||||
if (m->superClass()) { | ||||
PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className()); | ||||
info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo)); | ||||
} | ||||
florianlink
|
r10 | } | ||
if (first) { | ||||
first = false; | ||||
if (wrapperCreator) { | ||||
info->setDecoratorProvider(wrapperCreator); | ||||
} | ||||
florianlink
|
r24 | if (shell) { | ||
info->setShellSetInstanceWrapperCB(shell); | ||||
} | ||||
ezust
|
r0 | } | ||
m = m->superClass(); | ||||
} | ||||
} | ||||
florianlink
|
r24 | void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) | ||
florianlink
|
r18 | { | ||
florianlink
|
r19 | PyObject* pack = packageByName(package); | ||
florianlink
|
r18 | PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, package); | ||
florianlink
|
r24 | PyModule_AddObject(pack, info->className(), pyobj); | ||
florianlink
|
r18 | if (package && strncmp(package,"Qt",2)==0) { | ||
florianlink
|
r19 | // since PyModule_AddObject steals the reference, we need a incref once more... | ||
Py_INCREF(pyobj); | ||||
florianlink
|
r18 | // put all qt objects into Qt as well | ||
florianlink
|
r24 | PyModule_AddObject(packageByName("Qt"), info->className(), pyobj); | ||
florianlink
|
r18 | } | ||
info->setPythonQtClassWrapper(pyobj); | ||||
} | ||||
ezust
|
r0 | PyObject* PythonQtPrivate::wrapQObject(QObject* obj) | ||
{ | ||||
if (!obj) { | ||||
Py_INCREF(Py_None); | ||||
return Py_None; | ||||
} | ||||
florianlink
|
r16 | PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj); | ||
ezust
|
r0 | if (!wrap) { | ||
// smuggling it in... | ||||
florianlink
|
r24 | PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className()); | ||
if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) { | ||||
ezust
|
r0 | registerClass(obj->metaObject()); | ||
florianlink
|
r24 | classInfo = _knownClassInfos.value(obj->metaObject()->className()); | ||
ezust
|
r0 | } | ||
florianlink
|
r16 | wrap = createNewPythonQtInstanceWrapper(obj, classInfo); | ||
florianlink
|
r18 | // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1()); | ||
ezust
|
r0 | } else { | ||
Py_INCREF(wrap); | ||||
florianlink
|
r18 | // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1()); | ||
ezust
|
r0 | } | ||
return (PyObject*)wrap; | ||||
} | ||||
PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name) | ||||
{ | ||||
if (!ptr) { | ||||
Py_INCREF(Py_None); | ||||
return Py_None; | ||||
} | ||||
florianlink
|
r24 | |||
florianlink
|
r16 | PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr); | ||
ezust
|
r0 | if (!wrap) { | ||
florianlink
|
r24 | PythonQtClassInfo* info = _knownClassInfos.value(name); | ||
ezust
|
r0 | if (!info) { | ||
florianlink
|
r24 | // maybe it is a PyObject, which we can return directly | ||
if (name == "PyObject") { | ||||
PyObject* p = (PyObject*)ptr; | ||||
Py_INCREF(p); | ||||
return p; | ||||
} | ||||
ezust
|
r0 | // we do not know the metaobject yet, but we might know it by it's name: | ||
if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) { | ||||
// yes, we know it, so we can convert to QObject | ||||
QObject* qptr = (QObject*)ptr; | ||||
registerClass(qptr->metaObject()); | ||||
florianlink
|
r24 | info = _knownClassInfos.value(qptr->metaObject()->className()); | ||
ezust
|
r0 | } | ||
} | ||||
florianlink
|
r24 | if (info && info->isQObject()) { | ||
ezust
|
r0 | QObject* qptr = (QObject*)ptr; | ||
// if the object is a derived object, we want to switch the class info to the one of the derived class: | ||||
if (name!=(qptr->metaObject()->className())) { | ||||
registerClass(qptr->metaObject()); | ||||
florianlink
|
r24 | info = _knownClassInfos.value(qptr->metaObject()->className()); | ||
ezust
|
r0 | } | ||
florianlink
|
r16 | wrap = createNewPythonQtInstanceWrapper(qptr, info); | ||
florianlink
|
r18 | // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1()); | ||
florianlink
|
r24 | return (PyObject*)wrap; | ||
} | ||||
// not a known QObject, so try our wrapper factory: | ||||
QObject* wrapper = NULL; | ||||
for (int i=0; i<_cppWrapperFactories.size(); i++) { | ||||
wrapper = _cppWrapperFactories.at(i)->create(name, ptr); | ||||
if (wrapper) { | ||||
break; | ||||
ezust
|
r0 | } | ||
} | ||||
florianlink
|
r26 | |||
if (info) { | ||||
// try to downcast in the class hierarchy, which will modify info and ptr if it is successfull | ||||
ptr = info->castDownIfPossible(ptr, &info); | ||||
} | ||||
florianlink
|
r24 | if (!info || info->pythonQtClassWrapper()==NULL) { | ||
// still unknown, register as CPP class | ||||
registerCPPClass(name.constData()); | ||||
info = _knownClassInfos.value(name); | ||||
} | ||||
if (wrapper && (info->metaObject() != wrapper->metaObject())) { | ||||
// if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again! | ||||
info->setMetaObject(wrapper->metaObject()); | ||||
} | ||||
wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr); | ||||
// mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1()); | ||||
ezust
|
r0 | } else { | ||
Py_INCREF(wrap); | ||||
florianlink
|
r18 | //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1()); | ||
ezust
|
r0 | } | ||
return (PyObject*)wrap; | ||||
} | ||||
florianlink
|
r18 | PyObject* PythonQtPrivate::dummyTuple() { | ||
static PyObject* dummyTuple = NULL; | ||||
if (dummyTuple==NULL) { | ||||
dummyTuple = PyTuple_New(1); | ||||
PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy")); | ||||
} | ||||
return dummyTuple; | ||||
} | ||||
ezust
|
r0 | |||
florianlink
|
r16 | PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) { | ||
florianlink
|
r18 | // call the associated class type to create a new instance... | ||
PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL); | ||||
ezust
|
r0 | |||
florianlink
|
r4 | result->setQObject(obj); | ||
ezust
|
r0 | result->_wrappedPtr = wrappedPtr; | ||
result->_ownedByPythonQt = false; | ||||
florianlink
|
r10 | result->_useQMetaTypeDestroy = false; | ||
ezust
|
r0 | if (wrappedPtr) { | ||
_wrappedObjects.insert(wrappedPtr, result); | ||||
} else { | ||||
_wrappedObjects.insert(obj, result); | ||||
florianlink
|
r4 | if (obj->parent()== NULL && _wrappedCB) { | ||
// tell someone who is interested that the qobject is wrapped the first time, if it has no parent | ||||
(*_wrappedCB)(obj); | ||||
} | ||||
ezust
|
r0 | } | ||
return result; | ||||
} | ||||
florianlink
|
r18 | PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package) { | ||
florianlink
|
r16 | PythonQtClassWrapper* result; | ||
florianlink
|
r18 | |||
PyObject* className = PyString_FromString(info->className()); | ||||
PyObject* baseClasses = PyTuple_New(1); | ||||
PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type); | ||||
PyObject* typeDict = PyDict_New(); | ||||
QByteArray moduleName("PythonQt"); | ||||
if (package && strcmp(package, "")!=0) { | ||||
moduleName += "."; | ||||
moduleName += package; | ||||
} | ||||
PyDict_SetItemString(typeDict, "__module__", PyString_FromString(moduleName.constData())); | ||||
PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict); | ||||
// set the class info so that PythonQtClassWrapper_new can read it | ||||
_currentClassInfoForClassWrapperCreation = info; | ||||
// create the new type object by calling the type | ||||
result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL); | ||||
Py_DECREF(baseClasses); | ||||
Py_DECREF(typeDict); | ||||
Py_DECREF(args); | ||||
Py_DECREF(className); | ||||
ezust
|
r0 | return result; | ||
} | ||||
florianlink
|
r56 | PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue) | ||
{ | ||||
PyObject* args = Py_BuildValue("(i)", enumValue); | ||||
PyObject* result = PyObject_Call(enumType, args, NULL); | ||||
Py_DECREF(args); | ||||
return result; | ||||
} | ||||
florianlink
|
r51 | PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) { | ||
PyObject* result; | ||||
PyObject* className = PyString_FromString(enumName); | ||||
PyObject* baseClasses = PyTuple_New(1); | ||||
PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type); | ||||
PyObject* module = PyObject_GetAttrString(parentObject, "__module__"); | ||||
PyObject* typeDict = PyDict_New(); | ||||
PyDict_SetItemString(typeDict, "__module__", module); | ||||
PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict); | ||||
// create the new int derived type object by calling the core type | ||||
result = PyObject_Call((PyObject *)&PyType_Type, args, NULL); | ||||
Py_DECREF(baseClasses); | ||||
Py_DECREF(typeDict); | ||||
Py_DECREF(args); | ||||
Py_DECREF(className); | ||||
return result; | ||||
} | ||||
ezust
|
r0 | |||
PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj) | ||||
{ | ||||
PythonQtSignalReceiver* r = _p->_signalReceivers[obj]; | ||||
if (!r) { | ||||
r = new PythonQtSignalReceiver(obj); | ||||
_p->_signalReceivers.insert(obj, r); | ||||
} | ||||
return r; | ||||
} | ||||
bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname) | ||||
{ | ||||
bool flag = false; | ||||
PythonQtObjectPtr callable = lookupCallable(module, objectname); | ||||
if (callable) { | ||||
PythonQtSignalReceiver* r = getSignalReceiver(obj); | ||||
flag = r->addSignalHandler(signal, callable); | ||||
if (!flag) { | ||||
// signal not found | ||||
} | ||||
} else { | ||||
// callable not found | ||||
} | ||||
return flag; | ||||
} | ||||
bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver) | ||||
{ | ||||
bool flag = false; | ||||
PythonQtSignalReceiver* r = getSignalReceiver(obj); | ||||
if (r) { | ||||
flag = r->addSignalHandler(signal, receiver); | ||||
} | ||||
return flag; | ||||
} | ||||
bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname) | ||||
{ | ||||
bool flag = false; | ||||
PythonQtObjectPtr callable = lookupCallable(module, objectname); | ||||
if (callable) { | ||||
PythonQtSignalReceiver* r = _p->_signalReceivers[obj]; | ||||
if (r) { | ||||
flag = r->removeSignalHandler(signal, callable); | ||||
} | ||||
} else { | ||||
// callable not found | ||||
} | ||||
return flag; | ||||
} | ||||
bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver) | ||||
{ | ||||
bool flag = false; | ||||
PythonQtSignalReceiver* r = _p->_signalReceivers[obj]; | ||||
if (r) { | ||||
flag = r->removeSignalHandler(signal, receiver); | ||||
} | ||||
return flag; | ||||
} | ||||
PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name) | ||||
{ | ||||
PythonQtObjectPtr p = lookupObject(module, name); | ||||
if (p) { | ||||
if (PyCallable_Check(p)) { | ||||
return p; | ||||
} | ||||
} | ||||
PyErr_Clear(); | ||||
return NULL; | ||||
} | ||||
PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name) | ||||
{ | ||||
QStringList l = name.split('.'); | ||||
PythonQtObjectPtr p = module; | ||||
PythonQtObjectPtr prev; | ||||
QString s; | ||||
QByteArray b; | ||||
for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) { | ||||
prev = p; | ||||
b = (*i).toLatin1(); | ||||
florianlink
|
r25 | if (PyDict_Check(p)) { | ||
p = PyDict_GetItemString(p, b.data()); | ||||
} else { | ||||
p.setNewRef(PyObject_GetAttrString(p, b.data())); | ||||
} | ||||
ezust
|
r0 | } | ||
PyErr_Clear(); | ||||
return p; | ||||
} | ||||
PythonQtObjectPtr PythonQt::getMainModule() { | ||||
//both borrowed | ||||
PythonQtObjectPtr dict = PyImport_GetModuleDict(); | ||||
return PyDict_GetItemString(dict, "__main__"); | ||||
} | ||||
florianlink
|
r25 | QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) { | ||
ezust
|
r0 | QVariant result; | ||
if (pycode) { | ||||
florianlink
|
r25 | PyObject* dict = NULL; | ||
if (PyModule_Check(object)) { | ||||
dict = PyModule_GetDict(object); | ||||
} else if (PyDict_Check(object)) { | ||||
dict = object; | ||||
} | ||||
PyObject* r = NULL; | ||||
if (dict) { | ||||
r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict); | ||||
} | ||||
ezust
|
r0 | if (r) { | ||
result = PythonQtConv::PyObjToQVariant(r); | ||||
Py_DECREF(r); | ||||
} else { | ||||
handleError(); | ||||
} | ||||
} else { | ||||
handleError(); | ||||
} | ||||
return result; | ||||
} | ||||
florianlink
|
r25 | QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start) | ||
ezust
|
r0 | { | ||
QVariant result; | ||||
PythonQtObjectPtr p; | ||||
florianlink
|
r25 | PyObject* dict = NULL; | ||
if (PyModule_Check(object)) { | ||||
dict = PyModule_GetDict(object); | ||||
} else if (PyDict_Check(object)) { | ||||
dict = object; | ||||
} | ||||
if (dict) { | ||||
p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict)); | ||||
} | ||||
ezust
|
r0 | if (p) { | ||
result = PythonQtConv::PyObjToQVariant(p); | ||||
} else { | ||||
handleError(); | ||||
} | ||||
return result; | ||||
} | ||||
void PythonQt::evalFile(PyObject* module, const QString& filename) | ||||
{ | ||||
PythonQtObjectPtr code = parseFile(filename); | ||||
if (code) { | ||||
evalCode(module, code); | ||||
} else { | ||||
handleError(); | ||||
} | ||||
} | ||||
PythonQtObjectPtr PythonQt::parseFile(const QString& filename) | ||||
{ | ||||
PythonQtObjectPtr p; | ||||
p.setNewRef(PythonQtImport::getCodeFromPyc(filename)); | ||||
if (!p) { | ||||
handleError(); | ||||
} | ||||
return p; | ||||
} | ||||
florianlink
|
r4 | PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename) | ||
{ | ||||
PythonQtObjectPtr code = parseFile(filename); | ||||
PythonQtObjectPtr module = _p->createModule(name, code); | ||||
return module; | ||||
} | ||||
PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script) | ||||
{ | ||||
PyErr_Clear(); | ||||
QString scriptCode = script; | ||||
if (scriptCode.isEmpty()) { | ||||
// we always need at least a linefeed | ||||
scriptCode = "\n"; | ||||
} | ||||
PythonQtObjectPtr pycode; | ||||
pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input)); | ||||
PythonQtObjectPtr module = _p->createModule(name, pycode); | ||||
return module; | ||||
} | ||||
PythonQtObjectPtr PythonQt::createUniqueModule() | ||||
{ | ||||
static QString pyQtStr("PythonQt_module"); | ||||
QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++); | ||||
return createModuleFromScript(moduleName); | ||||
} | ||||
florianlink
|
r25 | void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject) | ||
ezust
|
r0 | { | ||
florianlink
|
r25 | if (PyModule_Check(object)) { | ||
PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject)); | ||||
} else if (PyDict_Check(object)) { | ||||
PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject)); | ||||
} else { | ||||
PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject)); | ||||
} | ||||
ezust
|
r0 | } | ||
florianlink
|
r25 | void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v) | ||
ezust
|
r0 | { | ||
florianlink
|
r25 | if (PyModule_Check(object)) { | ||
PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v)); | ||||
} else if (PyDict_Check(object)) { | ||||
PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v)); | ||||
} else { | ||||
PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v)); | ||||
} | ||||
ezust
|
r0 | } | ||
florianlink
|
r25 | void PythonQt::removeVariable(PyObject* object, const QString& name) | ||
ezust
|
r0 | { | ||
florianlink
|
r25 | if (PyDict_Check(object)) { | ||
PyDict_DelItemString(object, name.toLatin1().data()); | ||||
} else { | ||||
PyObject_DelAttrString(object, name.toLatin1().data()); | ||||
} | ||||
ezust
|
r0 | } | ||
florianlink
|
r25 | QVariant PythonQt::getVariable(PyObject* object, const QString& objectname) | ||
ezust
|
r0 | { | ||
QVariant result; | ||||
florianlink
|
r25 | PythonQtObjectPtr obj = lookupObject(object, objectname); | ||
ezust
|
r0 | if (obj) { | ||
result = PythonQtConv::PyObjToQVariant(obj); | ||||
} | ||||
return result; | ||||
} | ||||
QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type) | ||||
{ | ||||
QStringList results; | ||||
PythonQtObjectPtr object; | ||||
if (objectname.isEmpty()) { | ||||
object = module; | ||||
} else { | ||||
object = lookupObject(module, objectname); | ||||
if (!object && type == CallOverloads) { | ||||
PyObject* dict = lookupObject(module, "__builtins__"); | ||||
if (dict) { | ||||
object = PyDict_GetItemString(dict, objectname.toLatin1().constData()); | ||||
} | ||||
} | ||||
} | ||||
if (object) { | ||||
if (type == CallOverloads) { | ||||
if (PythonQtSlotFunction_Check(object)) { | ||||
PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object(); | ||||
PythonQtSlotInfo* info = o->m_ml; | ||||
while (info) { | ||||
florianlink
|
r23 | results << info->fullSignature(); | ||
ezust
|
r0 | info = info->nextInfo(); | ||
} | ||||
florianlink
|
r16 | } else if (object->ob_type == &PythonQtClassWrapper_Type) { | ||
PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object(); | ||||
florianlink
|
r18 | PythonQtSlotInfo* info = o->classInfo()->constructors(); | ||
ezust
|
r0 | |||
while (info) { | ||||
florianlink
|
r23 | results << info->fullSignature(); | ||
ezust
|
r0 | info = info->nextInfo(); | ||
} | ||||
} else { | ||||
//TODO: use pydoc! | ||||
PyObject* doc = PyObject_GetAttrString(object, "__doc__"); | ||||
if (doc) { | ||||
results << PyString_AsString(doc); | ||||
Py_DECREF(doc); | ||||
} | ||||
} | ||||
} else { | ||||
florianlink
|
r25 | PyObject* keys = NULL; | ||
bool isDict = false; | ||||
if (PyDict_Check(object)) { | ||||
keys = PyDict_Keys(object); | ||||
isDict = true; | ||||
} else { | ||||
keys = PyObject_Dir(object); | ||||
} | ||||
ezust
|
r0 | if (keys) { | ||
int count = PyList_Size(keys); | ||||
PyObject* key; | ||||
PyObject* value; | ||||
QString keystr; | ||||
for (int i = 0;i<count;i++) { | ||||
key = PyList_GetItem(keys,i); | ||||
florianlink
|
r25 | if (isDict) { | ||
value = PyDict_GetItem(object, key); | ||||
Py_INCREF(value); | ||||
} else { | ||||
value = PyObject_GetAttr(object, key); | ||||
} | ||||
ezust
|
r0 | if (!value) continue; | ||
keystr = PyString_AsString(key); | ||||
static const QString underscoreStr("__tmp"); | ||||
if (!keystr.startsWith(underscoreStr)) { | ||||
switch (type) { | ||||
case Anything: | ||||
results << keystr; | ||||
break; | ||||
case Class: | ||||
if (value->ob_type == &PyClass_Type) { | ||||
results << keystr; | ||||
} | ||||
break; | ||||
case Variable: | ||||
if (value->ob_type != &PyClass_Type | ||||
&& value->ob_type != &PyCFunction_Type | ||||
&& value->ob_type != &PyFunction_Type | ||||
&& value->ob_type != &PyModule_Type | ||||
) { | ||||
results << keystr; | ||||
} | ||||
break; | ||||
case Function: | ||||
if (value->ob_type == &PyFunction_Type || | ||||
value->ob_type == &PyMethod_Type | ||||
) { | ||||
results << keystr; | ||||
} | ||||
break; | ||||
case Module: | ||||
if (value->ob_type == &PyModule_Type) { | ||||
results << keystr; | ||||
} | ||||
break; | ||||
default: | ||||
std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl; | ||||
} | ||||
} | ||||
Py_DECREF(value); | ||||
} | ||||
Py_DECREF(keys); | ||||
} | ||||
} | ||||
} | ||||
return results; | ||||
} | ||||
florianlink
|
r36 | QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args) | ||
{ | ||||
PythonQtObjectPtr callable = lookupCallable(object, name); | ||||
if (callable) { | ||||
return call(callable, args); | ||||
} else { | ||||
return QVariant(); | ||||
} | ||||
} | ||||
QVariant PythonQt::call(PyObject* callable, const QVariantList& args) | ||||
ezust
|
r0 | { | ||
QVariant r; | ||||
if (callable) { | ||||
PythonQtObjectPtr pargs; | ||||
int count = args.size(); | ||||
if (count>0) { | ||||
pargs.setNewRef(PyTuple_New(count)); | ||||
} | ||||
bool err = false; | ||||
// transform QVariants to Python | ||||
for (int i = 0; i < count; i++) { | ||||
PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i)); | ||||
if (arg) { | ||||
// steals reference, no unref | ||||
PyTuple_SetItem(pargs, i,arg); | ||||
} else { | ||||
err = true; | ||||
break; | ||||
} | ||||
} | ||||
if (!err) { | ||||
PyErr_Clear(); | ||||
PythonQtObjectPtr result; | ||||
result.setNewRef(PyObject_CallObject(callable, pargs)); | ||||
if (result) { | ||||
// ok | ||||
r = PythonQtConv::PyObjToQVariant(result); | ||||
} else { | ||||
PythonQt::self()->handleError(); | ||||
} | ||||
} | ||||
} | ||||
return r; | ||||
} | ||||
void PythonQt::addInstanceDecorators(QObject* o) | ||||
{ | ||||
florianlink
|
r10 | _p->addDecorators(o, PythonQtPrivate::InstanceDecorator); | ||
ezust
|
r0 | } | ||
void PythonQt::addClassDecorators(QObject* o) | ||||
{ | ||||
florianlink
|
r10 | _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator); | ||
ezust
|
r0 | } | ||
void PythonQt::addDecorators(QObject* o) | ||||
{ | ||||
florianlink
|
r10 | _p->addDecorators(o, PythonQtPrivate::AllDecorators); | ||
ezust
|
r0 | } | ||
void PythonQt::registerQObjectClassNames(const QStringList& names) | ||||
{ | ||||
_p->registerQObjectClassNames(names); | ||||
} | ||||
void PythonQt::setImporter(PythonQtImportFileInterface* importInterface) | ||||
{ | ||||
florianlink
|
r8 | PythonQtImport::init(); | ||
_p->_importInterface = importInterface; | ||||
ezust
|
r0 | } | ||
void PythonQt::setImporterIgnorePaths(const QStringList& paths) | ||||
{ | ||||
_p->_importIgnorePaths = paths; | ||||
} | ||||
const QStringList& PythonQt::getImporterIgnorePaths() | ||||
{ | ||||
return _p->_importIgnorePaths; | ||||
} | ||||
void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory) | ||||
{ | ||||
_p->_cppWrapperFactories.append(factory); | ||||
} | ||||
//--------------------------------------------------------------------------------------------------- | ||||
PythonQtPrivate::PythonQtPrivate() | ||||
{ | ||||
_importInterface = NULL; | ||||
florianlink
|
r8 | _defaultImporter = new PythonQtQFileImporter; | ||
florianlink
|
r4 | _noLongerWrappedCB = NULL; | ||
_wrappedCB = NULL; | ||||
florianlink
|
r18 | _currentClassInfoForClassWrapperCreation = NULL; | ||
} | ||||
PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation() | ||||
{ | ||||
PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation; | ||||
_currentClassInfoForClassWrapperCreation = NULL; | ||||
return info; | ||||
ezust
|
r0 | } | ||
florianlink
|
r10 | void PythonQtPrivate::addDecorators(QObject* o, int decoTypes) | ||
ezust
|
r0 | { | ||
o->setParent(this); | ||||
int numMethods = o->metaObject()->methodCount(); | ||||
for (int i = 0; i < numMethods; i++) { | ||||
QMetaMethod m = o->metaObject()->method(i); | ||||
if ((m.methodType() == QMetaMethod::Method || | ||||
m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) { | ||||
if (qstrncmp(m.signature(), "new_", 4)==0) { | ||||
florianlink
|
r10 | if ((decoTypes & ConstructorDecorator) == 0) continue; | ||
florianlink
|
r55 | const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL); | ||
florianlink
|
r54 | if (info->parameters().at(0).isPointer) { | ||
ezust
|
r0 | QByteArray signature = m.signature(); | ||
QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4); | ||||
florianlink
|
r24 | PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass); | ||
florianlink
|
r54 | PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator); | ||
florianlink
|
r24 | classInfo->addConstructor(newSlot); | ||
ezust
|
r0 | } | ||
} else if (qstrncmp(m.signature(), "delete_", 7)==0) { | ||||
florianlink
|
r10 | if ((decoTypes & DestructorDecorator) == 0) continue; | ||
ezust
|
r0 | QByteArray signature = m.signature(); | ||
QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7); | ||||
florianlink
|
r24 | PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass); | ||
florianlink
|
r54 | PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator); | ||
florianlink
|
r24 | classInfo->setDestructor(newSlot); | ||
ezust
|
r0 | } else if (qstrncmp(m.signature(), "static_", 7)==0) { | ||
florianlink
|
r10 | if ((decoTypes & StaticDecorator) == 0) continue; | ||
ezust
|
r0 | QByteArray signature = m.signature(); | ||
QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1); | ||||
nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_')); | ||||
florianlink
|
r24 | PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass); | ||
florianlink
|
r54 | PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator); | ||
florianlink
|
r24 | classInfo->addDecoratorSlot(newSlot); | ||
ezust
|
r0 | } else { | ||
florianlink
|
r10 | if ((decoTypes & InstanceDecorator) == 0) continue; | ||
florianlink
|
r55 | const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL); | ||
ezust
|
r0 | if (info->parameters().count()>1) { | ||
PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1); | ||||
if (p.isPointer) { | ||||
florianlink
|
r24 | PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name); | ||
florianlink
|
r54 | PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator); | ||
florianlink
|
r24 | classInfo->addDecoratorSlot(newSlot); | ||
ezust
|
r0 | } | ||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
void PythonQtPrivate::registerQObjectClassNames(const QStringList& names) | ||||
{ | ||||
foreach(QString name, names) { | ||||
_knownQObjectClassNames.insert(name.toLatin1(), true); | ||||
} | ||||
} | ||||
florianlink
|
r4 | void PythonQtPrivate::removeSignalEmitter(QObject* obj) | ||
ezust
|
r0 | { | ||
florianlink
|
r4 | _signalReceivers.remove(obj); | ||
ezust
|
r0 | } | ||
bool PythonQt::handleError() | ||||
{ | ||||
bool flag = false; | ||||
if (PyErr_Occurred()) { | ||||
// currently we just print the error and the stderr handler parses the errors | ||||
PyErr_Print(); | ||||
/* | ||||
// EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above | ||||
PyObject *ptype; | ||||
PyObject *pvalue; | ||||
PyObject *ptraceback; | ||||
PyErr_Fetch( &ptype, &pvalue, &ptraceback); | ||||
Py_XDECREF(ptype); | ||||
Py_XDECREF(pvalue); | ||||
Py_XDECREF(ptraceback); | ||||
*/ | ||||
PyErr_Clear(); | ||||
flag = true; | ||||
} | ||||
return flag; | ||||
} | ||||
florianlink
|
r14 | void PythonQt::addSysPath(const QString& path) | ||
{ | ||||
PythonQtObjectPtr sys; | ||||
sys.setNewRef(PyImport_ImportModule("sys")); | ||||
PythonQtObjectPtr obj = lookupObject(sys, "path"); | ||||
PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path)); | ||||
} | ||||
ezust
|
r0 | void PythonQt::overwriteSysPath(const QStringList& paths) | ||
{ | ||||
PythonQtObjectPtr sys; | ||||
sys.setNewRef(PyImport_ImportModule("sys")); | ||||
PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths)); | ||||
} | ||||
void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths) | ||||
{ | ||||
PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths)); | ||||
} | ||||
void PythonQt::stdOutRedirectCB(const QString& str) | ||||
{ | ||||
emit PythonQt::self()->pythonStdOut(str); | ||||
} | ||||
void PythonQt::stdErrRedirectCB(const QString& str) | ||||
{ | ||||
emit PythonQt::self()->pythonStdErr(str); | ||||
} | ||||
florianlink
|
r4 | void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb) | ||
{ | ||||
_p->_wrappedCB = cb; | ||||
} | ||||
void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb) | ||||
{ | ||||
_p->_noLongerWrappedCB = cb; | ||||
} | ||||
ezust
|
r0 | |||
static PyMethodDef PythonQtMethods[] = { | ||||
{NULL, NULL, 0, NULL} | ||||
}; | ||||
void PythonQt::initPythonQtModule(bool redirectStdOut) | ||||
{ | ||||
florianlink
|
r19 | _p->_pythonQtModule = Py_InitModule("PythonQt", PythonQtMethods); | ||
ezust
|
r0 | |||
if (redirectStdOut) { | ||||
PythonQtObjectPtr sys; | ||||
PythonQtObjectPtr out; | ||||
PythonQtObjectPtr err; | ||||
sys.setNewRef(PyImport_ImportModule("sys")); | ||||
// create a redirection object for stdout and stderr | ||||
out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL); | ||||
((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB; | ||||
err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL); | ||||
((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB; | ||||
// replace the built in file objects with our own objects | ||||
PyModule_AddObject(sys, "stdout", out); | ||||
PyModule_AddObject(sys, "stderr", err); | ||||
} | ||||
} | ||||
florianlink
|
r24 | void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell) | ||
ezust
|
r0 | { | ||
florianlink
|
r24 | _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell); | ||
ezust
|
r0 | } | ||
florianlink
|
r24 | PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName) | ||
ezust
|
r0 | { | ||
florianlink
|
r24 | PythonQtClassInfo* info = _knownClassInfos.value(typeName); | ||
florianlink
|
r10 | if (!info) { | ||
florianlink
|
r24 | info = new PythonQtClassInfo(); | ||
info->setupCPPObject(typeName); | ||||
_knownClassInfos.insert(typeName, info); | ||||
florianlink
|
r10 | } | ||
florianlink
|
r24 | return info; | ||
} | ||||
florianlink
|
r26 | void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb) | ||
{ | ||||
_p->addPolymorphicHandler(typeName, cb); | ||||
} | ||||
void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb) | ||||
{ | ||||
PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName); | ||||
info->addPolymorphicHandler(cb); | ||||
} | ||||
florianlink
|
r24 | bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset) | ||
{ | ||||
return _p->addParentClass(typeName, parentTypeName, upcastingOffset); | ||||
} | ||||
bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset) | ||||
{ | ||||
PythonQtClassInfo* info = _knownClassInfos.value(typeName); | ||||
if (info) { | ||||
PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName); | ||||
info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset)); | ||||
return true; | ||||
} else { | ||||
return false; | ||||
} | ||||
} | ||||
void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell) | ||||
{ | ||||
PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName); | ||||
if (!info->pythonQtClassWrapper()) { | ||||
info->setupCPPObject(typeName); | ||||
createPythonQtClassWrapper(info, package); | ||||
} | ||||
if (parentTypeName && strcmp(parentTypeName,"")!=0) { | ||||
addParentClass(typeName, parentTypeName, 0); | ||||
florianlink
|
r10 | } | ||
if (wrapperCreator) { | ||||
info->setDecoratorProvider(wrapperCreator); | ||||
} | ||||
florianlink
|
r24 | if (shell) { | ||
info->setShellSetInstanceWrapperCB(shell); | ||||
} | ||||
ezust
|
r0 | } | ||
florianlink
|
r19 | PyObject* PythonQtPrivate::packageByName(const char* name) | ||
florianlink
|
r10 | { | ||
if (name==NULL || name[0]==0) { | ||||
return _pythonQtModule; | ||||
} | ||||
florianlink
|
r19 | PyObject* v = _packages.value(name); | ||
florianlink
|
r10 | if (!v) { | ||
florianlink
|
r19 | v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData()); | ||
florianlink
|
r10 | _packages.insert(name, v); | ||
florianlink
|
r19 | // AddObject steals the reference, so increment it! | ||
Py_INCREF(v); | ||||
florianlink
|
r10 | PyModule_AddObject(_pythonQtModule, name, v); | ||
} | ||||
return v; | ||||
} | ||||
ezust
|
r0 | PyObject* PythonQt::helpCalled(PythonQtClassInfo* info) | ||
{ | ||||
if (_p->_initFlags & ExternalHelp) { | ||||
emit pythonHelpRequest(QByteArray(info->className())); | ||||
return Py_BuildValue(""); | ||||
} else { | ||||
return PyString_FromString(info->help().toLatin1().data()); | ||||
} | ||||
} | ||||
florianlink
|
r4 | |||
void PythonQtPrivate::removeWrapperPointer(void* obj) | ||||
{ | ||||
_wrappedObjects.remove(obj); | ||||
} | ||||
florianlink
|
r18 | void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper) | ||
{ | ||||
_wrappedObjects.insert(obj, wrapper); | ||||
} | ||||
florianlink
|
r16 | PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj) | ||
florianlink
|
r4 | { | ||
florianlink
|
r16 | PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj); | ||
florianlink
|
r4 | if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) { | ||
// this is a wrapper whose QObject was already removed due to destruction | ||||
// so the obj pointer has to be a new QObject with the same address... | ||||
// we remove the old one and set the copy to NULL | ||||
wrap->_objPointerCopy = NULL; | ||||
removeWrapperPointer(obj); | ||||
wrap = NULL; | ||||
} | ||||
return wrap; | ||||
} | ||||
PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode) | ||||
{ | ||||
PythonQtObjectPtr result; | ||||
if (pycode) { | ||||
result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode)); | ||||
} else { | ||||
PythonQt::self()->handleError(); | ||||
} | ||||
return result; | ||||
} | ||||