PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self, PyObject *args, PyObject *kw) { if (PyObject_TypeCheck(m_self, &PythonQtInstanceWrapper_Type)) { PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) m_self; if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) { QString error = QString("Trying to call '") + info->slotName() + "' on a destroyed " + self->classInfo()->className() + " object"; PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); return NULL; } else { return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr); } } else if (m_self->ob_type == &PythonQtClassWrapper_Type) { PythonQtClassWrapper* type = (PythonQtClassWrapper*) m_self; if (info->isClassDecorator()) { return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw); } else { // otherwise, it is an unbound call and we have an instanceDecorator or normal slot... Py_ssize_t argc = PyTuple_Size(args); if (argc>0) { PyObject* firstArg = PyTuple_GET_ITEM(args, 0); if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type) && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) { PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg; if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) { QString error = QString("Trying to call '") + info->slotName() + "' on a destroyed " + self->classInfo()->className() + " object"; PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); return NULL; } // strip the first argument... PyObject* newargs = PyTuple_GetSlice(args, 1, argc); PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr); Py_DECREF(newargs); return result; } else { // first arg is not of correct type! QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name; PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); return NULL; } } else { // wrong number of args QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument."; PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); return NULL; } } } return NULL; }
static PyObject* PythonQtInstanceWrapper_binaryfunc(PyObject* self, PyObject* other, const QByteArray& opName, const QByteArray& fallbackOpName = QByteArray()) { // since we disabled type checking, we can receive any object as self, but we currently only support // different objects on the right. Otherwise we would need to generate __radd__ etc. methods. if (!PyObject_TypeCheck(self, &PythonQtInstanceWrapper_Type)) { QString error = "Unsupported operation " + opName + "(" + self->ob_type->tp_name + ", " + other->ob_type->tp_name + ")"; PyErr_SetString(PyExc_ArithmeticError, error.toLatin1().data()); return NULL; } PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self; PyObject* result = NULL; PythonQtMemberInfo opSlot = wrapper->classInfo()->member(opName); if (opSlot._type == PythonQtMemberInfo::Slot) { // TODO get rid of tuple PyObject* args = PyTuple_New(1); Py_INCREF(other); PyTuple_SET_ITEM(args, 0, other); result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr); Py_DECREF(args); if (!result && !fallbackOpName.isEmpty()) { // try fallback if we did not get a result result = PythonQtInstanceWrapper_binaryfunc(self, other, fallbackOpName); } } return result; }
static PyObject* PythonQtInstanceWrapper_invert(PythonQtInstanceWrapper* wrapper) { PyObject* result = NULL; static QByteArray memberName = "__invert__"; PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName); if (opSlot._type == PythonQtMemberInfo::Slot) { result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr); } return result; }
PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self) { PythonQtMemberInfo deleteSlot = self->classInfo()->member("py_delete"); if (deleteSlot._type == PythonQtMemberInfo::Slot) { // call the py_delete slot instead of internal C++ destructor... PyObject* resultObj = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, deleteSlot._slot, NULL, NULL, self->_wrappedPtr); Py_XDECREF(resultObj); } else { PythonQtInstanceWrapper_deleteObject(self, true); } Py_INCREF(Py_None); return Py_None; }
static int PythonQtInstanceWrapper_nonzero(PythonQtInstanceWrapper* wrapper) { int result = (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1; if (result) { static QByteArray memberName = "__nonzero__"; PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName); if (opSlot._type == PythonQtMemberInfo::Slot) { PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr); if (resultObj == Py_False) { result = 0; } Py_XDECREF(resultObj); } } return result; }
int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds) { 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(self->classInfo(), 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); PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB(); if (cb) { // if we are a derived python class, we set the wrapper // to activate the shell class, otherwise we just ignore that it is a shell... // we detect it be checking if the type does not have PythonQtInstanceWrapper_Type as direct base class, // which is the case for all non-python derived types if (((PyObject*)self)->ob_type->tp_base != &PythonQtInstanceWrapper_Type) { // set the wrapper and remember that we have a shell instance! (*cb)(directCPPPointer, self); self->_isShellInstance = true; } } } } else { QString error = QString("No constructors available for ") + self->classInfo()->className(); PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); return -1; } return 0; }
PyObject *PythonQtMetaObjectWrapper_call(PyObject *func, PyObject *args, PyObject *kw) { PythonQtMetaObjectWrapper* wrapper = (PythonQtMetaObjectWrapper*)func; PyObject* result = NULL; QString error; PyObject* err = NULL; if (wrapper->_info->constructors()) { result = PythonQtSlotFunction_CallImpl(NULL, wrapper->_info->constructors(), args, kw); err = PyErr_Occurred(); } if (!result) { QObject* v = NULL; QListIterator<PythonQtConstructorHandler*> it(PythonQt::self()->constructorHandlers()); while (!v && it.hasNext()) { v = it.next()->create(wrapper->_info->metaObject(), args, kw, error); } if (v) { result = PythonQt::priv()->wrapQObject(v); } } if (result) { // change ownershipflag to be owned by PythonQt if (result->ob_type == &PythonQtWrapper_Type) { ((PythonQtWrapper*)result)->_ownedByPythonQt = true; } } else { if (!wrapper->_info->constructors()) { if (!err) { if (error.isEmpty()) { error = QString("No constructors available for ") + wrapper->_info->className(); } PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); } } } return result; }
static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wrapper, PyObject* other, int code) { bool validPtrs = false; bool areSamePtrs = false; if (PyObject_TypeCheck((PyObject*)wrapper, &PythonQtInstanceWrapper_Type)) { if (PyObject_TypeCheck(other, &PythonQtInstanceWrapper_Type)) { validPtrs = true; PythonQtInstanceWrapper* w1 = wrapper; PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)other; // check pointers directly if (w1->_wrappedPtr != NULL) { if (w1->_wrappedPtr == w2->_wrappedPtr) { areSamePtrs = true; } } else if (w1->_obj == w2->_obj) { areSamePtrs = true; } } else if (other == Py_None) { validPtrs = true; if (wrapper->_obj || wrapper->_wrappedPtr) { areSamePtrs = false; } else { areSamePtrs = true; } } } if ((wrapper->classInfo()->typeSlots() & PythonQt::Type_RichCompare) == 0) { // shortcut if richcompare is not supported: if (validPtrs && code == Py_EQ) { return PythonQtConv::GetPyBool(areSamePtrs); } else if (validPtrs && code == Py_NE) { return PythonQtConv::GetPyBool(!areSamePtrs); } Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } QByteArray memberName; switch (code) { case Py_LT: { static QByteArray name = "__lt__"; memberName = name; } break; case Py_LE: { static QByteArray name = "__le__"; memberName = name; } break; case Py_EQ: { static QByteArray name = "__eq__"; memberName = name; } break; case Py_NE: { static QByteArray name = "__ne__"; memberName = name; } break; case Py_GT: { static QByteArray name = "__gt__"; memberName = name; } break; case Py_GE: { static QByteArray name = "__ge__"; memberName = name; } break; } PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName); if (opSlot._type == PythonQtMemberInfo::Slot) { // TODO get rid of tuple PyObject* args = PyTuple_New(1); Py_INCREF(other); PyTuple_SET_ITEM(args, 0, other); PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr); Py_DECREF(args); if (result == NULL) { // special handling of EQ and NE, if call fails we just return EQ == false / NE == true. if (code == Py_EQ) { PyErr_Clear(); Py_INCREF(Py_False); return Py_False; } else if (code == Py_NE) { PyErr_Clear(); Py_INCREF(Py_True); return Py_True; } } return result; } else { // not implemented, let python try something else! Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } }
int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds) { 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; PythonQtPassThisOwnershipType ownership; PythonQtSlotFunction_CallImpl(self->classInfo(), NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer, &ownership); if (PyErr_Occurred()) { return -1; } if (directCPPPointer) { // if this object is reference counted, we ref it: PythonQtVoidPtrCB* refCB = self->classInfo()->referenceCountingRefCB(); if (refCB) { (*refCB)(directCPPPointer); } // change ownership flag to be owned by PythonQt self->_ownedByPythonQt = true; self->_useQMetaTypeDestroy = false; bool isQObject = !self->classInfo()->isCPPWrapper(); if (!isQObject) { 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); PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB(); if (cb) { // if we are a derived python class, we set the wrapper // to activate the shell class, otherwise we just ignore that it is a shell... // we detect it be checking if the type does not have PythonQtInstanceWrapper_Type as direct base class, // which is the case for all non-python derived types if (((PyObject*)self)->ob_type->tp_base != &PythonQtInstanceWrapper_Type) { // set the wrapper and remember that we have a shell instance! (*cb)(directCPPPointer, self); self->_isShellInstance = true; } } // if the constructor has a PythonQtPassThisOwnership parameter and that owner is not NULL, // this wrapper is immediately owned by CPP // (Example: QGraphicsItem(QGraphicsItem* parent), if parent != NULL, ownership needs to be passed // to C++ immediately) // Alternatively, if it is a QObject and the object already has a parent when it is constructed, // the ownership should be moved to C++ as well, so that the shell instance stays alive. if (ownership == PassOwnershipToCPP || (isQObject && self->_obj && self->_obj->parent())) { self->passOwnershipToCPP(); } } } else { QString error = QString("No constructors available for ") + self->classInfo()->className(); PyErr_SetString(PyExc_ValueError, error.toLatin1().data()); return -1; } return 0; }