diff --git a/src/corelib/itemmodels/qgenericitemmodel.cpp b/src/corelib/itemmodels/qgenericitemmodel.cpp index 109d192e12e..24fd37c5710 100644 --- a/src/corelib/itemmodels/qgenericitemmodel.cpp +++ b/src/corelib/itemmodels/qgenericitemmodel.cpp @@ -448,6 +448,22 @@ QModelIndex QGenericItemModel::parent(const QModelIndex &child) const return impl->callConst(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(QGenericItemModelImplBase::Sibling, row, column, index); +} + /*! \reimp diff --git a/src/corelib/itemmodels/qgenericitemmodel.h b/src/corelib/itemmodels/qgenericitemmodel.h index f5b97dce789..bd1b2296bee 100644 --- a/src/corelib/itemmodels/qgenericitemmodel.h +++ b/src/corelib/itemmodels/qgenericitemmodel.h @@ -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(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 *) { } diff --git a/src/corelib/itemmodels/qgenericitemmodel_impl.h b/src/corelib/itemmodels/qgenericitemmodel_impl.h index 47e84bade5f..d7e2a08ed20 100644 --- a/src/corelib/itemmodels/qgenericitemmodel_impl.h +++ b/src/corelib/itemmodels/qgenericitemmodel_impl.h @@ -458,6 +458,7 @@ public: enum ConstOp { Index, Parent, + Sibling, RowCount, ColumnCount, Flags, diff --git a/tests/auto/corelib/itemmodels/qgenericitemmodel/tst_qgenericitemmodel.cpp b/tests/auto/corelib/itemmodels/qgenericitemmodel/tst_qgenericitemmodel.cpp index ddb2b204b30..d5ba4aa8e43 100644 --- a/tests/auto/corelib/itemmodels/qgenericitemmodel/tst_qgenericitemmodel.cpp +++ b/tests/auto/corelib/itemmodels/qgenericitemmodel/tst_qgenericitemmodel.cpp @@ -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);