|
|
/*
|
|
|
*
|
|
|
* Copyright (C) 2010 MeVis Medical Solutions AG 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 Medical Solutions AG, 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 "PythonQtSignal.h"
|
|
|
#include "PythonQtSignalReceiver.h"
|
|
|
#include "PythonQtConversion.h"
|
|
|
#include "PythonQtStdIn.h"
|
|
|
#include "PythonQtStdOut.h"
|
|
|
#include "PythonQtCppWrapperFactory.h"
|
|
|
#include "PythonQtVariants.h"
|
|
|
#include "PythonQtStdDecorators.h"
|
|
|
#include "PythonQtQFileImporter.h"
|
|
|
#include <pydebug.h>
|
|
|
#include <vector>
|
|
|
|
|
|
PythonQt* PythonQt::_self = NULL;
|
|
|
int PythonQt::_uniqueModuleCount = 0;
|
|
|
|
|
|
void PythonQt_init_QtGuiBuiltin(PyObject*);
|
|
|
void PythonQt_init_QtCoreBuiltin(PyObject*);
|
|
|
|
|
|
|
|
|
PyObject* PythonQtConvertFromStringRef(const void* inObject, int /*metaTypeId*/)
|
|
|
{
|
|
|
return PythonQtConv::QStringToPyObject(((QStringRef*)inObject)->toString());
|
|
|
}
|
|
|
|
|
|
void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
|
|
|
{
|
|
|
if (!_self) {
|
|
|
_self = new PythonQt(flags, pythonQtModuleName);
|
|
|
|
|
|
PythonQt::priv()->setupSharedLibrarySuffixes();
|
|
|
|
|
|
PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
|
|
|
qRegisterMetaType<QList<QObject*> >("QList<void*>");
|
|
|
|
|
|
int stringRefId = qRegisterMetaType<QStringRef>("QStringRef");
|
|
|
PythonQtConv::registerMetaTypeToPythonConverter(stringRefId, PythonQtConvertFromStringRef);
|
|
|
|
|
|
PythonQtRegisterToolClassesTemplateConverter(int);
|
|
|
PythonQtRegisterToolClassesTemplateConverter(float);
|
|
|
PythonQtRegisterToolClassesTemplateConverter(double);
|
|
|
PythonQtRegisterToolClassesTemplateConverter(qint32);
|
|
|
PythonQtRegisterToolClassesTemplateConverter(quint32);
|
|
|
PythonQtRegisterToolClassesTemplateConverter(qint64);
|
|
|
PythonQtRegisterToolClassesTemplateConverter(quint64);
|
|
|
// TODO: which other POD types should be available for QList etc.
|
|
|
|
|
|
PythonQt_init_QtCoreBuiltin(NULL);
|
|
|
PythonQt_init_QtGuiBuiltin(NULL);
|
|
|
|
|
|
PythonQt::self()->addDecorators(new PythonQtStdDecorators());
|
|
|
PythonQt::self()->registerCPPClass("QMetaObject",0, "QtCore", PythonQtCreateObject<PythonQtWrapper_QMetaObject>);
|
|
|
|
|
|
PythonQtRegisterToolClassesTemplateConverter(QByteArray);
|
|
|
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);
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
PyObject* pack = PythonQt::priv()->packageByName("QtCore");
|
|
|
PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
|
|
|
PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
|
|
|
const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
|
|
|
,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
|
|
|
for (unsigned int i = 0;i<16; i++) {
|
|
|
PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
|
|
|
if (obj) {
|
|
|
PyModule_AddObject(pack, names[i], obj);
|
|
|
Py_INCREF(obj);
|
|
|
PyModule_AddObject(pack2, names[i], obj);
|
|
|
} else {
|
|
|
std::cerr << "method not found " << names[i] << std::endl;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void PythonQt::cleanup()
|
|
|
{
|
|
|
if (_self) {
|
|
|
delete _self;
|
|
|
_self = NULL;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
PythonQt* PythonQt::self() { return _self; }
|
|
|
|
|
|
PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
|
|
|
{
|
|
|
_p = new PythonQtPrivate;
|
|
|
_p->_initFlags = flags;
|
|
|
|
|
|
_p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
|
|
|
|
|
|
if ((flags & PythonAlreadyInitialized) == 0) {
|
|
|
#ifdef PY3K
|
|
|
Py_SetProgramName(const_cast<wchar_t*>(L"PythonQt"));
|
|
|
#else
|
|
|
Py_SetProgramName(const_cast<char*>("PythonQt"));
|
|
|
#endif
|
|
|
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);
|
|
|
|
|
|
if (PyType_Ready(&PythonQtSignalFunction_Type) < 0) {
|
|
|
std::cerr << "could not initialize PythonQtSignalFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
|
|
|
}
|
|
|
Py_INCREF(&PythonQtSignalFunction_Type);
|
|
|
|
|
|
// 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
|
|
|
if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
|
|
|
std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
|
|
|
}
|
|
|
Py_INCREF(&PythonQtClassWrapper_Type);
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
// add our own python object types for redirection of stdin
|
|
|
if (PyType_Ready(&PythonQtStdInRedirectType) < 0) {
|
|
|
std::cerr << "could not initialize PythonQtStdInRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
|
|
|
}
|
|
|
Py_INCREF(&PythonQtStdInRedirectType);
|
|
|
|
|
|
initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
|
|
|
|
|
|
}
|
|
|
|
|
|
PythonQt::~PythonQt() {
|
|
|
delete _p;
|
|
|
_p = NULL;
|
|
|
}
|
|
|
|
|
|
PythonQtPrivate::~PythonQtPrivate() {
|
|
|
delete _defaultImporter;
|
|
|
_defaultImporter = NULL;
|
|
|
|
|
|
{
|
|
|
QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
|
|
|
while (i.hasNext()) {
|
|
|
delete i.next().value();
|
|
|
}
|
|
|
}
|
|
|
PythonQtConv::global_valueStorage.clear();
|
|
|
PythonQtConv::global_ptrStorage.clear();
|
|
|
PythonQtConv::global_variantStorage.clear();
|
|
|
|
|
|
PythonQtMethodInfo::cleanupCachedMethodInfos();
|
|
|
}
|
|
|
|
|
|
void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData)
|
|
|
{
|
|
|
if (!callback)
|
|
|
{
|
|
|
std::cerr << "PythonQt::setRedirectStdInCallback - callback parameter is NULL !" << std::endl;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
PythonQtObjectPtr sys;
|
|
|
PythonQtObjectPtr in;
|
|
|
sys.setNewRef(PyImport_ImportModule("sys"));
|
|
|
|
|
|
// Backup original 'sys.stdin' if not yet done
|
|
|
if( !PyObject_HasAttrString(sys.object(), "pythonqt_original_stdin") )
|
|
|
PyObject_SetAttrString(sys.object(), "pythonqt_original_stdin", PyObject_GetAttrString(sys.object(), "stdin"));
|
|
|
|
|
|
in = PythonQtStdInRedirectType.tp_new(&PythonQtStdInRedirectType, NULL, NULL);
|
|
|
((PythonQtStdInRedirect*)in.object())->_cb = callback;
|
|
|
((PythonQtStdInRedirect*)in.object())->_callData = callbackData;
|
|
|
// replace the built in file objects with our own objects
|
|
|
PyModule_AddObject(sys.object(), "stdin", in);
|
|
|
|
|
|
// Backup custom 'stdin' into 'pythonqt_stdin'
|
|
|
Py_IncRef(in);
|
|
|
PyModule_AddObject(sys.object(), "pythonqt_stdin", in);
|
|
|
}
|
|
|
|
|
|
void PythonQt::setRedirectStdInCallbackEnabled(bool enabled)
|
|
|
{
|
|
|
PythonQtObjectPtr sys;
|
|
|
sys.setNewRef(PyImport_ImportModule("sys"));
|
|
|
|
|
|
if (enabled)
|
|
|
{
|
|
|
if( !PyObject_HasAttrString(sys.object(), "pythonqt_stdin") )
|
|
|
PyObject_SetAttrString(sys.object(), "stdin", PyObject_GetAttrString(sys.object(), "pythonqt_stdin"));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if( !PyObject_HasAttrString(sys.object(), "pythonqt_original_stdin") )
|
|
|
PyObject_SetAttrString(sys.object(), "stdin", PyObject_GetAttrString(sys.object(), "pythonqt_original_stdin"));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
PythonQtImportFileInterface* PythonQt::importInterface()
|
|
|
{
|
|
|
return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
|
|
|
}
|
|
|
|
|
|
void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
|
|
|
{
|
|
|
if (_self->_p->_noLongerWrappedCB) {
|
|
|
(*_self->_p->_noLongerWrappedCB)(o);
|
|
|
};
|
|
|
}
|
|
|
|
|
|
void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
|
|
|
{
|
|
|
_p->registerClass(metaobject, package, wrapperCreator, shell);
|
|
|
}
|
|
|
|
|
|
void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
|
|
|
{
|
|
|
// we register all classes in the hierarchy
|
|
|
const QMetaObject* m = metaobject;
|
|
|
bool first = true;
|
|
|
while (m) {
|
|
|
PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
|
|
|
if (!info->pythonQtClassWrapper()) {
|
|
|
info->setTypeSlots(typeSlots);
|
|
|
info->setupQObject(m);
|
|
|
createPythonQtClassWrapper(info, package, module);
|
|
|
if (m->superClass()) {
|
|
|
PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
|
|
|
info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
|
|
|
}
|
|
|
} else if (first && module) {
|
|
|
// There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
|
|
|
// since it might have been placed into "private" earlier on.
|
|
|
// If the wrapper was already added to module before, it is just readded, which does no harm.
|
|
|
PyObject* classWrapper = info->pythonQtClassWrapper();
|
|
|
// AddObject steals a reference, so we need to INCREF
|
|
|
Py_INCREF(classWrapper);
|
|
|
PyModule_AddObject(module, info->className(), classWrapper);
|
|
|
}
|
|
|
if (first) {
|
|
|
first = false;
|
|
|
if (wrapperCreator) {
|
|
|
info->setDecoratorProvider(wrapperCreator);
|
|
|
}
|
|
|
if (shell) {
|
|
|
info->setShellSetInstanceWrapperCB(shell);
|
|
|
}
|
|
|
}
|
|
|
m = m->superClass();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
|
|
|
{
|
|
|
PyObject* pack = module?module:packageByName(package);
|
|
|
PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
|
|
|
PyModule_AddObject(pack, info->className(), pyobj);
|
|
|
if (!module && package && strncmp(package,"Qt",2)==0) {
|
|
|
// since PyModule_AddObject steals the reference, we need a incref once more...
|
|
|
Py_INCREF(pyobj);
|
|
|
// put all qt objects into Qt as well
|
|
|
PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
|
|
|
}
|
|
|
info->setPythonQtClassWrapper(pyobj);
|
|
|
}
|
|
|
|
|
|
PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
|
|
|
{
|
|
|
if (!obj) {
|
|
|
Py_INCREF(Py_None);
|
|
|
return Py_None;
|
|
|
}
|
|
|
PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
|
|
|
if (wrap && wrap->_wrappedPtr) {
|
|
|
// uh oh, we want to wrap a QObject, but have a C++ wrapper at that
|
|
|
// address, so probably that C++ wrapper has been deleted earlier and
|
|
|
// now we see a QObject with the same address.
|
|
|
// Do not use the old wrapper anymore.
|
|
|
wrap = NULL;
|
|
|
}
|
|
|
if (!wrap) {
|
|
|
// smuggling it in...
|
|
|
PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
|
|
|
if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
|
|
|
registerClass(obj->metaObject());
|
|
|
classInfo = _knownClassInfos.value(obj->metaObject()->className());
|
|
|
}
|
|
|
wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
|
|
|
// mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
|
|
|
} else {
|
|
|
Py_INCREF(wrap);
|
|
|
// mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
|
|
|
}
|
|
|
return (PyObject*)wrap;
|
|
|
}
|
|
|
|
|
|
PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
|
|
|
{
|
|
|
if (!ptr) {
|
|
|
Py_INCREF(Py_None);
|
|
|
return Py_None;
|
|
|
}
|
|
|
|
|
|
PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
|
|
|
PythonQtInstanceWrapper* possibleStillAliveWrapper = NULL;
|
|
|
if (wrap && wrap->_wrappedPtr) {
|
|
|
// we have a previous C++ wrapper... if the wrapper is for a C++ object,
|
|
|
// we are not sure if it may have been deleted earlier and we just see the same C++
|
|
|
// pointer once again. To make sure that we do not reuse a wrapper of the wrong type,
|
|
|
// we compare the classInfo() pointer and only reuse the wrapper if it has the same
|
|
|
// info. This is only needed for non-QObjects, since we know it when a QObject gets deleted.
|
|
|
possibleStillAliveWrapper = wrap;
|
|
|
wrap = NULL;
|
|
|
}
|
|
|
if (!wrap) {
|
|
|
PythonQtClassInfo* info = _knownClassInfos.value(name);
|
|
|
if (!info) {
|
|
|
// maybe it is a PyObject, which we can return directly
|
|
|
if (name == "PyObject") {
|
|
|
PyObject* p = (PyObject*)ptr;
|
|
|
Py_INCREF(p);
|
|
|
return p;
|
|
|
}
|
|
|
|
|
|
// we do not know the metaobject yet, but we might know it by its name:
|
|
|
if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
|
|
|
// yes, we know it, so we can convert to QObject
|
|
|
QObject* qptr = (QObject*)ptr;
|
|
|
registerClass(qptr->metaObject());
|
|
|
info = _knownClassInfos.value(qptr->metaObject()->className());
|
|
|
}
|
|
|
}
|
|
|
if (info && info->isQObject()) {
|
|
|
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())) {
|
|
|
info = _knownClassInfos.value(qptr->metaObject()->className());
|
|
|
if (!info) {
|
|
|
registerClass(qptr->metaObject());
|
|
|
info = _knownClassInfos.value(qptr->metaObject()->className());
|
|
|
}
|
|
|
}
|
|
|
wrap = createNewPythonQtInstanceWrapper(qptr, info);
|
|
|
// mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
|
|
|
return (PyObject*)wrap;
|
|
|
}
|
|
|
|
|
|
// not a known QObject, try to wrap via foreign wrapper factories
|
|
|
PyObject* foreignWrapper = NULL;
|
|
|
for (int i=0; i<_foreignWrapperFactories.size(); i++) {
|
|
|
foreignWrapper = _foreignWrapperFactories.at(i)->wrap(name, ptr);
|
|
|
if (foreignWrapper) {
|
|
|
return foreignWrapper;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 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;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (info) {
|
|
|
// try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
|
|
|
ptr = info->castDownIfPossible(ptr, &info);
|
|
|
|
|
|
// if downcasting found out that the object is a QObject,
|
|
|
// handle it like one:
|
|
|
if (info && info->isQObject()) {
|
|
|
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());
|
|
|
info = _knownClassInfos.value(qptr->metaObject()->className());
|
|
|
}
|
|
|
wrap = createNewPythonQtInstanceWrapper(qptr, info);
|
|
|
// mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
|
|
|
return (PyObject*)wrap;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
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());
|
|
|
}
|
|
|
|
|
|
if (possibleStillAliveWrapper && possibleStillAliveWrapper->classInfo() == info) {
|
|
|
wrap = possibleStillAliveWrapper;
|
|
|
Py_INCREF(wrap);
|
|
|
} else {
|
|
|
wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
|
|
|
}
|
|
|
// mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
|
|
|
} else {
|
|
|
Py_INCREF(wrap);
|
|
|
//mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
|
|
|
}
|
|
|
return (PyObject*)wrap;
|
|
|
}
|
|
|
|
|
|
PyObject* PythonQtPrivate::dummyTuple() {
|
|
|
static PyObject* dummyTuple = NULL;
|
|
|
if (dummyTuple==NULL) {
|
|
|
dummyTuple = PyTuple_New(1);
|
|
|
#ifdef PY3K
|
|
|
PyTuple_SET_ITEM(dummyTuple, 0, PyUnicode_FromString("dummy"));
|
|
|
#else
|
|
|
PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
|
|
|
#endif
|
|
|
}
|
|
|
return dummyTuple;
|
|
|
}
|
|
|
|
|
|
|
|
|
PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
|
|
|
// call the associated class type to create a new instance...
|
|
|
PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
|
|
|
|
|
|
result->setQObject(obj);
|
|
|
result->_wrappedPtr = wrappedPtr;
|
|
|
result->_ownedByPythonQt = false;
|
|
|
result->_useQMetaTypeDestroy = false;
|
|
|
|
|
|
if (wrappedPtr) {
|
|
|
_wrappedObjects.insert(wrappedPtr, result);
|
|
|
} else {
|
|
|
_wrappedObjects.insert(obj, result);
|
|
|
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);
|
|
|
}
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
|
|
|
PythonQtClassWrapper* result;
|
|
|
|
|
|
#ifdef PY3K
|
|
|
PyObject* className = PyUnicode_FromString(info->className());
|
|
|
#else
|
|
|
PyObject* className = PyString_FromString(info->className());
|
|
|
#endif
|
|
|
|
|
|
PyObject* baseClasses = PyTuple_New(1);
|
|
|
PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
|
|
|
|
|
|
PyObject* typeDict = PyDict_New();
|
|
|
PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
|
|
|
PyDict_SetItemString(typeDict, "__module__", moduleName);
|
|
|
|
|
|
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);
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
|
|
|
PyObject* result;
|
|
|
|
|
|
#ifdef PY3K
|
|
|
PyObject* className = PyUnicode_FromString(enumName);
|
|
|
#else
|
|
|
PyObject* className = PyString_FromString(enumName);
|
|
|
#endif
|
|
|
|
|
|
PyObject* baseClasses = PyTuple_New(1);
|
|
|
#ifdef PY3K
|
|
|
PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyLong_Type);
|
|
|
#else
|
|
|
PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
|
|
|
#endif
|
|
|
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
QByteArray b;
|
|
|
for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
|
|
|
prev = p;
|
|
|
b = (*i).toLatin1();
|
|
|
if (PyDict_Check(p)) {
|
|
|
p = PyDict_GetItemString(p, b.data());
|
|
|
} else {
|
|
|
p.setNewRef(PyObject_GetAttrString(p, b.data()));
|
|
|
}
|
|
|
}
|
|
|
PyErr_Clear();
|
|
|
return p;
|
|
|
}
|
|
|
|
|
|
PythonQtObjectPtr PythonQt::getMainModule() {
|
|
|
//both borrowed
|
|
|
PythonQtObjectPtr dict = PyImport_GetModuleDict();
|
|
|
return PyDict_GetItemString(dict, "__main__");
|
|
|
}
|
|
|
|
|
|
PythonQtObjectPtr PythonQt::importModule(const QString& name)
|
|
|
{
|
|
|
PythonQtObjectPtr mod;
|
|
|
mod.setNewRef(PyImport_ImportModule(name.toLatin1().constData()));
|
|
|
return mod;
|
|
|
}
|
|
|
|
|
|
|
|
|
QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
|
|
|
QVariant result;
|
|
|
clearError();
|
|
|
if (pycode) {
|
|
|
PyObject* dict = NULL;
|
|
|
PyObject* globals = NULL;
|
|
|
if (PyModule_Check(object)) {
|
|
|
dict = PyModule_GetDict(object);
|
|
|
globals = dict;
|
|
|
} else if (PyDict_Check(object)) {
|
|
|
dict = object;
|
|
|
globals = dict;
|
|
|
} else {
|
|
|
dict = PyObject_GetAttrString(object, "__dict__");
|
|
|
globals = PyObject_GetAttrString(PyImport_ImportModule(
|
|
|
#ifdef PY3K
|
|
|
PyUnicode_AsUTF8(
|
|
|
#else
|
|
|
PyString_AS_STRING(
|
|
|
#endif
|
|
|
PyObject_GetAttrString(object, "__module__"))),"__dict__");
|
|
|
}
|
|
|
PyObject* r = NULL;
|
|
|
if (dict) {
|
|
|
#ifdef PY3K
|
|
|
r = PyEval_EvalCode(pycode, globals, dict);
|
|
|
#else
|
|
|
r = PyEval_EvalCode((PyCodeObject*)pycode, globals , dict);
|
|
|
#endif
|
|
|
}
|
|
|
if (r) {
|
|
|
result = PythonQtConv::PyObjToQVariant(r);
|
|
|
Py_DECREF(r);
|
|
|
} else {
|
|
|
handleError();
|
|
|
}
|
|
|
} else {
|
|
|
handleError();
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
|
|
|
{
|
|
|
QVariant result;
|
|
|
PythonQtObjectPtr p;
|
|
|
PyObject* dict = NULL;
|
|
|
clearError();
|
|
|
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));
|
|
|
}
|
|
|
if (p) {
|
|
|
result = PythonQtConv::PyObjToQVariant(p);
|
|
|
} else {
|
|
|
handleError();
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
void PythonQt::evalFile(PyObject* module, const QString& filename)
|
|
|
{
|
|
|
PythonQtObjectPtr code = parseFile(filename);
|
|
|
clearError();
|
|
|
if (code) {
|
|
|
evalCode(module, code);
|
|
|
} else {
|
|
|
handleError();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
|
|
|
{
|
|
|
PythonQtObjectPtr p;
|
|
|
p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
|
|
|
clearError();
|
|
|
if (!p) {
|
|
|
handleError();
|
|
|
}
|
|
|
return p;
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
}
|
|
|
|
|
|
void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
|
|
|
{
|
|
|
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));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
|
|
|
{
|
|
|
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));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void PythonQt::removeVariable(PyObject* object, const QString& name)
|
|
|
{
|
|
|
if (PyDict_Check(object)) {
|
|
|
PyDict_DelItemString(object, name.toLatin1().data());
|
|
|
} else {
|
|
|
PyObject_DelAttrString(object, name.toLatin1().data());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
|
|
|
{
|
|
|
QVariant result;
|
|
|
PythonQtObjectPtr obj = lookupObject(object, objectname);
|
|
|
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) {
|
|
|
results = introspectObject(object, type);
|
|
|
}
|
|
|
|
|
|
return results;
|
|
|
}
|
|
|
|
|
|
QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
|
|
|
{
|
|
|
QStringList results;
|
|
|
|
|
|
if (type == CallOverloads) {
|
|
|
if (PythonQtSlotFunction_Check(object)) {
|
|
|
PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object;
|
|
|
PythonQtSlotInfo* info = o->m_ml;
|
|
|
|
|
|
while (info) {
|
|
|
results << info->fullSignature();
|
|
|
info = info->nextInfo();
|
|
|
}
|
|
|
} else if (PythonQtSignalFunction_Check(object)) {
|
|
|
PythonQtSignalFunctionObject* o = (PythonQtSignalFunctionObject*)object;
|
|
|
PythonQtSlotInfo* info = o->m_ml;
|
|
|
|
|
|
while (info) {
|
|
|
results << info->fullSignature();
|
|
|
info = info->nextInfo();
|
|
|
}
|
|
|
} else if (object->ob_type == &PythonQtClassWrapper_Type) {
|
|
|
PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
|
|
|
PythonQtSlotInfo* info = o->classInfo()->constructors();
|
|
|
|
|
|
while (info) {
|
|
|
results << info->fullSignature();
|
|
|
info = info->nextInfo();
|
|
|
}
|
|
|
} else {
|
|
|
QString signature = _p->getSignature(object);
|
|
|
if (!signature.isEmpty()) {
|
|
|
results << signature;
|
|
|
} else {
|
|
|
PyObject* doc = PyObject_GetAttrString(object, "__doc__");
|
|
|
if (doc) {
|
|
|
#ifdef PY3K
|
|
|
results << PyUnicode_AsUTF8(doc);
|
|
|
#else
|
|
|
results << PyString_AsString(doc);
|
|
|
#endif
|
|
|
Py_DECREF(doc);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
PyObject* keys = NULL;
|
|
|
bool isDict = false;
|
|
|
if (PyDict_Check(object)) {
|
|
|
keys = PyDict_Keys(object);
|
|
|
isDict = true;
|
|
|
} else {
|
|
|
keys = PyObject_Dir(object);
|
|
|
}
|
|
|
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);
|
|
|
if (isDict) {
|
|
|
value = PyDict_GetItem(object, key);
|
|
|
Py_INCREF(value);
|
|
|
} else {
|
|
|
value = PyObject_GetAttr(object, key);
|
|
|
}
|
|
|
if (!value) continue;
|
|
|
#ifdef PY3K
|
|
|
keystr = PyUnicode_AsUTF8(key);
|
|
|
#else
|
|
|
keystr = PyString_AsString(key);
|
|
|
#endif
|
|
|
static const QString underscoreStr("__tmp");
|
|
|
if (!keystr.startsWith(underscoreStr)) {
|
|
|
switch (type) {
|
|
|
case Anything:
|
|
|
results << keystr;
|
|
|
break;
|
|
|
case Class:
|
|
|
#ifdef PY3K
|
|
|
if(PyType_Check(value)) {
|
|
|
#else
|
|
|
if (value->ob_type == &PyClass_Type || value->ob_type == &PyType_Type) {
|
|
|
#endif
|
|
|
results << keystr;
|
|
|
}
|
|
|
break;
|
|
|
case Variable:
|
|
|
if (
|
|
|
#ifndef PY3K
|
|
|
value->ob_type != &PyClass_Type &&
|
|
|
#endif
|
|
|
value->ob_type != &PyCFunction_Type &&
|
|
|
value->ob_type != &PyFunction_Type &&
|
|
|
value->ob_type != &PyMethod_Type &&
|
|
|
value->ob_type != &PyModule_Type &&
|
|
|
value->ob_type != &PyType_Type &&
|
|
|
value->ob_type != &PythonQtSlotFunction_Type
|
|
|
) {
|
|
|
results << keystr;
|
|
|
}
|
|
|
break;
|
|
|
case Function:
|
|
|
if (value->ob_type == &PyCFunction_Type ||
|
|
|
value->ob_type == &PyFunction_Type ||
|
|
|
value->ob_type == &PyMethod_Type ||
|
|
|
value->ob_type == &PythonQtSlotFunction_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);
|
|
|
}
|
|
|
if ((type == Anything) || (type == Variable)) {
|
|
|
if (object->ob_type == &PythonQtClassWrapper_Type) {
|
|
|
PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
|
|
|
PythonQtClassInfo* info = o->classInfo();
|
|
|
results += info->propertyList();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return results;
|
|
|
}
|
|
|
|
|
|
PyObject* PythonQt::getObjectByType(const QString& typeName)
|
|
|
{
|
|
|
PythonQtObjectPtr sys;
|
|
|
sys.setNewRef(PyImport_ImportModule("sys"));
|
|
|
PythonQtObjectPtr modules = lookupObject(sys, "modules");
|
|
|
Q_ASSERT(PyDict_Check(modules));
|
|
|
|
|
|
QStringList tmp = typeName.split(".");
|
|
|
QString simpleTypeName = tmp.takeLast();
|
|
|
QString moduleName = tmp.join(".");
|
|
|
|
|
|
PyObject* object = NULL;
|
|
|
PyObject* moduleObject = PyDict_GetItemString(modules, moduleName.toLatin1().constData());
|
|
|
if (moduleObject) {
|
|
|
object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
|
|
|
}
|
|
|
|
|
|
if (!object) {
|
|
|
moduleObject = PyDict_GetItemString(modules, "__builtin__");
|
|
|
if (moduleObject) {
|
|
|
object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return object;
|
|
|
}
|
|
|
|
|
|
QStringList PythonQt::introspectType(const QString& typeName, ObjectType type)
|
|
|
{
|
|
|
QStringList results;
|
|
|
PyObject* object = getObjectByType(typeName);
|
|
|
if (!object) {
|
|
|
// the last item may be a member, split it away and try again
|
|
|
QStringList tmp = typeName.split(".");
|
|
|
QString memberName = tmp.takeLast();
|
|
|
QString typeName;
|
|
|
if (tmp.isEmpty()) {
|
|
|
typeName = memberName;
|
|
|
memberName.clear();
|
|
|
} else {
|
|
|
typeName = tmp.takeLast();
|
|
|
}
|
|
|
PyObject* typeObject = getObjectByType(typeName);
|
|
|
if (typeObject) {
|
|
|
object = PyObject_GetAttrString(typeObject, memberName.toLatin1().constData());
|
|
|
}
|
|
|
}
|
|
|
if (object) {
|
|
|
results = introspectObject(object, type);
|
|
|
Py_DECREF(object);
|
|
|
}
|
|
|
return results;
|
|
|
}
|
|
|
|
|
|
QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args, const QVariantMap& kwargs)
|
|
|
{
|
|
|
PythonQtObjectPtr callable = lookupCallable(object, name);
|
|
|
if (callable) {
|
|
|
return call(callable, args, kwargs);
|
|
|
} else {
|
|
|
return QVariant();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
QVariant PythonQt::call(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
|
|
|
{
|
|
|
QVariant r;
|
|
|
PythonQtObjectPtr result;
|
|
|
result.setNewRef(callAndReturnPyObject(callable, args, kwargs));
|
|
|
clearError();
|
|
|
if (result) {
|
|
|
r = PythonQtConv::PyObjToQVariant(result);
|
|
|
} else {
|
|
|
PythonQt::self()->handleError();
|
|
|
}
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args, const QVariantMap& kwargs)
|
|
|
{
|
|
|
PyObject* result = NULL;
|
|
|
if (callable) {
|
|
|
bool err = false;
|
|
|
PythonQtObjectPtr pargs;
|
|
|
int count = args.size();
|
|
|
if ((count > 0) || (kwargs.count() > 0)) { // create empty tuple if kwargs are given
|
|
|
pargs.setNewRef(PyTuple_New(count));
|
|
|
|
|
|
// transform QVariant arguments 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) {
|
|
|
if (kwargs.isEmpty()) {
|
|
|
// do a direct call if we have no keyword arguments
|
|
|
PyErr_Clear();
|
|
|
result = PyObject_CallObject(callable, pargs);
|
|
|
} else {
|
|
|
// convert keyword arguments to Python
|
|
|
PythonQtObjectPtr pkwargs;
|
|
|
pkwargs.setNewRef(PyDict_New());
|
|
|
QMapIterator<QString, QVariant> it(kwargs);
|
|
|
while (it.hasNext()) {
|
|
|
it.next();
|
|
|
PyObject* arg = PythonQtConv::QVariantToPyObject(it.value());
|
|
|
if (arg) {
|
|
|
PyDict_SetItemString(pkwargs, it.key().toLatin1().constData(), arg);
|
|
|
} else {
|
|
|
err = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if (!err) {
|
|
|
// call with arguments and keyword arguments
|
|
|
PyErr_Clear();
|
|
|
result = PyObject_Call(callable, pargs, pkwargs);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
void PythonQt::addInstanceDecorators(QObject* o)
|
|
|
{
|
|
|
_p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
|
|
|
}
|
|
|
|
|
|
void PythonQt::addClassDecorators(QObject* o)
|
|
|
{
|
|
|
_p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
|
|
|
}
|
|
|
|
|
|
void PythonQt::addDecorators(QObject* o)
|
|
|
{
|
|
|
_p->addDecorators(o, PythonQtPrivate::AllDecorators);
|
|
|
}
|
|
|
|
|
|
void PythonQt::registerQObjectClassNames(const QStringList& names)
|
|
|
{
|
|
|
_p->registerQObjectClassNames(names);
|
|
|
}
|
|
|
|
|
|
void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
|
|
|
{
|
|
|
_p->_importInterface = importInterface;
|
|
|
PythonQtImport::init();
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
}
|
|
|
|
|
|
void PythonQt::addWrapperFactory( PythonQtForeignWrapperFactory* factory )
|
|
|
{
|
|
|
_p->_foreignWrapperFactories.append(factory);
|
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------
|
|
|
PythonQtPrivate::PythonQtPrivate()
|
|
|
{
|
|
|
_importInterface = NULL;
|
|
|
_defaultImporter = new PythonQtQFileImporter;
|
|
|
_noLongerWrappedCB = NULL;
|
|
|
_wrappedCB = NULL;
|
|
|
_currentClassInfoForClassWrapperCreation = NULL;
|
|
|
_profilingCB = NULL;
|
|
|
_hadError = false;
|
|
|
_systemExitExceptionHandlerEnabled = false;
|
|
|
}
|
|
|
|
|
|
void PythonQtPrivate::setupSharedLibrarySuffixes()
|
|
|
{
|
|
|
_sharedLibrarySuffixes.clear();
|
|
|
PythonQtObjectPtr imp;
|
|
|
imp.setNewRef(PyImport_ImportModule("imp"));
|
|
|
int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
|
|
|
QVariant result = imp.call("get_suffixes");
|
|
|
#ifdef __linux
|
|
|
#ifdef _DEBUG
|
|
|
// First look for shared libraries with the '_d' suffix in debug mode on Linux.
|
|
|
// This is a workaround, because python does not append the '_d' suffix on Linux
|
|
|
// and would always load the release library otherwise.
|
|
|
_sharedLibrarySuffixes << "_d.so";
|
|
|
#endif
|
|
|
#endif
|
|
|
Q_FOREACH (QVariant entry, result.toList()) {
|
|
|
QVariantList suffixEntry = entry.toList();
|
|
|
if (suffixEntry.count()==3) {
|
|
|
int code = suffixEntry.at(2).toInt();
|
|
|
if (code == cExtensionCode) {
|
|
|
_sharedLibrarySuffixes << suffixEntry.at(0).toString();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
|
|
|
{
|
|
|
PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
|
|
|
_currentClassInfoForClassWrapperCreation = NULL;
|
|
|
return info;
|
|
|
}
|
|
|
|
|
|
void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
|
|
|
{
|
|
|
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) {
|
|
|
// QMetaMethod::signature changed to QMetaMethod::methodSignature in QT5
|
|
|
#if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) )
|
|
|
QByteArray signature = m.methodSignature();
|
|
|
#else
|
|
|
QByteArray signature = m.signature();
|
|
|
#endif
|
|
|
if (signature.startsWith("new_")) {
|
|
|
if ((decoTypes & ConstructorDecorator) == 0) continue;
|
|
|
const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
|
|
|
if (info->parameters().at(0).pointerCount == 1) {
|
|
|
QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
|
|
|
PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
|
|
|
PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
|
|
|
classInfo->addConstructor(newSlot);
|
|
|
}
|
|
|
} else if (signature.startsWith("delete_")) {
|
|
|
if ((decoTypes & DestructorDecorator) == 0) continue;
|
|
|
QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
|
|
|
PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
|
|
|
PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
|
|
|
classInfo->setDestructor(newSlot);
|
|
|
} else if (signature.startsWith("static_")) {
|
|
|
if ((decoTypes & StaticDecorator) == 0) continue;
|
|
|
QByteArray nameOfClass = signature.mid(7);
|
|
|
nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
|
|
|
PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
|
|
|
PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
|
|
|
classInfo->addDecoratorSlot(newSlot);
|
|
|
} else {
|
|
|
if ((decoTypes & InstanceDecorator) == 0) continue;
|
|
|
const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
|
|
|
if (info->parameters().count()>1) {
|
|
|
PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
|
|
|
if (p.pointerCount==1) {
|
|
|
PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
|
|
|
PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
|
|
|
classInfo->addDecoratorSlot(newSlot);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
|
|
|
{
|
|
|
Q_FOREACH(QString name, names) {
|
|
|
_knownQObjectClassNames.insert(name.toLatin1(), true);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void PythonQtPrivate::removeSignalEmitter(QObject* obj)
|
|
|
{
|
|
|
_signalReceivers.remove(obj);
|
|
|
}
|
|
|
|
|
|
namespace
|
|
|
{
|
|
|
//! adapted from python source file "pythonrun.c", function "handle_system_exit"
|
|
|
//! return the exitcode instead of calling "Py_Exit".
|
|
|
//! it gives the application an opportunity to properly terminate.
|
|
|
int custom_system_exit_exception_handler()
|
|
|
{
|
|
|
PyObject *exception, *value, *tb;
|
|
|
int exitcode = 0;
|
|
|
|
|
|
// if (Py_InspectFlag)
|
|
|
// /* Don't exit if -i flag was given. This flag is set to 0
|
|
|
// * when entering interactive mode for inspecting. */
|
|
|
// return exitcode;
|
|
|
|
|
|
PyErr_Fetch(&exception, &value, &tb);
|
|
|
#ifdef PY3K
|
|
|
std::cout << std::endl;
|
|
|
#else
|
|
|
if (Py_FlushLine())
|
|
|
PyErr_Clear();
|
|
|
#endif
|
|
|
fflush(stdout);
|
|
|
if (value == NULL || value == Py_None)
|
|
|
goto done;
|
|
|
if (PyExceptionInstance_Check(value)) {
|
|
|
/* The error code should be in the `code' attribute. */
|
|
|
PyObject *code = PyObject_GetAttrString(value, "code");
|
|
|
if (code) {
|
|
|
Py_DECREF(value);
|
|
|
value = code;
|
|
|
if (value == Py_None)
|
|
|
goto done;
|
|
|
}
|
|
|
/* If we failed to dig out the 'code' attribute,
|
|
|
just let the else clause below print the error. */
|
|
|
}
|
|
|
#ifdef PY3K
|
|
|
if (PyLong_Check(value))
|
|
|
exitcode = (int)PyLong_AsLong(value);
|
|
|
#else
|
|
|
if (PyInt_Check(value))
|
|
|
exitcode = (int)PyInt_AsLong(value);
|
|
|
#endif
|
|
|
else {
|
|
|
PyObject *sys_stderr = PySys_GetObject(const_cast<char*>("stderr"));
|
|
|
if (sys_stderr != NULL && sys_stderr != Py_None) {
|
|
|
PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW);
|
|
|
} else {
|
|
|
PyObject_Print(value, stderr, Py_PRINT_RAW);
|
|
|
fflush(stderr);
|
|
|
}
|
|
|
PySys_WriteStderr("\n");
|
|
|
exitcode = 1;
|
|
|
}
|
|
|
done:
|
|
|
/* Restore and clear the exception info, in order to properly decref
|
|
|
* the exception, value, and traceback. If we just exit instead,
|
|
|
* these leak, which confuses PYTHONDUMPREFS output, and may prevent
|
|
|
* some finalizers from running.
|
|
|
*/
|
|
|
PyErr_Restore(exception, value, tb);
|
|
|
PyErr_Clear();
|
|
|
return exitcode;
|
|
|
//Py_Exit(exitcode);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool PythonQt::handleError()
|
|
|
{
|
|
|
bool flag = false;
|
|
|
if (PyErr_Occurred()) {
|
|
|
|
|
|
if (_p->_systemExitExceptionHandlerEnabled &&
|
|
|
PyErr_ExceptionMatches(PyExc_SystemExit)) {
|
|
|
int exitcode = custom_system_exit_exception_handler();
|
|
|
Q_EMIT PythonQt::self()->systemExitExceptionRaised(exitcode);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// 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;
|
|
|
}
|
|
|
_p->_hadError = flag;
|
|
|
return flag;
|
|
|
}
|
|
|
|
|
|
bool PythonQt::hadError()const
|
|
|
{
|
|
|
return _p->_hadError;
|
|
|
}
|
|
|
|
|
|
void PythonQt::clearError()
|
|
|
{
|
|
|
_p->_hadError = false;
|
|
|
}
|
|
|
|
|
|
void PythonQt::setSystemExitExceptionHandlerEnabled(bool value)
|
|
|
{
|
|
|
_p->_systemExitExceptionHandlerEnabled = value;
|
|
|
}
|
|
|
|
|
|
bool PythonQt::systemExitExceptionHandlerEnabled() const
|
|
|
{
|
|
|
return _p->_systemExitExceptionHandlerEnabled;
|
|
|
}
|
|
|
|
|
|
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));
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
{
|
|
|
if (!PythonQt::self()) {
|
|
|
std::cout << str.toLatin1().data() << std::endl;
|
|
|
return;
|
|
|
}
|
|
|
Q_EMIT PythonQt::self()->pythonStdOut(str);
|
|
|
}
|
|
|
|
|
|
void PythonQt::stdErrRedirectCB(const QString& str)
|
|
|
{
|
|
|
if (!PythonQt::self()) {
|
|
|
std::cerr << str.toLatin1().data() << std::endl;
|
|
|
return;
|
|
|
}
|
|
|
Q_EMIT PythonQt::self()->pythonStdErr(str);
|
|
|
}
|
|
|
|
|
|
void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
|
|
|
{
|
|
|
_p->_wrappedCB = cb;
|
|
|
}
|
|
|
|
|
|
void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
|
|
|
{
|
|
|
_p->_noLongerWrappedCB = cb;
|
|
|
}
|
|
|
|
|
|
void PythonQt::setProfilingCallback(ProfilingCB* cb)
|
|
|
{
|
|
|
_p->_profilingCB = cb;
|
|
|
}
|
|
|
|
|
|
|
|
|
static PyMethodDef PythonQtMethods[] = {
|
|
|
{NULL, NULL, 0, NULL}
|
|
|
};
|
|
|
|
|
|
#ifdef PY3K
|
|
|
static PyModuleDef PythonQtModuleDef = {
|
|
|
PyModuleDef_HEAD_INIT,
|
|
|
"",
|
|
|
NULL,
|
|
|
-1,
|
|
|
PythonQtMethods,
|
|
|
NULL,
|
|
|
NULL,
|
|
|
NULL,
|
|
|
NULL
|
|
|
};
|
|
|
#endif
|
|
|
|
|
|
void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
|
|
|
{
|
|
|
QByteArray name = "PythonQt";
|
|
|
if (!pythonQtModuleName.isEmpty()) {
|
|
|
name = pythonQtModuleName;
|
|
|
}
|
|
|
#ifdef PY3K
|
|
|
PythonQtModuleDef.m_name = name.constData();
|
|
|
_p->_pythonQtModule = PyModule_Create(&PythonQtModuleDef);
|
|
|
#else
|
|
|
_p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
|
|
|
#endif
|
|
|
_p->_pythonQtModuleName = name;
|
|
|
|
|
|
PythonQtObjectPtr sys;
|
|
|
sys.setNewRef(PyImport_ImportModule("sys"));
|
|
|
|
|
|
if (redirectStdOut) {
|
|
|
PythonQtObjectPtr out;
|
|
|
PythonQtObjectPtr err;
|
|
|
// 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);
|
|
|
}
|
|
|
|
|
|
// add PythonQt to the list of builtin module names
|
|
|
PyObject *old_module_names = PyObject_GetAttrString(sys.object(),"builtin_module_names");
|
|
|
Py_ssize_t old_size = PyTuple_Size(old_module_names);
|
|
|
PyObject *module_names = PyTuple_New(old_size+1);
|
|
|
for(Py_ssize_t i = 0; i < old_size; i++)
|
|
|
PyTuple_SetItem(module_names, i, PyTuple_GetItem(old_module_names, i));
|
|
|
#ifdef PY3K
|
|
|
PyTuple_SetItem(module_names, old_size, PyUnicode_FromString(name.constData()));
|
|
|
#else
|
|
|
PyTuple_SetItem(module_names, old_size, PyString_FromString(name.constData()));
|
|
|
#endif
|
|
|
PyModule_AddObject(sys.object(),"builtin_module_names",module_names);
|
|
|
Py_DecRef(old_module_names);
|
|
|
|
|
|
#ifdef PY3K
|
|
|
PyDict_SetItem(PyObject_GetAttrString(sys.object(), "modules"), PyUnicode_FromString(name.constData()), _p->_pythonQtModule.object());
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString& name)
|
|
|
{
|
|
|
QStringList tmp = name.split(".");
|
|
|
QString methodName = tmp.takeLast();
|
|
|
QString variableName = tmp.join(".");
|
|
|
// TODO: the variableName may be a type name, this needs to be handled differently,
|
|
|
// because it is not necessarily known in the module context
|
|
|
PythonQtObjectPtr variableObject = lookupObject(module, variableName);
|
|
|
if (variableObject.isNull()) {
|
|
|
return "";
|
|
|
}
|
|
|
|
|
|
return getReturnTypeOfWrappedMethodHelper(variableObject, methodName, name);
|
|
|
}
|
|
|
|
|
|
QString PythonQt::getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName)
|
|
|
{
|
|
|
PythonQtObjectPtr typeObject = getObjectByType(typeName);
|
|
|
if (typeObject.isNull()) {
|
|
|
return "";
|
|
|
}
|
|
|
return getReturnTypeOfWrappedMethodHelper(typeObject, methodName, typeName + "." + methodName);
|
|
|
}
|
|
|
|
|
|
QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context)
|
|
|
{
|
|
|
PythonQtObjectPtr methodObject;
|
|
|
if (PyDict_Check(variableObject)) {
|
|
|
methodObject = PyDict_GetItemString(variableObject, methodName.toLatin1().constData());
|
|
|
} else {
|
|
|
methodObject.setNewRef(PyObject_GetAttrString(variableObject, methodName.toLatin1().constData()));
|
|
|
}
|
|
|
if (methodObject.isNull()) {
|
|
|
return "";
|
|
|
}
|
|
|
|
|
|
QString type;
|
|
|
|
|
|
#ifdef PY3K
|
|
|
if (PyType_Check(methodObject)) {
|
|
|
#else
|
|
|
if (methodObject->ob_type == &PyClass_Type || methodObject->ob_type == &PyType_Type) {
|
|
|
#endif
|
|
|
// the methodObject is not a method, but the name of a type/class. This means
|
|
|
// a constructor is called. Return the context.
|
|
|
type = context;
|
|
|
} else if (methodObject->ob_type == &PythonQtSlotFunction_Type) {
|
|
|
QString className;
|
|
|
|
|
|
if (PyObject_TypeCheck(variableObject, &PythonQtInstanceWrapper_Type)) {
|
|
|
// the type name of wrapped instance is the class name
|
|
|
className = variableObject->ob_type->tp_name;
|
|
|
} else {
|
|
|
PyObject* classNameObject = PyObject_GetAttrString(variableObject, "__name__");
|
|
|
if (classNameObject) {
|
|
|
#ifdef PY3K
|
|
|
Q_ASSERT(PyUnicode_Check(classNameObject));
|
|
|
className = PyUnicode_AsUTF8(classNameObject);
|
|
|
#else
|
|
|
Q_ASSERT(PyString_Check(classNameObject));
|
|
|
className = PyString_AsString(classNameObject);
|
|
|
#endif
|
|
|
Py_DECREF(classNameObject);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (!className.isEmpty()) {
|
|
|
PythonQtClassInfo* info = _p->_knownClassInfos.value(className.toLatin1().constData());
|
|
|
if (info) {
|
|
|
PythonQtSlotInfo* slotInfo = info->member(methodName.toLatin1().constData())._slot;
|
|
|
if (slotInfo) {
|
|
|
if (slotInfo->metaMethod()) {
|
|
|
type = slotInfo->metaMethod()->typeName();
|
|
|
if (!type.isEmpty()) {
|
|
|
QChar c = type.at(type.length()-1);
|
|
|
while (c == '*' || c == '&') {
|
|
|
type.truncate(type.length()-1);
|
|
|
if (!type.isEmpty()) {
|
|
|
c = type.at(type.length()-1);
|
|
|
} else {
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
// split away template arguments
|
|
|
type = type.split("<").first();
|
|
|
// split away const
|
|
|
type = type.split(" ").last().trimmed();
|
|
|
|
|
|
// if the type is a known class info, then create the full type name, i.e. include the
|
|
|
// module name. For example, the slot may return a QDate, then this looks up the
|
|
|
// name _PythonQt.QtCore.QDate.
|
|
|
PythonQtClassInfo* typeInfo = _p->_knownClassInfos.value(type.toLatin1().constData());
|
|
|
if (typeInfo && typeInfo->pythonQtClassWrapper()) {
|
|
|
PyObject* s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__module__");
|
|
|
#ifdef PY3K
|
|
|
Q_ASSERT(PyUnicode_Check(s));
|
|
|
type = QString(PyUnicode_AsUTF8(s));
|
|
|
#else
|
|
|
Q_ASSERT(PyString_Check(s));
|
|
|
type = QString(PyString_AsString(s)) + "." + type;
|
|
|
#endif
|
|
|
Py_DECREF(s);
|
|
|
s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__name__");
|
|
|
#ifdef PY3K
|
|
|
Q_ASSERT(PyUnicode_Check(s));
|
|
|
#else
|
|
|
Q_ASSERT(PyString_Check(s));
|
|
|
#endif
|
|
|
Py_DECREF(s);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return type;
|
|
|
}
|
|
|
|
|
|
void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
|
|
|
{
|
|
|
_p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
|
|
|
}
|
|
|
|
|
|
|
|
|
PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
|
|
|
{
|
|
|
PythonQtClassInfo* info = _knownClassInfos.value(typeName);
|
|
|
if (!info) {
|
|
|
info = new PythonQtClassInfo();
|
|
|
info->setupCPPObject(typeName);
|
|
|
_knownClassInfos.insert(typeName, info);
|
|
|
}
|
|
|
return info;
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
}
|
|
|
|
|
|
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, PyObject* module, int typeSlots)
|
|
|
{
|
|
|
PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
|
|
|
if (!info->pythonQtClassWrapper()) {
|
|
|
info->setTypeSlots(typeSlots);
|
|
|
info->setupCPPObject(typeName);
|
|
|
createPythonQtClassWrapper(info, package, module);
|
|
|
}
|
|
|
if (parentTypeName && strcmp(parentTypeName,"")!=0) {
|
|
|
addParentClass(typeName, parentTypeName, 0);
|
|
|
}
|
|
|
if (wrapperCreator) {
|
|
|
info->setDecoratorProvider(wrapperCreator);
|
|
|
}
|
|
|
if (shell) {
|
|
|
info->setShellSetInstanceWrapperCB(shell);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
PyObject* PythonQtPrivate::packageByName(const char* name)
|
|
|
{
|
|
|
if (name==NULL || name[0]==0) {
|
|
|
name = "private";
|
|
|
}
|
|
|
PyObject* v = _packages.value(name);
|
|
|
if (!v) {
|
|
|
v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
|
|
|
_packages.insert(name, v);
|
|
|
// AddObject steals the reference, so increment it!
|
|
|
Py_INCREF(v);
|
|
|
PyModule_AddObject(_pythonQtModule, name, v);
|
|
|
}
|
|
|
return v;
|
|
|
}
|
|
|
|
|
|
void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
|
|
|
{
|
|
|
QString error = "Return value '" + PythonQtConv::PyObjGetString(result) + "' can not be converted to expected C++ type '" + methodInfo->parameters().at(0).name + "' as return value of virtual method " + signature;
|
|
|
PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
|
|
|
PythonQt::self()->handleError();
|
|
|
}
|
|
|
|
|
|
PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
|
|
|
{
|
|
|
if (_p->_initFlags & ExternalHelp) {
|
|
|
Q_EMIT pythonHelpRequest(QByteArray(info->className()));
|
|
|
return Py_BuildValue("");
|
|
|
} else {
|
|
|
#ifdef PY3K
|
|
|
return PyUnicode_FromString(info->help().toLatin1().data());
|
|
|
#else
|
|
|
return PyString_FromString(info->help().toLatin1().data());
|
|
|
#endif
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void PythonQt::clearNotFoundCachedMembers()
|
|
|
{
|
|
|
Q_FOREACH(PythonQtClassInfo* info, _p->_knownClassInfos) {
|
|
|
info->clearNotFoundCachedMembers();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void PythonQt::removeWrapperFactory( PythonQtCppWrapperFactory* factory )
|
|
|
{
|
|
|
_p->_cppWrapperFactories.removeAll(factory);
|
|
|
}
|
|
|
|
|
|
void PythonQt::removeWrapperFactory( PythonQtForeignWrapperFactory* factory )
|
|
|
{
|
|
|
_p->_foreignWrapperFactories.removeAll(factory);
|
|
|
}
|
|
|
|
|
|
void PythonQtPrivate::removeWrapperPointer(void* obj)
|
|
|
{
|
|
|
_wrappedObjects.remove(obj);
|
|
|
}
|
|
|
|
|
|
void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
|
|
|
{
|
|
|
_wrappedObjects.insert(obj, wrapper);
|
|
|
}
|
|
|
|
|
|
PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
|
|
|
{
|
|
|
PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
|
|
|
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;
|
|
|
PythonQt::self()->clearError();
|
|
|
if (pycode) {
|
|
|
result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
|
|
|
} else {
|
|
|
PythonQt::self()->handleError();
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObject* obj )
|
|
|
{
|
|
|
void* foreignObject = NULL;
|
|
|
for (int i=0; i<_foreignWrapperFactories.size(); i++) {
|
|
|
foreignObject = _foreignWrapperFactories.at(i)->unwrap(classname, obj);
|
|
|
if (foreignObject) {
|
|
|
return foreignObject;
|
|
|
}
|
|
|
}
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
bool PythonQtPrivate::isMethodDescriptor(PyObject* object) const
|
|
|
{
|
|
|
// This implementation is the same as in inspect.ismethoddescriptor(), inspect.py.
|
|
|
if (PyObject_HasAttrString(object, "__get__") &&
|
|
|
!PyObject_HasAttrString(object, "__set__") &&
|
|
|
!PyMethod_Check(object) &&
|
|
|
!PyFunction_Check(object)
|
|
|
#ifndef PY3K
|
|
|
&& !PyClass_Check(object)
|
|
|
#endif
|
|
|
) {
|
|
|
return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
QString PythonQtPrivate::getSignature(PyObject* object)
|
|
|
{
|
|
|
QString signature;
|
|
|
|
|
|
if (object) {
|
|
|
PyMethodObject* method = NULL;
|
|
|
PyFunctionObject* func = NULL;
|
|
|
|
|
|
bool decrefMethod = false;
|
|
|
|
|
|
#ifdef PY3K
|
|
|
if (PyType_Check(object)) {
|
|
|
#else
|
|
|
if (object->ob_type == &PyClass_Type || object->ob_type == &PyType_Type) {
|
|
|
#endif
|
|
|
method = (PyMethodObject*)PyObject_GetAttrString(object, "__init__");
|
|
|
decrefMethod = true;
|
|
|
} else if (object->ob_type == &PyFunction_Type) {
|
|
|
func = (PyFunctionObject*)object;
|
|
|
} else if (object->ob_type == &PyMethod_Type) {
|
|
|
method = (PyMethodObject*)object;
|
|
|
}
|
|
|
if (method) {
|
|
|
if (PyFunction_Check(method->im_func)) {
|
|
|
func = (PyFunctionObject*)method->im_func;
|
|
|
} else if (isMethodDescriptor((PyObject*)method)) {
|
|
|
QString docstr;
|
|
|
PyObject* doc = PyObject_GetAttrString(object, "__doc__");
|
|
|
if (doc) {
|
|
|
#ifdef PY3K
|
|
|
docstr = PyUnicode_AsUTF8(doc);
|
|
|
#else
|
|
|
docstr = PyString_AsString(doc);
|
|
|
#endif
|
|
|
Py_DECREF(doc);
|
|
|
}
|
|
|
|
|
|
PyObject* s = PyObject_GetAttrString(object, "__name__");
|
|
|
if (s) {
|
|
|
#ifdef PY3K
|
|
|
Q_ASSERT(PyUnicode_Check(s));
|
|
|
signature = PyUnicode_AsUTF8(s);
|
|
|
#else
|
|
|
Q_ASSERT(PyString_Check(s));
|
|
|
signature = PyString_AsString(s);
|
|
|
#endif
|
|
|
if (docstr.startsWith(signature + "(")) {
|
|
|
signature = docstr;
|
|
|
} else {
|
|
|
signature += "(...)";
|
|
|
if (!docstr.isEmpty()) {
|
|
|
signature += "\n\n" + docstr;
|
|
|
}
|
|
|
}
|
|
|
Py_DECREF(s);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (func) {
|
|
|
QString funcName;
|
|
|
PyObject* s = PyObject_GetAttrString((PyObject*)func, "__name__");
|
|
|
if (s) {
|
|
|
#ifdef PY3K
|
|
|
Q_ASSERT(PyUnicode_Check(s));
|
|
|
funcName = PyUnicode_AsUTF8(s);
|
|
|
#else
|
|
|
Q_ASSERT(PyString_Check(s));
|
|
|
funcName = PyString_AsString(s);
|
|
|
#endif
|
|
|
Py_DECREF(s);
|
|
|
}
|
|
|
if (method && funcName == "__init__") {
|
|
|
PyObject* s = PyObject_GetAttrString(object, "__name__");
|
|
|
if (s) {
|
|
|
#ifdef PY3K
|
|
|
Q_ASSERT(PyUnicode_Check(s));
|
|
|
funcName = PyUnicode_AsUTF8(s);
|
|
|
#else
|
|
|
Q_ASSERT(PyString_Check(s));
|
|
|
funcName = PyString_AsString(s);
|
|
|
#endif
|
|
|
Py_DECREF(s);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
QStringList arguments;
|
|
|
QStringList defaults;
|
|
|
QString varargs;
|
|
|
QString varkeywords;
|
|
|
// NOTE: This implementation is based on function getargs() in inspect.py.
|
|
|
// inspect.getargs() can handle anonymous (tuple) arguments, while this code does not.
|
|
|
// It can be implemented, but it may be rarely needed and not necessary.
|
|
|
PyCodeObject* code = (PyCodeObject*)func->func_code;
|
|
|
if (code->co_varnames) {
|
|
|
int nargs = code->co_argcount;
|
|
|
Q_ASSERT(PyTuple_Check(code->co_varnames));
|
|
|
for (int i=0; i<nargs; i++) {
|
|
|
PyObject* name = PyTuple_GetItem(code->co_varnames, i);
|
|
|
#ifdef PY3K
|
|
|
Q_ASSERT(PyUnicode_Check(name));
|
|
|
arguments << PyUnicode_AsUTF8(name);
|
|
|
#else
|
|
|
Q_ASSERT(PyString_Check(name));
|
|
|
arguments << PyString_AsString(name);
|
|
|
#endif
|
|
|
}
|
|
|
if (code->co_flags & CO_VARARGS) {
|
|
|
PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
|
|
|
#ifdef PY3K
|
|
|
Q_ASSERT(PyUnicode_Check(s));
|
|
|
varargs = PyUnicode_AsUTF8(s);
|
|
|
#else
|
|
|
Q_ASSERT(PyString_Check(s));
|
|
|
varargs = PyString_AsString(s);
|
|
|
#endif
|
|
|
nargs += 1;
|
|
|
}
|
|
|
if (code->co_flags & CO_VARKEYWORDS) {
|
|
|
PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
|
|
|
#ifdef PY3K
|
|
|
Q_ASSERT(PyUnicode_Check(s));
|
|
|
varkeywords = PyUnicode_AsUTF8(s);
|
|
|
#else
|
|
|
Q_ASSERT(PyString_Check(s));
|
|
|
varkeywords = PyString_AsString(s);
|
|
|
#endif
|
|
|
}
|
|
|
}
|
|
|
|
|
|
PyObject* defaultsTuple = func->func_defaults;
|
|
|
if (defaultsTuple) {
|
|
|
Q_ASSERT(PyTuple_Check(defaultsTuple));
|
|
|
for (Py_ssize_t i=0; i<PyTuple_Size(defaultsTuple); i++) {
|
|
|
PyObject* d = PyTuple_GetItem(defaultsTuple, i);
|
|
|
PyObject* s = PyObject_Repr(d);
|
|
|
#ifdef PY3K
|
|
|
Q_ASSERT(PyUnicode_Check(s));
|
|
|
defaults << PyUnicode_AsUTF8(s);
|
|
|
#else
|
|
|
Q_ASSERT(PyString_Check(s));
|
|
|
defaults << PyString_AsString(s);
|
|
|
#endif
|
|
|
Py_DECREF(s);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int firstdefault = arguments.size() - defaults.size();
|
|
|
for (int i=0; i<arguments.size(); i++) {
|
|
|
if (!signature.isEmpty()) { signature += ", "; }
|
|
|
if (!method || i>0 || arguments[i] != "self") {
|
|
|
signature += arguments[i];
|
|
|
if (i >= firstdefault) {
|
|
|
signature += "=" + defaults[i-firstdefault];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (!varargs.isEmpty()) {
|
|
|
if (!signature.isEmpty()) { signature += ", "; }
|
|
|
signature += "*" + varargs;
|
|
|
}
|
|
|
if (!varkeywords.isEmpty()) {
|
|
|
if (!signature.isEmpty()) { signature += ", "; }
|
|
|
signature += "**" + varkeywords;
|
|
|
}
|
|
|
signature = funcName + "(" + signature + ")";
|
|
|
}
|
|
|
|
|
|
if (method && decrefMethod) {
|
|
|
Py_DECREF(method);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return signature;
|
|
|
}
|
|
|
|
|
|
void PythonQtPrivate::shellClassDeleted( void* shellClass )
|
|
|
{
|
|
|
PythonQtInstanceWrapper* wrap = _wrappedObjects.value(shellClass);
|
|
|
if (wrap && wrap->_wrappedPtr) {
|
|
|
// this is a pure C++ wrapper and the shell has gone, so we need
|
|
|
// to set the _wrappedPtr to NULL on the wrapper
|
|
|
wrap->_wrappedPtr = NULL;
|
|
|
// and then we remove the wrapper, since the wrapped class is gone
|
|
|
_wrappedObjects.remove(shellClass);
|
|
|
}
|
|
|
// if the wrapper is a QObject, we do not handle this here,
|
|
|
// it will be handled by the QPointer<> to the QObject, which becomes NULL
|
|
|
// via the QObject destructor.
|
|
|
}
|
|
|
|
|
|
PyObject* PythonQtPrivate::wrapMemoryAsBuffer( const void* data, Py_ssize_t size )
|
|
|
{
|
|
|
// P3K port needed later on! -- not anymore :D
|
|
|
#ifdef PY3K
|
|
|
return PyMemoryView_FromMemory((char*)data, size, PyBUF_READ);
|
|
|
#else
|
|
|
return PyBuffer_FromMemory((char*)data, size);
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
PyObject* PythonQtPrivate::wrapMemoryAsBuffer( void* data, Py_ssize_t size )
|
|
|
{
|
|
|
// P3K port needed later on! -- not anymore :D
|
|
|
#ifdef PY3K
|
|
|
return PyMemoryView_FromMemory((char*)data, size, PyBUF_READ | PyBUF_WRITE);
|
|
|
#else
|
|
|
return PyBuffer_FromReadWriteMemory((char*)data, size);
|
|
|
#endif
|
|
|
}
|
|
|
|