##// END OF EJS Templates
code cleanup and rename of PythonQtWrapper to PythonQtInstanceWrapper and PythonQtMetaObjectWrapper to PythonQtClassWrapper, since these names match much better what these classes wrap, regarding that we are wrapping CPP objects as well...
code cleanup and rename of PythonQtWrapper to PythonQtInstanceWrapper and PythonQtMetaObjectWrapper to PythonQtClassWrapper, since these names match much better what these classes wrap, regarding that we are wrapping CPP objects as well git-svn-id: svn://svn.code.sf.net/p/pythonqt/code/trunk@52 ea8d5007-eb21-0410-b261-ccb3ea6e24a9

File last commit:

r16:c68e0aff542c
r16:c68e0aff542c
Show More
PythonQtSlot.cpp
445 lines | 14.0 KiB | text/x-c | CppLexer
/*
*
* 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 PythonQtSlot.cpp
// \author Florian Link
// \author Last changed by $Author: florian $
// \date 2006-05
*/
//----------------------------------------------------------------------------------
#include "PythonQt.h"
#include "PythonQtSlot.h"
#include "PythonQtInstanceWrapper.h"
#include "PythonQtClassInfo.h"
#include "PythonQtMisc.h"
#include "PythonQtConversion.h"
#include <iostream>
#define PYTHONQT_MAX_ARGS 32
PyObject* PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument)
{
static unsigned int recursiveEntry = 0;
// store the current storage position, so that we can get back to this state after a slot is called
// (do this locally, so that we have all positions on the stack
PythonQtValueStoragePosition globalValueStoragePos;
PythonQtValueStoragePosition globalPtrStoragePos;
PythonQtValueStoragePosition globalVariantStoragePos;
PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
recursiveEntry++;
// the arguments that are passed to qt_metacall
void* argList[PYTHONQT_MAX_ARGS];
PyObject* result = NULL;
int argc = info->parameterCount();
const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
bool returnValueIsEnum = false;
const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
// set return argument to NULL
argList[0] = NULL;
if (returnValueParam.typeId != QMetaType::Void) {
// extra handling of enum return value
if (!returnValueParam.isPointer && returnValueParam.typeId == PythonQtMethodInfo::Unknown) {
returnValueIsEnum = PythonQt::priv()->isEnumType(objectToCall->metaObject(), returnValueParam.name);
if (returnValueIsEnum) {
// create enum return value
PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]);
}
}
if (argList[0]==NULL) {
// create empty default value for the return value
argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
}
}
const QMetaObject* meta = objectToCall?objectToCall->metaObject():NULL;
bool ok = true;
bool skipFirst = false;
if (info->isInstanceDecorator()) {
skipFirst = true;
if (!firstArgument) {
argList[1] = &objectToCall;
} else {
// for the variant call we take the ptr to the variant data, for decorators on CPP objects, we take the cpp ptr
argList[1] = &firstArgument;
}
if (ok) {
for (int i = 2; i<argc && ok; i++) {
const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
//std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, meta);
if (argList[i]==NULL) {
ok = false;
break;
}
}
}
} else {
for (int i = 1; i<argc && ok; i++) {
const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
//std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;
argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, meta);
if (argList[i]==NULL) {
ok = false;
break;
}
}
}
if (ok) {
(info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
if (!returnValueIsEnum) {
result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
} else {
result = PyInt_FromLong(*((unsigned int*)argList[0]));
}
} else {
QString e = QString("Called ") + info->fullSignature(skipFirst) + ", return type is ignored because it is unknown to PythonQt.";
PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
result = NULL;
}
}
recursiveEntry--;
// reset the parameter storage position to the stored pos to "pop" the parameter stack
PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
// NOTE: it is important to only return here, otherwise the stack will not be popped!!!
return result;
}
//-----------------------------------------------------------------------------------
static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
{
PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
PythonQtSlotInfo* info = f->m_ml;
if (f->m_self->ob_type == &PythonQtInstanceWrapper_Type) {
PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self;
return PythonQtSlotFunction_CallImpl(self->_obj, info, args, kw, self->_wrappedPtr);
} else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
return PythonQtSlotFunction_CallImpl(NULL, info, args, kw);
} else {
return NULL;
}
}
PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg)
{
int argc = PyTuple_Size(args);
#ifdef PYTHONQT_DEBUG
std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
#endif
PyObject* r = NULL;
if (info->nextInfo()) {
// overloaded slot call, try on all slots with strict conversion first
PythonQtSlotInfo* i = info;
while (i && r==NULL) {
bool skipFirst = i->isInstanceDecorator();
if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
PyErr_Clear();
r = PythonQtCallSlot(objectToCall, args, true, i, firstArg);
if (PyErr_Occurred()) break;
}
i = i->nextInfo();
}
if (!r) {
// try on all slots with non-strict conversion
i = info;
while (i && r==NULL) {
bool skipFirst = i->isInstanceDecorator();
if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
PyErr_Clear();
r = PythonQtCallSlot(objectToCall, args, false, i, firstArg);
if (PyErr_Occurred()) break;
}
i = i->nextInfo();
}
}
if (r==NULL && !PyErr_Occurred()) {
QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
PythonQtSlotInfo* i = info;
while (i) {
bool skipFirst = i->isInstanceDecorator();
e += QString(i->fullSignature(skipFirst)) + "\n";
i = i->nextInfo();
}
PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
}
} else {
// simple (non-overloaded) slot call
bool skipFirst = info->isInstanceDecorator();
if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
PyErr_Clear();
r = PythonQtCallSlot(objectToCall, args, false, info, firstArg);
if (r==NULL && !PyErr_Occurred()) {
QString e = QString("Called ") + info->fullSignature(skipFirst) + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
}
} else {
QString e = QString("Called ") + info->fullSignature(skipFirst) + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
}
}
return r;
}
PyObject *
PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
{
PythonQtSlotFunctionObject *op;
op = pythonqtslot_free_list;
if (op != NULL) {
pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
PyObject_INIT(op, &PythonQtSlotFunction_Type);
}
else {
op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
if (op == NULL)
return NULL;
}
op->m_ml = ml;
Py_XINCREF(self);
op->m_self = self;
Py_XINCREF(module);
op->m_module = module;
PyObject_GC_Track(op);
return (PyObject *)op;
}
PythonQtSlotInfo*
PythonQtSlotFunction_GetSlotInfo(PyObject *op)
{
if (!PythonQtSlotFunction_Check(op)) {
PyErr_BadInternalCall();
return NULL;
}
return ((PythonQtSlotFunctionObject *)op) -> m_ml;
}
PyObject *
PythonQtSlotFunction_GetSelf(PyObject *op)
{
if (!PythonQtSlotFunction_Check(op)) {
PyErr_BadInternalCall();
return NULL;
}
return ((PythonQtSlotFunctionObject *)op) -> m_self;
}
/* Methods (the standard built-in methods, that is) */
static void
meth_dealloc(PythonQtSlotFunctionObject *m)
{
PyObject_GC_UnTrack(m);
Py_XDECREF(m->m_self);
Py_XDECREF(m->m_module);
m->m_self = (PyObject *)pythonqtslot_free_list;
pythonqtslot_free_list = m;
}
static PyObject *
meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
{
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
{
return PyString_FromString(m->m_ml->metaMethod()->signature());
}
static int
meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
{
int err;
if (m->m_self != NULL) {
err = visit(m->m_self, arg);
if (err)
return err;
}
if (m->m_module != NULL) {
err = visit(m->m_module, arg);
if (err)
return err;
}
return 0;
}
static PyObject *
meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
{
PyObject *self;
if (PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError,
"method.__self__ not accessible in restricted mode");
return NULL;
}
self = m->m_self;
if (self == NULL)
self = Py_None;
Py_INCREF(self);
return self;
}
static PyGetSetDef meth_getsets [] = {
{"__doc__", (getter)meth_get__doc__, NULL, NULL},
{"__name__", (getter)meth_get__name__, NULL, NULL},
{"__self__", (getter)meth_get__self__, NULL, NULL},
{NULL, NULL, NULL,NULL},
};
#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
#define PY_WRITE_RESTRICTED WRITE_RESTRICTED
#endif
#define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
static PyMemberDef meth_members[] = {
{"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
{NULL}
};
static PyObject *
meth_repr(PythonQtSlotFunctionObject *m)
{
return PyString_FromFormat("<built-in qt slot %s of %s object at %p>",
m->m_ml->metaMethod()->signature(),
m->m_self->ob_type->tp_name,
m->m_self);
}
static int
meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
{
if (a->m_self != b->m_self)
return (a->m_self < b->m_self) ? -1 : 1;
if (a->m_ml == b->m_ml)
return 0;
if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
return -1;
else
return 1;
}
static long
meth_hash(PythonQtSlotFunctionObject *a)
{
long x,y;
if (a->m_self == NULL)
x = 0;
else {
x = PyObject_Hash(a->m_self);
if (x == -1)
return -1;
}
y = _Py_HashPointer((void*)(a->m_ml));
if (y == -1)
return -1;
x ^= y;
if (x == -1)
x = -2;
return x;
}
PyTypeObject PythonQtSlotFunction_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"builtin_qt_slot",
sizeof(PythonQtSlotFunctionObject),
0,
(destructor)meth_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)meth_compare, /* tp_compare */
(reprfunc)meth_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)meth_hash, /* tp_hash */
PythonQtSlotFunction_Call, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
0, /* tp_doc */
(traverseproc)meth_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
meth_members, /* tp_members */
meth_getsets, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
};
/* Clear out the free list */
void
PythonQtSlotFunction_Fini(void)
{
while (pythonqtslot_free_list) {
PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
PyObject_GC_Del(v);
}
}