/* * * 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 * */ #include "PythonQtProperty.h" #include "PythonQtSignal.h" #include "PythonQtConversion.h" int PythonQtProperty_init(PyObject* object, PyObject* args, PyObject* kw) { PythonQtProperty* self = (PythonQtProperty*)object; self->data = new PythonQtPropertyData(); PythonQtPropertyData* data = self->data; PyObject* type = nullptr; static const char* kwlist[] = {"type", "fget", "fset", "freset", "fdel", "doc", "designable", "scriptable", "stored", "user", "constant", "final", "notify", nullptr}; if (!PyArg_ParseTupleAndKeywords(args, kw, "O|OOOOObbbbbbO!:QtCore.QProperty", (char**)kwlist, &type, &(data->fget), &(data->fset), &(data->freset), &(data->fdel), &(data->doc), &(data->designable), &(data->scriptable), &(data->stored), &(data->user), &(data->constant), &(data->final), &PythonQtSignalFunction_Type, &(data->notify))) { return 0; } data->cppType = PythonQtConv::getCPPTypeName(type); if (data->cppType.isEmpty()) { PyErr_Format(PyExc_TypeError, "Unknown Property type: %s", type->ob_type->tp_name); return -1; } if (data->fget == Py_None) { data->fget = nullptr; } if (data->fset == Py_None) { data->fset = nullptr; } if (data->freset == Py_None) { data->freset = nullptr; } if (data->fdel == Py_None) { data->fdel = nullptr; } if (data->doc == Py_None) { data->doc = nullptr; } if (data->fdel) { std::cerr << "Property: fdel is not yet supported!" << std::endl; } Py_XINCREF(data->fget); Py_XINCREF(data->fset); Py_XINCREF(data->freset); Py_XINCREF(data->fdel); Py_XINCREF(data->notify); Py_XINCREF(data->doc); return 1; } void PythonQtProperty_dealloc(PyObject* object) { PythonQtProperty* self = (PythonQtProperty*)object; Py_CLEAR(self->data->fget); Py_CLEAR(self->data->fset); Py_CLEAR(self->data->freset); Py_CLEAR(self->data->fdel); Py_CLEAR(self->data->notify); Py_CLEAR(self->data->doc); delete self->data; self->data = nullptr; Py_TYPE(object)->tp_free(object); } PyObject* PythonQtProperty_setter(PyObject* object, PyObject* func) { PythonQtProperty* self = (PythonQtProperty*)object; if (PyFunction_Check(func)) { if (self->data->fset) { Py_DECREF(self->data->fset); } Py_INCREF(func); self->data->fset = func; // return ourselves, so that setter can be used as a decorator Py_INCREF(object); return object; } else { PyErr_SetString(PyExc_TypeError, "Property needs a callable as fset."); return nullptr; } } PyObject* PythonQtProperty_getter(PyObject* object, PyObject* func) { PythonQtProperty* self = (PythonQtProperty*)object; if (PyFunction_Check(func)) { if (self->data->fget) { Py_DECREF(self->data->fget); } Py_INCREF(func); self->data->fget = func; // return ourselves, so that setter can be used as a decorator Py_INCREF(object); return object; } else { PyErr_SetString(PyExc_TypeError, "Property needs a callable as fget."); return nullptr; } } PyObject* PythonQtProperty_call(PyObject* object, PyObject* args, PyObject* kw) { Q_UNUSED(kw) if (PyTuple_Size(args) == 1) { PyObject* func = PyTuple_GetItem(args, 0); return PythonQtProperty_getter(object, func); } else { PyErr_SetString(PyExc_TypeError, "Property expects a single callable."); return nullptr; } } static PyMethodDef PythonQtProperty_methods[] = { {"setter", (PyCFunction)PythonQtProperty_setter, METH_O, "Sets the fset function."}, {"getter", (PyCFunction)PythonQtProperty_getter, METH_O, "Sets the fget function."}, {"write", (PyCFunction)PythonQtProperty_setter, METH_O, "Sets the fset function."}, {"read", (PyCFunction)PythonQtProperty_getter, METH_O, "Sets the fget function."}, {nullptr, nullptr, 0, nullptr} /* Sentinel */ }; static PyObject* PythonQtProperty_get_doc(PythonQtProperty* self, void* /*closure*/) { if (self->data->doc) { Py_INCREF(self->data->doc); return self->data->doc; } else { //TODO: we could get the doc string from the fget method if no doc string is given... Py_RETURN_NONE; } } static PyGetSetDef PythonQtProperty_getsets[] = { {const_cast("__doc__"), (getter)PythonQtProperty_get_doc, nullptr, nullptr}, {nullptr, nullptr, nullptr, nullptr}, }; PyDoc_STRVAR(PythonQtProperty_doc, "Property(type, fget=None, fset=None, freset=None, fdel=None, doc=None,\n" " designable=True, scriptable=True, stored=True, user=False,\n" " constant=False, final=False, notify=None) -> Property\n"); PyTypeObject PythonQtProperty_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) /*tp_base*/ "PythonQt.QtCore.Property", /*tp_name*/ sizeof(PythonQtProperty), /*tp_basicsize*/ 0, /*tp_itemsize*/ PythonQtProperty_dealloc, /*tp_dealloc*/ 0, /*tp_vectorcall_offset*/ nullptr, /*tp_getattr*/ nullptr, /*tp_setattr*/ nullptr, /*tp_compare*/ nullptr, /*tp_repr*/ nullptr, /*tp_as_number*/ nullptr, /*tp_as_sequence*/ nullptr, /*tp_as_mapping*/ nullptr, /*tp_hash */ PythonQtProperty_call, /*tp_call*/ nullptr, /*tp_str*/ nullptr, /*tp_getattro*/ nullptr, /*tp_setattro*/ nullptr, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ PythonQtProperty_doc, /*tp_doc */ nullptr, /*tp_traverse */ nullptr, /*tp_clear */ nullptr, /*tp_richcompare */ 0, /*tp_weaklistoffset */ nullptr, /*tp_iter */ nullptr, /*tp_iternext */ PythonQtProperty_methods, /*tp_methods */ nullptr, /*tp_members */ PythonQtProperty_getsets, /*tp_getset */ nullptr, /*tp_base */ nullptr, /*tp_dict */ nullptr, /*tp_descr_get */ nullptr, /*tp_descr_set */ 0, /*tp_dictoffset */ PythonQtProperty_init, /*tp_init */ nullptr, /*tp_alloc */ PyType_GenericNew, /*tp_new */ nullptr, /*tp_free */ nullptr, /*tp_is_gc */ nullptr, /*tp_bases */ nullptr, /*tp_mro */ nullptr, /*tp_cache */ nullptr, /*tp_subclasses */ nullptr, /*tp_weaklist */ nullptr, /*tp_del */ }; bool PythonQtPropertyData::callSetter(PyObject* wrapper, PyObject* newValue) { if (fset) { PyObject* pyargs = PyTuple_New(2); PyTuple_SET_ITEM(pyargs, 0, wrapper); PyTuple_SET_ITEM(pyargs, 1, newValue); Py_INCREF(wrapper); Py_INCREF(newValue); PyObject* result = PyObject_CallObject(fset, pyargs); bool ok = (result != nullptr); Py_XDECREF(result); Py_DECREF(pyargs); return ok; } else { PyErr_Format(PyExc_TypeError, "Property is read only."); return false; } } PyObject* PythonQtPropertyData::callGetter(PyObject* wrapper) { if (fget) { PyObject* pyargs = PyTuple_New(1); PyTuple_SET_ITEM(pyargs, 0, wrapper); Py_INCREF(wrapper); PyObject* value = PyObject_CallObject(fget, pyargs); Py_DECREF(pyargs); return value; } else { PyErr_Format(PyExc_TypeError, "Property is write only."); return nullptr; } } bool PythonQtPropertyData::callReset(PyObject* wrapper) { if (freset) { PyObject* pyargs = PyTuple_New(1); PyTuple_SET_ITEM(pyargs, 0, wrapper); Py_INCREF(wrapper); PyObject* result = PyObject_CallObject(freset, pyargs); bool ok = (result != nullptr); Py_XDECREF(result); Py_DECREF(pyargs); return ok; } else { PyErr_Format(PyExc_TypeError, "Property is not resettable."); return false; } }