Path: blob/devel/ElmerGUI/PythonQt/src/PythonQtWrapper.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 PythonQtWrapper.cpp35// \author Florian Link36// \author Last changed by $Author: florian $37// \date 2006-0538*/39//----------------------------------------------------------------------------------4041#include "PythonQtWrapper.h"42#include <QObject>43#include "PythonQt.h"44#include "PythonQtSlot.h"45#include "PythonQtClassInfo.h"46#include "PythonQtConversion.h"4748static void PythonQtWrapper_dealloc(PythonQtWrapper* self)49{50if (self->_wrappedPtr) {5152//mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->_info->wrappedClassName().latin1());5354PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);55// we own our qobject, so we delete it now:56delete self->_obj;57self->_obj = NULL;58if (self->_ownedByPythonQt) {59PythonQtSlotInfo* slot = PythonQt::priv()->getDestructorSlot(self->_info->wrappedCPPClassName());60if (slot) {61void* args[2];62args[0] = NULL;63args[1] = &self->_wrappedPtr;64slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);65self->_wrappedPtr = NULL;66} else {67// TODO: print a warning? we can not destroy that object68}69}70} else if (self->_obj) {71//mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->_info->wrappedClassName().latin1());72PythonQt::priv()->removeWrapperPointer(self->_obj);73if (self->_ownedByPythonQt) {74if (!self->_obj->parent()) {75delete self->_obj;76self->_obj = NULL;77}78}79}80self->ob_type->tp_free((PyObject*)self);81}8283static PyObject* PythonQtWrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)84{85PythonQtWrapper *self;8687self = (PythonQtWrapper *)type->tp_alloc(type, 0);88if (self != NULL) {89self->_info = NULL;90self->_obj = NULL;91self->_wrappedPtr = NULL;92self->_ownedByPythonQt = false;93}94return (PyObject *)self;95}9697static int PythonQtWrapper_init(PythonQtWrapper *self, PyObject *args, PyObject *kwds)98{99return 0;100}101102static PyObject *PythonQtWrapper_classname(PythonQtWrapper* type)103{104return PyString_FromString(type->_info->className());105}106107static PyObject *PythonQtWrapper_help(PythonQtWrapper* type)108{109return PythonQt::self()->helpCalled(type->_info);110}111112113static PyMethodDef PythonQtWrapper_methods[] = {114{"className", (PyCFunction)PythonQtWrapper_classname, METH_NOARGS,115"Return the classname of the object"116},117{"help", (PyCFunction)PythonQtWrapper_help, METH_NOARGS,118"Shows the help of available methods for this class"119},120{NULL} /* Sentinel */121};122123124static PyObject *PythonQtWrapper_getattro(PyObject *obj,PyObject *name)125{126const char *attributeName;127PythonQtWrapper *wt = (PythonQtWrapper *)obj;128129if ((attributeName = PyString_AsString(name)) == NULL) {130return NULL;131}132133if (!wt->_obj && !wt->_wrappedPtr) {134QString error = QString("Trying to read attribute '") + attributeName + "' from a destroyed " + wt->_info->className() + " object";135PyErr_SetString(PyExc_ValueError, error.toLatin1().data());136return NULL;137}138139// mlabDebugConst("Python","get " << attributeName);140141// TODO: dynamic properties are missing142143PythonQtMemberInfo member = wt->_info->member(attributeName);144switch (member._type) {145case PythonQtMemberInfo::Property:146if (wt->_obj) {147return PythonQtConv::QVariantToPyObject(member._property.read(wt->_obj));148}149break;150case PythonQtMemberInfo::Slot:151return PythonQtSlotFunction_New(member._slot, obj, NULL);152break;153case PythonQtMemberInfo::EnumValue:154return PyInt_FromLong(member._enumValue);155break;156}157158// look for the internal methods (className(), help())159PyObject* internalMethod = Py_FindMethod( PythonQtWrapper_methods, obj, (char*)attributeName);160if (internalMethod) {161return internalMethod;162}163PyErr_Clear();164165if (wt->_obj) {166// look for a child167QObjectList children = wt->_obj->children();168for (int i = 0; i < children.count(); i++) {169QObject *child = children.at(i);170if (child->objectName() == attributeName) {171return PythonQt::self()->priv()->wrapQObject(child);172}173}174}175176if (qstrcmp(attributeName, "__dict__")==0) {177QStringList l = wt->_info->memberList(false);178PyObject* dict = PyDict_New();179foreach (QString name, l) {180//PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());181PyDict_SetItemString(dict, name.toLatin1().data(), Py_None);182//Py_DECREF(o);183}184// Note: we do not put children into the dict, is would look confusing?!185return dict;186}187188189QString error = QString(wt->_info->className()) + " has no attribute named '" + QString(attributeName) + "'";190PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());191return NULL;192}193194static int PythonQtWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)195{196QString error;197char *attributeName;198PythonQtWrapper *wt = (PythonQtWrapper *)obj;199200if ((attributeName = PyString_AsString(name)) == NULL)201return -1;202203if (!wt->_obj) {204error = QString("Trying to set attribute '") + attributeName + "' on a destroyed " + wt->_info->className() + " object";205PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());206return -1;207}208209PythonQtMemberInfo member = wt->_info->member(attributeName);210if (member._type == PythonQtMemberInfo::Property) {211QMetaProperty prop = member._property;212if (prop.isWritable()) {213QVariant v;214if (prop.isEnumType()) {215// this will give us either a string or an int, everything else will probably be an error216v = PythonQtConv::PyObjToQVariant(value);217} else {218int t = prop.userType();219v = PythonQtConv::PyObjToQVariant(value, t);220}221bool success = false;222if (v.isValid()) {223success = prop.write(wt->_obj, v);224}225if (success) {226return 0;227} else {228error = QString("Property '") + attributeName + "' of type '" +229prop.typeName() + "' does not accept an object of type "230+ QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";231}232} else {233error = QString("Property '") + attributeName + "' of " + wt->_info->className() + " object is not writable";234}235} else {236if (member._type == PythonQtMemberInfo::Slot) {237error = QString("Slot '") + attributeName + "' can not be overwritten on " + wt->_info->className() + " object";238} else if (member._type == PythonQtMemberInfo::EnumValue) {239error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + wt->_info->className() + " object";240}241}242243PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());244return -1;245}246247static PyObject * PythonQtWrapper_repr(PyObject * obj)248{249PythonQtWrapper* wt = (PythonQtWrapper*)obj;250if (wt->_wrappedPtr) {251if (wt->_obj) {252return PyString_FromFormat("%s (C++ Object 0x%x wrapped by %s 0x%x))", wt->_info->className(), wt->_wrappedPtr, wt->_obj->metaObject()->className(), wt->_obj);253} else {254return PyString_FromFormat("%s (C++ Object 0x%x unwrapped)", wt->_info->className(), wt->_wrappedPtr);255}256} else {257return PyString_FromFormat("%s (QObject 0x%x)", wt->_info->className(), wt->_obj, wt->_wrappedPtr);258}259}260261static int PythonQtWrapper_compare(PyObject * obj1, PyObject * obj2)262{263if (obj1->ob_type == &PythonQtWrapper_Type &&264obj2->ob_type == &PythonQtWrapper_Type) {265266PythonQtWrapper* w1 = (PythonQtWrapper*)obj1;267PythonQtWrapper* w2 = (PythonQtWrapper*)obj2;268if (w1->_wrappedPtr != NULL) {269if (w1->_wrappedPtr == w1->_wrappedPtr) {270return 0;271} else {272return -1;273}274} else if (w1->_obj == w2->_obj) {275return 0;276} else {277return -1;278}279} else {280return -1;281}282}283284static int PythonQtWrapper_nonzero(PyObject *obj)285{286PythonQtWrapper* wt = (PythonQtWrapper*)obj;287return (wt->_wrappedPtr == NULL && wt->_obj == NULL)?0:1;288}289290// we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr291static PyNumberMethods PythonQtWrapper_as_number = {2920, /* nb_add */2930, /* nb_subtract */2940, /* nb_multiply */2950, /* nb_divide */2960, /* nb_remainder */2970, /* nb_divmod */2980, /* nb_power */2990, /* nb_negative */3000, /* nb_positive */3010, /* nb_absolute */302PythonQtWrapper_nonzero, /* nb_nonzero */3030, /* nb_invert */3040, /* nb_lshift */3050, /* nb_rshift */3060, /* nb_and */3070, /* nb_xor */3080, /* nb_or */3090, /* nb_coerce */3100, /* nb_int */3110, /* nb_long */3120, /* nb_float */3130, /* nb_oct */3140, /* nb_hex */3150, /* nb_inplace_add */3160, /* nb_inplace_subtract */3170, /* nb_inplace_multiply */3180, /* nb_inplace_divide */3190, /* nb_inplace_remainder */3200, /* nb_inplace_power */3210, /* nb_inplace_lshift */3220, /* nb_inplace_rshift */3230, /* nb_inplace_and */3240, /* nb_inplace_xor */3250, /* nb_inplace_or */3260, /* nb_floor_divide */3270, /* nb_true_divide */3280, /* nb_inplace_floor_divide */3290, /* nb_inplace_true_divide */330};331332PyTypeObject PythonQtWrapper_Type = {333PyObject_HEAD_INIT(NULL)3340, /*ob_size*/335"PythonQt.PythonQtWrapper", /*tp_name*/336sizeof(PythonQtWrapper), /*tp_basicsize*/3370, /*tp_itemsize*/338(destructor)PythonQtWrapper_dealloc, /*tp_dealloc*/3390, /*tp_print*/3400, /*tp_getattr*/3410, /*tp_setattr*/342PythonQtWrapper_compare, /*tp_compare*/343PythonQtWrapper_repr, /*tp_repr*/344&PythonQtWrapper_as_number, /*tp_as_number*/3450, /*tp_as_sequence*/3460, /*tp_as_mapping*/3470, /*tp_hash */3480, /*tp_call*/3490, /*tp_str*/350PythonQtWrapper_getattro, /*tp_getattro*/351PythonQtWrapper_setattro, /*tp_setattro*/3520, /*tp_as_buffer*/353Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/354"PythonQtWrapper object", /* tp_doc */3550, /* tp_traverse */3560, /* tp_clear */3570, /* tp_richcompare */3580, /* tp_weaklistoffset */3590, /* tp_iter */3600, /* tp_iternext */3610, /* tp_methods */3620, /* tp_members */3630, /* tp_getset */3640, /* tp_base */3650, /* tp_dict */3660, /* tp_descr_get */3670, /* tp_descr_set */3680, /* tp_dictoffset */369(initproc)PythonQtWrapper_init, /* tp_init */3700, /* tp_alloc */371PythonQtWrapper_new, /* tp_new */372};373374//-------------------------------------------------------375376377378