From 1ff9b7799dfe1fea9b581c91742c70f88e3fd130 Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Fri, 8 Dec 2023 12:04:00 +0100 Subject: [PATCH 01/26] [Backport] Handle QStringView et al as argument/return value (cherry picked from commit MeVisLab/pythonqt@8769ef40fbf44434af4cb42ff1e9c7dbd9bddcdb) --- generator/typesystem.cpp | 8 ++++ src/PythonQt.cpp | 5 +- src/PythonQtConversion.cpp | 93 ++++++++++++++++++++++++++++++++++++-- src/PythonQtConversion.h | 12 +++++ 4 files changed, 111 insertions(+), 7 deletions(-) diff --git a/generator/typesystem.cpp b/generator/typesystem.cpp index ae8111c4..864be953 100644 --- a/generator/typesystem.cpp +++ b/generator/typesystem.cpp @@ -1519,6 +1519,14 @@ TypeDatabase::TypeDatabase() : m_suppressWarnings(true) e->setPreferredConversion(false); addType(e); + e = new StringTypeEntry("QStringView"); + e->setPreferredConversion(false); + addType(e); + + e = new StringTypeEntry("QAnyStringView"); + e->setPreferredConversion(false); + addType(e); + e = new StringTypeEntry("QXmlStreamStringRef"); e->setPreferredConversion(false); addType(e); diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 8ff82ab6..b4ff3bd7 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -122,10 +122,7 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) } else { qRegisterMetaType("size_t"); } -#if QT_VERSION < 0x060000 - int stringRefId = qRegisterMetaType("QStringRef"); - PythonQtConv::registerMetaTypeToPythonConverter(stringRefId, PythonQtConv::convertFromStringRef); -#endif + PythonQtConv::registerStringViewTypes(); int objectPtrListId = qRegisterMetaType >("QList"); PythonQtConv::registerMetaTypeToPythonConverter(objectPtrListId, PythonQtConv::convertFromQListOfPythonQtObjectPtr); diff --git a/src/PythonQtConversion.cpp b/src/PythonQtConversion.cpp index f47506fd..23bc7a15 100644 --- a/src/PythonQtConversion.cpp +++ b/src/PythonQtConversion.cpp @@ -48,6 +48,20 @@ #include #include +#if QT_VERSION < 0x060000 +#include + +Q_DECLARE_METATYPE(QStringRef) + +int PythonQtConv::stringRefTypeId = 0; +#else +#include +#include + +int PythonQtConv::stringViewTypeId = 0; +int PythonQtConv::anyStringViewTypeId = 0; +#endif + QHash PythonQtConv::_metaTypeToPythonConverters; QHash PythonQtConv::_pythonToMetaTypeConverters; @@ -633,19 +647,69 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i // we have a exact enum type match: val = PyInt_AS_LONG(obj); ok = true; - } else if (!strict) { + } + else if (!strict) { // we try to get any integer, when not being strict. If we are strict, integers are not wanted because // we want an integer overload to be taken first! val = (unsigned int)PyObjGetLongLong(obj, false, ok); } if (ok) { - PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, unsigned int, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, unsigned int, val, ptr); return ptr; - } else { + } + else { return nullptr; } } + // Handle QStringView et al, which need a reference to a persistent QString +#if QT_VERSION < 0x060000 + if (info.typeId == stringRefTypeId) { + QString str = PyObjGetString(obj, strict, ok); + if (ok) { + void* ptr2 = nullptr; + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr, frame, QVariant(str), ptr2); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, + QVariant::fromValue(QStringRef((const QString*)((QVariant*)ptr2)->constData())), ptr); + ptr = (void*)((QVariant*)ptr)->constData(); + return ptr; + } + else { + return nullptr; + } + } +#else + if (info.typeId == stringViewTypeId) { + QString str = PyObjGetString(obj, strict, ok); + if (ok) { + void* ptr2 = nullptr; + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr, frame, QVariant(str), ptr2); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, + QVariant::fromValue(QStringView(*((const QString*)((QVariant*)ptr2)->constData()))), ptr); + ptr = (void*)((QVariant*)ptr)->constData(); + return ptr; + } + else { + return nullptr; + } + } + else if (info.typeId == anyStringViewTypeId) { + // Handle QStringView et al, which need a reference to a persistent QString + QString str = PyObjGetString(obj, strict, ok); + if (ok) { + void* ptr2 = nullptr; + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr, frame, QVariant(str), ptr2); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, + QVariant::fromValue(QAnyStringView(*((const QString*)((QVariant*)ptr2)->constData()))), ptr); + ptr = (void*)((QVariant*)ptr)->constData(); + return ptr; + } + else { + return nullptr; + } + } +#endif + if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) { // check for QList case, where we will use a QList QVariant if (info.isQList && (info.innerNamePointerCount == 1)) { @@ -1499,6 +1563,16 @@ PyObject* PythonQtConv::convertFromStringRef(const void* inObject, int /*metaTyp { return PythonQtConv::QStringToPyObject(((QStringRef*)inObject)->toString()); } +#else +PyObject* PythonQtConv::convertFromStringView(const void* inObject, int /*metaTypeId*/) +{ + return PythonQtConv::QStringToPyObject(((QStringView*)inObject)->toString()); +} + +PyObject* PythonQtConv::convertFromAnyStringView(const void* inObject, int /*metaTypeId*/) +{ + return PythonQtConv::QStringToPyObject(((QAnyStringView*)inObject)->toString()); +} #endif QByteArray PythonQtConv::getCPPTypeName(PyObject* type) @@ -1551,6 +1625,19 @@ bool PythonQtConv::isStringType(PyTypeObject* type) #endif } +void PythonQtConv::registerStringViewTypes() +{ +#if QT_VERSION < 0x060000 + stringRefTypeId = qRegisterMetaType("QStringRef"); + PythonQtConv::registerMetaTypeToPythonConverter(stringRefTypeId, PythonQtConv::convertFromStringRef); +#else + stringViewTypeId = qRegisterMetaType("QStringView"); + PythonQtConv::registerMetaTypeToPythonConverter(stringViewTypeId, PythonQtConv::convertFromStringView); + anyStringViewTypeId = qRegisterMetaType("QAnyStringView"); + PythonQtConv::registerMetaTypeToPythonConverter(anyStringViewTypeId, PythonQtConv::convertFromAnyStringView); +#endif +} + PyObject* PythonQtConv::convertFromQListOfPythonQtObjectPtr(const void* inObject, int /*metaTypeId*/) { QList& list = *((QList*)inObject); diff --git a/src/PythonQtConversion.h b/src/PythonQtConversion.h index 7876b652..de21cbea 100644 --- a/src/PythonQtConversion.h +++ b/src/PythonQtConversion.h @@ -187,6 +187,9 @@ class PYTHONQT_EXPORT PythonQtConv { static PyObject* convertFromQListOfPythonQtObjectPtr(const void* /* QList* */ inObject, int /*metaTypeId*/); #if QT_VERSION < 0x060000 static PyObject* convertFromStringRef(const void* inObject, int /*metaTypeId*/); +#else + static PyObject* convertFromStringView(const void* inObject, int /*metaTypeId*/); + static PyObject* convertFromAnyStringView(const void* inObject, int /*metaTypeId*/); #endif //! Returns the name of the equivalent CPP type (for signals and slots) @@ -195,6 +198,9 @@ class PYTHONQT_EXPORT PythonQtConv { //! Returns if the given object is a string (or unicode string) static bool isStringType(PyTypeObject* type); + //! Register QStringView like types, that need to be handled specially + static void registerStringViewTypes(); + protected: static QHash _metaTypeToPythonConverters; static QHash _pythonToMetaTypeConverters; @@ -215,6 +221,12 @@ class PYTHONQT_EXPORT PythonQtConv { template static PyObject* mapToPython (const Map& m); +#if QT_VERSION < 0x060000 + static int stringRefTypeId; +#else + static int stringViewTypeId; + static int anyStringViewTypeId; +#endif }; template From 29ea88f48b35cb5a15af0617f73e5c5b856a2dfa Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Fri, 8 Dec 2023 15:08:08 +0100 Subject: [PATCH 02/26] [Backport generator] Filter out methods that do the same (at least in Python) (cherry picked from commit MeVisLab/pythonqt@2d72bc505508a517bf219209391c0e7edab0b0c0) --- generator/abstractmetabuilder.cpp | 42 +++++++++++++++++++++++++++++++ generator/abstractmetabuilder.h | 4 +++ generator/abstractmetalang.cpp | 5 ++++ generator/abstractmetalang.h | 1 + generator/typesystem.cpp | 7 +++++- generator/typesystem.h | 8 ++++++ 6 files changed, 66 insertions(+), 1 deletion(-) diff --git a/generator/abstractmetabuilder.cpp b/generator/abstractmetabuilder.cpp index faf16aee..ecdd6687 100644 --- a/generator/abstractmetabuilder.cpp +++ b/generator/abstractmetabuilder.cpp @@ -1166,6 +1166,48 @@ void AbstractMetaBuilder::traverseFunctions(ScopeModelItem scope_item, AbstractM } } } + removeEquivalentFunctions(meta_class); +} + +void AbstractMetaBuilder::removeEquivalentFunctions(AbstractMetaClass* parent) +{ + AbstractMetaFunctionList functions = parent->functions(); + for (AbstractMetaFunction* fun : functions) + { + AbstractMetaArgumentList args = fun->arguments(); + bool candidateToRemove = false; + for (AbstractMetaArgument* arg : args) { + const TypeEntry* argType = arg->type()->typeEntry(); + if (argType && argType->equivalentType()) { + candidateToRemove = true; + break; + } + } + if (!candidateToRemove) { + continue; + } + // check if there are other functions with the same name and equivalent parameters + AbstractMetaFunctionList overloadedFunctions = parent->queryFunctionsByName(fun->name()); + for (AbstractMetaFunction* overload : overloadedFunctions) { + if (overload != fun) { + AbstractMetaArgumentList overloadArgs = overload->arguments(); + if (overloadArgs.size() == args.size()) { + bool equivalentArgs = true; + for (int i = 0; i < args.size() && equivalentArgs; i++) { + const TypeEntry* argType = args[i]->type()->typeEntry(); + const TypeEntry* overloadArgType = overloadArgs[i]->type()->typeEntry(); + // This could have some more equivalency checks, but currently this seems to be sufficient + equivalentArgs = (argType && overloadArgType && + (argType == overloadArgType || argType->equivalentType() == overloadArgType)); + } + if (equivalentArgs) { + parent->removeFunction(fun); + break; + } + } + } + } + } } bool AbstractMetaBuilder::setupInheritance(AbstractMetaClass *meta_class) diff --git a/generator/abstractmetabuilder.h b/generator/abstractmetabuilder.h index 5fa72da6..5d0ed34d 100644 --- a/generator/abstractmetabuilder.h +++ b/generator/abstractmetabuilder.h @@ -96,6 +96,10 @@ class AbstractMetaBuilder void traverseStreamOperator(FunctionModelItem function_item); void traverseCompareOperator(FunctionModelItem item); void traverseBinaryArithmeticOperator(FunctionModelItem item); + + //! remove functions/methods that are overloads with equivalent parameter types + //! when called from Python + void removeEquivalentFunctions(AbstractMetaClass* parent); AbstractMetaFunction *traverseFunction(FunctionModelItem function); AbstractMetaField *traverseField(VariableModelItem field, const AbstractMetaClass *cls); diff --git a/generator/abstractmetalang.cpp b/generator/abstractmetalang.cpp index 67fc4d2a..b8c0cd33 100644 --- a/generator/abstractmetalang.cpp +++ b/generator/abstractmetalang.cpp @@ -1103,6 +1103,11 @@ void AbstractMetaClass::addFunction(AbstractMetaFunction *function) m_has_nonpublic |= !function->isPublic(); } +void AbstractMetaClass::removeFunction(AbstractMetaFunction* function) +{ + m_functions.removeOne(function); +} + bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const { if (!other->isSignal()) diff --git a/generator/abstractmetalang.h b/generator/abstractmetalang.h index f161c5c7..6bbdbe7b 100644 --- a/generator/abstractmetalang.h +++ b/generator/abstractmetalang.h @@ -688,6 +688,7 @@ class AbstractMetaClass : public AbstractMetaAttributes AbstractMetaFunctionList functions() const { return m_functions; } void setFunctions(const AbstractMetaFunctionList &functions); void addFunction(AbstractMetaFunction *function); + void removeFunction(AbstractMetaFunction* function); bool hasFunction(const AbstractMetaFunction *f) const; bool hasFunction(const QString &str) const; bool hasSignal(const AbstractMetaFunction *f) const; diff --git a/generator/typesystem.cpp b/generator/typesystem.cpp index 864be953..0509dbee 100644 --- a/generator/typesystem.cpp +++ b/generator/typesystem.cpp @@ -1509,22 +1509,27 @@ TypeDatabase *TypeDatabase::instance() TypeDatabase::TypeDatabase() : m_suppressWarnings(true) { - addType(new StringTypeEntry("QString")); + StringTypeEntry* mainStringType = new StringTypeEntry("QString"); + addType(mainStringType); StringTypeEntry *e = new StringTypeEntry("QLatin1String"); e->setPreferredConversion(false); + e->setEquivalentType(mainStringType); addType(e); e = new StringTypeEntry("QStringRef"); e->setPreferredConversion(false); + e->setEquivalentType(mainStringType); addType(e); e = new StringTypeEntry("QStringView"); e->setPreferredConversion(false); + e->setEquivalentType(mainStringType); addType(e); e = new StringTypeEntry("QAnyStringView"); e->setPreferredConversion(false); + e->setEquivalentType(mainStringType); addType(e); e = new StringTypeEntry("QXmlStreamStringRef"); diff --git a/generator/typesystem.h b/generator/typesystem.h index a68850d8..05adee68 100644 --- a/generator/typesystem.h +++ b/generator/typesystem.h @@ -549,6 +549,8 @@ class TypeEntry virtual bool isNativeIdBased() const { return false; } + virtual TypeEntry* equivalentType() const { return nullptr; } + private: QString m_name; Type m_type; @@ -1013,8 +1015,14 @@ class ValueTypeEntry : public ComplexTypeEntry virtual bool isNativeIdBased() const { return true; } + virtual TypeEntry* equivalentType() const { return _equivalentType; } + void setEquivalentType(TypeEntry* typeEntry) { _equivalentType = typeEntry; } + protected: ValueTypeEntry(const QString &name, Type t) : ComplexTypeEntry(name, t) { } + +private: + TypeEntry* _equivalentType{}; }; From ec40e12101ba355f0e46281ab259be98abb788fa Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Fri, 8 Dec 2023 18:40:37 +0100 Subject: [PATCH 03/26] [Backport generator] Add missing classes (and in some cases document when classes were introduced) (cherry picked from commit MeVisLab/pythonqt@467d3c0b1890aab7a00697e4cd43ca83d90a0ef1) --- generator/typesystem_core.xml | 19 ++++++++++++++++++- generator/typesystem_gui.xml | 20 ++++++++++++++++++-- generator/typesystem_multimedia.xml | 6 +++--- generator/typesystem_network.xml | 12 ++++++++++++ generator/typesystem_qml.xml | 13 ++++++++++++- generator/typesystem_webenginewidgets.xml | 17 ++++++++++++++++- generator/typesystem_xml.xml | 1 + 7 files changed, 80 insertions(+), 8 deletions(-) diff --git a/generator/typesystem_core.xml b/generator/typesystem_core.xml index 32d68413..15052b49 100644 --- a/generator/typesystem_core.xml +++ b/generator/typesystem_core.xml @@ -864,6 +864,14 @@ + + +public: + const static int Unspecified = QCalendar::Unspecified; + + + + @@ -1011,6 +1019,8 @@ + + @@ -1316,7 +1326,7 @@ - + @@ -1432,6 +1442,10 @@ + @@ -2006,6 +2020,7 @@ + @@ -2047,4 +2062,6 @@ + + diff --git a/generator/typesystem_gui.xml b/generator/typesystem_gui.xml index 80364fc9..b535379b 100644 --- a/generator/typesystem_gui.xml +++ b/generator/typesystem_gui.xml @@ -451,6 +451,7 @@ + @@ -525,8 +526,8 @@ - - + + @@ -730,6 +731,7 @@ + @@ -771,6 +773,7 @@ + @@ -2525,6 +2528,7 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -3092,6 +3096,7 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -3112,6 +3117,9 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -3171,6 +3179,14 @@ PyObject* constScanLine(QImage* image, int line) { + + + + + + + + diff --git a/generator/typesystem_multimedia.xml b/generator/typesystem_multimedia.xml index d4f1a984..9d16a39c 100644 --- a/generator/typesystem_multimedia.xml +++ b/generator/typesystem_multimedia.xml @@ -193,14 +193,14 @@ - + - + @@ -209,7 +209,7 @@ - + diff --git a/generator/typesystem_network.xml b/generator/typesystem_network.xml index 2b0a4b95..2c3d1360 100644 --- a/generator/typesystem_network.xml +++ b/generator/typesystem_network.xml @@ -81,6 +81,7 @@ + @@ -88,6 +89,7 @@ + @@ -230,6 +232,16 @@ + + + + + + + + + + diff --git a/generator/typesystem_qml.xml b/generator/typesystem_qml.xml index ebc664fd..21952240 100644 --- a/generator/typesystem_qml.xml +++ b/generator/typesystem_qml.xml @@ -10,11 +10,22 @@ - + + + + + + + + + + + + diff --git a/generator/typesystem_webenginewidgets.xml b/generator/typesystem_webenginewidgets.xml index 53fa87d5..8f8020be 100644 --- a/generator/typesystem_webenginewidgets.xml +++ b/generator/typesystem_webenginewidgets.xml @@ -12,7 +12,7 @@ - + @@ -22,6 +22,21 @@ + + + + + + + + + + + + + + + diff --git a/generator/typesystem_xml.xml b/generator/typesystem_xml.xml index 5fbba69e..4a57a218 100644 --- a/generator/typesystem_xml.xml +++ b/generator/typesystem_xml.xml @@ -36,6 +36,7 @@ + From df5ab05d333450b4c050627e6f371d5e325bd5e6 Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Fri, 8 Dec 2023 17:19:58 +0100 Subject: [PATCH 04/26] [Backport] Add "enum class" values to the enum type in Python Enum class values seem to have pretty generic names (as there is no danger of name clashes in C++, as they must always be prefixed with the enum class name). So add them to the enum type in Python too, so one can always write something like QActionGroup.ExclusionPolicy.None instead of QActionGroup.None. Ideally we wouldn't add the enum values to the parent class at all, but I don't want to break compatibility with older versions of PythonQt. (cherry picked from commit MeVisLab/pythonqt@c35d01034603b471086e5575ffcf7ac0af1832ee) --- src/PythonQtClassInfo.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index b2013b8a..658fc045 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -853,12 +853,26 @@ PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtCla } } +// required for the code below (for versions before Qt 6) +Q_DECLARE_METATYPE(PythonQtObjectPtr) + void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta) { for (int i = meta->enumeratorOffset();ienumeratorCount();i++) { QMetaEnum e = meta->enumerator(i); PythonQtObjectPtr p; p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper)); +#if QT_VERSION > 0x050800 + if (e.isScoped()) { + // add enum values to the enum type itself, in case enum value names are so generic + // that they are not unique + for (int j = 0; j < e.keyCount(); j++) { + PythonQtObjectPtr enumValuePtr; + enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(p.object(), e.value(j))); + p.addVariable(e.key(j), QVariant::fromValue(enumValuePtr)); + } + } +#endif _enumWrappers.append(p); } } From 5b4a6a9b1f14d9ba0e9a3a470fdf6c9f6fc01833 Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Fri, 8 Dec 2023 17:51:51 +0100 Subject: [PATCH 05/26] [Backport] Escape reserved names by adding "_" One example I stumbled upon is QActionGroup.ExclusionPolicy.None, which is a syntax error. So from now on it will be QActionGroup.ExclusionPolicy.None_. (cherry picked from commit MeVisLab/pythonqt@77eba422268cc5be4d60f3dcf1f140389d59ed51) --- src/PythonQtClassInfo.cpp | 19 +++++++++++++++++-- src/PythonQtClassInfo.h | 5 +++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index 658fc045..c8be0a15 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -49,6 +49,11 @@ QHash PythonQtMethodInfo::_parameterTypeDict; +// List of words that are reserved in Python, but not in C++, so they need escaping +QSet PythonQtClassInfo::_reservedNames{ + "None", "True", "False" +}; + PythonQtClassInfo::PythonQtClassInfo() { _meta = nullptr; _constructors = nullptr; @@ -282,7 +287,7 @@ bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* continue; } for (int j=0; j < e.keyCount(); j++) { - if (qstrcmp(e.key(j), memberName)==0) { + if (escapeReservedNames(e.key(j)) == memberName) { PyObject* enumType = findEnumWrapper(e.name()); if (enumType) { PythonQtObjectPtr enumValuePtr; @@ -869,7 +874,7 @@ void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta) for (int j = 0; j < e.keyCount(); j++) { PythonQtObjectPtr enumValuePtr; enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(p.object(), e.value(j))); - p.addVariable(e.key(j), QVariant::fromValue(enumValuePtr)); + p.addVariable(escapeReservedNames(e.key(j)), QVariant::fromValue(enumValuePtr)); } } #endif @@ -1018,6 +1023,16 @@ PythonQtVoidPtrCB* PythonQtClassInfo::referenceCountingUnrefCB() return _unrefCallback; } +QByteArray PythonQtClassInfo::escapeReservedNames(const QByteArray& name) +{ + if (_reservedNames.contains(name)) { + return name + "_"; + } + else { + return name; + } +} + void PythonQtClassInfo::updateRefCountingCBs() { if (!_refCallback) { diff --git a/src/PythonQtClassInfo.h b/src/PythonQtClassInfo.h index 5e3faf54..48f7364d 100644 --- a/src/PythonQtClassInfo.h +++ b/src/PythonQtClassInfo.h @@ -237,6 +237,10 @@ class PYTHONQT_EXPORT PythonQtClassInfo { //! _typeSlots with Type_RichCompare. The result is cached internally. bool supportsRichCompare(); + //! Sometimes enum values use a reserved name in Python. In this case + //! replace it with something that is not reserved + QByteArray escapeReservedNames(const QByteArray& name); + private: void updateRefCountingCBs(); @@ -300,6 +304,7 @@ class PYTHONQT_EXPORT PythonQtClassInfo { bool _searchPolymorphicHandlerOnParent; bool _searchRefCountCB; + static QSet _reservedNames; }; //--------------------------------------------------------------- From 3ca00bfb9a411d90480d6f12de3c2971bfc8bb57 Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Tue, 12 Dec 2023 13:22:46 +0100 Subject: [PATCH 06/26] [Backport generator] Add QtOpenGLWidgets to masterinclude - add missing modules for qt6 in CI (cherry picked from commit MeVisLab/pythonqt@c7a13c6324db1854e8a7f24a5c136fd490fb8e4d) --- generator/qtscript_masterinclude.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/generator/qtscript_masterinclude.h b/generator/qtscript_masterinclude.h index cc679058..8c0da0b8 100644 --- a/generator/qtscript_masterinclude.h +++ b/generator/qtscript_masterinclude.h @@ -127,9 +127,11 @@ #include #endif +#if QT_VERSION < 0x060000 #ifndef QT_NO_XMLPATTERNS # include #endif +#endif #ifndef QT_NO_WEBKIT # include @@ -1232,4 +1234,8 @@ #define GL_LOGIC_OP GL_INDEX_LOGIC_OP #define GL_TEXTURE_COMPONENTS GL_TEXTURE_INTERNAL_FORMAT #include +#if QT_VERSION >= 0x060000 +#include +#endif + #endif // QT_NO_OPENGL From ef515808053a56bfc718a91d5e004123a9533257 Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Tue, 12 Dec 2023 15:53:10 +0100 Subject: [PATCH 07/26] [Backport] Support QByteArrayView arguments + return values (cherry picked from commit MeVisLab/pythonqt@e132d963251033df762f05d3b62cd68f4895da31) --- generator/main.cpp | 6 +++- generator/typesystem.cpp | 13 ++++++++ generator/typesystem.h | 1 + src/PythonQtConversion.cpp | 66 +++++++++++++++++++++++++++++++------- src/PythonQtConversion.h | 4 +++ 5 files changed, 78 insertions(+), 12 deletions(-) diff --git a/generator/main.cpp b/generator/main.cpp index e438bcd9..b04ffe31 100644 --- a/generator/main.cpp +++ b/generator/main.cpp @@ -203,8 +203,12 @@ int main(int argc, char *argv[]) printf("Parsing typesystem file [%s]\n", qPrintable(typesystemFileName)); fflush(stdout); ReportHandler::setContext("Typesystem"); - if (!TypeDatabase::instance()->parseFile(typesystemFileName, qtVersion)) + if (TypeDatabase::instance()->parseFile(typesystemFileName, qtVersion)) { + TypeDatabase::instance()->finalSetup(); + } + else { qFatal("Cannot parse file: '%s'", qPrintable(typesystemFileName)); + } printf("PreProcessing - Generate [%s] using [%s] and include-paths [%s]\n", qPrintable(pp_file), qPrintable(fileName), qPrintable(args.value("include-paths"))); diff --git a/generator/typesystem.cpp b/generator/typesystem.cpp index 0509dbee..b98cf04d 100644 --- a/generator/typesystem.cpp +++ b/generator/typesystem.cpp @@ -1573,6 +1573,19 @@ TypeDatabase::TypeDatabase() : m_suppressWarnings(true) addRemoveFunctionToTemplates(this); } +void TypeDatabase::finalSetup() +{ + TypeEntry* byteArrayType = findType("QByteArray"); + if (byteArrayType) { + // Support QByteArrayView as alternative parameter type. + // Using StringTypeEntry for it, because no wrappers are generated for those types + StringTypeEntry* e = new StringTypeEntry("QByteArrayView"); + e->setPreferredConversion(false); + e->setEquivalentType(byteArrayType); + addType(e); + } +} + bool TypeDatabase::parseFile(const QString &filename, unsigned int qtVersion, bool generate) { QFile file(filename); diff --git a/generator/typesystem.h b/generator/typesystem.h index 05adee68..a6d8b4cb 100644 --- a/generator/typesystem.h +++ b/generator/typesystem.h @@ -1234,6 +1234,7 @@ class TypeDatabase QString filename() const { return "typesystem.txt"; } bool parseFile(const QString &filename, unsigned int qtVersion, bool generate = true); + void finalSetup(); private: bool m_suppressWarnings; diff --git a/src/PythonQtConversion.cpp b/src/PythonQtConversion.cpp index 23bc7a15..285cece4 100644 --- a/src/PythonQtConversion.cpp +++ b/src/PythonQtConversion.cpp @@ -57,9 +57,11 @@ int PythonQtConv::stringRefTypeId = 0; #else #include #include +#include int PythonQtConv::stringViewTypeId = 0; int PythonQtConv::anyStringViewTypeId = 0; +int PythonQtConv::byteArrayViewTypeId = 0; #endif QHash PythonQtConv::_metaTypeToPythonConverters; @@ -399,6 +401,9 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant && +#if QT_VERSION >= 0x060000 + info.typeId != byteArrayViewTypeId && // this case is handled later on +#endif !PythonQt::priv()->isPythonQtAnyObjectPtrMetaId(info.typeId)) { // if we have a Qt wrapper object and if we do not need a QVariant, we do the following: // (the Variant case is handled below in a switch) @@ -597,13 +602,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i break; case QMetaType::QByteArray: { - QByteArray bytes = PyObjGetBytes(obj, strict, ok); - if (!ok && !strict) { - // since Qt uses QByteArray in many places for identifier strings, - // we need to allow implicit conversion from unicode as well. - // We allow that for both Python 2.x and 3.x to be compatible. - bytes = PyObjGetString(obj, true, ok).toUtf8(); - } + QByteArray bytes = PyObjGetBytesAllowString(obj, strict, ok); if (ok) { PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, QVariant(bytes), ptr); ptr = (void*)((QVariant*)ptr)->constData(); @@ -680,6 +679,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i } #else if (info.typeId == stringViewTypeId) { + // Handle QStringView, which needs a reference to a persistent QString QString str = PyObjGetString(obj, strict, ok); if (ok) { void* ptr2 = nullptr; @@ -694,7 +694,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i } } else if (info.typeId == anyStringViewTypeId) { - // Handle QStringView et al, which need a reference to a persistent QString + // Handle QAnyStringView, which needs a reference to a persistent QString QString str = PyObjGetString(obj, strict, ok); if (ok) { void* ptr2 = nullptr; @@ -708,6 +708,21 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i return nullptr; } } + else if (info.typeId == byteArrayViewTypeId) { + // Handle QByteArrayView, which needs a reference to a persistent QByteArray + QByteArray ba = PyObjGetBytesAllowString(obj, strict, ok); + if (ok) { + void* ptr2 = nullptr; + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr, frame, QVariant(ba), ptr2); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, + QVariant::fromValue(QByteArrayView(*((const QByteArray*)((QVariant*)ptr2)->constData()))), ptr); + ptr = (void*)((QVariant*)ptr)->constData(); + return ptr; + } + else { + return nullptr; + } + } #endif if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) { @@ -847,6 +862,15 @@ QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) // TODO: support buffer objects in general QByteArray r; ok = true; + if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) { + // check if we already have a QByteArray wrapper here + PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)val; + bool baOk; + QByteArray* baPtr = (QByteArray*)castWrapperTo(wrapper, "QByteArray", baOk); + if (baOk && baPtr) { + return *baPtr; + } + } if (PyBytes_Check(val)) { r = QByteArray(PyBytes_AS_STRING(val), PyBytes_GET_SIZE(val)); } else { @@ -855,6 +879,18 @@ QByteArray PythonQtConv::PyObjGetBytes(PyObject* val, bool /*strict*/, bool& ok) return r; } +QByteArray PythonQtConv::PyObjGetBytesAllowString(PyObject* val, bool strict, bool& ok) +{ + QByteArray bytes = PyObjGetBytes(val, strict, ok); + if (!ok && !strict) { + // since Qt uses QByteArray in many places for identifier strings, + // we need to allow implicit conversion from unicode as well. + // We allow that for both Python 2.x and 3.x to be compatible. + bytes = PyObjGetString(val, true, ok).toUtf8(); + } + return bytes; +} + bool PythonQtConv::PyObjGetBool(PyObject* val, bool strict, bool &ok) { bool d = false; ok = false; @@ -1561,17 +1597,23 @@ PyObject* PythonQtConv::createCopyFromMetaType( int type, const void* data ) #if QT_VERSION < 0x060000 PyObject* PythonQtConv::convertFromStringRef(const void* inObject, int /*metaTypeId*/) { - return PythonQtConv::QStringToPyObject(((QStringRef*)inObject)->toString()); + return QStringToPyObject(((QStringRef*)inObject)->toString()); } #else PyObject* PythonQtConv::convertFromStringView(const void* inObject, int /*metaTypeId*/) { - return PythonQtConv::QStringToPyObject(((QStringView*)inObject)->toString()); + return QStringToPyObject(((QStringView*)inObject)->toString()); } PyObject* PythonQtConv::convertFromAnyStringView(const void* inObject, int /*metaTypeId*/) { - return PythonQtConv::QStringToPyObject(((QAnyStringView*)inObject)->toString()); + return QStringToPyObject(((QAnyStringView*)inObject)->toString()); +} + +PyObject* PythonQtConv::convertFromByteArrayView(const void* inObject, int) +{ + QByteArray ba = ((QByteArrayView*)inObject)->toByteArray(); + return createCopyFromMetaType(QMetaType::QByteArray, &ba); } #endif @@ -1635,6 +1677,8 @@ void PythonQtConv::registerStringViewTypes() PythonQtConv::registerMetaTypeToPythonConverter(stringViewTypeId, PythonQtConv::convertFromStringView); anyStringViewTypeId = qRegisterMetaType("QAnyStringView"); PythonQtConv::registerMetaTypeToPythonConverter(anyStringViewTypeId, PythonQtConv::convertFromAnyStringView); + byteArrayViewTypeId = qRegisterMetaType("QByteArrayView"); + PythonQtConv::registerMetaTypeToPythonConverter(byteArrayViewTypeId, PythonQtConv::convertFromByteArrayView); #endif } diff --git a/src/PythonQtConversion.h b/src/PythonQtConversion.h index de21cbea..22ad5ecc 100644 --- a/src/PythonQtConversion.h +++ b/src/PythonQtConversion.h @@ -132,6 +132,8 @@ class PYTHONQT_EXPORT PythonQtConv { static QString PyObjGetString(PyObject* val, bool strict, bool &ok); //! get bytes from py object static QByteArray PyObjGetBytes(PyObject* val, bool strict, bool &ok); + //! get bytes from py object, also allows Python string + static QByteArray PyObjGetBytesAllowString(PyObject* val, bool strict, bool& ok); //! get int from py object static int PyObjGetInt(PyObject* val, bool strict, bool &ok); //! get int64 from py object @@ -190,6 +192,7 @@ class PYTHONQT_EXPORT PythonQtConv { #else static PyObject* convertFromStringView(const void* inObject, int /*metaTypeId*/); static PyObject* convertFromAnyStringView(const void* inObject, int /*metaTypeId*/); + static PyObject* convertFromByteArrayView(const void* inObject, int /*metaTypeId*/); #endif //! Returns the name of the equivalent CPP type (for signals and slots) @@ -226,6 +229,7 @@ class PYTHONQT_EXPORT PythonQtConv { #else static int stringViewTypeId; static int anyStringViewTypeId; + static int byteArrayViewTypeId; #endif }; From e75d9ac5eb3b63212515d7b33edc16396c1c8417 Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Tue, 12 Dec 2023 15:56:27 +0100 Subject: [PATCH 08/26] [Backport generator] Suppress some methods of QByteArray and others... that have become visible again after the argument type has changed from int to qsizetype (these are the variants that take a const char pointer and a size argument - this is not supported in Python, instead we use the variants with QByteArrayView argument) (cherry picked from commit MeVisLab/pythonqt@af3d2ee6912ec2006284066eda6db8734a84b452) --- generator/typesystem_core.xml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/generator/typesystem_core.xml b/generator/typesystem_core.xml index 15052b49..55856eb1 100644 --- a/generator/typesystem_core.xml +++ b/generator/typesystem_core.xml @@ -853,6 +853,7 @@ + @@ -1127,8 +1128,9 @@ public: return PyBytes_FromStringAndSize(b->data(), b->size()); } - + + @@ -1151,16 +1153,24 @@ public: + + + + + + + + @@ -1168,15 +1178,21 @@ public: + + + + + + @@ -1201,6 +1217,7 @@ public: + @@ -1323,6 +1340,7 @@ public: + @@ -1977,7 +1995,9 @@ public: - + + + From 0df988222df6378a117e6334a8584226a89c0b50 Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Tue, 12 Dec 2023 17:41:29 +0100 Subject: [PATCH 09/26] [Backport generator] Fix misspelled attribute name (cherry picked from commit MeVisLab/pythonqt@6b875534626bee0b8619e391e9b068a5846e6b03) --- generator/typesystem_core.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generator/typesystem_core.xml b/generator/typesystem_core.xml index 55856eb1..c9e4ed7f 100644 --- a/generator/typesystem_core.xml +++ b/generator/typesystem_core.xml @@ -2082,6 +2082,6 @@ public: - + From 2798ddd2af624f24700a459a4ec4a084ccc0d0f3 Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Sun, 1 Jan 2023 18:04:40 +0100 Subject: [PATCH 10/26] [Partial Backport] Minor documentation fixes Backport note: Removed `.github/workflows/builddocs.yml` from original commit - updated Doxyfile to current doxygen version (using doxygen -u) - minor documentation fixes (cherry picked from commit MeVisLab/pythonqt@f2c49adff3e1ca405dc9750b63df9412b03b72eb) --- doxygen/Doxyfile | 602 +++++++++++++++++++++++++++------------------- src/PythonQtDoc.h | 14 +- 2 files changed, 368 insertions(+), 248 deletions(-) diff --git a/doxygen/Doxyfile b/doxygen/Doxyfile index 7c6f6092..8013ca1e 100644 --- a/doxygen/Doxyfile +++ b/doxygen/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.8.15 +# Doxyfile 1.9.5 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,16 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -60,12 +70,13 @@ PROJECT_LOGO = OUTPUT_DIRECTORY = . -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO @@ -81,26 +92,18 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English -# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all generated output in the proper direction. -# Possible values are: None, LTR, RTL and Context. -# The default value is: None. - -OUTPUT_TEXT_DIRECTION = None - # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -187,6 +190,16 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus @@ -207,6 +220,14 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. @@ -230,25 +251,19 @@ TAB_SIZE = 4 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines (in the resulting output). You can put ^^ in the value part of an -# alias to insert a newline as if a physical newline was in the original file. -# When you need a literal { or } or , in the value part of an alias you have to -# escape them by means of a backslash (\), this can lead to conflicts with the -# commands \{ and \} for these it is advised to use the version @{ and @} or use -# a double escape (\\{ and \\}) +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -289,19 +304,22 @@ OPTIMIZE_OUTPUT_SLICE = NO # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, -# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the -# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is -# Fortran), use: inc=Fortran f=C. +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. EXTENSION_MAPPING = @@ -319,7 +337,7 @@ MARKDOWN_SUPPORT = YES # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 0. +# Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 @@ -435,6 +453,19 @@ TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -455,6 +486,12 @@ EXTRACT_ALL = YES EXTRACT_PRIVATE = NO +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. @@ -492,6 +529,13 @@ EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation @@ -509,8 +553,8 @@ HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO, these declarations will be -# included in the documentation. +# declarations. If set to NO, these declarations will be included in the +# documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO @@ -529,12 +573,20 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES, upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. -# The default value is: system dependent. +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. CASE_SENSE_NAMES = YES @@ -552,6 +604,12 @@ HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +# SHOW_HEADERFILE = YES + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -709,7 +767,8 @@ FILE_VERSION_FILTER = # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE @@ -755,24 +814,28 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. If -# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. WARN_AS_ERROR = NO @@ -783,13 +846,27 @@ WARN_AS_ERROR = NO # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +# WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = doxygen.log @@ -808,8 +885,9 @@ INPUT = ../src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: https://www.gnu.org/software/libiconv/) for the list of -# possible encodings. +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 @@ -822,11 +900,15 @@ INPUT_ENCODING = UTF-8 # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, -# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.h @@ -865,7 +947,7 @@ EXCLUDE_PATTERNS = # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test +# ANamespace::AClass, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* @@ -913,6 +995,11 @@ IMAGE_PATH = . # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. @@ -954,6 +1041,15 @@ FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +# FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -1040,6 +1136,46 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -1051,13 +1187,6 @@ VERBATIM_HEADERS = YES ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored @@ -1157,7 +1286,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see +# this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. @@ -1167,7 +1296,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1196,9 +1325,9 @@ HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that -# are dynamically created via Javascript. If disabled, the navigation index will +# are dynamically created via JavaScript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML -# page. Disable this option to support browsers that do not have Javascript, +# page. Disable this option to support browsers that do not have JavaScript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1228,10 +1357,11 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: https://developer.apple.com/xcode/), introduced with OSX -# 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. @@ -1273,8 +1403,12 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1304,7 +1438,7 @@ CHM_FILE = HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1349,7 +1483,8 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1357,8 +1492,8 @@ QHP_NAMESPACE = # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1366,30 +1501,30 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = @@ -1432,16 +1567,28 @@ DISABLE_INDEX = NO # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +# FULL_SIDEBAR = NO + # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # @@ -1466,6 +1613,17 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1475,19 +1633,14 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. -FORMULA_TRANSPARENT = YES +FORMULA_MACROFILE = # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# https://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1498,10 +1651,17 @@ FORMULA_TRANSPARENT = YES USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1514,22 +1674,29 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1557,7 +1724,7 @@ MATHJAX_CODEFILE = SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. There +# implemented using a web server instead of a web client using JavaScript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH # setting. When disabled, doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing @@ -1576,7 +1743,8 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). +# Xapian (see: +# https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1589,8 +1757,9 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). See the section "External Indexing and -# Searching" for details. +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = @@ -1685,7 +1854,7 @@ COMPACT_LATEX = NO # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. -PAPER_TYPE = a4wide +PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names # that should be included in the LaTeX output. The package can be specified just @@ -1699,29 +1868,31 @@ PAPER_TYPE = a4wide EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empty -# string, for the replacement values of the other commands the user is referred -# to HTML_HEADER. +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. See +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what -# special commands can be used inside the footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = @@ -1754,9 +1925,11 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = NO -# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES, to get a -# higher quality PDF documentation. +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1764,8 +1937,7 @@ USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode # command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# if errors occur, instead of asking the user for help. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1778,16 +1950,6 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO -# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source -# code with syntax highlighting in the LaTeX output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_SOURCE_CODE = NO - # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See # https://en.wikipedia.org/wiki/BibTeX and \cite for more info. @@ -1868,16 +2030,6 @@ RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = -# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code -# with syntax highlighting in the RTF output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_RTF is set to YES. - -RTF_SOURCE_CODE = NO - #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- @@ -1974,15 +2126,6 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook -# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the -# program listings (including syntax highlighting and cross-referencing -# information) to the DOCBOOK output. Note that enabling this will significantly -# increase the size of the DOCBOOK output. -# The default value is: NO. -# This tag requires that the tag GENERATE_DOCBOOK is set to YES. - -DOCBOOK_PROGRAMLISTING = NO - #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- @@ -2069,7 +2212,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -2157,34 +2301,10 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. @@ -2217,35 +2337,20 @@ HAVE_DOT = NO DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_FONTNAME = - -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a +# graph for each documented class showing the direct and indirect inheritance +# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, +# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set +# to TEXT the direct and indirect inheritance relations will be shown as texts / +# links. +# Possible values are: NO, YES, TEXT and GRAPH. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES @@ -2259,7 +2364,8 @@ CLASS_GRAPH = YES COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. See also the chapter Grouping +# in the manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2282,10 +2388,32 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. +# This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will wrapped across multiple lines. Some heuristics are apply +# to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. @@ -2405,10 +2533,10 @@ MSCFILE_DIRS = DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = @@ -2446,18 +2574,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support @@ -2470,14 +2586,18 @@ DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES diff --git a/src/PythonQtDoc.h b/src/PythonQtDoc.h index ac7d3d56..48f51221 100644 --- a/src/PythonQtDoc.h +++ b/src/PythonQtDoc.h @@ -95,8 +95,8 @@ Qt framework. - Support for Qt namespace (with all enumerators) - All PythonQt wrapped objects support the dir() statement, so that you can see easily which attributes a QObject, CPP object or QVariant has - No preprocessing/wrapping tool needs to be started, PythonQt can script any QObject without prior knowledge about it (except for the MetaObject information from the \b moc) - - Multiple inheritance for C++ objects (e.g. a QWidget is derived from QObject and QPaintDevice, PythonQt will automatically cast a QWidget to a QPaintDevice when needed) - - Polymorphic downcasting (if e.g. PythonQt sees a QEvent, it can downcast it depending on the type(), so the Python e.g. sees a QPaintEvent instead of a plain QEvent) + - Multiple inheritance for C++ objects (e.g. if a QWidget is derived from QObject and QPaintDevice, PythonQt will automatically cast a QWidget to a QPaintDevice when needed) + - Polymorphic downcasting (if e.g. PythonQt sees a QEvent, it can downcast it depending on the type(), so the Python code e.g. sees a QPaintEvent instead of a plain QEvent) - Deriving C++ objects from Python and overwriting virtual method with a Python implementation (requires usage of wrapper generator or manual work!) - Extensible handler for Python/C++ conversion of complex types, e.g. mapping of QVector to/from a Python array - Setting of dynamic QObject properties via setProperty(), dynamic properties can be accessed for reading and writing like normal Python attributes (but creating a new property needs to be done with setProperty(), to distinguish from normal Python attributes) @@ -132,15 +132,15 @@ Qt framework. - Python 2 (>= Python 2.6) - Python 3 (>= Python 3.3) - Qt 4.x (Qt 4.7 and Qt 4.8 recommended) - - Qt 5.x (Tested with Qt 5.0, 5.3, 5.4 and 5.6) + - Qt 5.x (Tested with Qt 5.0, 5.3, 5.4, 5.6 and 5.11) The last working Qt4 version is available at svn branches/Qt4LastWorkingVersion or you can download the PythonQt 3.0 release. - The current svn trunk no longer supports Qt4, since we started to make use of some Qt5-only features. + The current git master branch no longer supports Qt4, since we started to make use of some Qt5-only features. \section Comparison Comparison with PySide - PythonQt is not as pythonic as PySide in many details (e.g. buffer protocol, pickling, translation support, ...) and it is mainly thought for embedding and intercommunication between Qt/Cpp and Python - - PythonQt offers properties as Python attributes, while PySide offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PySide) + - PythonQt offers properties as Python attributes, while PySide offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PySide, though in PySide6 in can also be made a property) - PythonQt currently does not support instanceof checks for Qt classes, except for the exact match and derived Python classes - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it like a normal slot - Ownership handling of objects is not as complete as in PySide and PySide, especially in situations where the ownership is not clearly passed to C++ on the C++ API. @@ -169,7 +169,7 @@ Qt framework. The PythonQt wrappers generated by the generator located in the "generated_cpp" directory are free to be used without any licensing restrictions. - The generated wrappers are pre-generated and checked-in for 5.0, 5.3, 5.4 and 5.6, so you only need to build and run the + The generated wrappers are pre-generated and checked-in for 5.0, 5.3, 5.4, 5.6 and 5.11, so you only need to build and run the generator when you want to build additional wrappers or you want to upgrade/downgrade to another Qt version. You may use the generator to generate C++ bindings for your own C++ classes (e.g., to make them inheritable in Python), but this is currently not documented and involves creating your own typesystem files. @@ -241,7 +241,7 @@ Qt framework. properties of the objects as if they where normal python properties. In addition to this, the wrapped objects support - - className() - returns a string that reprents the classname of the QObject + - className() - returns a string that represents the classname of the QObject - help() - shows all properties, slots, enums, decorator slots and constructors of the object, in a printable form - delete() - deletes the object (use with care, especially if you passed the ownership to C++) - connect(signal, function) - connect the signal of the given object to a python function From 91841650e5750614e99866e0185a241bc3a08f01 Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Wed, 13 Dec 2023 13:00:03 +0100 Subject: [PATCH 11/26] [Backport] Minor documentation updates (cherry picked from commit MeVisLab/pythonqt@5a3506af4a2f0b8c8d1b6e30484dd67c4279f3a2) --- src/PythonQtDoc.h | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/PythonQtDoc.h b/src/PythonQtDoc.h index 48f51221..84bbf9a6 100644 --- a/src/PythonQtDoc.h +++ b/src/PythonQtDoc.h @@ -129,10 +129,11 @@ Qt framework. \section Supported Supported Versions PythonQt supports: - - Python 2 (>= Python 2.6) - - Python 3 (>= Python 3.3) - - Qt 4.x (Qt 4.7 and Qt 4.8 recommended) - - Qt 5.x (Tested with Qt 5.0, 5.3, 5.4, 5.6 and 5.11) + - Python 2 (>= Python 2.7) + - Python 3 (>= Python 3.6) + - Qt 4.x (Qt 4.7 and Qt 4.8 recommended) (not in the master branch, see below) + - Qt 5.x (Tested with Qt 5.0, 5.3, 5.4, 5.6, 5.11, 5.12 and 5.15) + - Qt 6.x (Tested with Qt 6.5 and 6.6) - support may not be complete, support for optional modules may be added as needed The last working Qt4 version is available at svn branches/Qt4LastWorkingVersion or you can download the PythonQt 3.0 release. The current git master branch no longer supports Qt4, since we started to make use of some Qt5-only features. @@ -196,13 +197,13 @@ Qt framework. char/uchar,int/uint,short,ushort,QCharinteger longinteger ulong,longlong,ulonglonglong - QStringunicode string - QByteArrayQByteArray wrapper \ref qbytearray-bytes "(1)" + QString \ref qstring "(1)"unicode string + QByteArray \ref qbytearray "(2)"QByteArray wrapper \ref qbytearray-bytes "(3)" char*str QStringListtuple of unicode strings QVariantListtuple of objects QVariantMapdict of objects - QVariantdepends on type \ref qvariant "(2)" + QVariantdepends on type \ref qvariant "(4)" QSize, QRect and all other standard Qt QVariantsvariant wrapper that supports complete API of the respective Qt classes OwnRegisteredMetaTypeC++ wrapper, optionally with additional information/wrapping provided by registerCPPClass() QListconverts to a list of CPP wrappers @@ -210,9 +211,11 @@ Qt framework. EnumTypeEnum wrapper derived from python integer QObject (and derived classes)QObject wrapper C++ objectCPP wrapper, either wrapped via PythonQtCppWrapperFactory or just decorated with decorators - PyObjectPyObject \ref pyobject "(3)" + PyObjectPyObject \ref pyobject "(5)" + -# \anchor qstring QStringRef (Qt5), QStringView and QAnyStringView (Qt6) are handled like QString. + -# \anchor qbytearray QByteArrayView (Qt6) is handled like QByteArray. -# \anchor qbytearray-bytes The Python 'bytes' type will automatically be converted to QByteArray where required. For converting a QByteArray to 'bytes' use the .data() method. -# \anchor qvariant QVariants are mapped recursively as given above, e.g. a dictionary can contain lists of dictionaries of doubles. From de4b79c0d28dae106c1378d95acec40566697c50 Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Wed, 13 Dec 2023 14:26:06 +0100 Subject: [PATCH 12/26] [Backport generator] Move implementation from main.h into main.cpp (cherry picked from commit MeVisLab/pythonqt@47a0cf42b864af1280922bea0f5ac14f7dd815b8) --- generator/generator.pri | 1 - generator/main.cpp | 173 +++++++++++++++++++++++++++++++++------- generator/main.h | 153 ----------------------------------- 3 files changed, 142 insertions(+), 185 deletions(-) delete mode 100644 generator/main.h diff --git a/generator/generator.pri b/generator/generator.pri index 490e265c..d6bde5a4 100644 --- a/generator/generator.pri +++ b/generator/generator.pri @@ -35,7 +35,6 @@ win32-clang-msvc:QMAKE_CXXFLAGS += -Wno-language-extension-token -Wno-microsoft- # Input HEADERS += \ $$GENERATORPATH/generator.h \ - $$GENERATORPATH/main.h \ $$GENERATORPATH/reporthandler.h \ $$GENERATORPATH/typeparser.h \ $$GENERATORPATH/typesystem.h \ diff --git a/generator/main.cpp b/generator/main.cpp index b04ffe31..3cd72825 100644 --- a/generator/main.cpp +++ b/generator/main.cpp @@ -40,14 +40,15 @@ ****************************************************************************/ #include +#include -#include "main.h" #include "asttoxml.h" #include "reporthandler.h" #include "typesystem.h" #include "generatorset.h" #include "fileout.h" #include "control.h" +#include "pp.h" #include #include @@ -57,39 +58,150 @@ void displayHelp(GeneratorSet *generatorSet); -static unsigned int getQtVersion(const QString& commandLineIncludes) +namespace { - QRegularExpression re("#define\\s+QTCORE_VERSION\\s+0x([0-9a-f]+)", QRegularExpression::CaseInsensitiveOption); - for (const QString& includeDir : Preprocess::getIncludeDirectories(commandLineIncludes)) { - QFileInfo fi(QDir(includeDir), "qtcoreversion.h"); - if (fi.exists()) { - QString filePath = fi.absoluteFilePath(); - QFile f(filePath); - if (f.open(QIODevice::ReadOnly)) { - QTextStream ts(&f); - QString content = ts.readAll(); - f.close(); - auto match = re.match(content); - if (match.isValid()) { - unsigned int result; - bool ok; - result = match.captured(1).toUInt(&ok, 16); - if (!ok) { - printf("Could not parse Qt version in file [%s] (looked for #define QTCORE_VERSION)\n", - qPrintable(filePath)); + + QStringList getIncludeDirectories(const QString &commandLineIncludes) + { + QStringList includes; + includes << QString("."); + +#if defined(Q_OS_WIN32) + const char *path_splitter = ";"; +#else + const char *path_splitter = ":"; +#endif + + // Environment INCLUDE + QString includePath = getenv("INCLUDE"); + if (!includePath.isEmpty()) + includes += includePath.split(path_splitter); + + // Includes from the command line + if (!commandLineIncludes.isEmpty()) + includes += commandLineIncludes.split(path_splitter); + + // Include Qt + QString qtdir = getenv ("QTDIR"); + if (qtdir.isEmpty()) { +#if defined(Q_OS_MAC) + qWarning("QTDIR environment variable not set. Assuming standard binary install using frameworks."); + QString frameworkDir = "/Library/Frameworks"; + includes << (frameworkDir + "/QtXml.framework/Headers"); + includes << (frameworkDir + "/QtNetwork.framework/Headers"); + includes << (frameworkDir + "/QtCore.framework/Headers"); + includes << (frameworkDir + "/QtGui.framework/Headers"); + includes << (frameworkDir + "/QtOpenGL.framework/Headers"); + includes << frameworkDir; +#else + qWarning("QTDIR environment variable not set. This may cause problems with finding the necessary include files."); +#endif + } else { + std::cout << "-------------------------------------------------------------" << std::endl; + std::cout << "Using QT at: " << qtdir.toLocal8Bit().constData() << std::endl; + std::cout << "-------------------------------------------------------------" << std::endl; + qtdir += "/include"; + includes << (qtdir + "/QtXml"); + includes << (qtdir + "/QtNetwork"); + includes << (qtdir + "/QtCore"); + includes << (qtdir + "/QtGui"); + includes << (qtdir + "/QtOpenGL"); + includes << qtdir; + } + return includes; + } + + bool + preprocess(const QString &sourceFile, const QString &targetFile, const QString &commandLineIncludes = QString()) + { + rpp::pp_environment env; + rpp::pp preprocess(env); + + rpp::pp_null_output_iterator null_out; + + const char *ppconfig = ":/trolltech/generator/parser/rpp/pp-qt-configuration"; + + QFile file(ppconfig); + if (!file.open(QFile::ReadOnly)) + { + fprintf(stderr, "Preprocessor configuration file not found '%s'\n", ppconfig); + return false; + } + + QByteArray ba = file.readAll(); + file.close(); + preprocess.operator()(ba.constData(), ba.constData() + ba.size(), null_out); + + foreach(QString + include, getIncludeDirectories(commandLineIncludes)) { + preprocess.push_include_path(QDir::toNativeSeparators(include).toStdString()); + } + + QString currentDir = QDir::current().absolutePath(); + QFileInfo sourceInfo(sourceFile); + QDir::setCurrent(sourceInfo.absolutePath()); + + std::string result; + result.reserve(20 * 1024); // 20K + + result += "# 1 \"builtins\"\n"; + result += "# 1 \""; + result += sourceFile.toStdString(); + result += "\"\n"; + + preprocess.file(sourceInfo.fileName().toStdString(), + rpp::pp_output_iterator(result)); + + QDir::setCurrent(currentDir); + + QFile f(targetFile); + if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) + { + fprintf(stderr, "Failed to write preprocessed file: %s\n", qPrintable(targetFile)); + } + f.write(result.c_str(), result.length()); + + return true; + } + + unsigned int getQtVersion(const QString &commandLineIncludes) + { + QRegularExpression re("#define\\s+QTCORE_VERSION\\s+0x([0-9a-f]+)", QRegularExpression::CaseInsensitiveOption); + for (const QString &includeDir: getIncludeDirectories(commandLineIncludes)) + { + QFileInfo fi(QDir(includeDir), "qtcoreversion.h"); + if (fi.exists()) + { + QString filePath = fi.absoluteFilePath(); + QFile f(filePath); + if (f.open(QIODevice::ReadOnly)) + { + QTextStream ts(&f); + QString content = ts.readAll(); + f.close(); + auto match = re.match(content); + if (match.isValid()) + { + unsigned int result; + bool ok; + result = match.captured(1).toUInt(&ok, 16); + if (!ok) + { + printf("Could not parse Qt version in file [%s] (looked for #define QTCORE_VERSION)\n", + qPrintable(filePath)); + } + return result; + } } - return result; } } + printf("Error: Could not find Qt version (looked for qtcoreversion.h in %s)\n", + qPrintable(commandLineIncludes)); + return 0; } - } - printf("Error: Could not find Qt version (looked for qtcoreversion.h in %s)\n", - qPrintable(commandLineIncludes)); - return 0; -} +}; -#include int main(int argc, char *argv[]) { ReportHandler::setContext("Arguments"); @@ -102,7 +214,6 @@ int main(int argc, char *argv[]) QString fileName; QString typesystemFileName; QString pp_file = ".preprocessed.tmp"; - QStringList rebuild_classes; QMap args; unsigned int qtVersion{}; @@ -213,7 +324,7 @@ int main(int argc, char *argv[]) printf("PreProcessing - Generate [%s] using [%s] and include-paths [%s]\n", qPrintable(pp_file), qPrintable(fileName), qPrintable(args.value("include-paths"))); ReportHandler::setContext("Preprocess"); - if (!Preprocess::preprocess(fileName, pp_file, args.value("include-paths"))) { + if (!preprocess(fileName, pp_file, args.value("include-paths"))) { fprintf(stderr, "Preprocessor failed on file: '%s'\n", qPrintable(fileName)); return 1; } @@ -243,9 +354,9 @@ int main(int argc, char *argv[]) void displayHelp(GeneratorSet* generatorSet) { #if defined(Q_OS_WIN32) - char path_splitter = ';'; + char path_splitter = ';'; #else - char path_splitter = ':'; + char path_splitter = ':'; #endif printf("Usage:\n generator [options] header-file typesystem-file\n\n"); printf("Available options:\n\n"); diff --git a/generator/main.h b/generator/main.h deleted file mode 100644 index 388e9250..00000000 --- a/generator/main.h +++ /dev/null @@ -1,153 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Script Generator project on Qt Labs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MAIN_H -#define MAIN_H - -#include "pp.h" - -#include -#include - -struct Preprocess -{ - - static QStringList getIncludeDirectories(const QString& commandLineIncludes) - { - QStringList includes; - includes << QString("."); - -#if defined(Q_OS_WIN32) - const char *path_splitter = ";"; -#else - const char *path_splitter = ":"; -#endif - - // Environment INCLUDE - QString includePath = getenv("INCLUDE"); - if (!includePath.isEmpty()) - includes += includePath.split(path_splitter); - - // Includes from the command line - if (!commandLineIncludes.isEmpty()) - includes += commandLineIncludes.split(path_splitter); - - // Include Qt - QString qtdir = getenv ("QTDIR"); - if (qtdir.isEmpty()) { -#if defined(Q_OS_MAC) - qWarning("QTDIR environment variable not set. Assuming standard binary install using frameworks."); - QString frameworkDir = "/Library/Frameworks"; - includes << (frameworkDir + "/QtXml.framework/Headers"); - includes << (frameworkDir + "/QtNetwork.framework/Headers"); - includes << (frameworkDir + "/QtCore.framework/Headers"); - includes << (frameworkDir + "/QtGui.framework/Headers"); - includes << (frameworkDir + "/QtOpenGL.framework/Headers"); - includes << frameworkDir; -#else - qWarning("QTDIR environment variable not set. This may cause problems with finding the necessary include files."); -#endif - } else { - std::cout << "-------------------------------------------------------------" << std::endl; - std::cout << "Using QT at: " << qtdir.toLocal8Bit().constData() << std::endl; - std::cout << "-------------------------------------------------------------" << std::endl; - qtdir += "/include"; - includes << (qtdir + "/QtXml"); - includes << (qtdir + "/QtNetwork"); - includes << (qtdir + "/QtCore"); - includes << (qtdir + "/QtGui"); - includes << (qtdir + "/QtOpenGL"); - includes << qtdir; - } - return includes; - } - - static bool preprocess(const QString &sourceFile, const QString &targetFile, const QString &commandLineIncludes = QString()) - { - rpp::pp_environment env; - rpp::pp preprocess(env); - - rpp::pp_null_output_iterator null_out; - - const char *ppconfig = ":/trolltech/generator/parser/rpp/pp-qt-configuration"; - - QFile file(ppconfig); - if (!file.open(QFile::ReadOnly)) { - fprintf(stderr, "Preprocessor configuration file not found '%s'\n", ppconfig); - return false; - } - - QByteArray ba = file.readAll(); - file.close(); - preprocess.operator() (ba.constData(), ba.constData() + ba.size(), null_out); - - foreach (QString include, getIncludeDirectories(commandLineIncludes)) { - preprocess.push_include_path(QDir::toNativeSeparators(include).toStdString()); - } - - QString currentDir = QDir::current().absolutePath(); - QFileInfo sourceInfo(sourceFile); - QDir::setCurrent(sourceInfo.absolutePath()); - - std::string result; - result.reserve (20 * 1024); // 20K - - result += "# 1 \"builtins\"\n"; - result += "# 1 \""; - result += sourceFile.toStdString(); - result += "\"\n"; - - preprocess.file (sourceInfo.fileName().toStdString(), - rpp::pp_output_iterator (result)); - - QDir::setCurrent(currentDir); - - QFile f(targetFile); - if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { - fprintf(stderr, "Failed to write preprocessed file: %s\n", qPrintable(targetFile)); - } - f.write(result.c_str(), result.length()); - - return true; - } -}; - -#endif // MAIN_H From b58e3b090b8c0c557408c937da2f83121628ec75 Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Wed, 13 Dec 2023 14:27:22 +0100 Subject: [PATCH 13/26] [Backport generator] Replace INCLUDE by PYTHONQT_INCLUDE env var - avoids accidental inclusion of system-defined include dirs (cherry picked from commit MeVisLab/pythonqt@d0ddad60fe81b882e76c5f8fc5e2347ab28490d0) --- generator/main.cpp | 47 +++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/generator/main.cpp b/generator/main.cpp index 3cd72825..7cb3b79d 100644 --- a/generator/main.cpp +++ b/generator/main.cpp @@ -66,26 +66,37 @@ namespace QStringList includes; includes << QString("."); -#if defined(Q_OS_WIN32) - const char *path_splitter = ";"; -#else - const char *path_splitter = ":"; -#endif + QChar pathSplitter = QDir::listSeparator(); - // Environment INCLUDE - QString includePath = getenv("INCLUDE"); + // Environment PYTHONQT_INCLUDE + QString includePath = getenv("PYTHONQT_INCLUDE"); if (!includePath.isEmpty()) - includes += includePath.split(path_splitter); + includes += includePath.split(pathSplitter, Qt::SkipEmptyParts); // Includes from the command line if (!commandLineIncludes.isEmpty()) - includes += commandLineIncludes.split(path_splitter); + includes += commandLineIncludes.split(pathSplitter, Qt::SkipEmptyParts); + for (auto it = includes.begin(); it != includes.end();) + { + if (!QDir(*it).exists()) + { + qWarning("Include path %s does not exist, ignoring it.", it->toUtf8().constData()); + it = includes.erase(it); + } + else + { + ++it; + } + } // Include Qt - QString qtdir = getenv ("QTDIR"); - if (qtdir.isEmpty()) { + QString qtdir = getenv("QTDIR"); + if (qtdir.isEmpty() || !QDir(qtdir).exists(qtdir)) + { + QString reason = "The QTDIR environment variable " + qtdir.isEmpty() ? + "is not set. " : "points to a non-existing directory. "; #if defined(Q_OS_MAC) - qWarning("QTDIR environment variable not set. Assuming standard binary install using frameworks."); + qWarning((reason + "Assuming standard binary install using frameworks.").toUtf8().constData()); QString frameworkDir = "/Library/Frameworks"; includes << (frameworkDir + "/QtXml.framework/Headers"); includes << (frameworkDir + "/QtNetwork.framework/Headers"); @@ -94,9 +105,11 @@ namespace includes << (frameworkDir + "/QtOpenGL.framework/Headers"); includes << frameworkDir; #else - qWarning("QTDIR environment variable not set. This may cause problems with finding the necessary include files."); + qWarning((reason + "This may cause problems with finding the necessary include files.").toUtf8().constData()); #endif - } else { + } + else + { std::cout << "-------------------------------------------------------------" << std::endl; std::cout << "Using QT at: " << qtdir.toLocal8Bit().constData() << std::endl; std::cout << "-------------------------------------------------------------" << std::endl; @@ -353,11 +366,7 @@ int main(int argc, char *argv[]) void displayHelp(GeneratorSet* generatorSet) { -#if defined(Q_OS_WIN32) - char path_splitter = ';'; -#else - char path_splitter = ':'; -#endif + const auto path_splitter = QDir::listSeparator().toLatin1(); printf("Usage:\n generator [options] header-file typesystem-file\n\n"); printf("Available options:\n\n"); printf("General:\n"); From d0e46f4a54ddbc48255e005b3fa479cbf6d82f94 Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Thu, 14 Dec 2023 17:31:09 +0100 Subject: [PATCH 14/26] [Backport generator] More typesystem entries (added classes and rejections) Just so that there are no unknown rejected classes and enums in the log file for Qt 6.6. The support for some of the new classes might be incomplete. (cherry picked from commit MeVisLab/pythonqt@249e092190e15d6317e2f8edcb25add9aa696381) --- generator/typesystem_core.xml | 209 +++++++++++++++++++++- generator/typesystem_gui.xml | 21 ++- generator/typesystem_multimedia.xml | 5 + generator/typesystem_network.xml | 19 +- generator/typesystem_qml.xml | 15 ++ generator/typesystem_quick.xml | 11 +- generator/typesystem_webenginewidgets.xml | 18 ++ generator/typesystem_xml.xml | 1 + 8 files changed, 284 insertions(+), 15 deletions(-) diff --git a/generator/typesystem_core.xml b/generator/typesystem_core.xml index c9e4ed7f..ef2c2c3c 100644 --- a/generator/typesystem_core.xml +++ b/generator/typesystem_core.xml @@ -19,21 +19,38 @@ + + + + + + + + + + + + + + + + + @@ -203,6 +220,8 @@ + + @@ -220,6 +239,7 @@ + @@ -241,6 +261,7 @@ + @@ -416,6 +437,8 @@ + + @@ -444,43 +467,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -989,6 +1102,8 @@ public: + + @@ -1104,6 +1219,7 @@ public: + @@ -1220,6 +1336,7 @@ public: + @@ -1345,7 +1462,6 @@ public: - PythonQt::Type_EnterExit @@ -1354,6 +1470,8 @@ public: void __exit__(QMutexLocker* self, PyObject* /*type*/, PyObject* /*value*/, PyObject* /*traceback*/) { self->unlock(); } + + PythonQt::Type_EnterExit @@ -1436,6 +1554,7 @@ public: + @@ -1464,6 +1583,9 @@ public: --> + + + @@ -1839,6 +1961,9 @@ public: + + + @@ -1858,6 +1983,83 @@ public: + + + + + + + + + + + + + + + + + + QByteArray readByteArray(QCborStreamReader* theWrappedObject) { + auto result = theWrappedObject->readByteArray(); + return result.status == QCborStreamReader::Ok ? result.data : QByteArray(); + } + + QString readString(QCborStreamReader* theWrappedObject) { + auto result = theWrappedObject->readString(); + return result.status == QCborStreamReader::Ok ? result.data : QString(); + } + + qint64 toTag(QCborStreamReader* theWrappedObject) const { + return static_cast<qint64>(theWrappedObject->toTag()); + } + + + + + + + // replace QCborTag with qint64: + QCborValue* new_QCborValue(qint64 tag, const QCborValue& taggedValue) { + return new QCborValue(QCborTag(tag), taggedValue); + } + + qint64 tag(QCborValue* theWrappedObject, qint64 defaultValue) const { + return static_cast<qint64>(theWrappedObject->tag(QCborTag(defaultValue))); + } + + + + + + + + + + + + void insert(QCborMap* theWrappedObject, qint64 key, const QCborValue& value_) + { + theWrappedObject->insert(key, value_); + } + + void insert(QCborMap* theWrappedObject, const QString& key, const QCborValue& value_) + { + theWrappedObject->insert(key, value_); + } + + + + + + + + + + + + + @@ -2075,6 +2277,9 @@ public: + + + diff --git a/generator/typesystem_gui.xml b/generator/typesystem_gui.xml index b535379b..6ab6fe10 100644 --- a/generator/typesystem_gui.xml +++ b/generator/typesystem_gui.xml @@ -22,11 +22,13 @@ + + @@ -84,6 +86,7 @@ + @@ -104,6 +107,7 @@ + @@ -156,13 +160,15 @@ + + - + @@ -390,6 +396,8 @@ + + @@ -615,6 +623,7 @@ + @@ -641,6 +650,7 @@ + @@ -892,6 +902,7 @@ + @@ -1120,6 +1131,7 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -1326,6 +1338,7 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -2936,6 +2949,7 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -3078,6 +3092,7 @@ PyObject* constScanLine(QImage* image, int line) { + @@ -3096,7 +3111,8 @@ PyObject* constScanLine(QImage* image, int line) { - + + @@ -3180,6 +3196,7 @@ PyObject* constScanLine(QImage* image, int line) { + diff --git a/generator/typesystem_multimedia.xml b/generator/typesystem_multimedia.xml index 9d16a39c..54c1b0d1 100644 --- a/generator/typesystem_multimedia.xml +++ b/generator/typesystem_multimedia.xml @@ -7,6 +7,8 @@ + + @@ -126,11 +128,14 @@ + + + diff --git a/generator/typesystem_network.xml b/generator/typesystem_network.xml index 2c3d1360..77e998a8 100644 --- a/generator/typesystem_network.xml +++ b/generator/typesystem_network.xml @@ -5,10 +5,6 @@ - - - - @@ -112,8 +108,6 @@ - - @@ -174,8 +168,6 @@ - - @@ -193,6 +185,8 @@ + + @@ -236,10 +230,17 @@ + + + - + + + + + diff --git a/generator/typesystem_qml.xml b/generator/typesystem_qml.xml index 21952240..af5d0bdb 100644 --- a/generator/typesystem_qml.xml +++ b/generator/typesystem_qml.xml @@ -6,6 +6,14 @@ + + + + + + + + @@ -16,6 +24,13 @@ + + + + + + + diff --git a/generator/typesystem_quick.xml b/generator/typesystem_quick.xml index bd255e68..9b8c7a52 100644 --- a/generator/typesystem_quick.xml +++ b/generator/typesystem_quick.xml @@ -29,9 +29,16 @@ - + + - + + + + + + + diff --git a/generator/typesystem_webenginewidgets.xml b/generator/typesystem_webenginewidgets.xml index 8f8020be..0c376917 100644 --- a/generator/typesystem_webenginewidgets.xml +++ b/generator/typesystem_webenginewidgets.xml @@ -5,9 +5,13 @@ + + + + @@ -22,8 +26,14 @@ + + + + + + @@ -31,12 +41,20 @@ + + + + + + + + diff --git a/generator/typesystem_xml.xml b/generator/typesystem_xml.xml index 4a57a218..ad07ddea 100644 --- a/generator/typesystem_xml.xml +++ b/generator/typesystem_xml.xml @@ -181,6 +181,7 @@ + From 92ef871d8029e7064136871cbb451ecf2024c4ff Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Fri, 15 Dec 2023 13:28:27 +0100 Subject: [PATCH 15/26] [Backport] Fix potential crash for unknown inner type - fixes #60 (cherry picked from commit MeVisLab/pythonqt@e83dbed2515f4dd758b323d4af42349d5b33a19f) --- src/PythonQtConversion.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PythonQtConversion.h b/src/PythonQtConversion.h index 22ad5ecc..d0f0eeb1 100644 --- a/src/PythonQtConversion.h +++ b/src/PythonQtConversion.h @@ -289,7 +289,7 @@ PyObject* PythonQtConvertListOfKnownClassToPythonList(const void* /*QList* */ ListType* list = (ListType*)inList; static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(QByteArray(QMetaType::typeName(metaTypeId)))); if (innerType == nullptr) { - std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type " << innerType->className().constData() << std::endl; + std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type for " << QMetaType::typeName(metaTypeId) << std::endl; } PyObject* result = PyTuple_New(list->size()); int i = 0; @@ -309,7 +309,7 @@ bool PythonQtConvertPythonListToListOfKnownClass(PyObject* obj, void* /*QList ListType* list = (ListType*)outList; static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(QByteArray(QMetaType::typeName(metaTypeId)))); if (innerType == nullptr) { - std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type " << innerType->className().constData() << std::endl; + std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type for " << QMetaType::typeName(metaTypeId) << std::endl; } bool result = false; if (PySequence_Check(obj)) { From daaf0da6f6b67deee846e4d377acdf7a2fad0469 Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Fri, 15 Dec 2023 15:41:11 +0100 Subject: [PATCH 16/26] [Backport] Register container classes with bool - closes #52 (cherry picked from commit MeVisLab/pythonqt@8c371c0bfe71666a9c3e8925d2f3296712897a11) --- src/PythonQt.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index b4ff3bd7..a3f8cc5a 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -129,6 +129,7 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) PythonQtConv::registerPythonToMetaTypeConverter(objectPtrListId, PythonQtConv::convertToQListOfPythonQtObjectPtr); PythonQtRegisterToolClassesTemplateConverter(int); + PythonQtRegisterToolClassesTemplateConverter(bool); PythonQtRegisterToolClassesTemplateConverter(float); PythonQtRegisterToolClassesTemplateConverter(double); PythonQtRegisterToolClassesTemplateConverter(qint32); From e68762281d577c92d2ea245d379316e19af60d0d Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Fri, 15 Dec 2023 12:40:45 +0100 Subject: [PATCH 17/26] [Backport generator] Remove work-around for package spelling by putting the correct spelling in the package name in the typesystem files (cherry picked from commit MeVisLab/pythonqt@182df8d99519509c26df2195b6f478d91bd33292) --- generator/setupgenerator.cpp | 49 +++++------------------ generator/shellgenerator.h | 6 ++- generator/shellheadergenerator.cpp | 5 ++- generator/shellimplgenerator.cpp | 3 +- generator/typesystem_core.xml | 2 +- generator/typesystem_gui.xml | 2 +- generator/typesystem_multimedia.xml | 2 +- generator/typesystem_network.xml | 2 +- generator/typesystem_opengl.xml | 5 +-- generator/typesystem_qml.xml | 2 +- generator/typesystem_quick.xml | 2 +- generator/typesystem_sql.xml | 2 +- generator/typesystem_svg.xml | 2 +- generator/typesystem_uitools.xml | 2 +- generator/typesystem_webenginewidgets.xml | 2 +- generator/typesystem_webkit.xml | 2 +- generator/typesystem_xml.xml | 3 +- generator/typesystem_xmlpatterns.xml | 5 ++- 18 files changed, 36 insertions(+), 62 deletions(-) diff --git a/generator/setupgenerator.cpp b/generator/setupgenerator.cpp index f7eb31d0..40f175bf 100644 --- a/generator/setupgenerator.cpp +++ b/generator/setupgenerator.cpp @@ -52,10 +52,6 @@ void SetupGenerator::addClass(const QString& package, const AbstractMetaClass *c packHash[package].append(cls); } -void maybeDeclareMetaType(QTextStream &stream, const QString &typeName, - QSet ®isteredTypeNames); -bool hasDefaultConstructor(const AbstractMetaClass *meta_class); - static QStringList getOperatorCodes(const AbstractMetaClass* cls) { QSet operatorCodes; AbstractMetaFunctionList returned; @@ -247,34 +243,11 @@ void SetupGenerator::generate() continue; std::stable_sort(list.begin(), list.end(), AbstractMetaClass::less_than); - QString packKey = pack.key(); - QString packName = pack.key(); - QStringList components = packName.split("_"); - if ((components.size() > 2) && (components.at(0) == "com") - && (components.at(1) == "trolltech")) { - // kill com.trolltech in key - components.removeAt(0); - components.removeAt(0); - } - - QString shortPackName; - foreach (QString comp, components) { - comp[0] = comp[0].toUpper(); - shortPackName += comp; - } - // add missing camel case (workaround..) - if (shortPackName == "QtWebkit") { - shortPackName = "QtWebKit"; - } else if (shortPackName == "QtXmlpatterns") { - shortPackName = "QtXmlPatterns"; - } else if (shortPackName == "QtWebenginewidgets") { - shortPackName = "QtWebEngineWidgets"; - } else if (shortPackName == "QtOpengl") { - shortPackName = "QtOpenGL"; - } else if (shortPackName == "QtUitools") { - shortPackName = "QtUiTools"; - } - + QString packKey = ShellGenerator::toFileNameBase(pack.key()); + QString packName = packKey; + QString qtPackageName = "Qt" + pack.key().split('.').back().split('_').front(); + bool isBuiltin = packKey.endsWith("_builtin"); + QString initName = qtPackageName + (isBuiltin ? "Builtin" : ""); { QString fileName(packName + "/" + packKey + "_init.cpp"); @@ -291,7 +264,7 @@ void SetupGenerator::generate() s << endl; QStringList polymorphicHandlers; - if (!packName.endsWith("_builtin")) { + if (!isBuiltin) { polymorphicHandlers = writePolymorphicHandler(s, list.at(0)->package(), classes_with_polymorphic_id, list); s << endl; } @@ -328,11 +301,7 @@ void SetupGenerator::generate() s << endl; // declare individual class creation functions - s << "void PythonQt_init_" << shortPackName << "(PyObject* module) {" << endl; - - if (shortPackName.endsWith("Builtin")) { - shortPackName = shortPackName.mid(0, shortPackName.length()-strlen("builtin")); - } + s << "void PythonQt_init_" << initName << "(PyObject* module) {" << endl; foreach (const AbstractMetaClass *cls, list) { if (cls->qualifiedCppName().contains("Ssl")) { @@ -367,10 +336,10 @@ void SetupGenerator::generate() operatorCodes = "0"; } if (cls->isQObject()) { - s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; + s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << qtPackageName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; } else { QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():""; - s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; + s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << qtPackageName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; } for (AbstractMetaClass* interface : cls->interfaces()) { // the interface might be our own class... (e.g. QPaintDevice) diff --git a/generator/shellgenerator.h b/generator/shellgenerator.h index 1699b780..26b4c1ea 100644 --- a/generator/shellgenerator.h +++ b/generator/shellgenerator.h @@ -53,7 +53,7 @@ class ShellGenerator : public Generator public: virtual QString subDirectoryForClass(const AbstractMetaClass *cls) const { - return "generated_cpp/" + cls->package().replace(".", "_") + "/"; + return "generated_cpp/" + toFileNameBase(cls->package()) + "/"; } void writeTypeInfo(QTextStream &s, const AbstractMetaType *type, Option option = NoOption, TypeSystem::Ownership ownership = TypeSystem::InvalidOwnership); @@ -95,7 +95,9 @@ class ShellGenerator : public Generator static bool isBuiltIn(const QString& name); static bool isSpecialStreamingOperator(const AbstractMetaFunction *fun); - + + static QString toFileNameBase(QString packageName) { return packageName.replace('.', '_').toLower(); } + static void writeInclude(QTextStream &stream, const Include &inc); // this scope is used in writeFunctionArguments diff --git a/generator/shellheadergenerator.cpp b/generator/shellheadergenerator.cpp index b0a5c70a..e9d06e61 100644 --- a/generator/shellheadergenerator.cpp +++ b/generator/shellheadergenerator.cpp @@ -102,9 +102,10 @@ void ShellHeaderGenerator::write(QTextStream& s, const AbstractMetaClass* meta_c { setCurrentScope(meta_class); QString builtIn = ShellGenerator::isBuiltIn(meta_class->name()) ? "_builtin" : ""; - QString pro_file_name = meta_class->package().replace(".", "_") + builtIn + "/" + meta_class->package().replace(".", "_") + builtIn + ".pri"; + QString fileBaseName = toFileNameBase(meta_class->package() + builtIn); + QString pro_file_name = fileBaseName + "/" + fileBaseName + ".pri"; priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class)); - setupGenerator->addClass(meta_class->package().replace(".", "_") + builtIn, meta_class); + setupGenerator->addClass(meta_class->package() + builtIn, meta_class); QString include_block = "PYTHONQTWRAPPER_" + meta_class->name().toUpper() + "_H"; diff --git a/generator/shellimplgenerator.cpp b/generator/shellimplgenerator.cpp index b4ee83f3..2145af03 100644 --- a/generator/shellimplgenerator.cpp +++ b/generator/shellimplgenerator.cpp @@ -73,7 +73,8 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla setCurrentScope(meta_class); QString builtIn = ShellGenerator::isBuiltIn(meta_class->name())?"_builtin":""; - QString pro_file_name = meta_class->package().replace(".", "_") + builtIn + "/" + meta_class->package().replace(".", "_") + builtIn + ".pri"; + QString fileBaseName = toFileNameBase(meta_class->package() + builtIn); + QString pro_file_name = fileBaseName + "/" + fileBaseName + ".pri"; priGenerator->addSource(pro_file_name, fileNameForClass(meta_class)); s << "#include \"PythonQtWrapper_" << meta_class->name() << ".h\"" << endl << endl; diff --git a/generator/typesystem_core.xml b/generator/typesystem_core.xml index ef2c2c3c..6fe37a3d 100644 --- a/generator/typesystem_core.xml +++ b/generator/typesystem_core.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_gui.xml b/generator/typesystem_gui.xml index 6ab6fe10..dd772ca8 100644 --- a/generator/typesystem_gui.xml +++ b/generator/typesystem_gui.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_multimedia.xml b/generator/typesystem_multimedia.xml index 54c1b0d1..6c719988 100644 --- a/generator/typesystem_multimedia.xml +++ b/generator/typesystem_multimedia.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_network.xml b/generator/typesystem_network.xml index 77e998a8..239c574d 100644 --- a/generator/typesystem_network.xml +++ b/generator/typesystem_network.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_opengl.xml b/generator/typesystem_opengl.xml index c0c6d851..b8de602c 100644 --- a/generator/typesystem_opengl.xml +++ b/generator/typesystem_opengl.xml @@ -1,7 +1,6 @@ - - - + + diff --git a/generator/typesystem_qml.xml b/generator/typesystem_qml.xml index af5d0bdb..60db1e5e 100644 --- a/generator/typesystem_qml.xml +++ b/generator/typesystem_qml.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_quick.xml b/generator/typesystem_quick.xml index 9b8c7a52..ac889ecc 100644 --- a/generator/typesystem_quick.xml +++ b/generator/typesystem_quick.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_sql.xml b/generator/typesystem_sql.xml index f3377411..334860d8 100644 --- a/generator/typesystem_sql.xml +++ b/generator/typesystem_sql.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_svg.xml b/generator/typesystem_svg.xml index 06d9f565..c4e5a6a7 100644 --- a/generator/typesystem_svg.xml +++ b/generator/typesystem_svg.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_uitools.xml b/generator/typesystem_uitools.xml index 1b2c2edb..9b5b3b9d 100644 --- a/generator/typesystem_uitools.xml +++ b/generator/typesystem_uitools.xml @@ -1,4 +1,4 @@ - + diff --git a/generator/typesystem_webenginewidgets.xml b/generator/typesystem_webenginewidgets.xml index 0c376917..e89b61c9 100644 --- a/generator/typesystem_webenginewidgets.xml +++ b/generator/typesystem_webenginewidgets.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_webkit.xml b/generator/typesystem_webkit.xml index b1a4eb7f..84ba47e4 100644 --- a/generator/typesystem_webkit.xml +++ b/generator/typesystem_webkit.xml @@ -1,5 +1,5 @@ - + diff --git a/generator/typesystem_xml.xml b/generator/typesystem_xml.xml index ad07ddea..27d8f24f 100644 --- a/generator/typesystem_xml.xml +++ b/generator/typesystem_xml.xml @@ -1,5 +1,6 @@ - + + diff --git a/generator/typesystem_xmlpatterns.xml b/generator/typesystem_xmlpatterns.xml index 958ddfac..c61126d9 100644 --- a/generator/typesystem_xmlpatterns.xml +++ b/generator/typesystem_xmlpatterns.xml @@ -1,6 +1,5 @@ - - + @@ -112,6 +111,8 @@ + + From 331a50f1b8a23871847c1b3d86949c1502528dc1 Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Fri, 15 Dec 2023 17:00:02 +0100 Subject: [PATCH 18/26] [Backport] Create a global namespace wrapper for each package if required This currently just contains global enums. The content of these wrappers will be added to the current package, and to the "Qt" package. Also look in global namespace wrappers for scope-less enum types (cherry picked from commit MeVisLab/pythonqt@e9197ec0d73f481ef0e1d53e00a05132cb67f182) --- generator/abstractmetabuilder.cpp | 49 ++++++++++++---------- generator/abstractmetabuilder.h | 2 + generator/abstractmetalang.h | 7 +++- generator/setupgenerator.cpp | 2 + generator/shellgenerator.cpp | 2 - generator/shellheadergenerator.cpp | 3 +- generator/typesystem.cpp | 5 ++- src/PythonQt.cpp | 67 ++++++++++++++++++++++++++++++ src/PythonQt.h | 3 ++ src/PythonQtClassInfo.cpp | 23 ++++++++-- src/PythonQtClassInfo.h | 9 +++- 11 files changed, 140 insertions(+), 32 deletions(-) diff --git a/generator/abstractmetabuilder.cpp b/generator/abstractmetabuilder.cpp index ecdd6687..4a886c42 100644 --- a/generator/abstractmetabuilder.cpp +++ b/generator/abstractmetabuilder.cpp @@ -391,6 +391,28 @@ void AbstractMetaBuilder::sortLists() } } +AbstractMetaClass* AbstractMetaBuilder::getGlobalNamespace(const TypeEntry* typeEntry) +{ + QString package = typeEntry->javaPackage(); + QString globalName = TypeDatabase::globalNamespaceClassName(typeEntry); + + AbstractMetaClass* global = m_meta_classes.findClass(package + "." + globalName); + if (!global) { + ComplexTypeEntry* gte = new NamespaceTypeEntry(globalName); + gte->setTargetLangPackage(typeEntry->javaPackage()); + gte->setCodeGeneration(typeEntry->codeGeneration()); + global = createMetaClass(); + global->setIsGlobalNamespace(true); + global->setTypeEntry(gte); + *global += AbstractMetaAttributes::Final; + *global += AbstractMetaAttributes::Public; + *global += AbstractMetaAttributes::Fake; + + m_meta_classes << global; + } + return global; +} + bool AbstractMetaBuilder::build() { Q_ASSERT(!m_file_name.isEmpty()); @@ -460,36 +482,21 @@ bool AbstractMetaBuilder::build() AbstractMetaEnum *meta_enum = traverseEnum(item, 0, QSet()); if (meta_enum) { - QString package = meta_enum->typeEntry()->javaPackage(); - QString globalName = TypeDatabase::globalNamespaceClassName(meta_enum->typeEntry()); - - AbstractMetaClass *global = m_meta_classes.findClass(package + "." + globalName); - if (!global) { - ComplexTypeEntry *gte = new ObjectTypeEntry(globalName); - gte->setTargetLangPackage(meta_enum->typeEntry()->javaPackage()); - gte->setCodeGeneration(meta_enum->typeEntry()->codeGeneration()); - global = createMetaClass(); - global->setTypeEntry(gte); - *global += AbstractMetaAttributes::Final; - *global += AbstractMetaAttributes::Public; - *global += AbstractMetaAttributes::Fake; - - m_meta_classes << global; - } + AbstractMetaClass* global = getGlobalNamespace(meta_enum->typeEntry()); global->addEnum(meta_enum); - meta_enum->setEnclosingClass(global); - meta_enum->typeEntry()->setQualifier(globalName); // Global enums should be public despite not having public // identifiers so we'll fix the original attributes here. meta_enum->setOriginalAttributes(meta_enum->attributes()); - } - + // global enums have their own include + if (meta_enum->typeEntry()->include().isValid()) { + global->typeEntry()->addExtraInclude(meta_enum->typeEntry()->include()); + } + } } - // Go through all typedefs to see if we have defined any // specific typedefs to be used as classes. TypeAliasList typeAliases = m_dom->typeAliases(); diff --git a/generator/abstractmetabuilder.h b/generator/abstractmetabuilder.h index 5d0ed34d..abaf900c 100644 --- a/generator/abstractmetabuilder.h +++ b/generator/abstractmetabuilder.h @@ -149,6 +149,8 @@ class AbstractMetaBuilder private: void sortLists(); + AbstractMetaClass* getGlobalNamespace(const TypeEntry* typeEntry); + QString m_file_name; AbstractMetaClassList m_meta_classes; diff --git a/generator/abstractmetalang.h b/generator/abstractmetalang.h index 6bbdbe7b..560b8169 100644 --- a/generator/abstractmetalang.h +++ b/generator/abstractmetalang.h @@ -676,6 +676,7 @@ class AbstractMetaClass : public AbstractMetaAttributes m_has_clone_operator(false), m_is_type_alias(false), m_has_actual_declaration(false), + m_is_global_namespace(false), m_qDebug_stream_function(0) { } @@ -801,6 +802,9 @@ class AbstractMetaClass : public AbstractMetaAttributes void setHasActualDeclaration(bool on) { m_has_actual_declaration = on; } bool hasActualDeclaration() const { return m_has_actual_declaration; } + void setIsGlobalNamespace(bool on) { m_is_global_namespace = on; } + bool isGlobalNamespace() const { return m_is_global_namespace; } + QString getDefaultNonZeroFunction() const; void addPropertySpec(QPropertySpec *spec) { m_property_specs << spec; } @@ -862,7 +866,8 @@ class AbstractMetaClass : public AbstractMetaAttributes uint m_has_clone_operator :1; uint m_is_type_alias : 1; uint m_has_actual_declaration : 1; - uint m_reserved : 17; + uint m_is_global_namespace : 1; + uint m_reserved : 16; QString m_destructor_exception; const AbstractMetaClass *m_enclosing_class{}; diff --git a/generator/setupgenerator.cpp b/generator/setupgenerator.cpp index 40f175bf..e22c6325 100644 --- a/generator/setupgenerator.cpp +++ b/generator/setupgenerator.cpp @@ -337,6 +337,8 @@ void SetupGenerator::generate() } if (cls->isQObject()) { s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << qtPackageName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; + } else if (cls->isGlobalNamespace()) { + s << "PythonQt::priv()->registerGlobalNamespace(\"" << cls->qualifiedCppName() << "\", \"" << qtPackageName << "\", PythonQtCreateObjectname() << ">, PythonQtWrapper_" << cls->name() << "::staticMetaObject, module); " << endl; } else { QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():""; s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << qtPackageName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; diff --git a/generator/shellgenerator.cpp b/generator/shellgenerator.cpp index fa7a0672..0b4fa0c4 100644 --- a/generator/shellgenerator.cpp +++ b/generator/shellgenerator.cpp @@ -50,8 +50,6 @@ bool ShellGenerator::shouldGenerate(const AbstractMetaClass *meta_class) const { uint cg = meta_class->typeEntry()->codeGeneration(); - // ignore the "Global" namespace, which contains the QtMsgType enum - if (meta_class->name().startsWith("Global")) return false; return ((cg & TypeEntry::GenerateCode) != 0); } diff --git a/generator/shellheadergenerator.cpp b/generator/shellheadergenerator.cpp index e9d06e61..20431a83 100644 --- a/generator/shellheadergenerator.cpp +++ b/generator/shellheadergenerator.cpp @@ -312,7 +312,8 @@ void ShellHeaderGenerator::write(QTextStream& s, const AbstractMetaClass* meta_c bool isEnumClass = enum1->typeEntry()->isEnumClass(); s << "enum " << (isEnumClass ? "class " : "") << enum1->name() << "{" << endl; bool first = true; - QString scope = enum1->wasProtected() ? promoterClassName(meta_class) : meta_class->qualifiedCppName(); + QString scope = meta_class->isGlobalNamespace() ? QString() : + (enum1->wasProtected() ? promoterClassName(meta_class) : meta_class->qualifiedCppName()); if (isEnumClass) { scope += "::" + enum1->name(); } diff --git a/generator/typesystem.cpp b/generator/typesystem.cpp index b98cf04d..c9a2607f 100644 --- a/generator/typesystem.cpp +++ b/generator/typesystem.cpp @@ -1835,8 +1835,9 @@ FlagsTypeEntry *TypeDatabase::findFlagsType(const QString &name) const return fte ? fte : (FlagsTypeEntry *) m_flags_entries.value(name); } -QString TypeDatabase::globalNamespaceClassName(const TypeEntry * /*entry*/) { - return QLatin1String("Global"); +QString TypeDatabase::globalNamespaceClassName(const TypeEntry * entry) +{ + return "Qt" + entry->javaPackage().split('.').back(); } diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index a3f8cc5a..71eb42f2 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -2110,6 +2110,73 @@ void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentT } } +namespace { + + void addObjectToPackage(PyObject* obj, const char* name, const char* packageName, PyObject* package) + { + if (PyModule_AddObject(package, name, obj) < 0) { + Py_DECREF(obj); + std::cerr << "failed to add " << name << " to " << packageName << "\n"; + } + } + +}; + +void PythonQtPrivate::registerGlobalNamespace(const char* typeName, const char* packageName, PythonQtQObjectCreatorFunctionCB* wrapperCreator, const QMetaObject& metaObject, PyObject* module) +{ + registerCPPClass(typeName, "", packageName, wrapperCreator, nullptr, module, 0); + + PyObject* package = module ? module : PythonQt::priv()->packageByName(packageName); + PythonQtClassInfo* classInfo = PythonQt::priv()->getClassInfo(typeName); + PyObject* globalNamespace = classInfo->pythonQtClassWrapper(); + + // Collect the names of global methods + QSet methodNames; + for (int i = metaObject.methodOffset(); i < metaObject.methodCount(); i++) { + methodNames.insert(metaObject.method(i).name()); + } + QByteArray staticPrefix = "static_" + QByteArray(typeName) + "_"; // every static method starts with this string + for (auto name: methodNames) { + if (name.startsWith(staticPrefix)) { // non-static methods wouldn't work (and should not exists) + name = name.mid(staticPrefix.length()); + PyObject* obj = PyObject_GetAttrString(globalNamespace, name.constData()); + if (obj) { + addObjectToPackage(obj, name, packageName, package); + } + else { + std::cerr << "method not found " << name.constData() << " in " << typeName << std::endl; + } + } + } + + // Global enums + for (int i = metaObject.enumeratorOffset(); i < metaObject.enumeratorCount(); i++) { + QMetaEnum metaEnum = metaObject.enumerator(i); + PyObject* obj = PyObject_GetAttrString(globalNamespace, metaEnum.name()); + if (obj) { + addObjectToPackage(obj, metaEnum.name(), packageName, package); + } + else { + std::cerr << "enum type not found " << metaEnum.name() << " in " << typeName << std::endl; + } +#if QT_VERSION > 0x050800 + bool isScoped = metaEnum.isScoped(); +#else + bool isScoped = false; +#endif + if (!isScoped) { + for (int j = 0; j < metaEnum.keyCount(); j++) { + QByteArray key = PythonQtClassInfo::escapeReservedNames(metaEnum.key(j)); + int value = metaEnum.value(j); + PyObject* obj = PyInt_FromLong(value); + addObjectToPackage(obj, key, packageName, package); + } + } + } + + PythonQtClassInfo::addGlobalNamespaceWrapper(classInfo); +} + PyObject* PythonQtPrivate::packageByName(const char* name) { if (name==nullptr || name[0]==0) { diff --git a/src/PythonQt.h b/src/PythonQt.h index 767f9928..d7de9233 100644 --- a/src/PythonQt.h +++ b/src/PythonQt.h @@ -754,6 +754,9 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject { */ void registerCPPClass(const char* typeName, const char* parentTypeName = nullptr, const char* package = nullptr, PythonQtQObjectCreatorFunctionCB* wrapperCreator = nullptr, PythonQtShellSetInstanceWrapperCB* shell = nullptr, PyObject* module = nullptr, int typeSlots = 0); + //! Same as above, but all enums of the created wrapper will also be added to the given package and to the "Qt" package + void registerGlobalNamespace(const char* typeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, const QMetaObject& metaObject, PyObject* module = nullptr); + //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes //! and it will register the classes when it first sees a pointer to such a derived class void registerQObjectClassNames(const QStringList& names); diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index c8be0a15..cbcdc525 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -49,6 +49,9 @@ QHash PythonQtMethodInfo::_parameterTypeDict; +// List of registered global namespace wrappers that might contain a top-level enum definition +QList PythonQtClassInfo::_globalNamespaceWrappers; + // List of words that are reserved in Python, but not in C++, so they need escaping QSet PythonQtClassInfo::_reservedNames{ "None", "True", "False" @@ -851,11 +854,20 @@ PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtCla return nullptr; } } + PyObject* enumWrapper = nullptr; if (localScope) { - return localScope->findEnumWrapper(name); - } else { - return nullptr; + enumWrapper = localScope->findEnumWrapper(name); + } + if (!enumWrapper) { + // it might be a top-level enum - search in all currently registered global namespace wrappers + for (PythonQtClassInfo* globalWrapper : _globalNamespaceWrappers) { + enumWrapper = globalWrapper->findEnumWrapper(name); + if (enumWrapper) { + break; + } + } } + return enumWrapper; } // required for the code below (for versions before Qt 6) @@ -1033,6 +1045,11 @@ QByteArray PythonQtClassInfo::escapeReservedNames(const QByteArray& name) } } +void PythonQtClassInfo::addGlobalNamespaceWrapper(PythonQtClassInfo* namespaceWrapper) +{ + _globalNamespaceWrappers.insert(0, namespaceWrapper); +} + void PythonQtClassInfo::updateRefCountingCBs() { if (!_refCallback) { diff --git a/src/PythonQtClassInfo.h b/src/PythonQtClassInfo.h index 48f7364d..fa439f5d 100644 --- a/src/PythonQtClassInfo.h +++ b/src/PythonQtClassInfo.h @@ -239,7 +239,10 @@ class PYTHONQT_EXPORT PythonQtClassInfo { //! Sometimes enum values use a reserved name in Python. In this case //! replace it with something that is not reserved - QByteArray escapeReservedNames(const QByteArray& name); + static QByteArray escapeReservedNames(const QByteArray& name); + + //! Add a wrapper that contains global enums + static void addGlobalNamespaceWrapper(PythonQtClassInfo* namespaceWrapper); private: void updateRefCountingCBs(); @@ -304,7 +307,9 @@ class PYTHONQT_EXPORT PythonQtClassInfo { bool _searchPolymorphicHandlerOnParent; bool _searchRefCountCB; - static QSet _reservedNames; + static QList _globalNamespaceWrappers; + + static QSet _reservedNames; }; //--------------------------------------------------------------- From ce11938bb65395c4ecea75e0e78a1bc4c8f3a9ca Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Wed, 20 Dec 2023 14:42:49 +0100 Subject: [PATCH 19/26] [Backport] Add enum values to the enum type object itself in any case... ...not just when it is a enum class in C++. It seems PySide does this too. (cherry picked from commit MeVisLab/pythonqt@d059d7206160f3531d7c8ece0b29cabe54b5a1e4) --- src/PythonQtClassInfo.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index cbcdc525..e1247df6 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -870,26 +870,19 @@ PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtCla return enumWrapper; } -// required for the code below (for versions before Qt 6) -Q_DECLARE_METATYPE(PythonQtObjectPtr) - void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta) { for (int i = meta->enumeratorOffset();ienumeratorCount();i++) { QMetaEnum e = meta->enumerator(i); PythonQtObjectPtr p; p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper)); -#if QT_VERSION > 0x050800 - if (e.isScoped()) { - // add enum values to the enum type itself, in case enum value names are so generic - // that they are not unique - for (int j = 0; j < e.keyCount(); j++) { - PythonQtObjectPtr enumValuePtr; - enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(p.object(), e.value(j))); - p.addVariable(escapeReservedNames(e.key(j)), QVariant::fromValue(enumValuePtr)); - } + // add enum values to the enum type itself, in case enum value names are so generic + // that they are not unique + for (int j = 0; j < e.keyCount(); j++) { + PythonQtObjectPtr enumValuePtr; + enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(p.object(), e.value(j))); + p.addVariable(escapeReservedNames(e.key(j)), enumValuePtr.toLocalVariant()); } -#endif _enumWrappers.append(p); } } From ee7e54112e13e473c48942a0b8da42df87370e4c Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 17 Sep 2020 22:31:12 +0200 Subject: [PATCH 20/26] [Backport] Added MinGW build documentation for MinGW (cherry picked from commit MeVisLab/pythonqt@bc2b94511673b265e692823e67bbafcc9ac785f5) --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index d91cc315..6a656f6f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # PythonQt + [![License](https://img.shields.io/github/license/mevislab/pythonqt.svg?color=blue)](LICENSE) PythonQt is a dynamic [Python](https://www.python.org) binding for [Qt](https://www.qt.io). @@ -6,12 +7,15 @@ It offers an easy way to embed the Python scripting language into your Qt applications. # Documentation + API documentation is available at: https://mevislab.github.io/pythonqt # Licensing + PythonQt is distributed under the `LGPL 2.1` license. ## Licensing of Generator + The build system of PythonQt makes use of a patched version of the LGPL'ed QtScript generator, located in the `generator` directory. @@ -26,3 +30,20 @@ The generated wrappers are pre-generated and checked-in, so you only need to build and run the generator when you want to build additional wrappers or you want to upgrade/downgrade to another Qt version, but this requires updating the typesystems as well. + +# Building + +## Building on Windows with MinGW + +To build PythonQt, you need to set the environment variable `PYTHON_PATH` to +point to the root dir of the python installation and `PYTHON_LIB` to point to +the directory where the python lib file is located. Then you should set the +`PYTHON_VERSION` variable to the Python version number. + +When using the prebuild Python installer, this will be: + +```cmd +set PYTHON_PATH = c:\Python38 +set PYTHON_LIB = c:\Python38\libs +set PYTHON_VERSION = 38 +``` \ No newline at end of file From 587dc2ee8e6d1fb8aaa968dcecb0e69f57516a35 Mon Sep 17 00:00:00 2001 From: githubuser0xFFFF Date: Fri, 30 Dec 2022 08:43:17 +0100 Subject: [PATCH 21/26] [Backport] Fix setting environment vars in readme (#63) * Remove spaces from environment variable setting because it only works without spaces (cherry picked from commit MeVisLab/pythonqt@aa132d23351506df7d8029f09c5ec92e78e54d7d) --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6a656f6f..eaec7848 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ the directory where the python lib file is located. Then you should set the When using the prebuild Python installer, this will be: ```cmd -set PYTHON_PATH = c:\Python38 -set PYTHON_LIB = c:\Python38\libs -set PYTHON_VERSION = 38 -``` \ No newline at end of file +set PYTHON_PATH=c:\Python38 +set PYTHON_LIB=c:\Python38\libs +set PYTHON_VERSION=38 +``` From 7379b9c50a12799c97cada7375bbcbd2dd79dfb9 Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Fri, 3 Nov 2023 09:00:50 +0100 Subject: [PATCH 22/26] [Backport] Make sure the ubuntu artifacts do not overwrite each other - also fix minor readme error (cherry picked from commit MeVisLab/pythonqt@97038fdd1bfb618e8069bd3f77fa02216cdbb898) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eaec7848..c9d52a99 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ the directory where the python lib file is located. Then you should set the When using the prebuild Python installer, this will be: ```cmd -set PYTHON_PATH=c:\Python38 -set PYTHON_LIB=c:\Python38\libs -set PYTHON_VERSION=38 +set PYTHON_PATH=c:\Python311 +set PYTHON_LIB=c:\Python311\libs +set PYTHON_VERSION=3.11 ``` From 76d7da608847560cf007a51a41cc421d93a97f56 Mon Sep 17 00:00:00 2001 From: Uwe Siems Date: Wed, 20 Dec 2023 16:21:58 +0100 Subject: [PATCH 23/26] [Backport] Small documentation updates - changed default Python version from 2.6 to 3.10 (cherry picked from commit MeVisLab/pythonqt@bf9432e09bc805182a25b3d4102e533ae1cb04da) --- README.md | 8 +++----- build/python.prf | 14 +++++--------- src/PythonQtDoc.h | 47 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index c9d52a99..1d058e36 100644 --- a/README.md +++ b/README.md @@ -36,14 +36,12 @@ updating the typesystems as well. ## Building on Windows with MinGW To build PythonQt, you need to set the environment variable `PYTHON_PATH` to -point to the root dir of the python installation and `PYTHON_LIB` to point to -the directory where the python lib file is located. Then you should set the +point to the root dir of the python installation. Then you should set the `PYTHON_VERSION` variable to the Python version number. When using the prebuild Python installer, this will be: ```cmd -set PYTHON_PATH=c:\Python311 -set PYTHON_LIB=c:\Python311\libs -set PYTHON_VERSION=3.11 +set PYTHON_PATH=c:\Python310 +set PYTHON_VERSION=3.10 ``` diff --git a/build/python.prf b/build/python.prf index aae26277..87443b9a 100644 --- a/build/python.prf +++ b/build/python.prf @@ -1,12 +1,12 @@ # profile to include and link Python -# Change this variable to your python version (2.6, 2.7, 3.3, ...) +# Change this variable to your python version (3.7, 3.8, ...) isEmpty( PYTHON_VERSION ) { PYTHON_VERSION=$$(PYTHON_VERSION) } isEmpty( PYTHON_VERSION ) { - PYTHON_VERSION=2.7 + PYTHON_VERSION=3.10 } isEmpty( PYTHON_DIR ) { @@ -36,7 +36,7 @@ equals(PYTHON_VERSION_MAJOR, 2) { } contains(PKGCONFIG, "python.*"){ -# If `pkg-config` is configured, use `qmake PKGCONFIG+=python3.8-embed CONFIG+=...` +# If `pkg-config` is configured, use `qmake PKGCONFIG+=python3.10-embed CONFIG+=...` # or `PKGCONFIG+=python2.7m`-like form for older versions, # see `pkg-config --list-all | grep python` for details. # This can help with GNU/Linux (including macOS with Homebrew), MSYS2/MinGW environment, @@ -54,16 +54,12 @@ contains(PKGCONFIG, "python.*"){ # for windows install a Python development kit or build Python yourself from the sources # Make sure that you set the environment variable PYTHON_PATH to point to your # python installation (or the python sources/header files when building from source). - # Make sure that you set the environment variable PYTHON_LIB to point to - # the directory where the python libs are located. # # When using the prebuild Python installer, this will be: - # set PYTHON_PATH = c:\Python26 - # set PYTHON_LIB = c:\Python26\libs + # set PYTHON_PATH = c:\Python310 # # When using the python sources, this will be something like: - # set PYTHON_PATH = c:\yourDir\Python-2.6.1\ - # set PYTHON_LIB = c:\yourDir\Python-2.6.1\PCbuild8\Win32 + # set PYTHON_PATH = c:\yourDir\Python-3.10.12\ # check if debug or release CONFIG(debug, debug|release) { diff --git a/src/PythonQtDoc.h b/src/PythonQtDoc.h index 84bbf9a6..7adfe8d4 100644 --- a/src/PythonQtDoc.h +++ b/src/PythonQtDoc.h @@ -112,12 +112,13 @@ Qt framework. - QtCore - QtGui - QtNetwork - - QtOpenGL + - QtOpenGL (before Qt6) - QtSql - QtSvg - - QtWebKit + - QtWebEngineWidgets + - QtWebKit (when available) - QtXml - - QtXmlPatterns + - QtXmlPatterns (before Qt6) - QtMultimedia - QtQml - QtQuick @@ -268,6 +269,27 @@ Qt framework. \endcode + And this example shows how you can define your own signals and slots: + + \code + class MySender(QtCore.QObject): + + emitProgress = QtCore.Signal(float) # this is actually a double argument in C++ + + class MyReceiver(QtCore.QObject): + + @QtCore.Slot(float) + def progress(self, value): + print(f"progress: {value}") + + sender = MySender() + receiver = MyReceiver() + # connecting with the effective signature: + sender.connect("emitProgress(double)", receiver, "progress(double)") + sender.emitProgress(2.0) + + \endcode + \section CPP CPP Wrapping You can create dedicated wrapper QObjects for any C++ class. This is done by deriving from PythonQtCppWrapperFactory @@ -307,6 +329,8 @@ QtCore.QDate.currentDate() # enum value QtCore.QFont.UltraCondensed +# or, alternatively +QtCore.QFont.Stretch.UltraCondensed \endcode @@ -453,11 +477,11 @@ yourCpp = None \page Building Building - PythonQt requires at least Qt 4.6.1 (for earlier Qt versions, you will need to run the pythonqt_generator, Qt 4.3 is the absolute minimum) and Python 2.6.x/2.7.x or Python 3.3 (or higher). + PythonQt requires at least Qt 5.0 and Python 2.7.x or Python 3.6 (or higher). To compile PythonQt, you will need a python developer installation which includes Python's header files and the python2x.[lib | dll | so | dynlib]. The recommended way to build PythonQt is to use the QMake-based *.pro file. - The build scripts a currently set to use Python 2.6. + The build scripts are currently set to use Python 3.10 by default. You may need to tweak the \b build/python.prf file to set the correct Python includes and libs on your system. \subsection Windows @@ -468,21 +492,20 @@ the python2x.[lib | dll | so | dynlib]. Python yourself, using your compiler. To build PythonQt, you need to set the environment variable \b PYTHON_PATH to point to the root - dir of the python installation and \b PYTHON_LIB to point to - the directory where the python lib file is located. + dir of the python installation and \b PYTHON_VERSION should state the used Python version. When using the prebuild Python installer, this will be: \code - > set PYTHON_PATH = c:\Python26 - > set PYTHON_LIB = c:\Python26\libs + > set PYTHON_PATH = c:\Python310 + > set PYTHON_VERSION = 3.10 \endcode When using the python sources, this will be something like: \code - > set PYTHON_PATH = c:\yourDir\Python-2.6.1\ - > set PYTHON_LIB = c:\yourDir\Python-2.6.1\PCbuild8\Win32 + > set PYTHON_PATH = c:\yourDir\Python-3.10.12\ + > set PYTHON_VERSION = 3.10 \endcode To build all, do the following (after setting the above variables): @@ -522,7 +545,7 @@ the python2x.[lib | dll | so | dynlib]. You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime linker can find the *.so files. - \subsection MacOsX + \subsection MacOS On Mac, Python is installed as a Framework, so you should not need to install it. To build PythonQt, just do a: From 5cf6c9482684cfb9be5d392974a65d31355126f2 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Tue, 30 Jan 2024 20:10:23 -0500 Subject: [PATCH 24/26] Fix warning related to QSet::unite when building against Qt 5.15 --- src/PythonQtClassInfo.cpp | 2 +- src/PythonQtClassWrapper.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index e1247df6..c132b211 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -562,7 +562,7 @@ QStringList PythonQtClassInfo::memberList() } } -#if QT_VERSION >= 0x060000 +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) QSet set(l.begin(), l.end()); return set.values(); #else diff --git a/src/PythonQtClassWrapper.cpp b/src/PythonQtClassWrapper.cpp index ad8f5064..d4ab7d4c 100644 --- a/src/PythonQtClassWrapper.cpp +++ b/src/PythonQtClassWrapper.cpp @@ -465,7 +465,7 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) auto members = wrapper->classInfo()->memberList(); auto properties = wrapper->classInfo()->propertyList(); -#if QT_VERSION >= 0x060000 +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) QSet completeSet(members.begin(), members.end()); completeSet.unite(QSet(properties.begin(), properties.end())); #else From 162790a02832662f80c7a288277bd5839fe605c1 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Tue, 30 Jan 2024 20:11:17 -0500 Subject: [PATCH 25/26] Fix warning related to use of qrand() when building against Qt 5.15 --- src/PythonQtStdDecorators.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PythonQtStdDecorators.h b/src/PythonQtStdDecorators.h index f3f6948b..3b1179d1 100644 --- a/src/PythonQtStdDecorators.h +++ b/src/PythonQtStdDecorators.h @@ -58,7 +58,7 @@ #include #include #include -#if QT_VERSION >= 0x060000 +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) #include #endif @@ -109,7 +109,7 @@ public Q_SLOTS: int static_Qt_qrand() { -#if QT_VERSION < 0x060000 +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) return qrand(); #else return QRandomGenerator::global()->generate(); @@ -118,7 +118,7 @@ public Q_SLOTS: void static_Qt_qsrand(uint a) { -#if QT_VERSION < 0x060000 +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) qsrand(a); #else QRandomGenerator::global()->seed(a); From e88a1901084a6234f719d0ce78641b5062038023 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Tue, 30 Jan 2024 20:13:41 -0500 Subject: [PATCH 26/26] Re-introduce support for QMatrix when building against Qt < 6.0 This partially reverts 10a3e499 ("Qt6 compatibility fixes for core PythonQt library", 2023-08-21) --- src/PythonQt.cpp | 3 +++ src/PythonQtVariants.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 71eb42f2..3302854b 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -260,6 +260,9 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) PythonQtRegisterToolClassesTemplateConverterForKnownClass(QPen); PythonQtRegisterToolClassesTemplateConverterForKnownClass(QTextLength); PythonQtRegisterToolClassesTemplateConverterForKnownClass(QTextFormat); +#if QT_VERSION < 0x060000 + PythonQtRegisterToolClassesTemplateConverterForKnownClass(QMatrix); +#endif PyObject* pack = PythonQt::priv()->packageByName("QtCore"); PyObject* pack2 = PythonQt::priv()->packageByName("Qt"); diff --git a/src/PythonQtVariants.h b/src/PythonQtVariants.h index 833f35c8..d2ba9eff 100644 --- a/src/PythonQtVariants.h +++ b/src/PythonQtVariants.h @@ -72,6 +72,9 @@ #include #include #include +#if QT_VERSION < 0x060000 +#include +#endif #endif