From 83868d7a7982c83761fe9ae71bd2c29183844bdc 2009-05-25 10:16:55 From: florianlink Date: 2009-05-25 10:16:55 Subject: [PATCH] cache enumWrappers in method infos and make use of the extra information for better enum overloading git-svn-id: svn://svn.code.sf.net/p/pythonqt/code/trunk@91 ea8d5007-eb21-0410-b261-ccb3ea6e24a9 --- diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index f2ad6fc..9b355c8 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -915,9 +915,9 @@ void PythonQtPrivate::addDecorators(QObject* o, int decoTypes) QMetaMethod m = o->metaObject()->method(i); if ((m.methodType() == QMetaMethod::Method || m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) { - const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL); if (qstrncmp(m.signature(), "new_", 4)==0) { if ((decoTypes & ConstructorDecorator) == 0) continue; + const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL); if (info->parameters().at(0).isPointer) { QByteArray signature = m.signature(); QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4); @@ -942,6 +942,7 @@ void PythonQtPrivate::addDecorators(QObject* o, int decoTypes) classInfo->addDecoratorSlot(newSlot); } else { if ((decoTypes & InstanceDecorator) == 0) continue; + const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL); if (info->parameters().count()>1) { PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1); if (p.isPointer) { diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index 358c25d..681f57b 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -251,6 +251,9 @@ bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* int enumCount = meta->enumeratorCount(); for (int i=0;ienumerator(i); + // we do not want flags, they will cause our values to appear two times + if (e.isFlag()) continue; + for (int j=0; j < e.keyCount(); j++) { if (qstrcmp(e.key(j), memberName)==0) { PyObject* enumType = findEnumWrapper(e.name()); @@ -490,6 +493,9 @@ QStringList PythonQtClassInfo::memberList(bool metaOnly) for (int i = 0; ienumeratorCount(); i++) { QMetaEnum e = meta->enumerator(i); l << e.name(); + // we do not want flags, they will cause our values to appear two times + if (e.isFlag()) continue; + for (int j=0; j < e.keyCount(); j++) { l << QString(e.key(j)); } @@ -750,46 +756,27 @@ void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resul return resultPtr; } -bool PythonQtClassInfo::hasEnum(const QByteArray& name, PythonQtClassInfo* localScope) +PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool& isLocalEnum) { + isLocalEnum = true; int scopePos = name.lastIndexOf("::"); if (scopePos != -1) { + isLocalEnum = false; // 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); + return info->findEnumWrapper(enumName); } else{ - return false; + return NULL; } } if (localScope) { - return localScope->hasEnum(name); + return localScope->findEnumWrapper(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 NULL; } - return found; } void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta) diff --git a/src/PythonQtClassInfo.h b/src/PythonQtClassInfo.h index d4bd73d..620ab1d 100644 --- a/src/PythonQtClassInfo.h +++ b/src/PythonQtClassInfo.h @@ -195,16 +195,13 @@ public: 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); + static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool& isLocalEnum); private: void createEnumWrappers(); void createEnumWrappers(const QMetaObject* meta); PyObject* findEnumWrapper(const char* name); - //! 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 4eda03c..fcc1d0b 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, PythonQtClassInfo* meta, void* alreadyAllocatedCPPObject) + void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject) { bool ok; void* ptr = NULL; @@ -442,18 +442,25 @@ return Py_None; break; default: { - if (info.typeId == PythonQtMethodInfo::Unknown) { - // check for enum case - 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); - return ptr; - } else { - return NULL; - } + // check for enum case + if (info.enumWrapper) { + unsigned int val; + if ((PyObject*)obj->ob_type == info.enumWrapper) { + // we have a direct enum type match: + val = PyInt_AS_LONG(obj); + ok = true; + } else { + // we try to get an integer, and in strict mode, it may not be a derived int class, so that no other enum can be taken as an int + val = (unsigned int)PyObjGetLongLong(obj, strict, ok); + } + if (ok) { + PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr); + return ptr; + } else { + return NULL; } } + if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) { // check for QList case, where we will use a QList QVariant if (info.name.startsWith("QList<")) { diff --git a/src/PythonQtConversion.h b/src/PythonQtConversion.h index 3ddcce3..af8354f 100644 --- a/src/PythonQtConversion.h +++ b/src/PythonQtConversion.h @@ -77,8 +77,8 @@ public: //! converts the Qt parameter given in \c data, interpreting it as a \c info parameter, into a Python object, 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, PythonQtClassInfo* meta, void* alreadyAllocatedCPPObject = NULL); + //! convert python object to Qt (according to the given parameter) and if the conversion should be strict (classInfo is currently not used anymore) + static void* ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* classInfo, 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 9c6b729..5956b31 100644 --- a/src/PythonQtInstanceWrapper.cpp +++ b/src/PythonQtInstanceWrapper.cpp @@ -114,7 +114,7 @@ static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self) 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; @@ -415,7 +415,7 @@ static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj) return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr); } } else { - return PyString_FromFormat("%s (QObject %p)", typeName, wrapper->classInfo()->className(), qobj); + return PyString_FromFormat("%s (%s %p)", typeName, wrapper->classInfo()->className(), qobj); } } diff --git a/src/PythonQtMethodInfo.cpp b/src/PythonQtMethodInfo.cpp index 91786ee..074bcfa 100644 --- a/src/PythonQtMethodInfo.cpp +++ b/src/PythonQtMethodInfo.cpp @@ -56,12 +56,12 @@ PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInf #endif ParameterInfo type; - fillParameterInfo(type, QByteArray(meta.typeName())); + fillParameterInfo(type, QByteArray(meta.typeName()), classInfo); _parameters.append(type); QByteArray name; QList names = meta.parameterTypes(); foreach (name, names) { - fillParameterInfo(type, name); + fillParameterInfo(type, name, classInfo); _parameters.append(type); } } @@ -87,10 +87,12 @@ const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromMetaObjectA return PythonQtMethodInfo::getCachedMethodInfo(meta, NULL); } -void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName) +void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo) { QByteArray name = orgName; + type.enumWrapper = NULL; + int len = name.length(); if (len>0) { if (strncmp(name.constData(), "const ", 6)==0) { @@ -129,6 +131,12 @@ void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray } } type.name = name; + + if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) { + bool isLocalEnum; + // TODOXXX: make use of this flag! + type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, isLocalEnum); + } } else { type.typeId = QMetaType::Void; type.isPointer = false; diff --git a/src/PythonQtMethodInfo.h b/src/PythonQtMethodInfo.h index 256f40f..c5f6f1d 100644 --- a/src/PythonQtMethodInfo.h +++ b/src/PythonQtMethodInfo.h @@ -50,6 +50,8 @@ #include class PythonQtClassInfo; +struct _object; +typedef struct _object PyObject; //! stores information about a specific signal/slot/method class PYTHONQT_EXPORT PythonQtMethodInfo @@ -62,8 +64,9 @@ public: //! stores the QVariant id (if available) and the name of the type struct ParameterInfo { - int typeId; // a mixture from QMetaType and ParameterType QByteArray name; + PyObject* enumWrapper; // if it is an enum, a pointer to the enum wrapper + int typeId; // a mixture from QMetaType and ParameterType bool isPointer; bool isConst; }; @@ -98,7 +101,7 @@ public: static void addParameterTypeAlias(const QByteArray& alias, const QByteArray& name); protected: - static void fillParameterInfo(ParameterInfo& type, const QByteArray& name); + static void fillParameterInfo(ParameterInfo& type, const QByteArray& name, PythonQtClassInfo* classInfo); static QHash _parameterTypeDict; static QHash _parameterNameAliases; diff --git a/src/PythonQtSlot.cpp b/src/PythonQtSlot.cpp index 16f19fe..0e8d1c9 100644 --- a/src/PythonQtSlot.cpp +++ b/src/PythonQtSlot.cpp @@ -74,7 +74,6 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj int argc = info->parameterCount(); const QList& params = info->parameters(); - bool returnValueIsEnum = false; const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0); // set return argument to NULL argList[0] = NULL; @@ -119,17 +118,16 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj } if (ok) { + bool returnValueIsEnum = false; + // parameters are ok, now create the qt return value which is assigned to by metacall if (returnValueParam.typeId != QMetaType::Void) { // extra handling of enum return value - if (!returnValueParam.isPointer && returnValueParam.typeId == PythonQtMethodInfo::Unknown) { - returnValueIsEnum = PythonQtClassInfo::hasEnum(returnValueParam.name, classInfo); - if (returnValueIsEnum) { - // create enum return value - PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]); - } - } - if (argList[0]==NULL) { + if (!returnValueParam.isPointer && returnValueParam.enumWrapper) { + // create enum return value + PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, argList[0]); + returnValueIsEnum = true; + } else { // create empty default value for the return value if (!directReturnValuePointer) { // create empty default value for the return value