diff options
| author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2024-02-21 16:16:09 +0100 |
|---|---|---|
| committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2024-02-22 16:17:27 +0100 |
| commit | 732be9c2d39ff85b16720821eb29a4ef8e87ab85 (patch) | |
| tree | c7ec188b63e3f7c5227f7d8a16327212ab23d9ec | |
| parent | c892b9299db5d240f2753a877b055f13b6239a63 (diff) | |
Fix conversion of QVariant<->QMatrix<n>x<m>
QMatrix<n>x<m> is a template specialization of
QGenericMatrix<n,m,float> which the type name of the QVariant
contains. To find the proper Shiboken converter for this, change the
name back.
As a drive-by, fix @snippet conversion-sbkobject to return a
PyObjectWrapper() with warning in cases where the QMetaType is valid
but no converter can be found.
Fixes: PYSIDE-2599
Pick-to: 6.6
Change-Id: I4f41dcbaa394fcc1732536c0b7a6569f694f3c45
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
6 files changed, 69 insertions, 13 deletions
diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml index 6745f129b..25ceca5c8 100644 --- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml +++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml @@ -282,6 +282,9 @@ </primitive-type> <primitive-type name="QVariant" target-lang-api-name="PyObject"> + <extra-includes> + <include file-name="optional" location="global"/> + </extra-includes> <conversion-rule> <native-to-target file="../glue/qtcore.cpp" snippet="return-qvariant"/> <target-to-native> diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp index 07e9af0ad..0bf71de04 100644 --- a/sources/pyside6/PySide6/glue/qtcore.cpp +++ b/sources/pyside6/PySide6/glue/qtcore.cpp @@ -269,6 +269,30 @@ static QVariant QVariant_convertToVariantList(PyObject *list) } return QVariant(lst); } + +using SpecificConverter = Shiboken::Conversions::SpecificConverter; + +static std::optional<SpecificConverter> converterForQtType(const char *typeNameC) +{ + // Fix typedef "QGenericMatrix<3,3,float>" -> QMatrix3x3". The reverse + // conversion happens automatically in QMetaType::fromName() in + // QVariant_resolveMetaType(). + QByteArrayView typeNameV(typeNameC); + if (typeNameV.startsWith("QGenericMatrix<") && typeNameV.endsWith(",float>")) { + QByteArray typeName = typeNameV.toByteArray(); + typeName.remove(1, 7); + typeName.remove(7, 1); // '<' + typeName.chop(7); + typeName.replace(',', 'x'); + SpecificConverter matrixConverter(typeName.constData()); + if (matrixConverter) + return matrixConverter; + } + SpecificConverter converter(typeNameC); + if (converter) + return converter; + return std::nullopt; +} // @snippet qvariant-conversion // @snippet qt-qabs @@ -1484,15 +1508,23 @@ double in = %CONVERTTOCPP[double](%in); // @snippet conversion-sbkobject // a class supported by QVariant? const QMetaType metaType = QVariant_resolveMetaType(Py_TYPE(%in)); +bool ok = false; if (metaType.isValid()) { QVariant var(metaType); - Shiboken::Conversions::SpecificConverter converter(metaType.name()); - converter.toCpp(pyIn, var.data()); - %out = var; -} else { - // If the type was not encountered, return a default PyObjectWrapper - %out = QVariant::fromValue(PySide::PyObjectWrapper(%in)); + auto converterO = converterForQtType(metaType.name()); + ok = converterO.has_value(); + if (ok) { + converterO.value().toCpp(pyIn, var.data()); + %out = var; + } else { + qWarning("%s: Cannot find a converter for \"%s\".", + __FUNCTION__, metaType.name()); + } } + +// If the type was not encountered, return a default PyObjectWrapper +if (!ok) + %out = QVariant::fromValue(PySide::PyObjectWrapper(%in)); // @snippet conversion-sbkobject // @snippet conversion-pydict @@ -1650,11 +1682,10 @@ default: break; } -Shiboken::Conversions::SpecificConverter converter(cppInRef.typeName()); -if (converter) { - void *ptr = cppInRef.data(); - return converter.toPython(ptr); -} +auto converterO = converterForQtType(cppInRef.typeName()); +if (converterO.has_value()) + return converterO.value().toPython(cppInRef.data()); + PyErr_Format(PyExc_RuntimeError, "Can't find converter for '%s'.", %in.typeName()); return 0; // @snippet return-qvariant diff --git a/sources/pyside6/tests/pysidetest/CMakeLists.txt b/sources/pyside6/tests/pysidetest/CMakeLists.txt index 6dc56735d..38f42f342 100644 --- a/sources/pyside6/tests/pysidetest/CMakeLists.txt +++ b/sources/pyside6/tests/pysidetest/CMakeLists.txt @@ -46,6 +46,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/testbinding/sharedpointertestbench_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/testbinding/testview_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/testbinding/testbinding_module_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/testbinding/testqvariantenum_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/testbinding/qvariantholder_wrapper.cpp ) # Get per module include dirs. diff --git a/sources/pyside6/tests/pysidetest/qvariant_test.py b/sources/pyside6/tests/pysidetest/qvariant_test.py index 79ac446e3..8b789b2c7 100644 --- a/sources/pyside6/tests/pysidetest/qvariant_test.py +++ b/sources/pyside6/tests/pysidetest/qvariant_test.py @@ -11,9 +11,9 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) from init_paths import init_test_paths init_test_paths(True) -from testbinding import TestObject, TestQVariantEnum +from testbinding import TestObject, TestQVariantEnum, QVariantHolder from PySide6.QtCore import Qt, QKeyCombination -from PySide6.QtGui import QKeySequence, QAction +from PySide6.QtGui import QKeySequence, QAction, QMatrix3x3 from helper.usesqapplication import UsesQApplication @@ -64,6 +64,15 @@ class QVariantTest(UsesQApplication): # check toInt() conversion for IntEnum self.assertEqual(PyTestQVariantEnum.getNumberFromQVarEnum(Qt.GestureType.TapGesture), 1) + def testMatrixTemplates(self): + holder = QVariantHolder() + matrix = QMatrix3x3() + matrix.setToIdentity() + holder.setValue(matrix) + returned = holder.value() + self.assertTrue(returned, QMatrix3x3) + self.assertTrue(returned.isIdentity()) + if __name__ == '__main__': unittest.main() diff --git a/sources/pyside6/tests/pysidetest/testqvariantenum.h b/sources/pyside6/tests/pysidetest/testqvariantenum.h index 46564d268..4b729e3dd 100644 --- a/sources/pyside6/tests/pysidetest/testqvariantenum.h +++ b/sources/pyside6/tests/pysidetest/testqvariantenum.h @@ -22,4 +22,14 @@ private: QVariant m_enum; }; +class PYSIDETEST_API QVariantHolder // modeled after Q3DParameter, test QVariant conversion +{ +public: + void setValue(QVariant v) { m_variant = v; } + QVariant value() const { return m_variant; } + +private: + QVariant m_variant; +}; + #endif // TESTQVARIANT_H diff --git a/sources/pyside6/tests/pysidetest/typesystem_pysidetest.xml b/sources/pyside6/tests/pysidetest/typesystem_pysidetest.xml index bd959f7e3..592d90a83 100644 --- a/sources/pyside6/tests/pysidetest/typesystem_pysidetest.xml +++ b/sources/pyside6/tests/pysidetest/typesystem_pysidetest.xml @@ -72,6 +72,8 @@ <object-type name="SharedPointerTestbench"/> + <value-type name="QVariantHolder"/> + <smart-pointer-type name="QSharedPointer" type="shared" getter="data" reset-method="reset"/> |
