QRM: don't flag items as editable if we don't implement setData

Check for isMutable in the flags() implementation before checking type
specific attributes. We bail out of setData() and setItemData()
immediately if isMutable() returns false, so this produces a consistent
behavior.

Explicitly verify in the test that the ItemIsEditable flag is only set
when it should be.

Pick-to: 6.10 6.10.0
Change-Id: I0bb4ebcf5870b59fec12f84861d772be5d68735b
Reviewed-by: Artem Dyomin <artem.dyomin@qt.io>
This commit is contained in:
Volker Hilsheimer 2025-09-10 13:50:07 +02:00
parent 14b3f3da3c
commit a4ae63f7c1
2 changed files with 31 additions and 27 deletions

View File

@ -1187,33 +1187,34 @@ public:
Qt::ItemFlags f = Structure::defaultFlags(); Qt::ItemFlags f = Structure::defaultFlags();
if constexpr (row_traits::hasMetaObject) { if constexpr (isMutable()) {
if (index.column() < row_traits::fixed_size()) { if constexpr (row_traits::hasMetaObject) {
const QMetaObject mo = wrapped_row_type::staticMetaObject; if (index.column() < row_traits::fixed_size()) {
const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset()); const QMetaObject mo = wrapped_row_type::staticMetaObject;
if (prop.isWritable()) const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
f |= Qt::ItemIsEditable; if (prop.isWritable())
}
} else if constexpr (static_column_count <= 0) {
if constexpr (isMutable())
f |= Qt::ItemIsEditable;
} else if constexpr (std::is_reference_v<row_reference> && !std::is_const_v<row_reference>) {
// we want to know if the elements in the tuple are const; they'd always be, if
// we didn't remove the const of the range first.
const_row_reference row = rowData(index);
row_reference mutableRow = const_cast<row_reference>(row);
if (QRangeModelDetails::isValid(mutableRow)) {
QRangeModelImplBase::for_element_at(mutableRow, index.column(), [&f](auto &&ref){
using target_type = decltype(ref);
if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
f &= ~Qt::ItemIsEditable;
else if constexpr (std::is_lvalue_reference_v<target_type>)
f |= Qt::ItemIsEditable; f |= Qt::ItemIsEditable;
}); }
} else { } else if constexpr (static_column_count <= 0) {
// If there's no usable value stored in the row, then we can't f |= Qt::ItemIsEditable;
// do anything with this item. } else if constexpr (std::is_reference_v<row_reference> && !std::is_const_v<row_reference>) {
f &= ~Qt::ItemIsEditable; // we want to know if the elements in the tuple are const; they'd always be, if
// we didn't remove the const of the range first.
const_row_reference row = rowData(index);
row_reference mutableRow = const_cast<row_reference>(row);
if (QRangeModelDetails::isValid(mutableRow)) {
QRangeModelImplBase::for_element_at(mutableRow, index.column(), [&f](auto &&ref){
using target_type = decltype(ref);
if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
f &= ~Qt::ItemIsEditable;
else if constexpr (std::is_lvalue_reference_v<target_type>)
f |= Qt::ItemIsEditable;
});
} else {
// If there's no usable value stored in the row, then we can't
// do anything with this item.
f &= ~Qt::ItemIsEditable;
}
} }
} }
return f; return f;
@ -2399,7 +2400,7 @@ protected:
{ {
if constexpr (tree_traits::has_deleteRow) { if constexpr (tree_traits::has_deleteRow) {
for (auto it = begin; it != end; ++it) { for (auto it = begin; it != end; ++it) {
if constexpr (is_mutable_impl) { if constexpr (Base::isMutable()) {
decltype(auto) children = this->protocol().childRows(QRangeModelDetails::refTo(*it)); decltype(auto) children = this->protocol().childRows(QRangeModelDetails::refTo(*it));
if (QRangeModelDetails::isValid(children)) { if (QRangeModelDetails::isValid(children)) {
deleteRemovedRows(QRangeModelDetails::begin(children), deleteRemovedRows(QRangeModelDetails::begin(children),

View File

@ -1433,9 +1433,12 @@ void tst_QRangeModel::tree()
QFETCH(const int, expectedRootRowCount); QFETCH(const int, expectedRootRowCount);
QFETCH(const int, expectedColumnCount); QFETCH(const int, expectedColumnCount);
QFETCH(QList<int>, rowsWithChildren); QFETCH(QList<int>, rowsWithChildren);
QFETCH(ChangeActions, changeActions);
QCOMPARE(model->rowCount(), expectedRootRowCount); QCOMPARE(model->rowCount(), expectedRootRowCount);
QCOMPARE(model->columnCount(), expectedColumnCount); QCOMPARE(model->columnCount(), expectedColumnCount);
QCOMPARE(model->flags(model->index(0, 0)).testFlag(Qt::ItemIsEditable),
!!(changeActions & ChangeAction::SetData));
for (int row = 0; row < model->rowCount(); ++row) { for (int row = 0; row < model->rowCount(); ++row) {
const bool expectedChildren = rowsWithChildren.contains(row); const bool expectedChildren = rowsWithChildren.contains(row);