PythonQt Code
Dynamic Python binding for Qt Applications
Brought to you by:
florianlink,
marcusbarann
--- a/trunk/src/PythonQtInstanceWrapper.cpp +++ b/trunk/src/PythonQtInstanceWrapper.cpp @@ -45,24 +45,31 @@ #include "PythonQtSlot.h" #include "PythonQtClassInfo.h" #include "PythonQtConversion.h" +#include "PythonQtClassWrapper.h" + +PythonQtClassInfo* PythonQtInstanceWrapper::classInfo() +{ + // take the class info from our type object + return ((PythonQtClassWrapper*)ob_type)->_classInfo; +} static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) { // is this a C++ wrapper? if (self->_wrappedPtr) { - //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->_info->wrappedClassName().latin1()); + //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1()); PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr); // we own our qobject, so we delete it now: delete self->_obj; self->_obj = NULL; - if (force || self->_info->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) { - int type = self->_info->metaTypeId(); + if (force || self->classInfo()->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) { + int type = self->classInfo()->metaTypeId(); if (self->_useQMetaTypeDestroy && type>=0) { // use QMetaType to destroy the object QMetaType::destroy(type, self->_wrappedPtr); } else { - PythonQtSlotInfo* slot = PythonQt::priv()->getDestructorSlot(self->_info->className()); + PythonQtSlotInfo* slot = PythonQt::priv()->getDestructorSlot(self->classInfo()->className()); if (slot) { void* args[2]; args[0] = NULL; @@ -80,7 +87,7 @@ } } } else { - //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->_info->wrappedClassName().latin1()); + //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1()); if (self->_objPointerCopy) { PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy); } @@ -107,13 +114,18 @@ self->ob_type->tp_free((PyObject*)self); } -static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/) -{ +static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * args, PyObject * /*kwds*/) +{ + PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type; PythonQtInstanceWrapper *self; - - self = (PythonQtInstanceWrapper *)type->tp_alloc(type, 0); + static PyObject* emptyTuple = NULL; + if (emptyTuple==NULL) { + emptyTuple = PyTuple_New(0); + } + + self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL); + if (self != NULL) { - self->_info = NULL; new (&self->_obj) QPointer<QObject>(); self->_wrappedPtr = NULL; self->_ownedByPythonQt = false; @@ -122,19 +134,51 @@ return (PyObject *)self; } -static int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/) -{ +static int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds) +{ + PyObject* result = NULL; + + if (args == PythonQtPrivate::dummyTuple()) { + // we are called from the internal PythonQt API, so our data will be filled later on... + return 0; + } + + // we are called from python, try to construct our object + if (self->classInfo()->constructors()) { + void* directCPPPointer = NULL; + PythonQtSlotFunction_CallImpl(NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer); + if (PyErr_Occurred()) { + return -1; + } + if (directCPPPointer) { + // change ownershipflag to be owned by PythonQt + self->_ownedByPythonQt = true; + self->_useQMetaTypeDestroy = false; + if (self->classInfo()->isCPPWrapper()) { + self->_wrappedPtr = directCPPPointer; + // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?! + } else { + self->setQObject((QObject*)directCPPPointer); + } + // register with PythonQt + PythonQt::priv()->addWrapperPointer(directCPPPointer, self); + } + } else { + QString error = QString("No constructors available for ") + self->classInfo()->className(); + PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); + return -1; + } return 0; } static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* type) { - return PyString_FromString(type->_info->className()); + return PyString_FromString(type->classInfo()->className()); } static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* type) { - return PythonQt::self()->helpCalled(type->_info); + return PythonQt::self()->helpCalled(type->classInfo()); } static PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self) @@ -169,7 +213,7 @@ } if (!wrapper->_obj && !wrapper->_wrappedPtr) { - QString error = QString("Trying to read attribute '") + attributeName + "' from a destroyed " + wrapper->_info->className() + " object"; + QString error = QString("Trying to read attribute '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object"; PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); return NULL; } @@ -178,7 +222,7 @@ // TODO: dynamic properties are missing - PythonQtMemberInfo member = wrapper->_info->member(attributeName); + PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName); switch (member._type) { case PythonQtMemberInfo::Property: if (wrapper->_obj) { @@ -215,7 +259,7 @@ } if (qstrcmp(attributeName, "__dict__")==0) { - QStringList l = wrapper->_info->memberList(false); + QStringList l = wrapper->classInfo()->memberList(false); PyObject* dict = PyDict_New(); foreach (QString name, l) { //PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data()); @@ -227,7 +271,7 @@ } - QString error = QString(wrapper->_info->className()) + " has no attribute named '" + QString(attributeName) + "'"; + QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'"; PyErr_SetString(PyExc_AttributeError, error.toLatin1().data()); return NULL; } @@ -242,12 +286,12 @@ return -1; if (!wrapper->_obj) { - error = QString("Trying to set attribute '") + attributeName + "' on a destroyed " + wrapper->_info->className() + " object"; + error = QString("Trying to set attribute '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object"; PyErr_SetString(PyExc_AttributeError, error.toLatin1().data()); return -1; } - PythonQtMemberInfo member = wrapper->_info->member(attributeName); + PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName); if (member._type == PythonQtMemberInfo::Property) { QMetaProperty prop = member._property; if (prop.isWritable()) { @@ -271,13 +315,13 @@ + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")"; } } else { - error = QString("Property '") + attributeName + "' of " + wrapper->_info->className() + " object is not writable"; + error = QString("Property '") + attributeName + "' of " + wrapper->classInfo()->className() + " object is not writable"; } } else { if (member._type == PythonQtMemberInfo::Slot) { - error = QString("Slot '") + attributeName + "' can not be overwritten on " + wrapper->_info->className() + " object"; + error = QString("Slot '") + attributeName + "' can not be overwritten on " + wrapper->classInfo()->className() + " object"; } else if (member._type == PythonQtMemberInfo::EnumValue) { - error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + wrapper->_info->className() + " object"; + error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + wrapper->classInfo()->className() + " object"; } } @@ -290,17 +334,17 @@ PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj; QObject *qobj = wrapper->_obj; if (wrapper->_wrappedPtr) { - QString str = PythonQtConv::CPPObjectToString(wrapper->_info->metaTypeId(), wrapper->_wrappedPtr); + QString str = PythonQtConv::CPPObjectToString(wrapper->classInfo()->metaTypeId(), wrapper->_wrappedPtr); if (!str.isEmpty()) { return PyString_FromFormat("%s", str.toLatin1().constData()); } else if (wrapper->_obj) { - return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wrapper->_info->className(), wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj); + return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wrapper->classInfo()->className(), wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj); } else { - return PyString_FromFormat("%s (C++ Object %p)", wrapper->_info->className(), wrapper->_wrappedPtr); + return PyString_FromFormat("%s (C++ Object %p)", wrapper->classInfo()->className(), wrapper->_wrappedPtr); } } else { - return PyString_FromFormat("%s (QObject %p)", wrapper->_info->className(), qobj); + return PyString_FromFormat("%s (QObject %p)", wrapper->classInfo()->className(), qobj); } } @@ -309,24 +353,24 @@ PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj; QObject *qobj = wrapper->_obj; if (wrapper->_wrappedPtr) { - QString str = PythonQtConv::CPPObjectToString(wrapper->_info->metaTypeId(), wrapper->_wrappedPtr); + QString str = PythonQtConv::CPPObjectToString(wrapper->classInfo()->metaTypeId(), wrapper->_wrappedPtr); if (!str.isEmpty()) { - return PyString_FromFormat("%s(%s, %p)", QMetaType::typeName(wrapper->_info->metaTypeId()), str.toLatin1().constData(), wrapper->_wrappedPtr); + return PyString_FromFormat("%s(%s, %p)", QMetaType::typeName(wrapper->classInfo()->metaTypeId()), str.toLatin1().constData(), wrapper->_wrappedPtr); } else if (wrapper->_obj) { - return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wrapper->_info->className(), wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj); + return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", wrapper->classInfo()->className(), wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj); } else { - return PyString_FromFormat("%s (C++ Object %p)", wrapper->_info->className(), wrapper->_wrappedPtr); + return PyString_FromFormat("%s (C++ Object %p)", wrapper->classInfo()->className(), wrapper->_wrappedPtr); } } else { - return PyString_FromFormat("%s (QObject %p)", wrapper->_info->className(), qobj); + return PyString_FromFormat("%s (QObject %p)", wrapper->classInfo()->className(), qobj); } } static int PythonQtInstanceWrapper_compare(PyObject * obj1, PyObject * obj2) { - if (obj1->ob_type == &PythonQtInstanceWrapper_Type && - obj2->ob_type == &PythonQtInstanceWrapper_Type) { + if (PyObject_TypeCheck(obj1, &PythonQtInstanceWrapper_Type) && + PyObject_TypeCheck(obj2, &PythonQtInstanceWrapper_Type)) { PythonQtInstanceWrapper* w1 = (PythonQtInstanceWrapper*)obj1; PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)obj2; @@ -338,11 +382,11 @@ } else if (w1->_obj == w2->_obj) { return 0; } - const char* class1 = w1->_info->className(); - const char* class2 = w2->_info->className(); + const char* class1 = w1->classInfo()->className(); + const char* class2 = w2->classInfo()->className(); if (strcmp(class1, class2) == 0) { // same class names, so we can try the operator_equal - PythonQtMemberInfo info = w1->_info->member("operator_equal"); + PythonQtMemberInfo info = w1->classInfo()->member("operator_equal"); if (info._type == PythonQtMemberInfo::Slot) { bool result = false; void* obj1 = w1->_wrappedPtr; @@ -440,7 +484,7 @@ }; PyTypeObject PythonQtInstanceWrapper_Type = { - PyObject_HEAD_INIT(NULL) + PyObject_HEAD_INIT(&PythonQtClassWrapper_Type) 0, /*ob_size*/ "PythonQt.PythonQtInstanceWrapper", /*tp_name*/ sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/