diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2021-11-23 19:08:06 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2021-11-24 10:54:20 +0100 |
commit | 3636b306dc0638470473f37a1bb6291f6db7bf2d (patch) | |
tree | 1f3ac2107c224bff4c2d1e324f5f8b6d24110f57 | |
parent | 42ca2d6052624445559ae44fa3f5d57ca591fb52 (diff) |
PySide6: Move some code from the core snippets into a static source file
Split out code which does not use any code snippet placeholders into
a separate source file for better maintainability.
Change-Id: Id8d923b8faf58783f28e56b4bf4397117c39c51b
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Christian Tismer <tismer@stackless.com>
-rw-r--r-- | sources/pyside6/PySide6/QtCore/CMakeLists.txt | 7 | ||||
-rw-r--r-- | sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp | 275 | ||||
-rw-r--r-- | sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h | 87 | ||||
-rw-r--r-- | sources/pyside6/PySide6/QtCore/typesystem_core_common.xml | 3 | ||||
-rw-r--r-- | sources/pyside6/PySide6/glue/qtcore.cpp | 210 |
5 files changed, 376 insertions, 206 deletions
diff --git a/sources/pyside6/PySide6/QtCore/CMakeLists.txt b/sources/pyside6/PySide6/QtCore/CMakeLists.txt index 00ed9a62c..dba4261f1 100644 --- a/sources/pyside6/PySide6/QtCore/CMakeLists.txt +++ b/sources/pyside6/PySide6/QtCore/CMakeLists.txt @@ -1,6 +1,9 @@ project(QtCore) -set(QtCore_gluecode "${QtCore_SOURCE_DIR}/glue/qeasingcurve_glue.cpp") +set(QtCore_static_sources + "${QtCore_SOURCE_DIR}/glue/qeasingcurve_glue.cpp" + "${QtCore_SOURCE_DIR}/glue/core_snippets.cpp" +) if(ENABLE_WIN) set(SPECIFIC_OS_FILES @@ -208,7 +211,7 @@ create_pyside_module(NAME QtCore LIBRARIES QtCore_libraries TYPESYSTEM_PATH QtCore_SOURCE_DIR SOURCES QtCore_SRC - STATIC_SOURCES QtCore_gluecode + STATIC_SOURCES QtCore_static_sources TYPESYSTEM_NAME ${QtCore_BINARY_DIR}/typesystem_core.xml GLUE_SOURCES QtCore_glue_sources ) diff --git a/sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp b/sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp new file mode 100644 index 000000000..86cfec1f8 --- /dev/null +++ b/sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp @@ -0,0 +1,275 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "core_snippets_p.h" +#include "pyside.h" + +#include "shiboken.h" +#include "basewrapper.h" +#include "autodecref.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QDebug> +#include <QtCore/QMetaType> +#include <QtCore/QObject> +#include <QtCore/QRegularExpression> +#include <QtCore/QStack> +#include <QtCore/QVariant> + +// Helpers for QVariant conversion + +QMetaType QVariant_resolveMetaType(PyTypeObject *type) +{ + if (!PyObject_TypeCheck(type, SbkObjectType_TypeF())) + return {}; + const char *typeName = Shiboken::ObjectType::getOriginalName(type); + if (!typeName) + return {}; + const bool valueType = '*' != typeName[qstrlen(typeName) - 1]; + // Do not convert user type of value + if (valueType && Shiboken::ObjectType::isUserType(type)) + return {}; + QMetaType metaType = QMetaType::fromName(typeName); + if (metaType.isValid()) + return metaType; + // Do not resolve types to value type + if (valueType) + return {}; + // Find in base types. First check tp_bases, and only after check tp_base, because + // tp_base does not always point to the first base class, but rather to the first + // that has added any python fields or slots to its object layout. + // See https://mail.python.org/pipermail/python-list/2009-January/520733.html + if (type->tp_bases) { + for (Py_ssize_t i = 0, size = PyTuple_GET_SIZE(type->tp_bases); i < size; ++i) { + auto baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(type->tp_bases, i)); + const QMetaType derived = QVariant_resolveMetaType(baseType); + if (derived.isValid()) + return derived; + } + } else if (type->tp_base) { + return QVariant_resolveMetaType(type->tp_base); + } + return {}; +} + +QVariant QVariant_convertToValueList(PyObject *list) +{ + if (PySequence_Size(list) < 0) { + // clear the error if < 0 which means no length at all + PyErr_Clear(); + return {}; + } + + Shiboken::AutoDecRef element(PySequence_GetItem(list, 0)); + + QMetaType metaType = QVariant_resolveMetaType(element.cast<PyTypeObject *>()); + if (!metaType.isValid()) + return {}; + + const QByteArray listTypeName = QByteArrayLiteral("QList<") + metaType.name() + '>'; + metaType = QMetaType::fromName(listTypeName); + if (!metaType.isValid()) + return {}; + + Shiboken::Conversions::SpecificConverter converter(listTypeName); + if (!converter) { + qWarning("Type converter for: %s not registered.", listTypeName.constData()); + return {}; + } + + QVariant var(metaType); + converter.toCpp(list, &var); + return var; +} + +bool QVariant_isStringList(PyObject *list) +{ + if (!PySequence_Check(list)) { + // If it is not a list or a derived list class + // we assume that will not be a String list neither. + return false; + } + + if (PySequence_Size(list) < 0) { + // clear the error if < 0 which means no length at all + PyErr_Clear(); + return false; + } + + Shiboken::AutoDecRef fast(PySequence_Fast(list, "Failed to convert QVariantList")); + const Py_ssize_t size = PySequence_Fast_GET_SIZE(fast.object()); + for (Py_ssize_t i = 0; i < size; ++i) { + PyObject *item = PySequence_Fast_GET_ITEM(fast.object(), i); + if (PyUnicode_Check(item) == 0) + return false; + } + return true; +} + +// Helpers for qAddPostRoutine + +namespace PySide { + +static QStack<PyObject *> globalPostRoutineFunctions; + +void globalPostRoutineCallback() +{ + Shiboken::GilState state; + for (auto *callback : globalPostRoutineFunctions) { + Shiboken::AutoDecRef result(PyObject_CallObject(callback, nullptr)); + Py_DECREF(callback); + } + globalPostRoutineFunctions.clear(); +} + +void addPostRoutine(PyObject *callback) +{ + if (PyCallable_Check(callback)) { + globalPostRoutineFunctions << callback; + Py_INCREF(callback); + } else { + PyErr_SetString(PyExc_TypeError, "qAddPostRoutine: The argument must be a callable object."); + } +} +} // namespace PySide + +// Helpers for QObject::findChild(ren)() + +static bool _findChildTypeMatch(const QObject *child, PyTypeObject *desiredType) +{ + auto *pyChildType = PySide::getTypeForQObject(child); + return pyChildType != nullptr && PyType_IsSubtype(pyChildType, desiredType); +} + +static inline bool _findChildrenComparator(const QObject *child, + const QRegularExpression &name) +{ + return name.match(child->objectName()).hasMatch(); +} + +static inline bool _findChildrenComparator(const QObject *child, + const QString &name) +{ + return name.isNull() || name == child->objectName(); +} + +QObject *qObjectFindChild(const QObject *parent, const QString &name, + PyTypeObject *desiredType, Qt::FindChildOptions options) +{ + for (auto *child : parent->children()) { + if (_findChildrenComparator(child, name) + && _findChildTypeMatch(child, desiredType)) { + return child; + } + } + + if (options.testFlag(Qt::FindChildrenRecursively)) { + for (auto *child : parent->children()) { + if (auto *obj = qObjectFindChild(child, name, desiredType, options)) + return obj; + } + } + return nullptr; +} + +template<typename T> // QString/QRegularExpression +static void _findChildrenHelper(const QObject *parent, const T& name, PyTypeObject *desiredType, + Qt::FindChildOptions options, FindChildHandler handler) +{ + for (auto *child : parent->children()) { + if (_findChildrenComparator(child, name) && _findChildTypeMatch(child, desiredType)) + handler(child); + if (options.testFlag(Qt::FindChildrenRecursively)) + _findChildrenHelper(child, name, desiredType, options, handler); + } +} + +void qObjectFindChildren(const QObject *parent, const QString &name, + PyTypeObject *desiredType, Qt::FindChildOptions options, + FindChildHandler handler) +{ + _findChildrenHelper(parent, name, desiredType, options, handler); +} + +void qObjectFindChildren(const QObject *parent, const QRegularExpression &pattern, + PyTypeObject *desiredType, Qt::FindChildOptions options, + FindChildHandler handler) +{ + _findChildrenHelper(parent, pattern, desiredType, options, handler); +} + +////////////////////////////////////////////////////////////////////////////// +// Helpers for translation: +// PYSIDE-131: Use the class name as context where the calling function is +// living. Derived Python classes have the wrong context. +// +// The original patch uses Python introspection to look up the current +// function (from the frame stack) in the class __dict__ along the mro. +// +// The problem is that looking into the frame stack works for Python +// functions, only. For including builtin function callers, the following +// approach turned out to be much simpler: +// +// Walk the __mro__ +// - translate the string +// - if the translated string is changed: +// - return the translation. + +QString qObjectTr(PyTypeObject *type, const char *sourceText, const char *disambiguation, int n) +{ + PyObject *mro = type->tp_mro; + auto len = PyTuple_GET_SIZE(mro); + QString result = QString::fromUtf8(sourceText); + QString oldResult = result; + static auto *sbkObjectType = reinterpret_cast<PyTypeObject *>(SbkObject_TypeF()); + for (Py_ssize_t idx = 0; idx < len - 1; ++idx) { + // Skip the last class which is `object`. + auto *type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx)); + if (type == sbkObjectType) + continue; + const char *context = type->tp_name; + const char *dotpos = strrchr(context, '.'); + if (dotpos != nullptr) + context = dotpos + 1; + result = QCoreApplication::translate(context, sourceText, disambiguation, n); + if (result != oldResult) + break; + } + return result; +} diff --git a/sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h b/sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h new file mode 100644 index 000000000..9956288ad --- /dev/null +++ b/sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CORE_SNIPPETS_P_H +#define CORE_SNIPPETS_P_H + +#include "pysidemacros.h" + +#include <sbkpython.h> + +#include <QtCore/qnamespace.h> + +#include <functional> + +QT_FORWARD_DECLARE_CLASS(QMetaType) +QT_FORWARD_DECLARE_CLASS(QObject) +QT_FORWARD_DECLARE_CLASS(QRegularExpression) +QT_FORWARD_DECLARE_CLASS(QVariant); + +// Helpers for QVariant conversion + +QMetaType QVariant_resolveMetaType(PyTypeObject *type); + +QVariant QVariant_convertToValueList(PyObject *list); + +bool QVariant_isStringList(PyObject *list); + +// Helpers for qAddPostRoutine +namespace PySide { +void globalPostRoutineCallback(); +void addPostRoutine(PyObject *callback); +} + +// Helpers for QObject::findChild(ren)() +QObject *qObjectFindChild(const QObject *parent, const QString &name, + PyTypeObject *desiredType, Qt::FindChildOptions options); + +using FindChildHandler = std::function<void(QObject *)>; + +void qObjectFindChildren(const QObject *parent, const QString &name, + PyTypeObject *desiredType, Qt::FindChildOptions options, + FindChildHandler handler); + +void qObjectFindChildren(const QObject *parent, const QRegularExpression &pattern, + PyTypeObject *desiredType, Qt::FindChildOptions options, + FindChildHandler handler); + +// Helpers for translation +QString qObjectTr(PyTypeObject *type, const char *sourceText, const char *disambiguation, int n); + +#endif // CORE_SNIPPETS_P_H diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml index 4b9f31da1..81b6c65d0 100644 --- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml +++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml @@ -629,7 +629,6 @@ <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qt-qabs"/> </add-function> - <inject-code class="native" position="beginning" file="../glue/qtcore.cpp" snippet="qt-postroutine"/> <add-function signature="qAddPostRoutine(PyObject*)"> <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qt-addpostroutine"/> </add-function> @@ -1567,6 +1566,7 @@ <include file-name="QThread" location="global"/> <include file-name="QCoreApplication" location="global"/> <include file-name="signalmanager.h" location="local"/> + <include file-name="glue/core_snippets_p.h" location="local"/> </extra-includes> <modify-function signature="metaObject()const"> <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qobject-metaobject"/> @@ -1655,7 +1655,6 @@ </add-function> - <inject-code class="native" file="../glue/qtcore.cpp" snippet="qobject-findchild-1"/> <add-function signature="findChild(PyTypeObject*@type@,const QString&@name@={},Qt::FindChildOptions@options@=Qt::FindChildrenRecursively)" return-type="PyObject*"> <inject-documentation format="target" mode="append"> diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp index 14025e72a..692062637 100644 --- a/sources/pyside6/PySide6/glue/qtcore.cpp +++ b/sources/pyside6/PySide6/glue/qtcore.cpp @@ -44,6 +44,7 @@ // @snippet include-pyside #include <pyside.h> #include <limits> +#include "glue/core_snippets_p.h" // @snippet include-pyside // @snippet qsettings-value @@ -148,90 +149,6 @@ return %out; // @snippet conversion-qmetatype-pytypeobject // @snippet qvariant-conversion -static QMetaType QVariant_resolveMetaType(PyTypeObject *type) -{ - if (PyObject_TypeCheck(type, SbkObjectType_TypeF())) { - const char *typeName = Shiboken::ObjectType::getOriginalName(type); - if (!typeName) - return {}; - const bool valueType = '*' != typeName[qstrlen(typeName) - 1]; - // Do not convert user type of value - if (valueType && Shiboken::ObjectType::isUserType(type)) - return {}; - QMetaType metaType = QMetaType::fromName(typeName); - if (metaType.isValid()) - return metaType; - // Do not resolve types to value type - if (valueType) - return {}; - // Find in base types. First check tp_bases, and only after check tp_base, because - // tp_base does not always point to the first base class, but rather to the first - // that has added any python fields or slots to its object layout. - // See https://mail.python.org/pipermail/python-list/2009-January/520733.html - if (type->tp_bases) { - for (int i = 0, size = PyTuple_GET_SIZE(type->tp_bases); i < size; ++i) { - auto baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(type->tp_bases, i)); - const QMetaType derived = QVariant_resolveMetaType(baseType); - if (derived.isValid()) - return derived; - } - } else if (type->tp_base) { - return QVariant_resolveMetaType(type->tp_base); - } - } - return {}; -} -static QVariant QVariant_convertToValueList(PyObject *list) -{ - if (PySequence_Size(list) < 0) { - // clear the error if < 0 which means no length at all - PyErr_Clear(); - return QVariant(); - } - - Shiboken::AutoDecRef element(PySequence_GetItem(list, 0)); - - const QMetaType metaType = QVariant_resolveMetaType(element.cast<PyTypeObject *>()); - if (metaType.isValid()) { - QByteArray listTypeName("QList<"); - listTypeName += metaType.name(); - listTypeName += '>'; - QMetaType metaType = QMetaType::fromName(listTypeName); - if (metaType.isValid()) { - Shiboken::Conversions::SpecificConverter converter(listTypeName); - if (converter) { - QVariant var(metaType); - converter.toCpp(list, &var); - return var; - } - qWarning() << "Type converter for :" << listTypeName << "not registered."; - } - } - return QVariant(); -} -static bool QVariant_isStringList(PyObject *list) -{ - if (!PySequence_Check(list)) { - // If it is not a list or a derived list class - // we assume that will not be a String list neither. - return false; - } - - if (PySequence_Size(list) < 0) { - // clear the error if < 0 which means no length at all - PyErr_Clear(); - return false; - } - - Shiboken::AutoDecRef fast(PySequence_Fast(list, "Failed to convert QVariantList")); - const Py_ssize_t size = PySequence_Fast_GET_SIZE(fast.object()); - for (Py_ssize_t i = 0; i < size; ++i) { - PyObject *item = PySequence_Fast_GET_ITEM(fast.object(), i); - if (!%CHECKTYPE[QString](item)) - return false; - } - return true; -} static QVariant QVariant_convertToVariantMap(PyObject *map) { Py_ssize_t pos = 0; @@ -281,30 +198,6 @@ double _abs = qAbs(%1); %PYARG_0 = %CONVERTTOPYTHON[double](_abs); // @snippet qt-qabs -// @snippet qt-postroutine -namespace PySide { -static QStack<PyObject *> globalPostRoutineFunctions; -void globalPostRoutineCallback() -{ - Shiboken::GilState state; - for (auto *callback : globalPostRoutineFunctions) { - Shiboken::AutoDecRef result(PyObject_CallObject(callback, nullptr)); - Py_DECREF(callback); - } - globalPostRoutineFunctions.clear(); -} -void addPostRoutine(PyObject *callback) -{ - if (PyCallable_Check(callback)) { - globalPostRoutineFunctions << callback; - Py_INCREF(callback); - } else { - PyErr_SetString(PyExc_TypeError, "qAddPostRoutine: The argument must be a callable object."); - } -} -} // namespace -// @snippet qt-postroutine - // @snippet qt-addpostroutine PySide::addPostRoutine(%1); // @snippet qt-addpostroutine @@ -600,109 +493,22 @@ qRegisterMetaType<QList<int> >("QList<int>"); %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); // @snippet qobject-metaobject -// @snippet qobject-findchild-1 -static bool _findChildTypeMatch(const QObject *child, PyTypeObject *desiredType) -{ - auto *pyChildType = PySide::getTypeForQObject(child); - return pyChildType != nullptr && PyType_IsSubtype(pyChildType, desiredType); -} - -static inline bool _findChildrenComparator(const QObject *child, - const QRegularExpression &name) -{ - return name.match(child->objectName()).hasMatch(); -} - -static inline bool _findChildrenComparator(const QObject *child, - const QString &name) -{ - return name.isNull() || name == child->objectName(); -} - -static QObject *_findChildHelper(const QObject *parent, const QString &name, - PyTypeObject *desiredType, - Qt::FindChildOptions options) -{ - for (auto *child : parent->children()) { - if (_findChildrenComparator(child, name) - && _findChildTypeMatch(child, desiredType)) { - return child; - } - } - - if (options.testFlag(Qt::FindChildrenRecursively)) { - for (auto *child : parent->children()) { - QObject *obj = _findChildHelper(child, name, desiredType, options); - if (obj) - return obj; - } - } - return nullptr; -} - -template<typename T> // QString/QRegularExpression -static void _findChildrenHelper(const QObject *parent, const T& name, PyTypeObject *desiredType, - Qt::FindChildOptions options, - PyObject *result) -{ - for (const auto *child : parent->children()) { - if (_findChildrenComparator(child, name) && - _findChildTypeMatch(child, desiredType)) { - Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child)); - PyList_Append(result, pyChild.object()); - } - if (options.testFlag(Qt::FindChildrenRecursively)) - _findChildrenHelper(child, name, desiredType, options, result); - } -} -// @snippet qobject-findchild-1 - // @snippet qobject-findchild-2 -QObject *child = _findChildHelper(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>(%PYARG_1), %3); +QObject *child = qObjectFindChild(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>(%PYARG_1), %3); %PYARG_0 = %CONVERTTOPYTHON[QObject *](child); // @snippet qobject-findchild-2 // @snippet qobject-findchildren %PYARG_0 = PyList_New(0); -_findChildrenHelper(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>(%PYARG_1), %3, %PYARG_0); +qObjectFindChildren(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>(%PYARG_1), %3, + [%PYARG_0](QObject *child) { + Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child)); + PyList_Append(%PYARG_0, pyChild.object()); + }); // @snippet qobject-findchildren -////////////////////////////////////////////////////////////////////////////// -// PYSIDE-131: Use the class name as context where the calling function is -// living. Derived Python classes have the wrong context. -// -// The original patch uses Python introspection to look up the current -// function (from the frame stack) in the class __dict__ along the mro. -// -// The problem is that looking into the frame stack works for Python -// functions, only. For including builtin function callers, the following -// approach turned out to be much simpler: -// -// Walk the __mro__ -// - translate the string -// - if the translated string is changed: -// - return the translation. - // @snippet qobject-tr -PyTypeObject *type = reinterpret_cast<PyTypeObject *>(%PYSELF); -PyObject *mro = type->tp_mro; -auto len = PyTuple_GET_SIZE(mro); -QString result = QString::fromUtf8(%1); -QString oldResult = result; -static auto *sbkObjectType = reinterpret_cast<PyTypeObject *>(SbkObject_TypeF()); -for (Py_ssize_t idx = 0; idx < len - 1; ++idx) { - // Skip the last class which is `object`. - auto *type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx)); - if (type == sbkObjectType) - continue; - const char *context = type->tp_name; - const char *dotpos = strrchr(context, '.'); - if (dotpos != nullptr) - context = dotpos + 1; - result = QCoreApplication::translate(context, %1, %2, %3); - if (result != oldResult) - break; -} +const QString result = qObjectTr(reinterpret_cast<PyTypeObject *>(%PYSELF), %1, %2, %3); %PYARG_0 = %CONVERTTOPYTHON[QString](result); // @snippet qobject-tr |