diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 57a3b0a..773dcea 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -276,33 +276,6 @@ void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const info->setPythonQtClassWrapper(pyobj); } -bool PythonQtPrivate::isEnumType(const QMetaObject* meta, const QByteArray& name) { - int i = meta?meta->indexOfEnumerator(name.constData()):-1; - if (i!=-1) { - return true; - } else { - // look for scope - int scopePos = name.indexOf("::"); - if (scopePos != -1) { - // slit into scope and enum name - QByteArray enumScope = name.mid(0,scopePos); - QByteArray enumName = name.mid(scopePos+2); - if (enumScope == "Qt") { - // special qt namespace case - return isEnumType(&staticQtMetaObject, enumName); - } else { - // look for known classes as scope - // TODO: Q_GADGETS are not yet handled - PythonQtClassInfo* info = _knownClassInfos.value(enumScope); - if (info) { - return isEnumType(info->metaObject(), enumName); - } - } - } - } - return false; -} - PyObject* PythonQtPrivate::wrapQObject(QObject* obj) { if (!obj) { diff --git a/src/PythonQt.h b/src/PythonQt.h index d9472de..649a362 100644 --- a/src/PythonQt.h +++ b/src/PythonQt.h @@ -443,10 +443,6 @@ public: //! add a decorator object void addDecorators(QObject* o, int decoTypes); - //! check if the enum is either part of the \c meta class or contains a scope and is - //! an enum of another known metaobject (and as last resort, of the Qt namespace) - bool isEnumType(const QMetaObject* meta, const QByteArray& name); - //! helper method that creates a PythonQtClassWrapper object PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, const char* package = NULL); diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index f322c64..cd7abcb 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -725,3 +725,46 @@ void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resul } return resultPtr; } + +bool PythonQtClassInfo::hasEnum(const QByteArray& name, PythonQtClassInfo* localScope) +{ + int scopePos = name.lastIndexOf("::"); + if (scopePos != -1) { + // slit into scope and enum name + QByteArray enumScope = name.mid(0,scopePos); + QByteArray enumName = name.mid(scopePos+2); + PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope); + if (info) { + return info->hasEnum(enumName); + } else{ + return false; + } + } + if (localScope) { + return localScope->hasEnum(name); + } else { + return false; + } +} + +bool PythonQtClassInfo::hasEnum(const QByteArray& name) +{ + bool found = false; + if (_meta) { + found = _meta->indexOfEnumerator(name)!=-1; + } + if (!found) { + // check enums in the class hierachy of CPP classes + // look for dynamic decorators in this class and in derived classes + QList decoObjects; + recursiveCollectDecoratorObjects(decoObjects); + foreach(QObject* deco, decoObjects) { + found = deco->metaObject()->indexOfEnumerator(name)!=-1; + if (found) { + break; + } + } + } + return found; +} + diff --git a/src/PythonQtClassInfo.h b/src/PythonQtClassInfo.h index 3023f09..30838fa 100644 --- a/src/PythonQtClassInfo.h +++ b/src/PythonQtClassInfo.h @@ -191,7 +191,13 @@ public: //! cast the pointer down in the class hierarchy if a polymorphic handler allows to do that void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo); + //! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum + static bool hasEnum(const QByteArray& name, PythonQtClassInfo* localScope); + private: + //! checks if the enum is part of this class (without any leading scope!) + bool hasEnum(const QByteArray& name); + //! clear all cached members void clearCachedMembers(); diff --git a/src/PythonQtConversion.cpp b/src/PythonQtConversion.cpp index dfe6f16..e02d87c 100644 --- a/src/PythonQtConversion.cpp +++ b/src/PythonQtConversion.cpp @@ -240,7 +240,7 @@ return Py_None; return object; } - void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, const QMetaObject* meta, void* alreadyAllocatedCPPObject) + void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* meta, void* alreadyAllocatedCPPObject) { bool ok; void* ptr = NULL; @@ -444,7 +444,7 @@ return Py_None; { if (info.typeId == PythonQtMethodInfo::Unknown) { // check for enum case - if (meta && PythonQt::priv()->isEnumType(meta, info.name)) { + if (PythonQtClassInfo::hasEnum(info.name, meta)) { unsigned int val = (unsigned int)PyObjGetLongLong(obj, strict, ok); if (ok) { PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr); diff --git a/src/PythonQtConversion.h b/src/PythonQtConversion.h index 68879e6..3ddcce3 100644 --- a/src/PythonQtConversion.h +++ b/src/PythonQtConversion.h @@ -78,7 +78,7 @@ public: static PyObject* ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data); //! convert python object to Qt (according to the given parameter) and if the conversion should be strict, the meta object is passed in for enum resolving - static void* ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, const QMetaObject* meta, void* alreadyAllocatedCPPObject = NULL); + static void* ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* meta, void* alreadyAllocatedCPPObject = NULL); //! creates a data storage for the passed parameter type and returns a void pointer to be set as arg[0] of qt_metacall static void* CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info); diff --git a/src/PythonQtInstanceWrapper.cpp b/src/PythonQtInstanceWrapper.cpp index 21c5c6a..6ccafdf 100644 --- a/src/PythonQtInstanceWrapper.cpp +++ b/src/PythonQtInstanceWrapper.cpp @@ -145,7 +145,7 @@ int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args // 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); + PythonQtSlotFunction_CallImpl(self->classInfo(), NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer); if (PyErr_Occurred()) { return -1; } diff --git a/src/PythonQtSlot.cpp b/src/PythonQtSlot.cpp index 1661866..cf4538f 100644 --- a/src/PythonQtSlot.cpp +++ b/src/PythonQtSlot.cpp @@ -50,7 +50,7 @@ #define PYTHONQT_MAX_ARGS 32 -bool PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer) +bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer) { static unsigned int recursiveEntry = 0; @@ -82,7 +82,7 @@ bool PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, Python if (returnValueParam.typeId != QMetaType::Void) { // extra handling of enum return value if (!returnValueParam.isPointer && returnValueParam.typeId == PythonQtMethodInfo::Unknown) { - returnValueIsEnum = PythonQt::priv()->isEnumType(objectToCall->metaObject(), returnValueParam.name); + returnValueIsEnum = PythonQtClassInfo::hasEnum(returnValueParam.name, classInfo); if (returnValueIsEnum) { // create enum return value PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]); @@ -100,7 +100,6 @@ bool PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, Python } } - const QMetaObject* meta = objectToCall?objectToCall->metaObject():NULL; bool ok = true; bool skipFirst = false; if (info->isInstanceDecorator()) { @@ -121,7 +120,7 @@ bool PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, Python for (int i = 2; im_ml; if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) { PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self; - return PythonQtSlotFunction_CallImpl(self->_obj, info, args, kw, self->_wrappedPtr); + return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr); } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) { + PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self; if (info->isClassDecorator()) { - return PythonQtSlotFunction_CallImpl(NULL, info, args, kw); + return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw); } else { // otherwise, it is an unbound call and we have an instanceDecorator or normal slot... - PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self; Py_ssize_t argc = PyTuple_Size(args); if (argc>0) { PyObject* firstArg = PyTuple_GET_ITEM(args, 0); @@ -196,7 +195,7 @@ PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg; // strip the first argument... PyObject* newargs = PyTuple_GetSlice(args, 1, argc); - PyObject* result = PythonQtSlotFunction_CallImpl(self->_obj, info, newargs, kw, self->_wrappedPtr); + PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr); Py_DECREF(newargs); return result; } else { @@ -216,7 +215,7 @@ PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw return NULL; } -PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer) +PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer) { int argc = PyTuple_Size(args); @@ -237,7 +236,7 @@ PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* bool skipFirst = i->isInstanceDecorator(); if (i->parameterCount()-1-(skipFirst?1:0) == argc) { PyErr_Clear(); - ok = PythonQtCallSlot(objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer); + ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer); if (PyErr_Occurred() || ok) break; } i = i->nextInfo(); @@ -263,7 +262,7 @@ PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* bool skipFirst = info->isInstanceDecorator(); if (info->parameterCount()-1-(skipFirst?1:0) == argc) { PyErr_Clear(); - ok = PythonQtCallSlot(objectToCall, args, false, info, firstArg, &r, directReturnValuePointer); + ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer); if (!ok && !PyErr_Occurred()) { QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args); PyErr_SetString(PyExc_ValueError, e.toLatin1().data()); diff --git a/src/PythonQtSlot.h b/src/PythonQtSlot.h index 18129f7..55b3d84 100644 --- a/src/PythonQtSlot.h +++ b/src/PythonQtSlot.h @@ -62,7 +62,7 @@ PyObject* PythonQtSlotFunction_GetSelf(PyObject *); PyObject* PythonQtSlotFunction_Call(PyObject *, PyObject *, PyObject *); -PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL, void** directReturnValuePointer=NULL); +PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL, void** directReturnValuePointer=NULL); PyObject* PythonQtSlotFunction_New(PythonQtSlotInfo *, PyObject *,