diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-05-17 15:48:39 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-05-22 14:48:57 +0000 |
commit | a5ff9fa2cf2abbfd316b21518a7193b1594212b8 (patch) | |
tree | 417128d3c29312db89e84970122ed5576f23269b | |
parent | 449369643e144c636b96f1ec465bbea855a68a0e (diff) |
PySide6: Fix connecting signals with arguments by constructor kwargs
The search was only implemented for signals without arguments by
appending "()" to the signal name to form the search signature.
Implement a search by signal name only.
Fixes: PYSIDE-2329
Change-Id: I295150cdebe60c886891553c9f31d14011a004d6
Reviewed-by: Shyamnath Premnadh <Shyamnath.Premnadh@qt.io>
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
(cherry picked from commit 64bacdf74cc7a32cd5bd60ed50bf5cbe998483ff)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | sources/pyside6/libpyside/pyside.cpp | 27 | ||||
-rw-r--r-- | sources/pyside6/tests/QtCore/signal_sender.py | 30 |
2 files changed, 51 insertions, 6 deletions
diff --git a/sources/pyside6/libpyside/pyside.cpp b/sources/pyside6/libpyside/pyside.cpp index 29a3d2884..33a05cc0d 100644 --- a/sources/pyside6/libpyside/pyside.cpp +++ b/sources/pyside6/libpyside/pyside.cpp @@ -37,6 +37,7 @@ #include <QtCore/QCoreApplication> #include <QtCore/QDir> #include <QtCore/QFileInfo> +#include <QtCore/QMetaMethod> #include <QtCore/QMutex> #include <QtCore/QStack> #include <QtCore/QThread> @@ -45,6 +46,7 @@ #include <cstring> #include <cctype> #include <memory> +#include <optional> #include <typeinfo> using namespace Qt::StringLiterals; @@ -299,6 +301,21 @@ static bool _setProperty(PyObject *qObj, PyObject *name, PyObject *value, bool * return true; } +// PYSIDE-2329: Search a signal by name (Note: QMetaObject::indexOfSignal() +// searches by signature). +static std::optional<QMetaMethod> findSignal(const QMetaObject *mo, + const QByteArray &name) +{ + const auto count = mo->methodCount(); + for (int i = mo->methodOffset(); i < count; ++i) { + const auto method = mo->method(i); + if (method.methodType() == QMetaMethod::Signal && method.name() == name) + return method; + } + auto *base = mo->superClass(); + return base != nullptr ? findSignal(base, name) : std::nullopt; +} + bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, PyObject *kwds, bool allowErrors) { @@ -309,7 +326,7 @@ bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, int snake_flag = flags & 0x01; while (PyDict_Next(kwds, &pos, &key, &value)) { - QByteArray propName(Shiboken::String::toCString(key)); + const QByteArray propName = Shiboken::String::toCString(key); QByteArray unmangledName = _sigWithOrigName(propName, snake_flag); bool accept = false; // PYSIDE-1705: Make sure that un-mangled names are not recognized in snake_case mode. @@ -318,11 +335,11 @@ bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, if (!_setProperty(qObj, key, value, &accept)) return false; } else { - propName.append("()"); - if (metaObj->indexOfSignal(propName) != -1) { + const auto methodO = findSignal(metaObj, propName); + if (methodO.has_value()) { + const auto signature = "2"_ba + methodO->methodSignature(); accept = true; - propName.prepend('2'); - if (!PySide::Signal::connect(qObj, propName, value)) + if (!PySide::Signal::connect(qObj, signature, value)) return false; } } diff --git a/sources/pyside6/tests/QtCore/signal_sender.py b/sources/pyside6/tests/QtCore/signal_sender.py index c85dc6da9..2552591e5 100644 --- a/sources/pyside6/tests/QtCore/signal_sender.py +++ b/sources/pyside6/tests/QtCore/signal_sender.py @@ -12,7 +12,8 @@ init_test_paths(False) from helper.usesqapplication import UsesQApplication -from PySide6.QtCore import QCoreApplication, QObject, QTimer, Signal, Slot +from PySide6.QtCore import (QCoreApplication, QObject, QStringListModel, + QTimer, Signal, Slot, Qt) class Sender(QObject): @@ -59,5 +60,32 @@ class TestSignalSender(UsesQApplication): self.assertEqual(derived_receiver._sender, sender) +class TestConstructorConnection(UsesQApplication): + """PYSIDE-2329: Check constructor connections for signals from the + base as well as signals with arguments.""" + def testConstructorConnection(self): + + was_destroyed = False + was_changed = False + + def destroyed_handler(): + nonlocal was_destroyed + was_destroyed = True + + def changed_handler(): + nonlocal was_changed + was_changed = True + + data_list = ["blub"] + model = QStringListModel(data_list, + destroyed=destroyed_handler, + dataChanged=changed_handler) + model.setData(model.index(0, 0), "bla", Qt.EditRole) + del model + + self.assertTrue(was_changed) + self.assertTrue(was_destroyed) + + if __name__ == '__main__': unittest.main() |