QGIM: override sibling() to avoid the roundtrip through parent()

Change-Id: I91bc8d3e94d35fb30bc4886ba6be554ca7cf866b
Reviewed-by: Artem Dyomin <artem.dyomin@qt.io>
This commit is contained in:
Volker Hilsheimer 2025-02-12 14:36:19 +01:00
parent 4b198c5e64
commit 0ae202c2a7
4 changed files with 73 additions and 1 deletions

View File

@ -448,6 +448,22 @@ QModelIndex QGenericItemModel::parent(const QModelIndex &child) const
return impl->callConst<QModelIndex>(QGenericItemModelImplBase::Parent, child);
}
/*!
\reimp
Returns the sibling at \a row and \a column for the item at \a index, or an
invalid QModelIndex if there is no sibling at that location.
This implementation is significantly faster than going through the parent()
of the \a index.
\sa index(), QModelIndex::row(), QModelIndex::column()
*/
QModelIndex QGenericItemModel::sibling(int row, int column, const QModelIndex &index) const
{
return impl->callConst<QModelIndex>(QGenericItemModelImplBase::Sibling, row, column, index);
}
/*!
\reimp

View File

@ -58,6 +58,7 @@ public:
QModelIndex index(int row, int column, const QModelIndex &parent = {}) const override;
QModelIndex parent(const QModelIndex &child) const override;
QModelIndex sibling(int row, int column, const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = {}) const override;
int columnCount(const QModelIndex &parent = {}) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
@ -210,6 +211,8 @@ public:
break;
case Parent: makeCall(that, &Structure::parent, r, args);
break;
case Sibling: makeCall(that, &Self::sibling, r, args);
break;
case RowCount: makeCall(that, &Structure::rowCount, r, args);
break;
case ColumnCount: makeCall(that, &Structure::columnCount, r, args);
@ -258,6 +261,24 @@ public:
return that().indexImpl(row, column, parent);
}
QModelIndex sibling(int row, int column, const QModelIndex &index) const
{
if (row == index.row() && column == index.column())
return index;
if (column < 0 || column >= m_itemModel->columnCount())
return {};
if (row == index.row())
return createIndex(row, column, index.constInternalPointer());
const_row_ptr parentRow = static_cast<const_row_ptr>(index.constInternalPointer());
const auto siblingCount = size(that().childrenOf(parentRow));
if (row < 0 || row >= int(siblingCount))
return {};
return createIndex(row, column, parentRow);
}
Qt::ItemFlags flags(const QModelIndex &index) const
{
if (!index.isValid())
@ -1199,7 +1220,6 @@ protected:
return std::addressof(*children);
}
private:
const range_type &childrenOf(const_row_ptr row) const
{
if (!row)
@ -1210,6 +1230,7 @@ private:
return *m_protocol.childRows(*row);
}
private:
range_type &childrenOf(row_ptr row)
{
if (!row)
@ -1232,6 +1253,7 @@ class QGenericTableItemModelImpl
using range_type = typename Base::range_type;
using range_features = typename Base::range_features;
using row_type = typename Base::row_type;
using const_row_ptr = typename Base::const_row_ptr;
using row_traits = typename Base::row_traits;
using row_features = typename Base::row_features;
@ -1350,6 +1372,12 @@ protected:
return nullptr;
}
const range_type &childrenOf(const_row_ptr row) const
{
Q_ASSERT(!row);
return *this->m_data.model();
}
void resetParentInChildren(range_type *)
{
}

View File

@ -458,6 +458,7 @@ public:
enum ConstOp {
Index,
Parent,
Sibling,
RowCount,
ColumnCount,
Flags,

View File

@ -292,6 +292,8 @@ private slots:
void dimensions_data() { createTestData(); }
void dimensions();
void sibling_data() { createTestData(); }
void sibling();
void flags_data() { createTestData(); }
void flags();
void data_data() { createTestData(); }
@ -892,6 +894,31 @@ void tst_QGenericItemModel::dimensions()
QCOMPARE(model->columnCount(), expectedColumnCount);
}
void tst_QGenericItemModel::sibling()
{
QFETCH(Factory, factory);
auto model = factory();
QModelIndex withChildren;
const auto test = [model = model.get(), &withChildren](const QModelIndex &parent){
const QModelIndex first = model->index(0, 0, parent);
// deliberately requesting siblings outside of the range
for (int r = 0; r < model->rowCount() + 1; ++r) {
for (int c = 0; c < model->columnCount() + 1; ++c) {
const QModelIndex next = model->sibling(r, c, first);
const QModelIndex qaimNext = model->QAbstractItemModel::sibling(r, c, first);
if (!withChildren.isValid() && model->hasChildren(next))
withChildren = next;
QCOMPARE(next, qaimNext);
}
}
};
test({});
if (withChildren.isValid())
test(withChildren);
}
void tst_QGenericItemModel::flags()
{
QFETCH(Factory, factory);