From 3c46f2ef96f1c017e54dd689279ed9cbff414100 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Fri, 25 Apr 2025 14:59:34 +0200 Subject: [PATCH] QGIM: standardise detection of metaobject, also for smart pointers Change-Id: I01acbfecfad582dd663c9ae2540be277414935db Reviewed-by: Artem Dyomin --- src/corelib/itemmodels/qgenericitemmodel.h | 34 +++++++++---------- .../itemmodels/qgenericitemmodel_impl.h | 13 ++++++- .../tst_qgenericitemmodel.cpp | 2 -- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/corelib/itemmodels/qgenericitemmodel.h b/src/corelib/itemmodels/qgenericitemmodel.h index c9c1d529de5..0408fb39dca 100644 --- a/src/corelib/itemmodels/qgenericitemmodel.h +++ b/src/corelib/itemmodels/qgenericitemmodel.h @@ -249,9 +249,8 @@ protected: using const_row_ptr = const wrapped_row_type *; template - static constexpr bool has_metaobject = - (QtPrivate::QMetaTypeForType>::flags() & QMetaType::IsGadget) - || (QtPrivate::QMetaTypeForType::flags() & QMetaType::PointerToQObject); + static constexpr bool has_metaobject = QGenericItemModelDetails::has_metaobject_v< + std::remove_pointer_t>>; using ModelData = QGenericItemModelDetails::ModelData, @@ -384,9 +383,9 @@ public: Qt::ItemFlags f = Structure::defaultFlags(); - if constexpr (has_metaobject) { + if constexpr (has_metaobject) { if (index.column() < row_traits::fixed_size()) { - const QMetaObject mo = std::remove_pointer_t::staticMetaObject; + const QMetaObject mo = wrapped_row_type::staticMetaObject; const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset()); if (prop.isWritable()) f |= Qt::ItemIsEditable; @@ -424,14 +423,13 @@ public: return m_itemModel->QAbstractItemModel::headerData(section, orientation, role); } - if constexpr (has_metaobject) { - using meta_type = std::remove_pointer_t; + if constexpr (has_metaobject) { if (row_traits::fixed_size() == 1) { - const QMetaType metaType = QMetaType::fromType(); + const QMetaType metaType = QMetaType::fromType(); result = QString::fromUtf8(metaType.name()); } else if (section <= row_traits::fixed_size()) { - const QMetaProperty prop = meta_type::staticMetaObject.property( - section + meta_type::staticMetaObject.propertyOffset()); + const QMetaProperty prop = wrapped_row_type::staticMetaObject.property( + section + wrapped_row_type::staticMetaObject.propertyOffset()); result = QString::fromUtf8(prop.name()); } } else if constexpr (static_column_count >= 1) { @@ -453,10 +451,10 @@ public: using multi_role = QGenericItemModelDetails::is_multi_role; if constexpr (has_metaobject) { if (row_traits::fixed_size() <= 1) { - result = readRole(role, value); + result = readRole(role, QGenericItemModelDetails::pointerTo(value)); } else if (column <= row_traits::fixed_size() && (role == Qt::DisplayRole || role == Qt::EditRole)) { - result = readProperty(column, value); + result = readProperty(column, QGenericItemModelDetails::pointerTo(value)); } } else if constexpr (multi_role::value) { const auto it = [this, &value, role]{ @@ -509,7 +507,7 @@ public: } else if constexpr (has_metaobject) { if (row_traits::fixed_size() <= 1) { tried = true; - using meta_type = std::remove_pointer_t; + using meta_type = QGenericItemModelDetails::wrapped_t; const QMetaObject &mo = meta_type::staticMetaObject; for (auto &&[role, roleName] : roleNames().asKeyValueRange()) { QVariant data; @@ -567,10 +565,10 @@ public: return false; } } else if (row_traits::fixed_size() <= 1) { - return writeRole(role, target, data); + return writeRole(role, QGenericItemModelDetails::pointerTo(target), data); } else if (column <= row_traits::fixed_size() && (role == Qt::DisplayRole || role == Qt::EditRole)) { - return writeProperty(column, target, data); + return writeProperty(column, QGenericItemModelDetails::pointerTo(target), data); } } else if constexpr (multi_role::value) { Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role); @@ -646,7 +644,7 @@ public: } else if constexpr (has_metaobject) { if (row_traits::fixed_size() <= 1) { tried = true; - using meta_type = std::remove_pointer_t; + using meta_type = QGenericItemModelDetails::wrapped_t; const QMetaObject &mo = meta_type::staticMetaObject; // transactional: if possible, modify a copy and only // update target if all values from data could be stored. @@ -721,9 +719,9 @@ public: if constexpr (has_metaobject) { if (row_traits::fixed_size() <= 1) { // multi-role object/gadget: reset all properties - return resetProperty(-1, target); + return resetProperty(-1, QGenericItemModelDetails::pointerTo(target)); } else if (column <= row_traits::fixed_size()) { - return resetProperty(column, target); + return resetProperty(column, QGenericItemModelDetails::pointerTo(target)); } } else { // normal structs, values, associative containers target = {}; diff --git a/src/corelib/itemmodels/qgenericitemmodel_impl.h b/src/corelib/itemmodels/qgenericitemmodel_impl.h index 21e887ee74a..bbadb5ffdcc 100644 --- a/src/corelib/itemmodels/qgenericitemmodel_impl.h +++ b/src/corelib/itemmodels/qgenericitemmodel_impl.h @@ -328,6 +328,17 @@ namespace QGenericItemModelDetails [[maybe_unused]] static constexpr int static_size_v = row_traits>>::static_size; + // we can't add this as a member to row_traits, as we'd end up with + // ambiguous specializations for gadgets implementing tuple protocol. + template + struct has_metaobject : std::false_type {}; + template + struct has_metaobject::staticMetaObject)>> + : std::true_type {}; + + template + [[maybe_unused]] static constexpr bool has_metaobject_v = has_metaobject::value; + template struct ListProtocol { @@ -364,7 +375,7 @@ namespace QGenericItemModelDetails }; template >::value_type> - using table_protocol_t = std::conditional_t == 0, + using table_protocol_t = std::conditional_t == 0 && !has_metaobject_v, ListProtocol, TableProtocol>; // Default tree traversal protocol implementation for row types that have diff --git a/tests/auto/corelib/itemmodels/qgenericitemmodel/tst_qgenericitemmodel.cpp b/tests/auto/corelib/itemmodels/qgenericitemmodel/tst_qgenericitemmodel.cpp index 9a3ab720f3a..1c9a959b4c9 100644 --- a/tests/auto/corelib/itemmodels/qgenericitemmodel/tst_qgenericitemmodel.cpp +++ b/tests/auto/corelib/itemmodels/qgenericitemmodel/tst_qgenericitemmodel.cpp @@ -1235,10 +1235,8 @@ void tst_QGenericItemModel::insertRows() QEXPECT_FAIL("tableOfPointersPointer", "No item created", Continue); QEXPECT_FAIL("tableOfPointersRef", "No item created", Continue); - QEXPECT_FAIL("listOfObjectsCopy", "No object created", Continue); QEXPECT_FAIL("listOfMetaObjectTupleCopy", "No object created", Continue); QEXPECT_FAIL("tableOfMetaObjectTupleCopy", "No object created", Continue); - QEXPECT_FAIL("movedListOfObjects", "No object created", Continue); QVERIFY(firstValue.isValid() && lastValue.isValid()); QCOMPARE(model->setData(firstItem, lastValue), canSetData && lastValue.isValid());