Path: blob/devel/ElmerGUI/PythonQt/src/PythonQtSlot.cpp
3206 views
/*1*2* Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.3*4* This library is free software; you can redistribute it and/or5* modify it under the terms of the GNU Lesser General Public6* License as published by the Free Software Foundation; either7* version 2.1 of the License, or (at your option) any later version.8*9* This library is distributed in the hope that it will be useful,10* but WITHOUT ANY WARRANTY; without even the implied warranty of11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12* Lesser General Public License for more details.13*14* Further, this software is distributed without any warranty that it is15* free of the rightful claim of any third person regarding infringement16* or the like. Any license provided herein, whether implied or17* otherwise, applies only to this software file. Patent licenses, if18* any, provided herein do not apply to combinations of this program with19* other software, or any other product whatsoever.20*21* You should have received a copy of the GNU Lesser General Public22* License along with this library; if not, write to the Free Software23* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA24*25* Contact information: MeVis Research GmbH, Universitaetsallee 29,26* 28359 Bremen, Germany or:27*28* http://www.mevis.de29*30*/3132//----------------------------------------------------------------------------------33/*!34// \file PythonQtSlot.cpp35// \author Florian Link36// \author Last changed by $Author: florian $37// \date 2006-0538*/39//----------------------------------------------------------------------------------4041#include "PythonQt.h"42#include "PythonQtSlot.h"43#include "PythonQtWrapper.h"44#include "PythonQtClassInfo.h"45#include "PythonQtMisc.h"46#include "PythonQtConversion.h"47#include <iostream>4849#define PYTHONQT_MAX_ARGS 325051// Correction by A. Powell:52#if PY_VERSION_HEX >= 0x02060000 || defined EG_MODS53#define WRITE_RESTRICTED PY_WRITE_RESTRICTED54#endif5556PyObject* PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, bool isVariantCall, void* firstArgument)57{58if (isVariantCall && info->isInstanceDecorator()) return NULL;5960static unsigned int recursiveEntry = 0;6162// store the current storage position, so that we can get back to this state after a slot is called63// (do this locally, so that we have all positions on the stack64PythonQtValueStoragePosition globalValueStoragePos;65PythonQtValueStoragePosition globalPtrStoragePos;66PythonQtValueStoragePosition globalVariantStoragePos;67PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);68PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);69PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);7071recursiveEntry++;7273// the arguments that are passed to qt_metacall74void* argList[PYTHONQT_MAX_ARGS];75PyObject* result = NULL;76int argc = info->parameterCount();77const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();7879bool returnValueIsEnum = false;80const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);81if (returnValueParam.typeId != QMetaType::Void) {82// extra handling of enum return value83if (!returnValueParam.isPointer && returnValueParam.typeId == PythonQtMethodInfo::Unknown) {84returnValueIsEnum = PythonQt::priv()->isEnumType(objectToCall->metaObject(), returnValueParam.name);85if (returnValueIsEnum) {86PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]);87}88} else {89// create empty default value for the return value90argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);91}92} else {93argList[0] = NULL;94}9596const QMetaObject* meta = objectToCall?objectToCall->metaObject():NULL;97bool ok = true;98if (info->isInstanceDecorator() || isVariantCall) {99if (!firstArgument) {100argList[1] = &objectToCall;101} else {102// for the variant call we take the ptr to the variant data, for decorators on CPP objects, we take the cpp ptr103argList[1] = &firstArgument;104}105if (ok) {106for (int i = 2; i<argc && ok; i++) {107const PythonQtSlotInfo::ParameterInfo& param = params.at(i);108//std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;109argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, meta);110if (argList[i]==NULL) {111ok = false;112break;113}114}115}116} else {117for (int i = 1; i<argc && ok; i++) {118const PythonQtSlotInfo::ParameterInfo& param = params.at(i);119//std::cout << param.name.data() << " " << param.typeId << (param.isPointer?"*":"") << (param.isConst?" const":"") << std::endl;120argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, meta);121if (argList[i]==NULL) {122ok = false;123break;124}125}126}127128if (ok) {129(info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);130131if (!returnValueIsEnum) {132result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);133} else {134result = PyInt_FromLong(*((unsigned int*)argList[0]));135}136}137recursiveEntry--;138139// reset the parameter storage position to the stored pos to "pop" the parameter stack140PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);141PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);142PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);143144// NOTE: it is important to only return here, otherwise the stack will not be popped!!!145return result;146}147148//-----------------------------------------------------------------------------------149150static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;151152PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)153{154PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;155PythonQtSlotInfo* info = f->m_ml;156if (f->m_self->ob_type == &PythonQtWrapper_Type) {157PythonQtWrapper* self = (PythonQtWrapper*) f->m_self;158return PythonQtSlotFunction_CallImpl(self->_obj, info, args, kw, false, self->_wrappedPtr);159} else if (f->m_self->ob_type == &PythonQtVariantWrapper_Type) {160PythonQtVariantWrapper* self = (PythonQtVariantWrapper*) f->m_self;161if (!info->isClassDecorator()) {162return PythonQtSlotFunction_CallImpl(self->_wrapper, info, args, kw, true, (void*)self->_variant->constData());163} else {164return PythonQtSlotFunction_CallImpl(NULL, info, args, kw);165}166} else if (f->m_self->ob_type == &PythonQtMetaObjectWrapper_Type) {167return PythonQtSlotFunction_CallImpl(NULL, info, args, kw);168} else {169return NULL;170}171}172173PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, bool isVariantCall, void* firstArg)174{175int argc = PyTuple_Size(args);176177#ifdef PYTHONQT_DEBUG178std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;179#endif180181PyObject* r = NULL;182183if (info->nextInfo()) {184// overloaded slot call, try on all slots with strict conversion first185PythonQtSlotInfo* i = info;186while (i && r==NULL) {187bool skipFirst = (i->isInstanceDecorator() || isVariantCall);188if (i->parameterCount()-1-(skipFirst?1:0) == argc) {189r = PythonQtCallSlot(objectToCall, args, true, i, isVariantCall, firstArg);190}191i = i->nextInfo();192}193if (!r) {194// try on all slots with non-strict conversion195i = info;196while (i && r==NULL) {197bool skipFirst = (i->isInstanceDecorator() || isVariantCall);198if (i->parameterCount()-1-(skipFirst?1:0) == argc) {199r = PythonQtCallSlot(objectToCall, args, false, i, isVariantCall, firstArg);200}201i = i->nextInfo();202}203}204if (r==0) {205QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");206PythonQtSlotInfo* i = info;207while (i) {208bool skipFirst = (i->isInstanceDecorator() || isVariantCall);209e += QString(i->fullSignature(skipFirst)) + "\n";210i = i->nextInfo();211}212PyErr_SetString(PyExc_ValueError, e.toLatin1().data());213}214} else {215// simple (non-overloaded) slot call216bool skipFirst = (info->isInstanceDecorator() || isVariantCall);217if (info->parameterCount()-1-(skipFirst?1:0) == argc) {218r = PythonQtCallSlot(objectToCall, args, false, info, isVariantCall, firstArg);219if (!r) {220QString e = QString("Called ") + info->fullSignature(skipFirst) + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);221PyErr_SetString(PyExc_ValueError, e.toLatin1().data());222}223} else {224QString e = QString("Called ") + info->fullSignature(skipFirst) + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);225PyErr_SetString(PyExc_ValueError, e.toLatin1().data());226}227}228229return r;230}231232PyObject *233PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)234{235PythonQtSlotFunctionObject *op;236op = pythonqtslot_free_list;237if (op != NULL) {238pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);239PyObject_INIT(op, &PythonQtSlotFunction_Type);240}241else {242op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);243if (op == NULL)244return NULL;245}246op->m_ml = ml;247Py_XINCREF(self);248op->m_self = self;249Py_XINCREF(module);250op->m_module = module;251PyObject_GC_Track(op);252return (PyObject *)op;253}254255PythonQtSlotInfo*256PythonQtSlotFunction_GetSlotInfo(PyObject *op)257{258if (!PythonQtSlotFunction_Check(op)) {259PyErr_BadInternalCall();260return NULL;261}262return ((PythonQtSlotFunctionObject *)op) -> m_ml;263}264265PyObject *266PythonQtSlotFunction_GetSelf(PyObject *op)267{268if (!PythonQtSlotFunction_Check(op)) {269PyErr_BadInternalCall();270return NULL;271}272return ((PythonQtSlotFunctionObject *)op) -> m_self;273}274275/* Methods (the standard built-in methods, that is) */276277static void278meth_dealloc(PythonQtSlotFunctionObject *m)279{280PyObject_GC_UnTrack(m);281Py_XDECREF(m->m_self);282Py_XDECREF(m->m_module);283m->m_self = (PyObject *)pythonqtslot_free_list;284pythonqtslot_free_list = m;285}286287static PyObject *288meth_get__doc__(PythonQtSlotFunctionObject *m, void *closure)289{290Py_INCREF(Py_None);291return Py_None;292}293294static PyObject *295meth_get__name__(PythonQtSlotFunctionObject *m, void *closure)296{297return PyString_FromString(m->m_ml->metaMethod()->signature());298}299300static int301meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)302{303int err;304if (m->m_self != NULL) {305err = visit(m->m_self, arg);306if (err)307return err;308}309if (m->m_module != NULL) {310err = visit(m->m_module, arg);311if (err)312return err;313}314return 0;315}316317static PyObject *318meth_get__self__(PythonQtSlotFunctionObject *m, void *closure)319{320PyObject *self;321if (PyEval_GetRestricted()) {322PyErr_SetString(PyExc_RuntimeError,323"method.__self__ not accessible in restricted mode");324return NULL;325}326self = m->m_self;327if (self == NULL)328self = Py_None;329Py_INCREF(self);330return self;331}332333static PyGetSetDef meth_getsets [] = {334{"__doc__", (getter)meth_get__doc__, NULL, NULL},335{"__name__", (getter)meth_get__name__, NULL, NULL},336{"__self__", (getter)meth_get__self__, NULL, NULL},337{0}338};339340#define OFF(x) offsetof(PythonQtSlotFunctionObject, x)341342static PyMemberDef meth_members[] = {343{"__module__", T_OBJECT, OFF(m_module), WRITE_RESTRICTED},344{NULL}345};346347static PyObject *348meth_repr(PythonQtSlotFunctionObject *m)349{350return PyString_FromFormat("<built-in qt slot %s of %s object at %p>",351m->m_ml->metaMethod()->signature(),352m->m_self->ob_type->tp_name,353m->m_self);354}355356static int357meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)358{359if (a->m_self != b->m_self)360return (a->m_self < b->m_self) ? -1 : 1;361if (a->m_ml == b->m_ml)362return 0;363if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)364return -1;365else366return 1;367}368369static long370meth_hash(PythonQtSlotFunctionObject *a)371{372long x,y;373if (a->m_self == NULL)374x = 0;375else {376x = PyObject_Hash(a->m_self);377if (x == -1)378return -1;379}380y = _Py_HashPointer((void*)(a->m_ml));381if (y == -1)382return -1;383x ^= y;384if (x == -1)385x = -2;386return x;387}388389390PyTypeObject PythonQtSlotFunction_Type = {391PyObject_HEAD_INIT(&PyType_Type)3920,393"builtin_qt_slot",394sizeof(PythonQtSlotFunctionObject),3950,396(destructor)meth_dealloc, /* tp_dealloc */3970, /* tp_print */3980, /* tp_getattr */3990, /* tp_setattr */400(cmpfunc)meth_compare, /* tp_compare */401(reprfunc)meth_repr, /* tp_repr */4020, /* tp_as_number */4030, /* tp_as_sequence */4040, /* tp_as_mapping */405(hashfunc)meth_hash, /* tp_hash */406PythonQtSlotFunction_Call, /* tp_call */4070, /* tp_str */408PyObject_GenericGetAttr, /* tp_getattro */4090, /* tp_setattro */4100, /* tp_as_buffer */411Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */4120, /* tp_doc */413(traverseproc)meth_traverse, /* tp_traverse */4140, /* tp_clear */4150, /* tp_richcompare */4160, /* tp_weaklistoffset */4170, /* tp_iter */4180, /* tp_iternext */4190, /* tp_methods */420meth_members, /* tp_members */421meth_getsets, /* tp_getset */4220, /* tp_base */4230, /* tp_dict */424};425426/* Clear out the free list */427428void429PythonQtSlotFunction_Fini(void)430{431while (pythonqtslot_free_list) {432PythonQtSlotFunctionObject *v = pythonqtslot_free_list;433pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);434PyObject_GC_Del(v);435}436}437438439440