diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 6f13ab0..2e14bb9 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -372,6 +372,12 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name) break; } } + + if (info) { + // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull + ptr = info->castDownIfPossible(ptr, &info); + } + if (!info || info->pythonQtClassWrapper()==NULL) { // still unknown, register as CPP class registerCPPClass(name.constData()); @@ -1066,6 +1072,17 @@ PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const c return info; } +void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb) +{ + _p->addPolymorphicHandler(typeName, cb); +} + +void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb) +{ + PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName); + info->addPolymorphicHandler(cb); +} + bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset) { return _p->addParentClass(typeName, parentTypeName, upcastingOffset); diff --git a/src/PythonQt.h b/src/PythonQt.h index f6ef2bc..cde8086 100644 --- a/src/PythonQt.h +++ b/src/PythonQt.h @@ -65,8 +65,9 @@ class PythonQtImportFileInterface; class PythonQtCppWrapperFactory; class PythonQtQFileImporter; -typedef void PythonQtQObjectWrappedCB(QObject* object); -typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object); +typedef void PythonQtQObjectWrappedCB(QObject* object); +typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object); +typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, char **class_name); typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper); @@ -154,6 +155,9 @@ public: //! Returns false if the typeName was not yet registered. bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0); + //! add a handler for polymorphic downcasting + void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb); + //! parses the given file and returns the python code object, this can then be used to call evalCode() PythonQtObjectPtr parseFile(const QString& filename); @@ -399,6 +403,9 @@ public: //! add parent class relation bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset); + //! add a handler for polymorphic downcasting + void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb); + //! lookup existing classinfo and return new if not yet present PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName); diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index d21fdce..e033177 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -466,7 +466,8 @@ QStringList PythonQtClassInfo::memberList(bool metaOnly) } } } - return l; + + return QSet::fromList(l).toList(); } const char* PythonQtClassInfo::className() @@ -669,3 +670,37 @@ bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object) return false; } } + +void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName) +{ + if (!_polymorphicHandlers.isEmpty()) { + foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) { + void* resultPtr = (*cb)(ptr, resultClassName); + if (resultPtr) { + return resultPtr; + } + } + } + foreach(const ParentClassInfo& info, _parentClasses) { + if (!info._parent->isQObject()) { + void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName); + if (resultPtr) { + return resultPtr; + } + } + } + return NULL; +} + +void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo) +{ + char* className; + void* resultPtr = recursiveCastDownIfPossible(ptr, &className); + if (resultPtr) { + *resultClassInfo = PythonQt::priv()->getClassInfo(className); + } else { + *resultClassInfo = this; + resultPtr = ptr; + } + return resultPtr; +} diff --git a/src/PythonQtClassInfo.h b/src/PythonQtClassInfo.h index 724b03f..2b6fd38 100644 --- a/src/PythonQtClassInfo.h +++ b/src/PythonQtClassInfo.h @@ -182,10 +182,18 @@ public: return _shellSetInstanceWrapperCB; } + //! add a handler for polymorphic downcasting + void addPolymorphicHandler(PythonQtPolymorphicHandlerCB* cb) { _polymorphicHandlers.append(cb); } + + //! cast the pointer down in the class hierarchy if a polymorphic handler allows to do that + void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo); + private: //! clear all cached members void clearCachedMembers(); + void* recursiveCastDownIfPossible(void* ptr, char** resultClassName); + PythonQtSlotInfo* findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash& memberCache, int upcastingOffset); void listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly); PythonQtSlotInfo* recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash& memberCache, int upcastingOffset); @@ -211,6 +219,8 @@ private: QByteArray _wrappedClassName; QList _parentClasses; + QList _polymorphicHandlers; + QObject* _decoratorProvider; PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB;