QGIM: Rename to QRangeModel

As per the discussion on the mailing list [1], we want to avoid the word
"Generic" in class names. And QGIM is by design not using 'items', so
similar to e.g. QAbstractListModel or QSqlQueryModel, we don't need to
have "item" in the class name either.

It is a "Model", which is a well defined concept in Qt, that operates on
any C++ range, which is a well defined concept in C++. QRangeModel
is the best name.

Future evolutions on this API, e.g. adding a C++ template class that
provides an idiomatic C++ range API around the data while also updating
the Qt model, are not expected to be problematic by using this name.

[1] https://lists.qt-project.org/pipermail/development/2025-May/046322.html

Change-Id: Idaa70f8b2a30754cb28da13a0e6b0e22334afa11
Reviewed-by: Artem Dyomin <artem.dyomin@qt.io>
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
Reviewed-by: Samuel Gaist <samuel.gaist@idiap.ch>
This commit is contained in:
Volker Hilsheimer 2025-05-22 12:24:13 +02:00
parent 2d0e3c5001
commit bdbe4c8858
9 changed files with 432 additions and 432 deletions

View File

@ -1170,7 +1170,7 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_itemmodel
SOURCES SOURCES
itemmodels/qabstractitemmodel.cpp itemmodels/qabstractitemmodel.h itemmodels/qabstractitemmodel_p.h itemmodels/qabstractitemmodel.cpp itemmodels/qabstractitemmodel.h itemmodels/qabstractitemmodel_p.h
itemmodels/qitemselectionmodel.cpp itemmodels/qitemselectionmodel.h itemmodels/qitemselectionmodel_p.h itemmodels/qitemselectionmodel.cpp itemmodels/qitemselectionmodel.h itemmodels/qitemselectionmodel_p.h
itemmodels/qgenericitemmodel.h itemmodels/qgenericitemmodel_impl.h itemmodels/qgenericitemmodel.cpp itemmodels/qrangemodel.h itemmodels/qrangemodel_impl.h itemmodels/qrangemodel.cpp
) )
qt_internal_extend_target(Core CONDITION QT_FEATURE_proxymodel qt_internal_extend_target(Core CONDITION QT_FEATURE_proxymodel

View File

@ -2,7 +2,7 @@
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
add_library(corelib_snippets OBJECT add_library(corelib_snippets OBJECT
qgenericitemmodel/main.cpp qrangemodel/main.cpp
) )
target_link_libraries(corelib_snippets PRIVATE target_link_libraries(corelib_snippets PRIVATE

View File

@ -1,7 +1,7 @@
// Copyright (C) 2025 The Qt Company Ltd. // Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtCore/qgenericitemmodel.h> #include <QtCore/qrangemodel.h>
#ifndef QT_NO_WIDGETS #ifndef QT_NO_WIDGETS
@ -19,7 +19,7 @@ void array()
//! [array] //! [array]
std::array<int, 5> numbers = {1, 2, 3, 4, 5}; std::array<int, 5> numbers = {1, 2, 3, 4, 5};
QGenericItemModel model(numbers); QRangeModel model(numbers);
listView.setModel(&model); listView.setModel(&model);
//! [array] //! [array]
} }
@ -30,26 +30,26 @@ void construct_by()
{ {
//! [value] //! [value]
QGenericItemModel model(numbers); QRangeModel model(numbers);
//! [value] //! [value]
} }
{ {
//! [pointer] //! [pointer]
QGenericItemModel model(&numbers); QRangeModel model(&numbers);
//! [pointer] //! [pointer]
} }
{ {
//! [reference_wrapper] //! [reference_wrapper]
QGenericItemModel model(std::ref(numbers)); QRangeModel model(std::ref(numbers));
//! [reference_wrapper] //! [reference_wrapper]
} }
{ {
//! [smart_pointer] //! [smart_pointer]
auto shared_numbers = std::make_shared<std::vector<int>>(numbers); auto shared_numbers = std::make_shared<std::vector<int>>(numbers);
QGenericItemModel model(shared_numbers); QRangeModel model(shared_numbers);
//! [smart_pointer] //! [smart_pointer]
} }
} }
@ -59,7 +59,7 @@ void const_array()
//! [const_array] //! [const_array]
const std::array<int, 5> numbers = {1, 2, 3, 4, 5}; const std::array<int, 5> numbers = {1, 2, 3, 4, 5};
//! [const_array] //! [const_array]
QGenericItemModel model(numbers); QRangeModel model(numbers);
} }
void const_values() void const_values()
@ -67,14 +67,14 @@ void const_values()
//! [const_values] //! [const_values]
std::array<const int, 5> numbers = {1, 2, 3, 4, 5}; std::array<const int, 5> numbers = {1, 2, 3, 4, 5};
//! [const_values] //! [const_values]
QGenericItemModel model(numbers); QRangeModel model(numbers);
} }
void const_ref() void const_ref()
{ {
std::vector<int> numbers = {1, 2, 3, 4, 5}; std::vector<int> numbers = {1, 2, 3, 4, 5};
//! [const_ref] //! [const_ref]
QGenericItemModel model(std::cref(numbers)); QRangeModel model(std::cref(numbers));
//! [const_ref] //! [const_ref]
} }
@ -82,7 +82,7 @@ void list_of_int()
{ {
//! [list_of_int] //! [list_of_int]
QList<int> numbers = {1, 2, 3, 4, 5}; QList<int> numbers = {1, 2, 3, 4, 5};
QGenericItemModel model(numbers); // columnCount() == 1 QRangeModel model(numbers); // columnCount() == 1
QListView listView; QListView listView;
listView.setModel(&model); listView.setModel(&model);
//! [list_of_int] //! [list_of_int]
@ -96,7 +96,7 @@ std::vector<std::vector<int>> gridOfNumbers = {
{6, 7, 8, 9, 10}, {6, 7, 8, 9, 10},
{11, 12, 13, 14, 15}, {11, 12, 13, 14, 15},
}; };
QGenericItemModel model(&gridOfNumbers); // columnCount() == 5 QRangeModel model(&gridOfNumbers); // columnCount() == 5
QTableView tableView; QTableView tableView;
tableView.setModel(&model); tableView.setModel(&model);
//! [grid_of_numbers] //! [grid_of_numbers]
@ -111,7 +111,7 @@ QList<TableRow> numberNames = {
{2, "two"}, {2, "two"},
{3, "three"} {3, "three"}
}; };
QGenericItemModel model(&numberNames); // columnCount() == 2 QRangeModel model(&numberNames); // columnCount() == 2
QTableView tableView; QTableView tableView;
tableView.setModel(&model); tableView.setModel(&model);
//! [pair_int_QString] //! [pair_int_QString]
@ -220,7 +220,7 @@ public:
std::optional<Tree> &childRows() { return m_children; } std::optional<Tree> &childRows() { return m_children; }
//! [tree_protocol_3] //! [tree_protocol_3]
//! [tree_protocol_4] //! [tree_protocol_4]
// Helper to assembly a tree of rows, not used by QGenericItemModel // Helper to assembly a tree of rows, not used by QRangeModel
template <typename ...Args> template <typename ...Args>
TreeRow &addChild(Args &&...args) TreeRow &addChild(Args &&...args)
{ {
@ -259,7 +259,7 @@ tree[2].addChild("...");
{ {
//! [tree_protocol_6] //! [tree_protocol_6]
// instantiate the model with a pointer to the tree, not a copy! // instantiate the model with a pointer to the tree, not a copy!
QGenericItemModel model(&tree); QRangeModel model(&tree);
QTreeView view; QTreeView view;
view.setModel(&model); view.setModel(&model);
//! [tree_protocol_6] //! [tree_protocol_6]
@ -280,7 +280,7 @@ void explicit_tree_protocol()
{ {
Tree tree; Tree tree;
//! [explicit_tree_protocol_1] //! [explicit_tree_protocol_1]
QGenericItemModel model(&tree, TreeTraversal{}); QRangeModel model(&tree, TreeTraversal{});
//! [explicit_tree_protocol_1] //! [explicit_tree_protocol_1]
} }
} // namespace tree_protocol } // namespace tree_protocol
@ -366,7 +366,7 @@ int main(int argc, char **argv)
Tree tree = make_tree_of_pointers(); Tree tree = make_tree_of_pointers();
QGenericItemModel model(std::move(tree), TreeTraversal{}); QRangeModel model(std::move(tree), TreeTraversal{});
QTreeView treeView; QTreeView treeView;
treeView.setModel(&model); treeView.setModel(&model);
treeView.show(); treeView.show();
@ -391,7 +391,7 @@ for (const QString &name : colorNames) {
{Qt::DecorationRole, color}, {Qt::DecorationRole, color},
{Qt::ToolTipRole, color.name()}}; {Qt::ToolTipRole, color.name()}};
} }
QGenericItemModel colorModel(colors); QRangeModel colorModel(colors);
QListView list; QListView list;
list.setModel(&colorModel); list.setModel(&colorModel);
//! [color_map] //! [color_map]
@ -427,12 +427,12 @@ private:
void color_list() { void color_list() {
//! [color_gadget_1] //! [color_gadget_1]
const QStringList colorNames = QColor::colorNames(); const QStringList colorNames = QColor::colorNames();
QList<QGenericItemModel::SingleColumn<ColorEntry>> colors; QList<QRangeModel::SingleColumn<ColorEntry>> colors;
colors.reserve(colorNames.size()); colors.reserve(colorNames.size());
for (const QString &name : colorNames) for (const QString &name : colorNames)
colors << ColorEntry{name}; colors << ColorEntry{name};
QGenericItemModel colorModel(colors); QRangeModel colorModel(colors);
QListView list; QListView list;
list.setModel(&colorModel); list.setModel(&colorModel);
//! [color_gadget_1] //! [color_gadget_1]

View File

@ -1,29 +1,29 @@
// Copyright (C) 2025 The Qt Company Ltd. // Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qgenericitemmodel.h" #include "qrangemodel.h"
#include <QtCore/qsize.h> #include <QtCore/qsize.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
/*! /*!
\class QGenericItemModel \class QRangeModel
\inmodule QtCore \inmodule QtCore
\since 6.10 \since 6.10
\ingroup model-view \ingroup model-view
\brief QGenericItemModel implements QAbstractItemModel for any C++ range. \brief QRangeModel implements QAbstractItemModel for any C++ range.
\reentrant \reentrant
QGenericItemModel can make the data in any sequentially iterable C++ type QRangeModel can make the data in any sequentially iterable C++ type
available to the \l{Model/View Programming}{model/view framework} of Qt. available to the \l{Model/View Programming}{model/view framework} of Qt.
This makes it easy to display existing data structures in the Qt Widgets This makes it easy to display existing data structures in the Qt Widgets
and Qt Quick item views, and to allow the user of the application to and Qt Quick item views, and to allow the user of the application to
manipulate the data using a graphical user interface. manipulate the data using a graphical user interface.
To use QGenericItemModel, instantiate it with a C++ range and set it as To use QRangeModel, instantiate it with a C++ range and set it as
the model of one or more views: the model of one or more views:
\snippet qgenericitemmodel/main.cpp array \snippet qrangemodel/main.cpp array
The range can be any C++ type for which the standard methods The range can be any C++ type for which the standard methods
\c{std::cbegin} and \c{std::cend} are implemented, and for which the \c{std::cbegin} and \c{std::cend} are implemented, and for which the
@ -43,7 +43,7 @@ QT_BEGIN_NAMESPACE
QAbstractItemModel APIs that modify the model, such as setData() or QAbstractItemModel APIs that modify the model, such as setData() or
insertRows(), have no impact on the original range. insertRows(), have no impact on the original range.
\snippet qgenericitemmodel/main.cpp value \snippet qrangemodel/main.cpp value
As there is no API to retrieve the range again, constructing the model from As there is no API to retrieve the range again, constructing the model from
a range by value is mostly only useful for displaying read-only data. a range by value is mostly only useful for displaying read-only data.
@ -58,8 +58,8 @@ QT_BEGIN_NAMESPACE
To make modifications of the model affect the original range, provide the To make modifications of the model affect the original range, provide the
range either by reference wrapper or by pointer. range either by reference wrapper or by pointer.
\snippet qgenericitemmodel/main.cpp pointer \snippet qrangemodel/main.cpp pointer
\snippet qgenericitemmodel/main.cpp reference_wrapper \snippet qrangemodel/main.cpp reference_wrapper
In this case, QAbstractItemModel APIs that modify the model also modify the In this case, QAbstractItemModel APIs that modify the model also modify the
range. Methods that modify the structure of the range, such as insertRows() range. Methods that modify the structure of the range, such as insertRows()
@ -78,32 +78,32 @@ QT_BEGIN_NAMESPACE
Use smart pointers to make sure that the range is only deleted when all Use smart pointers to make sure that the range is only deleted when all
clients are done with it. clients are done with it.
\snippet qgenericitemmodel/main.cpp smart_pointer \snippet qrangemodel/main.cpp smart_pointer
QGenericItemModel supports both shared and unique pointers. QRangeModel supports both shared and unique pointers.
\section2 Read-only or mutable \section2 Read-only or mutable
For ranges that are const objects, for which access always yields constant For ranges that are const objects, for which access always yields constant
values, or where the required container APIs are not available, values, or where the required container APIs are not available,
QGenericItemModel implements write-access APIs to do nothing and return QRangeModel implements write-access APIs to do nothing and return
\c{false}. In the example using \c{std::array}, the model cannot add or \c{false}. In the example using \c{std::array}, the model cannot add or
remove rows, as the number of entries in a C++ array is fixed. But the remove rows, as the number of entries in a C++ array is fixed. But the
values can be changed using setData(), and the user can trigger editing of values can be changed using setData(), and the user can trigger editing of
the values in the list view. By making the array const, the values also the values in the list view. By making the array const, the values also
become read-only. become read-only.
\snippet qgenericitemmodel/main.cpp const_array \snippet qrangemodel/main.cpp const_array
The values are also read-only if the element type is const, like in The values are also read-only if the element type is const, like in
\snippet qgenericitemmodel/main.cpp const_values \snippet qrangemodel/main.cpp const_values
In the above examples using \c{std::vector}, the model can add or remove In the above examples using \c{std::vector}, the model can add or remove
rows, and the data can be changed. Passing the range as a constant rows, and the data can be changed. Passing the range as a constant
reference will make the model read-only. reference will make the model read-only.
\snippet qgenericitemmodel/main.cpp const_ref \snippet qrangemodel/main.cpp const_ref
\note If the values in the range are const, then it's also not possible \note If the values in the range are const, then it's also not possible
to remove or insert columns and rows through the QAbstractItemModel API. to remove or insert columns and rows through the QAbstractItemModel API.
@ -112,18 +112,18 @@ QT_BEGIN_NAMESPACE
\section1 Rows and columns \section1 Rows and columns
The elements in the range are interpreted as rows of the model. Depending The elements in the range are interpreted as rows of the model. Depending
on the type of these row elements, QGenericItemModel exposes the range as a on the type of these row elements, QRangeModel exposes the range as a
list, a table, or a tree. list, a table, or a tree.
If the row elements are simple values, then the range gets represented as a If the row elements are simple values, then the range gets represented as a
list. list.
\snippet qgenericitemmodel/main.cpp list_of_int \snippet qrangemodel/main.cpp list_of_int
If the type of the row elements is an iterable range, such as a vector, If the type of the row elements is an iterable range, such as a vector,
list, or array, then the range gets represented as a table. list, or array, then the range gets represented as a table.
\snippet qgenericitemmodel/main.cpp grid_of_numbers \snippet qrangemodel/main.cpp grid_of_numbers
If the row type provides the standard C++ container APIs \c{resize()}, If the row type provides the standard C++ container APIs \c{resize()},
\c{insert()}, \c{erase()}, then columns can be added and removed via \c{insert()}, \c{erase()}, then columns can be added and removed via
@ -135,14 +135,14 @@ QT_BEGIN_NAMESPACE
If the row type implements \l{the C++ tuple protocol}, then the range gets If the row type implements \l{the C++ tuple protocol}, then the range gets
represented as a table with a fixed number of columns. represented as a table with a fixed number of columns.
\snippet qgenericitemmodel/main.cpp pair_int_QString \snippet qrangemodel/main.cpp pair_int_QString
An easier and more flexible alternative to implementing the tuple protocol An easier and more flexible alternative to implementing the tuple protocol
for a C++ type is to use Qt's \l{Meta-Object System}{meta-object system} to for a C++ type is to use Qt's \l{Meta-Object System}{meta-object system} to
declare a type with \l{Qt's Property System}{properties}. This can be a declare a type with \l{Qt's Property System}{properties}. This can be a
value type that is declared as a \l{Q_GADGET}{gadget}, or a QObject subclass. value type that is declared as a \l{Q_GADGET}{gadget}, or a QObject subclass.
\snippet qgenericitemmodel/main.cpp gadget \snippet qrangemodel/main.cpp gadget
Using QObject subclasses allows properties to be \l{Qt Bindable Properties} Using QObject subclasses allows properties to be \l{Qt Bindable Properties}
{bindable}, or to have change notification signals. However, using QObject {bindable}, or to have change notification signals. However, using QObject
@ -170,13 +170,13 @@ QT_BEGIN_NAMESPACE
If the item is an associative container that uses \c{int}, If the item is an associative container that uses \c{int},
\l{Qt::ItemDataRole}, or QString as the key type, and QVariant as the \l{Qt::ItemDataRole}, or QString as the key type, and QVariant as the
mapped type, then QGenericItemModel interprets that container as the storage mapped type, then QRangeModel interprets that container as the storage
of the data for multiple roles. The data() and setData() functions return of the data for multiple roles. The data() and setData() functions return
and modify the mapped value in the container, and setItemData() modifies all and modify the mapped value in the container, and setItemData() modifies all
provided values, itemData() returns all stored values, and clearItemData() provided values, itemData() returns all stored values, and clearItemData()
clears the entire container. clears the entire container.
\snippet qgenericitemmodel/main.cpp color_map \snippet qrangemodel/main.cpp color_map
The most efficient data type to use as the key is Qt::ItemDataRole or The most efficient data type to use as the key is Qt::ItemDataRole or
\c{int}. When using \c{int}, itemData() returns the container as is, and \c{int}. When using \c{int}, itemData() returns the container as is, and
@ -186,36 +186,36 @@ QT_BEGIN_NAMESPACE
are the item type in a table. The names of the properties have to match the are the item type in a table. The names of the properties have to match the
names of the roles. names of the roles.
\snippet qgenericitemmodel/main.cpp color_gadget_0 \snippet qrangemodel/main.cpp color_gadget_0
When used in a list, these types are ambiguous: they can be represented as When used in a list, these types are ambiguous: they can be represented as
multi-column rows, with each property represented as a separate column. Or multi-column rows, with each property represented as a separate column. Or
they can be single items with each property being a role. To disambiguate, they can be single items with each property being a role. To disambiguate,
use the QGenericItemModel::SingleColumn and QGenericItemModel::MultiColumn use the QRangeModel::SingleColumn and QRangeModel::MultiColumn
wrappers. wrappers.
\snippet qgenericitemmodel/main.cpp color_gadget_1 \snippet qrangemodel/main.cpp color_gadget_1
\section1 Trees of data \section1 Trees of data
QGenericItemModel can represent a data structure as a tree model. Such a QRangeModel can represent a data structure as a tree model. Such a
tree data structure needs to be homomorphic: on all levels of the tree, the tree data structure needs to be homomorphic: on all levels of the tree, the
list of child rows needs to use the exact same representation as the tree list of child rows needs to use the exact same representation as the tree
itself. In addition, the row type needs be of a static size: either a gadget itself. In addition, the row type needs be of a static size: either a gadget
or QObject type, or a type that implements the {C++ tuple protocol}. or QObject type, or a type that implements the {C++ tuple protocol}.
To represent such data as a tree, the row type has to implement a traversal To represent such data as a tree, the row type has to implement a traversal
protocol that allows QGenericItemModel to navigate up and down the tree. protocol that allows QRangeModel to navigate up and down the tree.
For any given row, the model needs to be able to retrieve the parent row, For any given row, the model needs to be able to retrieve the parent row,
and the span of children for any given row. and the span of children for any given row.
\snippet qgenericitemmodel/main.cpp tree_protocol_0 \snippet qrangemodel/main.cpp tree_protocol_0
The tree itself is a vector of \c{TreeRow} values. See \l{Rows as pointers The tree itself is a vector of \c{TreeRow} values. See \l{Rows as pointers
or values} for the considerations on whether to use values or pointers of or values} for the considerations on whether to use values or pointers of
items for the rows. items for the rows.
\snippet qgenericitemmodel/main.cpp tree_protocol_1 \snippet qrangemodel/main.cpp tree_protocol_1
The row class can be of any fixed-size type described above: a type that The row class can be of any fixed-size type described above: a type that
implements the tuple protocol, a gadget, or a QObject. In this example, we implements the tuple protocol, a gadget, or a QObject. In this example, we
@ -229,7 +229,7 @@ QT_BEGIN_NAMESPACE
to construct new row data elements, for instance in the insertRow() or to construct new row data elements, for instance in the insertRow() or
moveRows() implementations. moveRows() implementations.
\snippet qgenericitemmodel/main.cpp tree_protocol_2 \snippet qrangemodel/main.cpp tree_protocol_2
The tree traversal protocol can then be implemented as member functions of The tree traversal protocol can then be implemented as member functions of
the row data type. A const \c{parentRow()} function has to return a pointer the row data type. A const \c{parentRow()} function has to return a pointer
@ -242,7 +242,7 @@ QT_BEGIN_NAMESPACE
model to implement mutating model APIs such as insertRows(), removeRows(), model to implement mutating model APIs such as insertRows(), removeRows(),
and moveRows(), we have to implement additional functions for write-access: and moveRows(), we have to implement additional functions for write-access:
\snippet qgenericitemmodel/main.cpp tree_protocol_3 \snippet qrangemodel/main.cpp tree_protocol_3
The model calls the \c{setParentRow()} function and mutable \c{childRows()} The model calls the \c{setParentRow()} function and mutable \c{childRows()}
overload to move or insert rows into an existing tree branch, and to update overload to move or insert rows into an existing tree branch, and to update
@ -255,29 +255,29 @@ QT_BEGIN_NAMESPACE
as separate steps. This keeps the protocol interface small. as separate steps. This keeps the protocol interface small.
\dots \dots
\snippet qgenericitemmodel/main.cpp tree_protocol_4 \snippet qrangemodel/main.cpp tree_protocol_4
The rest of the class implementation is not relevant for the model, but The rest of the class implementation is not relevant for the model, but
a \c{addChild()} helper provides us with a convenient way to construct the a \c{addChild()} helper provides us with a convenient way to construct the
initial state of the tree. initial state of the tree.
\snippet qgenericitemmodel/main.cpp tree_protocol_5 \snippet qrangemodel/main.cpp tree_protocol_5
A QGenericItemModel instantiated with an instance of such a range will A QRangeModel instantiated with an instance of such a range will
represent the data as a tree. represent the data as a tree.
\snippet qgenericitemmodel/main.cpp tree_protocol_6 \snippet qrangemodel/main.cpp tree_protocol_6
\section3 Tree traversal protocol in a separate class \section3 Tree traversal protocol in a separate class
The tree traversal protocol can also be implemented in a separate class. The tree traversal protocol can also be implemented in a separate class.
\snippet qgenericitemmodel/main.cpp explicit_tree_protocol_0 \snippet qrangemodel/main.cpp explicit_tree_protocol_0
Pass an instance of this protocol implementation to the QGenericItemModel Pass an instance of this protocol implementation to the QRangeModel
constructor: constructor:
\snippet qgenericitemmodel/main.cpp explicit_tree_protocol_1 \snippet qrangemodel/main.cpp explicit_tree_protocol_1
\section2 Rows as pointers or values \section2 Rows as pointers or values
@ -290,41 +290,41 @@ QT_BEGIN_NAMESPACE
the location of the parent row within the vector. Making sure that this the location of the parent row within the vector. Making sure that this
parent (and QPersistentModelIndex instances referring to items within it) parent (and QPersistentModelIndex instances referring to items within it)
stays valid can incurr substantial performance overhead. The stays valid can incurr substantial performance overhead. The
QGenericItemModel implementation has to assume that all references into the QRangeModel implementation has to assume that all references into the
range become invalid when modifying the range. range become invalid when modifying the range.
Alternatively, we can also use a range of row pointers as the tree type: Alternatively, we can also use a range of row pointers as the tree type:
\snippet qgenericitemmodel/main.cpp tree_of_pointers_0 \snippet qrangemodel/main.cpp tree_of_pointers_0
In this case, we have to allocate all TreeRow instances explicitly using In this case, we have to allocate all TreeRow instances explicitly using
operator \c{new}, and implement the destructor to \c{delete} all items in operator \c{new}, and implement the destructor to \c{delete} all items in
the vector of children. the vector of children.
\snippet qgenericitemmodel/main.cpp tree_of_pointers_1 \snippet qrangemodel/main.cpp tree_of_pointers_1
\snippet qgenericitemmodel/main.cpp tree_of_pointers_2 \snippet qrangemodel/main.cpp tree_of_pointers_2
Before we can construct a model that represents this data as a tree, we need Before we can construct a model that represents this data as a tree, we need
to also implement the tree traversal protocol. to also implement the tree traversal protocol.
\snippet qgenericitemmodel/main.cpp tree_of_pointers_3 \snippet qrangemodel/main.cpp tree_of_pointers_3
An explicit protocol implementation for mutable trees of pointers has to An explicit protocol implementation for mutable trees of pointers has to
provide two additional member functions, \c{newRow()} and provide two additional member functions, \c{newRow()} and
\c{deleteRow(RowType *)}. \c{deleteRow(RowType *)}.
\snippet qgenericitemmodel/main.cpp tree_of_pointers_4 \snippet qrangemodel/main.cpp tree_of_pointers_4
The model will call those functions when creating new rows in insertRows(), The model will call those functions when creating new rows in insertRows(),
and when removing rows in removeRows(). In addition, if the model has and when removing rows in removeRows(). In addition, if the model has
ownership of the data, then it will also delete all top-level rows upon ownership of the data, then it will also delete all top-level rows upon
destruction. Note how in this example, we move the tree into the model, so destruction. Note how in this example, we move the tree into the model, so
we must no longer perform any operations on it. QGenericItemModel, when we must no longer perform any operations on it. QRangeModel, when
constructed by moving tree-data with row-pointers into it, will take constructed by moving tree-data with row-pointers into it, will take
ownership of the data, and delete the row pointers in it's destructor. ownership of the data, and delete the row pointers in it's destructor.
\note This is not the case for tables and lists that use pointers as their \note This is not the case for tables and lists that use pointers as their
row type. QGenericItemModel will never allocate new rows in lists and tables row type. QRangeModel will never allocate new rows in lists and tables
using operator new, and will never free any rows. using operator new, and will never free any rows.
Using pointers at rows comes with some memory allocation and management Using pointers at rows comes with some memory allocation and management
@ -346,7 +346,7 @@ QT_BEGIN_NAMESPACE
type to make existing structured data available to the model/view framework type to make existing structured data available to the model/view framework
in Qt. in Qt.
\snippet qgenericitemmodel/main.cpp tuple_protocol \snippet qrangemodel/main.cpp tuple_protocol
In the above implementation, the \c{title} and \c{author} values of the In the above implementation, the \c{title} and \c{author} values of the
\c{Book} type are returned as \c{const}, so the model flags items in those \c{Book} type are returned as \c{const}, so the model flags items in those
@ -358,25 +358,25 @@ QT_BEGIN_NAMESPACE
those columns editable, both for the user and for programmatic access. those columns editable, both for the user and for programmatic access.
\note The implementation of \c{get} above requires C++23. A C++17 compliant \note The implementation of \c{get} above requires C++23. A C++17 compliant
implementation can be found in the unit test code for QGenericItemModel. implementation can be found in the unit test code for QRangeModel.
Types that have a meta objects, and implement the C++ tuple protocol, also Types that have a meta objects, and implement the C++ tuple protocol, also
can cause compile-time ambiguity when used as the row type, as the framework can cause compile-time ambiguity when used as the row type, as the framework
won't know which API to use to access the individual values. Use the won't know which API to use to access the individual values. Use the
QGenericItemModel::SingleColumn and QGenericItemModel::MultiColumns wrapper QRangeModel::SingleColumn and QRangeModel::MultiColumns wrapper
to disambiguate. to disambiguate.
\sa {Model/View Programming} \sa {Model/View Programming}
*/ */
/*! /*!
\typedef QGenericItemModel::SingleColumn \typedef QRangeModel::SingleColumn
Use this type to disambiguate when using the type \c{T} as the row type in Use this type to disambiguate when using the type \c{T} as the row type in
the range. If \c{T} provides a metaobject, then the framework will by the range. If \c{T} provides a metaobject, then the framework will by
default represent the type as multiple columns, resulting in a table model. default represent the type as multiple columns, resulting in a table model.
\snippet qgenericitemmodel/main.cpp color_gadget_0 \snippet qrangemodel/main.cpp color_gadget_0
When stored in a sequential range, this type will be interpreted as When stored in a sequential range, this type will be interpreted as
multi-column rows with each property being one column. The range will be multi-column rows with each property being one column. The range will be
@ -386,25 +386,25 @@ QT_BEGIN_NAMESPACE
QList<ColorEntry> colors = { QList<ColorEntry> colors = {
// ... // ...
}; };
QGenericItemModel tableModel(colors); // columnCount() == 3 QRangeModel tableModel(colors); // columnCount() == 3
\endcode \endcode
When wrapped into QGenericItemModel::SingleColumn, the model will be a list, When wrapped into QRangeModel::SingleColumn, the model will be a list,
with each instance of \c{T} represented as an item with multiple roles. with each instance of \c{T} represented as an item with multiple roles.
\code \code
QList<QGenericItemModel::SingleColumn<ColorEntry>> colors = { QList<QRangeModel::SingleColumn<ColorEntry>> colors = {
// ... // ...
}; };
QGenericItemModel listModel(colors); // columnCount() == 1 QRangeModel listModel(colors); // columnCount() == 1
\endcode \endcode
\sa QGenericItemModel::MultiColumn \sa QRangeModel::MultiColumn
*/ */
/*! /*!
\class QGenericItemModel::MultiColumn \class QRangeModel::MultiColumn
\brief Represents the wrapped type \c{T} as multiple columns in a QGenericItemModel. \brief Represents the wrapped type \c{T} as multiple columns in a QRangeModel.
\inmodule QtCore \inmodule QtCore
\ingroup model-view \ingroup model-view
\since 6.10 \since 6.10
@ -414,29 +414,29 @@ QT_BEGIN_NAMESPACE
multiple columns, and the individual values will be accessed through the multiple columns, and the individual values will be accessed through the
tuple protocol. tuple protocol.
\snippet qgenericitemmodel/main.cpp color_gadget_0 \snippet qrangemodel/main.cpp color_gadget_0
\code \code
namespace std { namespace std {
template <> struct tuple_size<ColorEntry> : integral_constant<size_t, 3> {}; template <> struct tuple_size<ColorEntry> : integral_constant<size_t, 3> {};
// ... // ...
} }
QList<QGenericItemModel::MultiColumn<ColorEntry>> colors = { QList<QRangeModel::MultiColumn<ColorEntry>> colors = {
// ... // ...
}; };
QGenericItemModel colorList(colors); QRangeModel colorList(colors);
\endcode \endcode
To represent the type a single column value with multiple roles, use To represent the type a single column value with multiple roles, use
QGenericItemModel::SingleColumn instead. QRangeModel::SingleColumn instead.
\sa QGenericItemModel::SingleColumn \sa QRangeModel::SingleColumn
*/ */
/*! /*!
\fn template <typename Range, QGenericItemModelDetails::if_is_table_range<Range>> QGenericItemModel::QGenericItemModel(Range &&range, QObject *parent) \fn template <typename Range, QRangeModelDetails::if_is_table_range<Range>> QRangeModel::QRangeModel(Range &&range, QObject *parent)
\fn template <typename Range, QGenericItemModelDetails::if_is_tree_range<Range>> QGenericItemModel::QGenericItemModel(Range &&range, QObject *parent) \fn template <typename Range, QRangeModelDetails::if_is_tree_range<Range>> QRangeModel::QRangeModel(Range &&range, QObject *parent)
\fn template <typename Range, typename Protocol, QGenericItemModelDetails::if_is_tree_range<Range, Protocol>> QGenericItemModel::QGenericItemModel(Range &&range, Protocol &&protocol, QObject *parent) \fn template <typename Range, typename Protocol, QRangeModelDetails::if_is_tree_range<Range, Protocol>> QRangeModel::QRangeModel(Range &&range, Protocol &&protocol, QObject *parent)
Constructs a generic item model instance that operates on the data in \a Constructs a generic item model instance that operates on the data in \a
range. The \a range has to be a sequential range for which \c{std::cbegin} range. The \a range has to be a sequential range for which \c{std::cbegin}
@ -461,7 +461,7 @@ QT_BEGIN_NAMESPACE
The range that the model was constructed from is not destroyed. The range that the model was constructed from is not destroyed.
*/ */
QGenericItemModel::~QGenericItemModel() = default; QRangeModel::~QRangeModel() = default;
/*! /*!
\reimp \reimp
@ -473,9 +473,9 @@ QGenericItemModel::~QGenericItemModel() = default;
\sa parent() \sa parent()
*/ */
QModelIndex QGenericItemModel::index(int row, int column, const QModelIndex &parent) const QModelIndex QRangeModel::index(int row, int column, const QModelIndex &parent) const
{ {
return impl->callConst<QModelIndex>(QGenericItemModelImplBase::Index, row, column, parent); return impl->callConst<QModelIndex>(QRangeModelImplBase::Index, row, column, parent);
} }
/*! /*!
@ -490,9 +490,9 @@ QModelIndex QGenericItemModel::index(int row, int column, const QModelIndex &par
\sa index(), hasChildren() \sa index(), hasChildren()
*/ */
QModelIndex QGenericItemModel::parent(const QModelIndex &child) const QModelIndex QRangeModel::parent(const QModelIndex &child) const
{ {
return impl->callConst<QModelIndex>(QGenericItemModelImplBase::Parent, child); return impl->callConst<QModelIndex>(QRangeModelImplBase::Parent, child);
} }
/*! /*!
@ -506,9 +506,9 @@ QModelIndex QGenericItemModel::parent(const QModelIndex &child) const
\sa index(), QModelIndex::row(), QModelIndex::column() \sa index(), QModelIndex::row(), QModelIndex::column()
*/ */
QModelIndex QGenericItemModel::sibling(int row, int column, const QModelIndex &index) const QModelIndex QRangeModel::sibling(int row, int column, const QModelIndex &index) const
{ {
return impl->callConst<QModelIndex>(QGenericItemModelImplBase::Sibling, row, column, index); return impl->callConst<QModelIndex>(QRangeModelImplBase::Sibling, row, column, index);
} }
/*! /*!
@ -524,9 +524,9 @@ QModelIndex QGenericItemModel::sibling(int row, int column, const QModelIndex &i
\sa columnCount(), insertRows(), hasChildren() \sa columnCount(), insertRows(), hasChildren()
*/ */
int QGenericItemModel::rowCount(const QModelIndex &parent) const int QRangeModel::rowCount(const QModelIndex &parent) const
{ {
return impl->callConst<int>(QGenericItemModelImplBase::RowCount, parent); return impl->callConst<int>(QRangeModelImplBase::RowCount, parent);
} }
/*! /*!
@ -542,9 +542,9 @@ int QGenericItemModel::rowCount(const QModelIndex &parent) const
\sa rowCount, insertColumns() \sa rowCount, insertColumns()
*/ */
int QGenericItemModel::columnCount(const QModelIndex &parent) const int QRangeModel::columnCount(const QModelIndex &parent) const
{ {
return impl->callConst<int>(QGenericItemModelImplBase::ColumnCount, parent); return impl->callConst<int>(QRangeModelImplBase::ColumnCount, parent);
} }
/*! /*!
@ -559,9 +559,9 @@ int QGenericItemModel::columnCount(const QModelIndex &parent) const
\sa Qt::ItemFlags \sa Qt::ItemFlags
*/ */
Qt::ItemFlags QGenericItemModel::flags(const QModelIndex &index) const Qt::ItemFlags QRangeModel::flags(const QModelIndex &index) const
{ {
return impl->callConst<Qt::ItemFlags>(QGenericItemModelImplBase::Flags, index); return impl->callConst<Qt::ItemFlags>(QRangeModelImplBase::Flags, index);
} }
/*! /*!
@ -576,9 +576,9 @@ Qt::ItemFlags QGenericItemModel::flags(const QModelIndex &index) const
\sa Qt::ItemDataRole, setHeaderData(), QHeaderView \sa Qt::ItemDataRole, setHeaderData(), QHeaderView
*/ */
QVariant QGenericItemModel::headerData(int section, Qt::Orientation orientation, int role) const QVariant QRangeModel::headerData(int section, Qt::Orientation orientation, int role) const
{ {
return impl->callConst<QVariant>(QGenericItemModelImplBase::HeaderData, return impl->callConst<QVariant>(QRangeModelImplBase::HeaderData,
section, orientation, role); section, orientation, role);
} }
@ -599,9 +599,9 @@ QVariant QGenericItemModel::headerData(int section, Qt::Orientation orientation,
\sa Qt::ItemDataRole, setData(), headerData() \sa Qt::ItemDataRole, setData(), headerData()
*/ */
QVariant QGenericItemModel::data(const QModelIndex &index, int role) const QVariant QRangeModel::data(const QModelIndex &index, int role) const
{ {
return impl->callConst<QVariant>(QGenericItemModelImplBase::Data, index, role); return impl->callConst<QVariant>(QRangeModelImplBase::Data, index, role);
} }
/*! /*!
@ -624,9 +624,9 @@ QVariant QGenericItemModel::data(const QModelIndex &index, int role) const
returns \c{false} immediately. returns \c{false} immediately.
//! [read-only-setData] //! [read-only-setData]
*/ */
bool QGenericItemModel::setData(const QModelIndex &index, const QVariant &data, int role) bool QRangeModel::setData(const QModelIndex &index, const QVariant &data, int role)
{ {
return impl->call<bool>(QGenericItemModelImplBase::SetData, index, data, role); return impl->call<bool>(QRangeModelImplBase::SetData, index, data, role);
} }
/*! /*!
@ -647,9 +647,9 @@ bool QGenericItemModel::setData(const QModelIndex &index, const QVariant &data,
\sa setItemData(), Qt::ItemDataRole, data() \sa setItemData(), Qt::ItemDataRole, data()
*/ */
QMap<int, QVariant> QGenericItemModel::itemData(const QModelIndex &index) const QMap<int, QVariant> QRangeModel::itemData(const QModelIndex &index) const
{ {
return impl->callConst<QMap<int, QVariant>>(QGenericItemModelImplBase::ItemData, index); return impl->callConst<QMap<int, QVariant>>(QRangeModelImplBase::ItemData, index);
} }
/*! /*!
@ -678,9 +678,9 @@ QMap<int, QVariant> QGenericItemModel::itemData(const QModelIndex &index) const
\sa itemData(), setData(), Qt::ItemDataRole \sa itemData(), setData(), Qt::ItemDataRole
*/ */
bool QGenericItemModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &data) bool QRangeModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &data)
{ {
return impl->call<bool>(QGenericItemModelImplBase::SetItemData, index, data); return impl->call<bool>(QRangeModelImplBase::SetItemData, index, data);
} }
/*! /*!
@ -689,11 +689,11 @@ bool QGenericItemModel::setItemData(const QModelIndex &index, const QMap<int, QV
Replaces the value stored in the range at \a index with a default- Replaces the value stored in the range at \a index with a default-
constructed value. constructed value.
\include qgenericitemmodel.cpp read-only-setData \include qrangemodel.cpp read-only-setData
*/ */
bool QGenericItemModel::clearItemData(const QModelIndex &index) bool QRangeModel::clearItemData(const QModelIndex &index)
{ {
return impl->call<bool>(QGenericItemModelImplBase::ClearItemData, index); return impl->call<bool>(QRangeModelImplBase::ClearItemData, index);
} }
/* /*
@ -714,11 +714,11 @@ bool QGenericItemModel::clearItemData(const QModelIndex &index)
of the range at \a parent. Returns \c{true} if successful; otherwise of the range at \a parent. Returns \c{true} if successful; otherwise
returns \c{false}. returns \c{false}.
\include qgenericitemmodel.cpp {column-change-requirement} {insert(const_iterator, size_t, value_type)} \include qrangemodel.cpp {column-change-requirement} {insert(const_iterator, size_t, value_type)}
*/ */
bool QGenericItemModel::insertColumns(int column, int count, const QModelIndex &parent) bool QRangeModel::insertColumns(int column, int count, const QModelIndex &parent)
{ {
return impl->call<bool>(QGenericItemModelImplBase::InsertColumns, column, count, parent); return impl->call<bool>(QRangeModelImplBase::InsertColumns, column, count, parent);
} }
/*! /*!
@ -728,11 +728,11 @@ bool QGenericItemModel::insertColumns(int column, int count, const QModelIndex &
range at \a parent. Returns \c{true} if successful, otherwise returns range at \a parent. Returns \c{true} if successful, otherwise returns
\c{false}. \c{false}.
\include qgenericitemmodel.cpp {column-change-requirement} {erase(const_iterator, size_t)} \include qrangemodel.cpp {column-change-requirement} {erase(const_iterator, size_t)}
*/ */
bool QGenericItemModel::removeColumns(int column, int count, const QModelIndex &parent) bool QRangeModel::removeColumns(int column, int count, const QModelIndex &parent)
{ {
return impl->call<bool>(QGenericItemModelImplBase::RemoveColumns, column, count, parent); return impl->call<bool>(QRangeModelImplBase::RemoveColumns, column, count, parent);
} }
/*! /*!
@ -744,10 +744,10 @@ bool QGenericItemModel::removeColumns(int column, int count, const QModelIndex &
Returns \c{true} if the columns were successfully moved; otherwise returns Returns \c{true} if the columns were successfully moved; otherwise returns
\c{false}. \c{false}.
*/ */
bool QGenericItemModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, bool QRangeModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count,
const QModelIndex &destinationParent, int destinationColumn) const QModelIndex &destinationParent, int destinationColumn)
{ {
return impl->call<bool>(QGenericItemModelImplBase::MoveColumns, return impl->call<bool>(QRangeModelImplBase::MoveColumns,
sourceParent, sourceColumn, count, sourceParent, sourceColumn, count,
destinationParent, destinationColumn); destinationParent, destinationColumn);
} }
@ -769,14 +769,14 @@ bool QGenericItemModel::moveColumns(const QModelIndex &sourceParent, int sourceC
Inserts \a count empty rows before the given \a row into the range at Inserts \a count empty rows before the given \a row into the range at
\a parent. Returns \c{true} if successful; otherwise returns \c{false}. \a parent. Returns \c{true} if successful; otherwise returns \c{false}.
\include qgenericitemmodel.cpp {row-change-requirement} {insert(const_iterator, size_t, value_type)} \include qrangemodel.cpp {row-change-requirement} {insert(const_iterator, size_t, value_type)}
\note For ranges with a dynamically sized column type, the column needs \note For ranges with a dynamically sized column type, the column needs
to provide a \c{resize(size_t)} member function. to provide a \c{resize(size_t)} member function.
*/ */
bool QGenericItemModel::insertRows(int row, int count, const QModelIndex &parent) bool QRangeModel::insertRows(int row, int count, const QModelIndex &parent)
{ {
return impl->call<bool>(QGenericItemModelImplBase::InsertRows, row, count, parent); return impl->call<bool>(QRangeModelImplBase::InsertRows, row, count, parent);
} }
/*! /*!
@ -785,11 +785,11 @@ bool QGenericItemModel::insertRows(int row, int count, const QModelIndex &parent
Removes \a count rows from the range at \a parent, starting with the Removes \a count rows from the range at \a parent, starting with the
given \a row. Returns \c{true} if successful, otherwise returns \c{false}. given \a row. Returns \c{true} if successful, otherwise returns \c{false}.
\include qgenericitemmodel.cpp {row-change-requirement} {erase(const_iterator, size_t)} \include qrangemodel.cpp {row-change-requirement} {erase(const_iterator, size_t)}
*/ */
bool QGenericItemModel::removeRows(int row, int count, const QModelIndex &parent) bool QRangeModel::removeRows(int row, int count, const QModelIndex &parent)
{ {
return impl->call<bool>(QGenericItemModelImplBase::RemoveRows, row, count, parent); return impl->call<bool>(QRangeModelImplBase::RemoveRows, row, count, parent);
} }
/*! /*!
@ -801,10 +801,10 @@ bool QGenericItemModel::removeRows(int row, int count, const QModelIndex &parent
Returns \c{true} if the rows were successfully moved; otherwise returns Returns \c{true} if the rows were successfully moved; otherwise returns
\c{false}. \c{false}.
*/ */
bool QGenericItemModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, bool QRangeModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
const QModelIndex &destinationParent, int destinationRow) const QModelIndex &destinationParent, int destinationRow)
{ {
return impl->call<bool>(QGenericItemModelImplBase::MoveRows, return impl->call<bool>(QRangeModelImplBase::MoveRows,
sourceParent, sourceRow, count, sourceParent, sourceRow, count,
destinationParent, destinationRow); destinationParent, destinationRow);
} }
@ -812,7 +812,7 @@ bool QGenericItemModel::moveRows(const QModelIndex &sourceParent, int sourceRow,
/*! /*!
\reimp \reimp
*/ */
bool QGenericItemModel::canFetchMore(const QModelIndex &parent) const bool QRangeModel::canFetchMore(const QModelIndex &parent) const
{ {
return QAbstractItemModel::canFetchMore(parent); return QAbstractItemModel::canFetchMore(parent);
} }
@ -820,7 +820,7 @@ bool QGenericItemModel::canFetchMore(const QModelIndex &parent) const
/*! /*!
\reimp \reimp
*/ */
void QGenericItemModel::fetchMore(const QModelIndex &parent) void QRangeModel::fetchMore(const QModelIndex &parent)
{ {
QAbstractItemModel::fetchMore(parent); QAbstractItemModel::fetchMore(parent);
} }
@ -828,7 +828,7 @@ void QGenericItemModel::fetchMore(const QModelIndex &parent)
/*! /*!
\reimp \reimp
*/ */
bool QGenericItemModel::hasChildren(const QModelIndex &parent) const bool QRangeModel::hasChildren(const QModelIndex &parent) const
{ {
return QAbstractItemModel::hasChildren(parent); return QAbstractItemModel::hasChildren(parent);
} }
@ -836,7 +836,7 @@ bool QGenericItemModel::hasChildren(const QModelIndex &parent) const
/*! /*!
\reimp \reimp
*/ */
QModelIndex QGenericItemModel::buddy(const QModelIndex &index) const QModelIndex QRangeModel::buddy(const QModelIndex &index) const
{ {
return QAbstractItemModel::buddy(index); return QAbstractItemModel::buddy(index);
} }
@ -844,7 +844,7 @@ QModelIndex QGenericItemModel::buddy(const QModelIndex &index) const
/*! /*!
\reimp \reimp
*/ */
bool QGenericItemModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, bool QRangeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent) const int row, int column, const QModelIndex &parent) const
{ {
return QAbstractItemModel::canDropMimeData(data, action, row, column, parent); return QAbstractItemModel::canDropMimeData(data, action, row, column, parent);
@ -853,7 +853,7 @@ bool QGenericItemModel::canDropMimeData(const QMimeData *data, Qt::DropAction ac
/*! /*!
\reimp \reimp
*/ */
bool QGenericItemModel::dropMimeData(const QMimeData *data, Qt::DropAction action, bool QRangeModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent) int row, int column, const QModelIndex &parent)
{ {
return QAbstractItemModel::dropMimeData(data, action, row, column, parent); return QAbstractItemModel::dropMimeData(data, action, row, column, parent);
@ -862,7 +862,7 @@ bool QGenericItemModel::dropMimeData(const QMimeData *data, Qt::DropAction actio
/*! /*!
\reimp \reimp
*/ */
QMimeData *QGenericItemModel::mimeData(const QModelIndexList &indexes) const QMimeData *QRangeModel::mimeData(const QModelIndexList &indexes) const
{ {
return QAbstractItemModel::mimeData(indexes); return QAbstractItemModel::mimeData(indexes);
} }
@ -870,7 +870,7 @@ QMimeData *QGenericItemModel::mimeData(const QModelIndexList &indexes) const
/*! /*!
\reimp \reimp
*/ */
QStringList QGenericItemModel::mimeTypes() const QStringList QRangeModel::mimeTypes() const
{ {
return QAbstractItemModel::mimeTypes(); return QAbstractItemModel::mimeTypes();
} }
@ -878,7 +878,7 @@ QStringList QGenericItemModel::mimeTypes() const
/*! /*!
\reimp \reimp
*/ */
QModelIndexList QGenericItemModel::match(const QModelIndex &start, int role, const QVariant &value, QModelIndexList QRangeModel::match(const QModelIndex &start, int role, const QVariant &value,
int hits, Qt::MatchFlags flags) const int hits, Qt::MatchFlags flags) const
{ {
return QAbstractItemModel::match(start, role, value, hits, flags); return QAbstractItemModel::match(start, role, value, hits, flags);
@ -887,7 +887,7 @@ QModelIndexList QGenericItemModel::match(const QModelIndex &start, int role, con
/*! /*!
\reimp \reimp
*/ */
void QGenericItemModel::multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const void QRangeModel::multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const
{ {
QAbstractItemModel::multiData(index, roleDataSpan); QAbstractItemModel::multiData(index, roleDataSpan);
} }
@ -895,7 +895,7 @@ void QGenericItemModel::multiData(const QModelIndex &index, QModelRoleDataSpan r
/*! /*!
\reimp \reimp
*/ */
QHash<int, QByteArray> QGenericItemModel::roleNames() const QHash<int, QByteArray> QRangeModel::roleNames() const
{ {
return QAbstractItemModel::roleNames(); return QAbstractItemModel::roleNames();
} }
@ -903,7 +903,7 @@ QHash<int, QByteArray> QGenericItemModel::roleNames() const
/*! /*!
\reimp \reimp
*/ */
void QGenericItemModel::sort(int column, Qt::SortOrder order) void QRangeModel::sort(int column, Qt::SortOrder order)
{ {
return QAbstractItemModel::sort(column, order); return QAbstractItemModel::sort(column, order);
} }
@ -911,7 +911,7 @@ void QGenericItemModel::sort(int column, Qt::SortOrder order)
/*! /*!
\reimp \reimp
*/ */
QSize QGenericItemModel::span(const QModelIndex &index) const QSize QRangeModel::span(const QModelIndex &index) const
{ {
return QAbstractItemModel::span(index); return QAbstractItemModel::span(index);
} }
@ -919,7 +919,7 @@ QSize QGenericItemModel::span(const QModelIndex &index) const
/*! /*!
\reimp \reimp
*/ */
Qt::DropActions QGenericItemModel::supportedDragActions() const Qt::DropActions QRangeModel::supportedDragActions() const
{ {
return QAbstractItemModel::supportedDragActions(); return QAbstractItemModel::supportedDragActions();
} }
@ -927,7 +927,7 @@ Qt::DropActions QGenericItemModel::supportedDragActions() const
/*! /*!
\reimp \reimp
*/ */
Qt::DropActions QGenericItemModel::supportedDropActions() const Qt::DropActions QRangeModel::supportedDropActions() const
{ {
return QAbstractItemModel::supportedDropActions(); return QAbstractItemModel::supportedDropActions();
} }
@ -935,7 +935,7 @@ Qt::DropActions QGenericItemModel::supportedDropActions() const
/*! /*!
\reimp \reimp
*/ */
void QGenericItemModel::resetInternalData() void QRangeModel::resetInternalData()
{ {
QAbstractItemModel::resetInternalData(); QAbstractItemModel::resetInternalData();
} }
@ -943,7 +943,7 @@ void QGenericItemModel::resetInternalData()
/*! /*!
\reimp \reimp
*/ */
bool QGenericItemModel::event(QEvent *event) bool QRangeModel::event(QEvent *event)
{ {
return QAbstractItemModel::event(event); return QAbstractItemModel::event(event);
} }
@ -951,11 +951,11 @@ bool QGenericItemModel::event(QEvent *event)
/*! /*!
\reimp \reimp
*/ */
bool QGenericItemModel::eventFilter(QObject *object, QEvent *event) bool QRangeModel::eventFilter(QObject *object, QEvent *event)
{ {
return QAbstractItemModel::eventFilter(object, event); return QAbstractItemModel::eventFilter(object, event);
} }
QT_END_NAMESPACE QT_END_NAMESPACE
#include "moc_qgenericitemmodel.cpp" #include "moc_qrangemodel.cpp"

View File

@ -1,14 +1,14 @@
// Copyright (C) 2025 The Qt Company Ltd. // Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QGENERICITEMMODEL_H #ifndef QRANGEMODEL_H
#define QGENERICITEMMODEL_H #define QRANGEMODEL_H
#include <QtCore/qgenericitemmodel_impl.h> #include <QtCore/qrangemodel_impl.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QGenericItemModel : public QAbstractItemModel class Q_CORE_EXPORT QRangeModel : public QAbstractItemModel
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -25,7 +25,7 @@ public:
MultiColumn<T>>, bool>; MultiColumn<T>>, bool>;
template <typename V = T, template <typename V = T,
std::enable_if_t<QGenericItemModelDetails::is_validatable<V>::value, bool> = true> std::enable_if_t<QRangeModelDetails::is_validatable<V>::value, bool> = true>
constexpr explicit operator bool() const noexcept { return bool(data); } constexpr explicit operator bool() const noexcept { return bool(data); }
// unconstrained on size_t I, gcc internal error #3280 // unconstrained on size_t I, gcc internal error #3280
@ -33,23 +33,23 @@ public:
friend inline decltype(auto) get(V &&multiColumn) friend inline decltype(auto) get(V &&multiColumn)
{ {
static_assert(I < std::tuple_size_v<type>, "Index out of bounds for wrapped type"); static_assert(I < std::tuple_size_v<type>, "Index out of bounds for wrapped type");
return get<I>(QGenericItemModelDetails::refTo(q23::forward_like<V>(multiColumn.data))); return get<I>(QRangeModelDetails::refTo(q23::forward_like<V>(multiColumn.data)));
} }
}; };
template <typename Range, template <typename Range,
QGenericItemModelDetails::if_is_table_range<Range> = true> QRangeModelDetails::if_is_table_range<Range> = true>
explicit QGenericItemModel(Range &&range, QObject *parent = nullptr); explicit QRangeModel(Range &&range, QObject *parent = nullptr);
template <typename Range, template <typename Range,
QGenericItemModelDetails::if_is_tree_range<Range> = true> QRangeModelDetails::if_is_tree_range<Range> = true>
explicit QGenericItemModel(Range &&range, QObject *parent = nullptr); explicit QRangeModel(Range &&range, QObject *parent = nullptr);
template <typename Range, typename Protocol, template <typename Range, typename Protocol,
QGenericItemModelDetails::if_is_tree_range<Range, Protocol> = true> QRangeModelDetails::if_is_tree_range<Range, Protocol> = true>
explicit QGenericItemModel(Range &&range, Protocol &&protocol, QObject *parent = nullptr); explicit QRangeModel(Range &&range, Protocol &&protocol, QObject *parent = nullptr);
~QGenericItemModel() override; ~QRangeModel() override;
QModelIndex index(int row, int column, const QModelIndex &parent = {}) const override; QModelIndex index(int row, int column, const QModelIndex &parent = {}) const override;
QModelIndex parent(const QModelIndex &child) const override; QModelIndex parent(const QModelIndex &child) const override;
@ -100,112 +100,112 @@ protected:
bool eventFilter(QObject *, QEvent *) override; bool eventFilter(QObject *, QEvent *) override;
private: private:
Q_DISABLE_COPY_MOVE(QGenericItemModel) Q_DISABLE_COPY_MOVE(QRangeModel)
friend class QGenericItemModelImplBase; friend class QRangeModelImplBase;
struct Deleter { void operator()(QGenericItemModelImplBase *that) { that->destroy(); } }; struct Deleter { void operator()(QRangeModelImplBase *that) { that->destroy(); } };
std::unique_ptr<QGenericItemModelImplBase, Deleter> impl; std::unique_ptr<QRangeModelImplBase, Deleter> impl;
}; };
// implementation of forwarders // implementation of forwarders
QModelIndex QGenericItemModelImplBase::createIndex(int row, int column, const void *ptr) const QModelIndex QRangeModelImplBase::createIndex(int row, int column, const void *ptr) const
{ {
return m_itemModel->createIndex(row, column, ptr); return m_rangeModel->createIndex(row, column, ptr);
} }
void QGenericItemModelImplBase::changePersistentIndexList(const QModelIndexList &from, void QRangeModelImplBase::changePersistentIndexList(const QModelIndexList &from,
const QModelIndexList &to) const QModelIndexList &to)
{ {
m_itemModel->changePersistentIndexList(from, to); m_rangeModel->changePersistentIndexList(from, to);
} }
QHash<int, QByteArray> QGenericItemModelImplBase::roleNames() const QHash<int, QByteArray> QRangeModelImplBase::roleNames() const
{ {
return m_itemModel->roleNames(); return m_rangeModel->roleNames();
} }
void QGenericItemModelImplBase::dataChanged(const QModelIndex &from, const QModelIndex &to, void QRangeModelImplBase::dataChanged(const QModelIndex &from, const QModelIndex &to,
const QList<int> &roles) const QList<int> &roles)
{ {
m_itemModel->dataChanged(from, to, roles); m_rangeModel->dataChanged(from, to, roles);
} }
void QGenericItemModelImplBase::beginInsertColumns(const QModelIndex &parent, int start, int count) void QRangeModelImplBase::beginInsertColumns(const QModelIndex &parent, int start, int count)
{ {
m_itemModel->beginInsertColumns(parent, start, count); m_rangeModel->beginInsertColumns(parent, start, count);
} }
void QGenericItemModelImplBase::endInsertColumns() void QRangeModelImplBase::endInsertColumns()
{ {
m_itemModel->endInsertColumns(); m_rangeModel->endInsertColumns();
} }
void QGenericItemModelImplBase::beginRemoveColumns(const QModelIndex &parent, int start, int count) void QRangeModelImplBase::beginRemoveColumns(const QModelIndex &parent, int start, int count)
{ {
m_itemModel->beginRemoveColumns(parent, start, count); m_rangeModel->beginRemoveColumns(parent, start, count);
} }
void QGenericItemModelImplBase::endRemoveColumns() void QRangeModelImplBase::endRemoveColumns()
{ {
m_itemModel->endRemoveColumns(); m_rangeModel->endRemoveColumns();
} }
bool QGenericItemModelImplBase::beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst, bool QRangeModelImplBase::beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst,
int sourceLast, const QModelIndex &destParent, int sourceLast, const QModelIndex &destParent,
int destColumn) int destColumn)
{ {
return m_itemModel->beginMoveColumns(sourceParent, sourceFirst, sourceLast, return m_rangeModel->beginMoveColumns(sourceParent, sourceFirst, sourceLast,
destParent, destColumn); destParent, destColumn);
} }
void QGenericItemModelImplBase::endMoveColumns() void QRangeModelImplBase::endMoveColumns()
{ {
m_itemModel->endMoveColumns(); m_rangeModel->endMoveColumns();
} }
void QGenericItemModelImplBase::beginInsertRows(const QModelIndex &parent, int start, int count) void QRangeModelImplBase::beginInsertRows(const QModelIndex &parent, int start, int count)
{ {
m_itemModel->beginInsertRows(parent, start, count); m_rangeModel->beginInsertRows(parent, start, count);
} }
void QGenericItemModelImplBase::endInsertRows() void QRangeModelImplBase::endInsertRows()
{ {
m_itemModel->endInsertRows(); m_rangeModel->endInsertRows();
} }
void QGenericItemModelImplBase::beginRemoveRows(const QModelIndex &parent, int start, int count) void QRangeModelImplBase::beginRemoveRows(const QModelIndex &parent, int start, int count)
{ {
m_itemModel->beginRemoveRows(parent, start, count); m_rangeModel->beginRemoveRows(parent, start, count);
} }
void QGenericItemModelImplBase::endRemoveRows() void QRangeModelImplBase::endRemoveRows()
{ {
m_itemModel->endRemoveRows(); m_rangeModel->endRemoveRows();
} }
bool QGenericItemModelImplBase::beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, bool QRangeModelImplBase::beginMoveRows(const QModelIndex &sourceParent, int sourceFirst,
int sourceLast, int sourceLast,
const QModelIndex &destParent, int destRow) const QModelIndex &destParent, int destRow)
{ {
return m_itemModel->beginMoveRows(sourceParent, sourceFirst, sourceLast, destParent, destRow); return m_rangeModel->beginMoveRows(sourceParent, sourceFirst, sourceLast, destParent, destRow);
} }
void QGenericItemModelImplBase::endMoveRows() void QRangeModelImplBase::endMoveRows()
{ {
m_itemModel->endMoveRows(); m_rangeModel->endMoveRows();
} }
QAbstractItemModel &QGenericItemModelImplBase::itemModel() QAbstractItemModel &QRangeModelImplBase::itemModel()
{ {
return *m_itemModel; return *m_rangeModel;
} }
const QAbstractItemModel &QGenericItemModelImplBase::itemModel() const const QAbstractItemModel &QRangeModelImplBase::itemModel() const
{ {
return *m_itemModel; return *m_rangeModel;
} }
template <typename Range, template <typename Range,
QGenericItemModelDetails::if_is_table_range<Range>> QRangeModelDetails::if_is_table_range<Range>>
QGenericItemModel::QGenericItemModel(Range &&range, QObject *parent) QRangeModel::QRangeModel(Range &&range, QObject *parent)
: QAbstractItemModel(parent) : QAbstractItemModel(parent)
, impl(new QGenericTableItemModelImpl<Range>(std::forward<Range>(range), this)) , impl(new QGenericTableItemModelImpl<Range>(std::forward<Range>(range), this))
{} {}
template <typename Range, template <typename Range,
QGenericItemModelDetails::if_is_tree_range<Range>> QRangeModelDetails::if_is_tree_range<Range>>
QGenericItemModel::QGenericItemModel(Range &&range, QObject *parent) QRangeModel::QRangeModel(Range &&range, QObject *parent)
: QGenericItemModel(std::forward<Range>(range), : QRangeModel(std::forward<Range>(range),
QGenericItemModelDetails::DefaultTreeProtocol<Range>{}, parent) QRangeModelDetails::DefaultTreeProtocol<Range>{}, parent)
{} {}
template <typename Range, typename Protocol, template <typename Range, typename Protocol,
QGenericItemModelDetails::if_is_tree_range<Range, Protocol>> QRangeModelDetails::if_is_tree_range<Range, Protocol>>
QGenericItemModel::QGenericItemModel(Range &&range, Protocol &&protocol, QObject *parent) QRangeModel::QRangeModel(Range &&range, Protocol &&protocol, QObject *parent)
: QAbstractItemModel(parent) : QAbstractItemModel(parent)
, impl(new QGenericTreeItemModelImpl<Range, Protocol>(std::forward<Range>(range), , impl(new QGenericTreeItemModelImpl<Range, Protocol>(std::forward<Range>(range),
std::forward<Protocol>(protocol), this)) std::forward<Protocol>(protocol), this))
@ -215,13 +215,13 @@ QT_END_NAMESPACE
namespace std { namespace std {
template <typename T> template <typename T>
struct tuple_size<QT_PREPEND_NAMESPACE(QGenericItemModel)::MultiColumn<T>> struct tuple_size<QT_PREPEND_NAMESPACE(QRangeModel)::MultiColumn<T>>
: tuple_size<typename QT_PREPEND_NAMESPACE(QGenericItemModel)::MultiColumn<T>::type> : tuple_size<typename QT_PREPEND_NAMESPACE(QRangeModel)::MultiColumn<T>::type>
{}; {};
template <std::size_t I, typename T> template <std::size_t I, typename T>
struct tuple_element<I, QT_PREPEND_NAMESPACE(QGenericItemModel)::MultiColumn<T>> struct tuple_element<I, QT_PREPEND_NAMESPACE(QRangeModel)::MultiColumn<T>>
: tuple_element<I, typename QT_PREPEND_NAMESPACE(QGenericItemModel)::MultiColumn<T>::type> : tuple_element<I, typename QT_PREPEND_NAMESPACE(QRangeModel)::MultiColumn<T>::type>
{}; {};
} }
#endif // QGENERICITEMMODEL_H #endif // QRANGEMODEL_H

View File

@ -1,13 +1,13 @@
// Copyright (C) 2025 The Qt Company Ltd. // Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QGENERICITEMMODEL_IMPL_H #ifndef QRANGEMODEL_IMPL_H
#define QGENERICITEMMODEL_IMPL_H #define QRANGEMODEL_IMPL_H
#ifndef Q_QDOC #ifndef Q_QDOC
#ifndef QGENERICITEMMODEL_H #ifndef QRANGEMODEL_H
#error Do not include qgenericitemmodel_impl.h directly #error Do not include qrangemodel_impl.h directly
#endif #endif
#if 0 #if 0
@ -30,7 +30,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace QGenericItemModelDetails namespace QRangeModelDetails
{ {
template <typename T, template <typename...> typename... Templates> template <typename T, template <typename...> typename... Templates>
struct is_any_of_impl : std::false_type {}; struct is_any_of_impl : std::false_type {};
@ -145,10 +145,10 @@ namespace QGenericItemModelDetails
{ return std::cend(refTo(std::forward<C>(c))); } { return std::cend(refTo(std::forward<C>(c))); }
template <typename C> template <typename C>
static auto pos(C &&c, int i) static auto pos(C &&c, int i)
{ return std::next(QGenericItemModelDetails::begin(std::forward<C>(c)), i); } { return std::next(QRangeModelDetails::begin(std::forward<C>(c)), i); }
template <typename C> template <typename C>
static auto cpos(C &&c, int i) static auto cpos(C &&c, int i)
{ return std::next(QGenericItemModelDetails::cbegin(std::forward<C>(c)), i); } { return std::next(QRangeModelDetails::cbegin(std::forward<C>(c)), i); }
// Test if a type is a range, and whether we can modify it using the // Test if a type is a range, and whether we can modify it using the
// standard C++ container member functions insert, erase, and resize. // standard C++ container member functions insert, erase, and resize.
@ -501,26 +501,26 @@ namespace QGenericItemModelDetails
}; };
} }
class QGenericItemModel; class QRangeModel;
class QGenericItemModelImplBase class QRangeModelImplBase
{ {
Q_DISABLE_COPY_MOVE(QGenericItemModelImplBase) Q_DISABLE_COPY_MOVE(QRangeModelImplBase)
protected: protected:
// Helpers for calling a lambda with the tuple element at a runtime index. // Helpers for calling a lambda with the tuple element at a runtime index.
template <typename Tuple, typename F, size_t ...Is> template <typename Tuple, typename F, size_t ...Is>
static void call_at(Tuple &&tuple, size_t idx, std::index_sequence<Is...>, F &&function) static void call_at(Tuple &&tuple, size_t idx, std::index_sequence<Is...>, F &&function)
{ {
if (QGenericItemModelDetails::isValid(tuple)) if (QRangeModelDetails::isValid(tuple))
((Is == idx ? static_cast<void>(function(get<Is>( ((Is == idx ? static_cast<void>(function(get<Is>(
QGenericItemModelDetails::refTo(std::forward<Tuple>(tuple))))) QRangeModelDetails::refTo(std::forward<Tuple>(tuple)))))
: static_cast<void>(0)), ...); : static_cast<void>(0)), ...);
} }
template <typename T, typename F> template <typename T, typename F>
static auto for_element_at(T &&tuple, size_t idx, F &&function) static auto for_element_at(T &&tuple, size_t idx, F &&function)
{ {
using type = QGenericItemModelDetails::wrapped_t<T>; using type = QRangeModelDetails::wrapped_t<T>;
constexpr size_t size = std::tuple_size_v<type>; constexpr size_t size = std::tuple_size_v<type>;
Q_ASSERT(idx < size); Q_ASSERT(idx < size);
return call_at(std::forward<T>(tuple), idx, std::make_index_sequence<size>{}, return call_at(std::forward<T>(tuple), idx, std::make_index_sequence<size>{},
@ -537,7 +537,7 @@ protected:
template <typename T> template <typename T>
static constexpr QMetaType meta_type_at(size_t idx) static constexpr QMetaType meta_type_at(size_t idx)
{ {
using type = QGenericItemModelDetails::wrapped_t<T>; using type = QRangeModelDetails::wrapped_t<T>;
constexpr auto size = std::tuple_size_v<type>; constexpr auto size = std::tuple_size_v<type>;
Q_ASSERT(idx < size); Q_ASSERT(idx < size);
return makeMetaTypes<type>(std::make_index_sequence<size>{}).at(idx); return makeMetaTypes<type>(std::make_index_sequence<size>{}).at(idx);
@ -550,7 +550,7 @@ protected:
return std::invoke(fn, obj, std::get<I>(tuple)...); return std::invoke(fn, obj, std::get<I>(tuple)...);
} }
template <typename Ret, typename Class, typename ...Args> template <typename Ret, typename Class, typename ...Args>
static void makeCall(QGenericItemModelImplBase *obj, Ret(Class::* &&fn)(Args...), static void makeCall(QRangeModelImplBase *obj, Ret(Class::* &&fn)(Args...),
void *ret, const void *args) void *ret, const void *args)
{ {
const auto &tuple = *static_cast<const std::tuple<Args&...> *>(args); const auto &tuple = *static_cast<const std::tuple<Args&...> *>(args);
@ -558,7 +558,7 @@ protected:
static_cast<Class *>(obj), fn, tuple); static_cast<Class *>(obj), fn, tuple);
} }
template <typename Ret, typename Class, typename ...Args> template <typename Ret, typename Class, typename ...Args>
static void makeCall(const QGenericItemModelImplBase *obj, Ret(Class::* &&fn)(Args...) const, static void makeCall(const QRangeModelImplBase *obj, Ret(Class::* &&fn)(Args...) const,
void *ret, const void *args) void *ret, const void *args)
{ {
const auto &tuple = *static_cast<const std::tuple<Args&...> *>(args); const auto &tuple = *static_cast<const std::tuple<Args&...> *>(args);
@ -599,22 +599,22 @@ public:
private: private:
// prototypes // prototypes
static void callConst(ConstOp, const QGenericItemModelImplBase *, void *, const void *); static void callConst(ConstOp, const QRangeModelImplBase *, void *, const void *);
static void call(Op, QGenericItemModelImplBase *, void *, const void *); static void call(Op, QRangeModelImplBase *, void *, const void *);
using CallConstFN = decltype(callConst); using CallConstFN = decltype(callConst);
using CallTupleFN = decltype(call); using CallTupleFN = decltype(call);
CallConstFN *callConst_fn; CallConstFN *callConst_fn;
CallTupleFN *call_fn; CallTupleFN *call_fn;
QGenericItemModel *m_itemModel; QRangeModel *m_rangeModel;
protected: protected:
template <typename Impl> // type deduction template <typename Impl> // type deduction
explicit QGenericItemModelImplBase(QGenericItemModel *itemModel, const Impl *) explicit QRangeModelImplBase(QRangeModel *itemModel, const Impl *)
: callConst_fn(&Impl::callConst), call_fn(&Impl::call), m_itemModel(itemModel) : callConst_fn(&Impl::callConst), call_fn(&Impl::call), m_rangeModel(itemModel)
{} {}
~QGenericItemModelImplBase() = default; ~QRangeModelImplBase() = default;
inline QModelIndex createIndex(int row, int column, const void *ptr = nullptr) const; inline QModelIndex createIndex(int row, int column, const void *ptr = nullptr) const;
inline void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to); inline void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to);
@ -659,52 +659,52 @@ public:
}; };
template <typename Structure, typename Range, template <typename Structure, typename Range,
typename Protocol = QGenericItemModelDetails::table_protocol_t<Range>> typename Protocol = QRangeModelDetails::table_protocol_t<Range>>
class QGenericItemModelImpl : public QGenericItemModelImplBase class QRangeModelImpl : public QRangeModelImplBase
{ {
Q_DISABLE_COPY_MOVE(QGenericItemModelImpl) Q_DISABLE_COPY_MOVE(QRangeModelImpl)
public: public:
using range_type = QGenericItemModelDetails::wrapped_t<Range>; using range_type = QRangeModelDetails::wrapped_t<Range>;
using row_reference = decltype(*QGenericItemModelDetails::begin(std::declval<range_type&>())); using row_reference = decltype(*QRangeModelDetails::begin(std::declval<range_type&>()));
using const_row_reference = decltype(*QGenericItemModelDetails::cbegin(std::declval<range_type&>())); using const_row_reference = decltype(*QRangeModelDetails::cbegin(std::declval<range_type&>()));
using row_type = std::remove_reference_t<row_reference>; using row_type = std::remove_reference_t<row_reference>;
using protocol_type = QGenericItemModelDetails::wrapped_t<Protocol>; using protocol_type = QRangeModelDetails::wrapped_t<Protocol>;
static_assert(!QGenericItemModelDetails::is_any_of<range_type, std::optional>() && static_assert(!QRangeModelDetails::is_any_of<range_type, std::optional>() &&
!QGenericItemModelDetails::is_any_of<row_type, std::optional>(), !QRangeModelDetails::is_any_of<row_type, std::optional>(),
"Currently, std::optional is not supported for ranges and rows, as " "Currently, std::optional is not supported for ranges and rows, as "
"it has range semantics in c++26. Once the required behavior is clarified, " "it has range semantics in c++26. Once the required behavior is clarified, "
"std::optional for ranges and rows will be supported."); "std::optional for ranges and rows will be supported.");
protected: protected:
using Self = QGenericItemModelImpl<Structure, Range, Protocol>; using Self = QRangeModelImpl<Structure, Range, Protocol>;
Structure& that() { return static_cast<Structure &>(*this); } Structure& that() { return static_cast<Structure &>(*this); }
const Structure& that() const { return static_cast<const Structure &>(*this); } const Structure& that() const { return static_cast<const Structure &>(*this); }
template <typename C> template <typename C>
static constexpr int size(const C &c) static constexpr int size(const C &c)
{ {
if (!QGenericItemModelDetails::isValid(c)) if (!QRangeModelDetails::isValid(c))
return 0; return 0;
if constexpr (QGenericItemModelDetails::test_size<C>()) { if constexpr (QRangeModelDetails::test_size<C>()) {
return int(std::size(c)); return int(std::size(c));
} else { } else {
#if defined(__cpp_lib_ranges) #if defined(__cpp_lib_ranges)
return int(std::ranges::distance(QGenericItemModelDetails::begin(c), return int(std::ranges::distance(QRangeModelDetails::begin(c),
QGenericItemModelDetails::end(c))); QRangeModelDetails::end(c)));
#else #else
return int(std::distance(QGenericItemModelDetails::begin(c), return int(std::distance(QRangeModelDetails::begin(c),
QGenericItemModelDetails::end(c))); QRangeModelDetails::end(c)));
#endif #endif
} }
} }
using range_features = QGenericItemModelDetails::range_traits<range_type>; using range_features = QRangeModelDetails::range_traits<range_type>;
using wrapped_row_type = QGenericItemModelDetails::wrapped_t<row_type>; using wrapped_row_type = QRangeModelDetails::wrapped_t<row_type>;
using row_features = QGenericItemModelDetails::range_traits<wrapped_row_type>; using row_features = QRangeModelDetails::range_traits<wrapped_row_type>;
using row_traits = QGenericItemModelDetails::row_traits<std::remove_cv_t<wrapped_row_type>>; using row_traits = QRangeModelDetails::row_traits<std::remove_cv_t<wrapped_row_type>>;
using protocol_traits = QGenericItemModelDetails::protocol_traits<Range, protocol_type>; using protocol_traits = QRangeModelDetails::protocol_traits<Range, protocol_type>;
static constexpr bool isMutable() static constexpr bool isMutable()
{ {
@ -713,11 +713,11 @@ protected:
&& Structure::is_mutable_impl; && Structure::is_mutable_impl;
} }
static constexpr int static_row_count = QGenericItemModelDetails::static_size_v<range_type>; static constexpr int static_row_count = QRangeModelDetails::static_size_v<range_type>;
static constexpr bool rows_are_raw_pointers = std::is_pointer_v<row_type>; static constexpr bool rows_are_raw_pointers = std::is_pointer_v<row_type>;
static constexpr bool rows_are_owning_or_raw_pointers = static constexpr bool rows_are_owning_or_raw_pointers =
QGenericItemModelDetails::is_owning_or_raw_pointer<row_type>(); QRangeModelDetails::is_owning_or_raw_pointer<row_type>();
static constexpr int static_column_count = QGenericItemModelDetails::static_size_v<row_type>; static constexpr int static_column_count = QRangeModelDetails::static_size_v<row_type>;
static constexpr bool one_dimensional_range = static_column_count == 0; static constexpr bool one_dimensional_range = static_column_count == 0;
static constexpr bool dynamicRows() { return isMutable() && static_row_count < 0; } static constexpr bool dynamicRows() { return isMutable() && static_row_count < 0; }
@ -729,10 +729,10 @@ protected:
using const_row_ptr = const wrapped_row_type *; using const_row_ptr = const wrapped_row_type *;
template <typename T> template <typename T>
static constexpr bool has_metaobject = QGenericItemModelDetails::has_metaobject_v< static constexpr bool has_metaobject = QRangeModelDetails::has_metaobject_v<
std::remove_pointer_t<std::remove_reference_t<T>>>; std::remove_pointer_t<std::remove_reference_t<T>>>;
using ModelData = QGenericItemModelDetails::ModelData<std::conditional_t< using ModelData = QRangeModelDetails::ModelData<std::conditional_t<
std::is_pointer_v<Range>, std::is_pointer_v<Range>,
Range, std::remove_reference_t<Range>> Range, std::remove_reference_t<Range>>
>; >;
@ -769,15 +769,15 @@ protected:
"The range holding a move-only row-type must support insert(pos, start, end)"); "The range holding a move-only row-type must support insert(pos, start, end)");
public: public:
explicit QGenericItemModelImpl(Range &&model, Protocol&& protocol, QGenericItemModel *itemModel) explicit QRangeModelImpl(Range &&model, Protocol&& protocol, QRangeModel *itemModel)
: QGenericItemModelImplBase(itemModel, static_cast<const Self*>(nullptr)) : QRangeModelImplBase(itemModel, static_cast<const Self*>(nullptr))
, m_data{std::forward<Range>(model)} , m_data{std::forward<Range>(model)}
, m_protocol(std::forward<Protocol>(protocol)) , m_protocol(std::forward<Protocol>(protocol))
{ {
} }
// static interface, called by QGenericItemModelImplBase // static interface, called by QRangeModelImplBase
static void callConst(ConstOp op, const QGenericItemModelImplBase *that, void *r, const void *args) static void callConst(ConstOp op, const QRangeModelImplBase *that, void *r, const void *args)
{ {
switch (op) { switch (op) {
case Index: makeCall(that, &Self::index, r, args); case Index: makeCall(that, &Self::index, r, args);
@ -801,7 +801,7 @@ public:
} }
} }
static void call(Op op, QGenericItemModelImplBase *that, void *r, const void *args) static void call(Op op, QRangeModelImplBase *that, void *r, const void *args)
{ {
switch (op) { switch (op) {
case Destroy: delete static_cast<Structure *>(that); case Destroy: delete static_cast<Structure *>(that);
@ -878,7 +878,7 @@ public:
// we didn't remove the const of the range first. // we didn't remove the const of the range first.
const_row_reference row = rowData(index); const_row_reference row = rowData(index);
row_reference mutableRow = const_cast<row_reference>(row); row_reference mutableRow = const_cast<row_reference>(row);
if (QGenericItemModelDetails::isValid(mutableRow)) { if (QRangeModelDetails::isValid(mutableRow)) {
for_element_at(mutableRow, index.column(), [&f](auto &&ref){ for_element_at(mutableRow, index.column(), [&f](auto &&ref){
using target_type = decltype(ref); using target_type = decltype(ref);
if constexpr (std::is_const_v<std::remove_reference_t<target_type>>) if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
@ -928,13 +928,13 @@ public:
const auto readData = [this, column = index.column(), &result, role](const auto &value) { const auto readData = [this, column = index.column(), &result, role](const auto &value) {
Q_UNUSED(this); Q_UNUSED(this);
using value_type = q20::remove_cvref_t<decltype(value)>; using value_type = q20::remove_cvref_t<decltype(value)>;
using multi_role = QGenericItemModelDetails::is_multi_role<value_type>; using multi_role = QRangeModelDetails::is_multi_role<value_type>;
if constexpr (has_metaobject<value_type>) { if constexpr (has_metaobject<value_type>) {
if (row_traits::fixed_size() <= 1) { if (row_traits::fixed_size() <= 1) {
result = readRole(role, QGenericItemModelDetails::pointerTo(value)); result = readRole(role, QRangeModelDetails::pointerTo(value));
} else if (column <= row_traits::fixed_size() } else if (column <= row_traits::fixed_size()
&& (role == Qt::DisplayRole || role == Qt::EditRole)) { && (role == Qt::DisplayRole || role == Qt::EditRole)) {
result = readProperty(column, QGenericItemModelDetails::pointerTo(value)); result = readProperty(column, QRangeModelDetails::pointerTo(value));
} }
} else if constexpr (multi_role::value) { } else if constexpr (multi_role::value) {
const auto it = [this, &value, role]{ const auto it = [this, &value, role]{
@ -945,7 +945,7 @@ public:
return std::as_const(value).find(roleNames().value(role)); return std::as_const(value).find(roleNames().value(role));
}(); }();
if (it != value.cend()) { if (it != value.cend()) {
result = QGenericItemModelDetails::value(it); result = QRangeModelDetails::value(it);
} }
} else if (role == Qt::DisplayRole || role == Qt::EditRole) { } else if (role == Qt::DisplayRole || role == Qt::EditRole) {
result = read(value); result = read(value);
@ -965,14 +965,14 @@ public:
const auto readItemData = [this, &result, &tried](auto &&value){ const auto readItemData = [this, &result, &tried](auto &&value){
Q_UNUSED(this); Q_UNUSED(this);
using value_type = q20::remove_cvref_t<decltype(value)>; using value_type = q20::remove_cvref_t<decltype(value)>;
using multi_role = QGenericItemModelDetails::is_multi_role<value_type>; using multi_role = QRangeModelDetails::is_multi_role<value_type>;
if constexpr (multi_role()) { if constexpr (multi_role()) {
tried = true; tried = true;
if constexpr (std::is_convertible_v<value_type, decltype(result)>) { if constexpr (std::is_convertible_v<value_type, decltype(result)>) {
result = value; result = value;
} else { } else {
for (auto it = std::cbegin(value); it != std::cend(value); ++it) { for (auto it = std::cbegin(value); it != std::cend(value); ++it) {
int role = [this, key = QGenericItemModelDetails::key(it)]() { int role = [this, key = QRangeModelDetails::key(it)]() {
Q_UNUSED(this); Q_UNUSED(this);
if constexpr (multi_role::int_key) if constexpr (multi_role::int_key)
return int(key); return int(key);
@ -981,13 +981,13 @@ public:
}(); }();
if (role != -1) if (role != -1)
result.insert(role, QGenericItemModelDetails::value(it)); result.insert(role, QRangeModelDetails::value(it));
} }
} }
} else if constexpr (has_metaobject<value_type>) { } else if constexpr (has_metaobject<value_type>) {
if (row_traits::fixed_size() <= 1) { if (row_traits::fixed_size() <= 1) {
tried = true; tried = true;
using meta_type = QGenericItemModelDetails::wrapped_t<value_type>; using meta_type = QRangeModelDetails::wrapped_t<value_type>;
const QMetaObject &mo = meta_type::staticMetaObject; const QMetaObject &mo = meta_type::staticMetaObject;
for (auto &&[role, roleName] : roleNames().asKeyValueRange()) { for (auto &&[role, roleName] : roleNames().asKeyValueRange()) {
QVariant data; QVariant data;
@ -999,7 +999,7 @@ public:
if (pi >= 0) { if (pi >= 0) {
const QMetaProperty prop = mo.property(pi); const QMetaProperty prop = mo.property(pi);
if (prop.isValid()) if (prop.isValid())
data = prop.readOnGadget(QGenericItemModelDetails::pointerTo(value)); data = prop.readOnGadget(QRangeModelDetails::pointerTo(value));
} }
} }
if (data.isValid()) if (data.isValid())
@ -1034,7 +1034,7 @@ public:
const auto writeData = [this, column = index.column(), &data, role](auto &&target) -> bool { const auto writeData = [this, column = index.column(), &data, role](auto &&target) -> bool {
using value_type = q20::remove_cvref_t<decltype(target)>; using value_type = q20::remove_cvref_t<decltype(target)>;
using multi_role = QGenericItemModelDetails::is_multi_role<value_type>; using multi_role = QRangeModelDetails::is_multi_role<value_type>;
if constexpr (has_metaobject<value_type>) { if constexpr (has_metaobject<value_type>) {
if (QMetaType::fromType<value_type>() == data.metaType()) { if (QMetaType::fromType<value_type>() == data.metaType()) {
if constexpr (std::is_copy_assignable_v<value_type>) { if constexpr (std::is_copy_assignable_v<value_type>) {
@ -1045,10 +1045,10 @@ public:
return false; return false;
} }
} else if (row_traits::fixed_size() <= 1) { } else if (row_traits::fixed_size() <= 1) {
return writeRole(role, QGenericItemModelDetails::pointerTo(target), data); return writeRole(role, QRangeModelDetails::pointerTo(target), data);
} else if (column <= row_traits::fixed_size() } else if (column <= row_traits::fixed_size()
&& (role == Qt::DisplayRole || role == Qt::EditRole)) { && (role == Qt::DisplayRole || role == Qt::EditRole)) {
return writeProperty(column, QGenericItemModelDetails::pointerTo(target), data); return writeProperty(column, QRangeModelDetails::pointerTo(target), data);
} }
} else if constexpr (multi_role::value) { } else if constexpr (multi_role::value) {
Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role); Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role);
@ -1094,7 +1094,7 @@ public:
auto writeItemData = [this, &tried, &data](auto &target) -> bool { auto writeItemData = [this, &tried, &data](auto &target) -> bool {
Q_UNUSED(this); Q_UNUSED(this);
using value_type = q20::remove_cvref_t<decltype(target)>; using value_type = q20::remove_cvref_t<decltype(target)>;
using multi_role = QGenericItemModelDetails::is_multi_role<value_type>; using multi_role = QRangeModelDetails::is_multi_role<value_type>;
if constexpr (multi_role()) { if constexpr (multi_role()) {
using key_type = typename value_type::key_type; using key_type = typename value_type::key_type;
tried = true; tried = true;
@ -1124,7 +1124,7 @@ public:
} else if constexpr (has_metaobject<value_type>) { } else if constexpr (has_metaobject<value_type>) {
if (row_traits::fixed_size() <= 1) { if (row_traits::fixed_size() <= 1) {
tried = true; tried = true;
using meta_type = QGenericItemModelDetails::wrapped_t<value_type>; using meta_type = QRangeModelDetails::wrapped_t<value_type>;
const QMetaObject &mo = meta_type::staticMetaObject; const QMetaObject &mo = meta_type::staticMetaObject;
// transactional: if possible, modify a copy and only // transactional: if possible, modify a copy and only
// update target if all values from data could be stored. // update target if all values from data could be stored.
@ -1149,7 +1149,7 @@ public:
if (pi >= 0) { if (pi >= 0) {
const QMetaProperty prop = mo.property(pi); const QMetaProperty prop = mo.property(pi);
if (prop.isValid()) if (prop.isValid())
written = prop.writeOnGadget(QGenericItemModelDetails::pointerTo(targetCopy), value); written = prop.writeOnGadget(QRangeModelDetails::pointerTo(targetCopy), value);
} }
} }
if (!written) { if (!written) {
@ -1199,9 +1199,9 @@ public:
if constexpr (has_metaobject<row_type>) { if constexpr (has_metaobject<row_type>) {
if (row_traits::fixed_size() <= 1) { if (row_traits::fixed_size() <= 1) {
// multi-role object/gadget: reset all properties // multi-role object/gadget: reset all properties
return resetProperty(-1, QGenericItemModelDetails::pointerTo(target)); return resetProperty(-1, QRangeModelDetails::pointerTo(target));
} else if (column <= row_traits::fixed_size()) { } else if (column <= row_traits::fixed_size()) {
return resetProperty(column, QGenericItemModelDetails::pointerTo(target)); return resetProperty(column, QRangeModelDetails::pointerTo(target));
} }
} else { // normal structs, values, associative containers } else { // normal structs, values, associative containers
target = {}; target = {};
@ -1226,8 +1226,8 @@ public:
beginInsertColumns(parent, column, column + count - 1); beginInsertColumns(parent, column, column + count - 1);
for (auto &child : *children) { for (auto &child : *children) {
auto it = QGenericItemModelDetails::pos(child, column); auto it = QRangeModelDetails::pos(child, column);
QGenericItemModelDetails::refTo(child).insert(it, count, {}); QRangeModelDetails::refTo(child).insert(it, count, {});
} }
endInsertColumns(); endInsertColumns();
return true; return true;
@ -1247,8 +1247,8 @@ public:
beginRemoveColumns(parent, column, column + count - 1); beginRemoveColumns(parent, column, column + count - 1);
for (auto &child : *children) { for (auto &child : *children) {
const auto start = QGenericItemModelDetails::pos(child, column); const auto start = QRangeModelDetails::pos(child, column);
QGenericItemModelDetails::refTo(child).erase(start, std::next(start, count)); QRangeModelDetails::refTo(child).erase(start, std::next(start, count));
} }
endRemoveColumns(); endRemoveColumns();
return true; return true;
@ -1279,9 +1279,9 @@ public:
} }
for (auto &child : *children) { for (auto &child : *children) {
const auto first = QGenericItemModelDetails::pos(child, sourceColumn); const auto first = QRangeModelDetails::pos(child, sourceColumn);
const auto middle = std::next(first, count); const auto middle = std::next(first, count);
const auto last = QGenericItemModelDetails::pos(child, destColumn); const auto last = QRangeModelDetails::pos(child, destColumn);
if (sourceColumn < destColumn) // moving right if (sourceColumn < destColumn) // moving right
std::rotate(first, middle, last); std::rotate(first, middle, last);
@ -1307,7 +1307,7 @@ public:
beginInsertRows(parent, row, row + count - 1); beginInsertRows(parent, row, row + count - 1);
const auto pos = QGenericItemModelDetails::pos(children, row); const auto pos = QRangeModelDetails::pos(children, row);
if constexpr (range_features::has_insert_range) { if constexpr (range_features::has_insert_range) {
children->insert(pos, generator, EmptyRowGenerator{count}); children->insert(pos, generator, EmptyRowGenerator{count});
} else if constexpr (rows_are_owning_or_raw_pointers) { } else if constexpr (rows_are_owning_or_raw_pointers) {
@ -1352,7 +1352,7 @@ public:
} }
} }
{ // erase invalidates iterators { // erase invalidates iterators
const auto begin = QGenericItemModelDetails::pos(children, row); const auto begin = QRangeModelDetails::pos(children, row);
const auto end = std::next(begin, count); const auto end = std::next(begin, count);
that().deleteRemovedRows(begin, end); that().deleteRemovedRows(begin, end);
children->erase(begin, end); children->erase(begin, end);
@ -1397,9 +1397,9 @@ public:
if (!beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow)) if (!beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow))
return false; return false;
const auto first = QGenericItemModelDetails::pos(source, sourceRow); const auto first = QRangeModelDetails::pos(source, sourceRow);
const auto middle = std::next(first, count); const auto middle = std::next(first, count);
const auto last = QGenericItemModelDetails::pos(source, destRow); const auto last = QRangeModelDetails::pos(source, destRow);
if (sourceRow < destRow) // moving down if (sourceRow < destRow) // moving down
std::rotate(first, middle, last); std::rotate(first, middle, last);
@ -1416,7 +1416,7 @@ public:
} }
protected: protected:
~QGenericItemModelImpl() ~QRangeModelImpl()
{ {
// We delete row objects if we are not operating on a reference or pointer // We delete row objects if we are not operating on a reference or pointer
// to a range, as in that case, the owner of the referenced/pointed to // to a range, as in that case, the owner of the referenced/pointed to
@ -1426,9 +1426,9 @@ protected:
// client can never delete those. But copied rows will be the same pointer, // client can never delete those. But copied rows will be the same pointer,
// which we must not delete (as we didn't create them). // which we must not delete (as we didn't create them).
if constexpr (protocol_traits::has_deleteRow && !std::is_pointer_v<Range> if constexpr (protocol_traits::has_deleteRow && !std::is_pointer_v<Range>
&& !QGenericItemModelDetails::is_any_of<Range, std::reference_wrapper>()) { && !QRangeModelDetails::is_any_of<Range, std::reference_wrapper>()) {
const auto begin = QGenericItemModelDetails::begin(*m_data.model()); const auto begin = QRangeModelDetails::begin(*m_data.model());
const auto end = QGenericItemModelDetails::end(*m_data.model()); const auto end = QRangeModelDetails::end(*m_data.model());
that().deleteRemovedRows(begin, end); that().deleteRemovedRows(begin, end);
} }
} }
@ -1461,9 +1461,9 @@ protected:
if constexpr (one_dimensional_range) { if constexpr (one_dimensional_range) {
result = writer(row); result = writer(row);
} else if (QGenericItemModelDetails::isValid(row)) { } else if (QRangeModelDetails::isValid(row)) {
if constexpr (dynamicColumns()) { if constexpr (dynamicColumns()) {
result = writer(*QGenericItemModelDetails::pos(row, index.column())); result = writer(*QRangeModelDetails::pos(row, index.column()));
} else { } else {
for_element_at(row, index.column(), [&writer, &result](auto &&target) { for_element_at(row, index.column(), [&writer, &result](auto &&target) {
using target_type = decltype(target); using target_type = decltype(target);
@ -1484,9 +1484,9 @@ protected:
const_row_reference row = rowData(index); const_row_reference row = rowData(index);
if constexpr (one_dimensional_range) { if constexpr (one_dimensional_range) {
return reader(row); return reader(row);
} else if (QGenericItemModelDetails::isValid(row)) { } else if (QRangeModelDetails::isValid(row)) {
if constexpr (dynamicColumns()) if constexpr (dynamicColumns())
reader(*QGenericItemModelDetails::cpos(row, index.column())); reader(*QRangeModelDetails::cpos(row, index.column()));
else else
for_element_at(row, index.column(), std::forward<F>(reader)); for_element_at(row, index.column(), std::forward<F>(reader));
} }
@ -1683,8 +1683,8 @@ protected:
} }
const protocol_type& protocol() const { return QGenericItemModelDetails::refTo(m_protocol); } const protocol_type& protocol() const { return QRangeModelDetails::refTo(m_protocol); }
protocol_type& protocol() { return QGenericItemModelDetails::refTo(m_protocol); } protocol_type& protocol() { return QRangeModelDetails::refTo(m_protocol); }
ModelData m_data; ModelData m_data;
Protocol m_protocol; Protocol m_protocol;
@ -1695,10 +1695,10 @@ protected:
// support through a protocol type. // support through a protocol type.
template <typename Range, typename Protocol> template <typename Range, typename Protocol>
class QGenericTreeItemModelImpl class QGenericTreeItemModelImpl
: public QGenericItemModelImpl<QGenericTreeItemModelImpl<Range, Protocol>, Range, Protocol> : public QRangeModelImpl<QGenericTreeItemModelImpl<Range, Protocol>, Range, Protocol>
{ {
using Base = QGenericItemModelImpl<QGenericTreeItemModelImpl<Range, Protocol>, Range, Protocol>; using Base = QRangeModelImpl<QGenericTreeItemModelImpl<Range, Protocol>, Range, Protocol>;
friend class QGenericItemModelImpl<QGenericTreeItemModelImpl<Range, Protocol>, Range, Protocol>; friend class QRangeModelImpl<QGenericTreeItemModelImpl<Range, Protocol>, Range, Protocol>;
using range_type = typename Base::range_type; using range_type = typename Base::range_type;
using range_features = typename Base::range_features; using range_features = typename Base::range_features;
@ -1710,12 +1710,12 @@ class QGenericTreeItemModelImpl
static constexpr bool is_mutable_impl = tree_traits::has_mutable_childRows; static constexpr bool is_mutable_impl = tree_traits::has_mutable_childRows;
static constexpr bool rows_are_any_refs_or_pointers = Base::rows_are_raw_pointers || static constexpr bool rows_are_any_refs_or_pointers = Base::rows_are_raw_pointers ||
QGenericItemModelDetails::is_smart_ptr<row_type>() || QRangeModelDetails::is_smart_ptr<row_type>() ||
QGenericItemModelDetails::is_any_of<row_type, std::reference_wrapper>(); QRangeModelDetails::is_any_of<row_type, std::reference_wrapper>();
static_assert(!Base::dynamicColumns(), "A tree must have a static number of columns!"); static_assert(!Base::dynamicColumns(), "A tree must have a static number of columns!");
public: public:
QGenericTreeItemModelImpl(Range &&model, Protocol &&p, QGenericItemModel *itemModel) QGenericTreeItemModelImpl(Range &&model, Protocol &&p, QRangeModel *itemModel)
: Base(std::forward<Range>(model), std::forward<Protocol>(p), itemModel) : Base(std::forward<Range>(model), std::forward<Protocol>(p), itemModel)
{}; {};
@ -1730,8 +1730,8 @@ protected:
const_row_ptr grandParent = static_cast<const_row_ptr>(parent.constInternalPointer()); const_row_ptr grandParent = static_cast<const_row_ptr>(parent.constInternalPointer());
const auto &parentSiblings = childrenOf(grandParent); const auto &parentSiblings = childrenOf(grandParent);
const auto it = QGenericItemModelDetails::cpos(parentSiblings, parent.row()); const auto it = QRangeModelDetails::cpos(parentSiblings, parent.row());
return this->createIndex(row, column, QGenericItemModelDetails::pointerTo(*it)); return this->createIndex(row, column, QRangeModelDetails::pointerTo(*it));
} }
QModelIndex parent(const QModelIndex &child) const QModelIndex parent(const QModelIndex &child) const
@ -1745,17 +1745,17 @@ protected:
return {}; return {};
// get the siblings of the parent via the grand parent // get the siblings of the parent via the grand parent
decltype(auto) grandParent = this->protocol().parentRow(QGenericItemModelDetails::refTo(parentRow)); decltype(auto) grandParent = this->protocol().parentRow(QRangeModelDetails::refTo(parentRow));
const range_type &parentSiblings = childrenOf(QGenericItemModelDetails::pointerTo(grandParent)); const range_type &parentSiblings = childrenOf(QRangeModelDetails::pointerTo(grandParent));
// find the index of parentRow // find the index of parentRow
const auto begin = QGenericItemModelDetails::cbegin(parentSiblings); const auto begin = QRangeModelDetails::cbegin(parentSiblings);
const auto end = QGenericItemModelDetails::cend(parentSiblings); const auto end = QRangeModelDetails::cend(parentSiblings);
const auto it = std::find_if(begin, end, [parentRow](auto &&s){ const auto it = std::find_if(begin, end, [parentRow](auto &&s){
return QGenericItemModelDetails::pointerTo(s) == parentRow; return QRangeModelDetails::pointerTo(s) == parentRow;
}); });
if (it != end) if (it != end)
return this->createIndex(std::distance(begin, it), 0, return this->createIndex(std::distance(begin, it), 0,
QGenericItemModelDetails::pointerTo(grandParent)); QRangeModelDetails::pointerTo(grandParent));
return {}; return {};
} }
@ -1826,9 +1826,9 @@ protected:
// If we can insert data from another range into, then // If we can insert data from another range into, then
// use that to move the old data over. // use that to move the old data over.
const auto destStart = QGenericItemModelDetails::pos(destination, destRow); const auto destStart = QRangeModelDetails::pos(destination, destRow);
if constexpr (range_features::has_insert_range) { if constexpr (range_features::has_insert_range) {
const auto sourceStart = QGenericItemModelDetails::pos(*source, sourceRow); const auto sourceStart = QRangeModelDetails::pos(*source, sourceRow);
const auto sourceEnd = std::next(sourceStart, count); const auto sourceEnd = std::next(sourceStart, count);
destination->insert(destStart, std::move_iterator(sourceStart), destination->insert(destStart, std::move_iterator(sourceStart),
@ -1839,7 +1839,7 @@ protected:
} }
row_ptr parentRow = destParent.isValid() row_ptr parentRow = destParent.isValid()
? QGenericItemModelDetails::pointerTo(this->rowData(destParent)) ? QRangeModelDetails::pointerTo(this->rowData(destParent))
: nullptr; : nullptr;
// if the source's parent was already inside the new parent row, // if the source's parent was already inside the new parent row,
@ -1856,9 +1856,9 @@ protected:
// move the data over and update the parent pointer // move the data over and update the parent pointer
{ {
const auto writeStart = QGenericItemModelDetails::pos(destination, destRow); const auto writeStart = QRangeModelDetails::pos(destination, destRow);
const auto writeEnd = std::next(writeStart, count); const auto writeEnd = std::next(writeStart, count);
const auto sourceStart = QGenericItemModelDetails::pos(source, sourceRow); const auto sourceStart = QRangeModelDetails::pos(source, sourceRow);
const auto sourceEnd = std::next(sourceStart, count); const auto sourceEnd = std::next(sourceStart, count);
for (auto write = writeStart, read = sourceStart; write != writeEnd; ++write, ++read) { for (auto write = writeStart, read = sourceStart; write != writeEnd; ++write, ++read) {
@ -1866,7 +1866,7 @@ protected:
// only fix the parent pointer // only fix the parent pointer
if constexpr (!range_features::has_insert_range) if constexpr (!range_features::has_insert_range)
*write = std::move(*read); *write = std::move(*read);
this->protocol().setParentRow(QGenericItemModelDetails::refTo(*write), parentRow); this->protocol().setParentRow(QRangeModelDetails::refTo(*write), parentRow);
} }
// remove the old rows from the source parent // remove the old rows from the source parent
source->erase(sourceStart, sourceEnd); source->erase(sourceStart, sourceEnd);
@ -1889,9 +1889,9 @@ protected:
// to change the parent of a row. // to change the parent of a row.
static_assert(tree_traits::has_setParentRow); static_assert(tree_traits::has_setParentRow);
row_type empty_row = this->protocol().newRow(); row_type empty_row = this->protocol().newRow();
if (QGenericItemModelDetails::isValid(empty_row) && parent.isValid()) { if (QRangeModelDetails::isValid(empty_row) && parent.isValid()) {
this->protocol().setParentRow(QGenericItemModelDetails::refTo(empty_row), this->protocol().setParentRow(QRangeModelDetails::refTo(empty_row),
QGenericItemModelDetails::pointerTo(this->rowData(parent))); QRangeModelDetails::pointerTo(this->rowData(parent)));
} }
return empty_row; return empty_row;
} }
@ -1908,15 +1908,15 @@ protected:
void resetParentInChildren(range_type *children) void resetParentInChildren(range_type *children)
{ {
if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) { if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) {
const auto begin = QGenericItemModelDetails::begin(*children); const auto begin = QRangeModelDetails::begin(*children);
const auto end = QGenericItemModelDetails::end(*children); const auto end = QRangeModelDetails::end(*children);
for (auto it = begin; it != end; ++it) { for (auto it = begin; it != end; ++it) {
if (auto &maybeChildren = this->protocol().childRows(*it)) { if (auto &maybeChildren = this->protocol().childRows(*it)) {
QModelIndexList fromIndexes; QModelIndexList fromIndexes;
QModelIndexList toIndexes; QModelIndexList toIndexes;
fromIndexes.reserve(Base::size(*maybeChildren)); fromIndexes.reserve(Base::size(*maybeChildren));
toIndexes.reserve(Base::size(*maybeChildren)); toIndexes.reserve(Base::size(*maybeChildren));
auto *parentRow = QGenericItemModelDetails::pointerTo(*it); auto *parentRow = QRangeModelDetails::pointerTo(*it);
int row = 0; int row = 0;
for (auto &child : *maybeChildren) { for (auto &child : *maybeChildren) {
@ -1929,7 +1929,7 @@ protected:
++row; ++row;
} }
this->changePersistentIndexList(fromIndexes, toIndexes); this->changePersistentIndexList(fromIndexes, toIndexes);
resetParentInChildren(QGenericItemModelDetails::pointerTo(*maybeChildren)); resetParentInChildren(QRangeModelDetails::pointerTo(*maybeChildren));
} }
} }
} }
@ -1940,7 +1940,7 @@ protected:
const_row_ptr parentRow = static_cast<const_row_ptr>(index.constInternalPointer()); const_row_ptr parentRow = static_cast<const_row_ptr>(index.constInternalPointer());
const range_type &siblings = childrenOf(parentRow); const range_type &siblings = childrenOf(parentRow);
Q_ASSERT(index.row() < int(Base::size(siblings))); Q_ASSERT(index.row() < int(Base::size(siblings)));
return *QGenericItemModelDetails::cpos(siblings, index.row()); return *QRangeModelDetails::cpos(siblings, index.row());
} }
decltype(auto) rowDataImpl(const QModelIndex &index) decltype(auto) rowDataImpl(const QModelIndex &index)
@ -1948,47 +1948,47 @@ protected:
row_ptr parentRow = static_cast<row_ptr>(index.internalPointer()); row_ptr parentRow = static_cast<row_ptr>(index.internalPointer());
range_type &siblings = childrenOf(parentRow); range_type &siblings = childrenOf(parentRow);
Q_ASSERT(index.row() < int(Base::size(siblings))); Q_ASSERT(index.row() < int(Base::size(siblings)));
return *QGenericItemModelDetails::pos(siblings, index.row()); return *QRangeModelDetails::pos(siblings, index.row());
} }
const range_type *childRangeImpl(const QModelIndex &index) const const range_type *childRangeImpl(const QModelIndex &index) const
{ {
const auto &row = this->rowData(index); const auto &row = this->rowData(index);
if (!QGenericItemModelDetails::isValid(row)) if (!QRangeModelDetails::isValid(row))
return static_cast<const range_type *>(nullptr); return static_cast<const range_type *>(nullptr);
decltype(auto) children = this->protocol().childRows(QGenericItemModelDetails::refTo(row)); decltype(auto) children = this->protocol().childRows(QRangeModelDetails::refTo(row));
return QGenericItemModelDetails::pointerTo(std::forward<decltype(children)>(children)); return QRangeModelDetails::pointerTo(std::forward<decltype(children)>(children));
} }
range_type *childRangeImpl(const QModelIndex &index) range_type *childRangeImpl(const QModelIndex &index)
{ {
auto &row = this->rowData(index); auto &row = this->rowData(index);
if (!QGenericItemModelDetails::isValid(row)) if (!QRangeModelDetails::isValid(row))
return static_cast<range_type *>(nullptr); return static_cast<range_type *>(nullptr);
decltype(auto) children = this->protocol().childRows(QGenericItemModelDetails::refTo(row)); decltype(auto) children = this->protocol().childRows(QRangeModelDetails::refTo(row));
using Children = std::remove_reference_t<decltype(children)>; using Children = std::remove_reference_t<decltype(children)>;
if constexpr (QGenericItemModelDetails::is_any_of<Children, std::optional>() if constexpr (QRangeModelDetails::is_any_of<Children, std::optional>()
&& std::is_default_constructible<typename Children::value_type>()) { && std::is_default_constructible<typename Children::value_type>()) {
if (!children) if (!children)
children.emplace(range_type{}); children.emplace(range_type{});
} }
return QGenericItemModelDetails::pointerTo(std::forward<decltype(children)>(children)); return QRangeModelDetails::pointerTo(std::forward<decltype(children)>(children));
} }
const range_type &childrenOf(const_row_ptr row) const const range_type &childrenOf(const_row_ptr row) const
{ {
return row ? QGenericItemModelDetails::refTo(this->protocol().childRows(*row)) return row ? QRangeModelDetails::refTo(this->protocol().childRows(*row))
: *this->m_data.model(); : *this->m_data.model();
} }
private: private:
range_type &childrenOf(row_ptr row) range_type &childrenOf(row_ptr row)
{ {
return row ? QGenericItemModelDetails::refTo(this->protocol().childRows(*row)) return row ? QRangeModelDetails::refTo(this->protocol().childRows(*row))
: *this->m_data.model(); : *this->m_data.model();
} }
}; };
@ -1996,10 +1996,10 @@ private:
// specialization for flat models without protocol // specialization for flat models without protocol
template <typename Range> template <typename Range>
class QGenericTableItemModelImpl class QGenericTableItemModelImpl
: public QGenericItemModelImpl<QGenericTableItemModelImpl<Range>, Range> : public QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>
{ {
using Base = QGenericItemModelImpl<QGenericTableItemModelImpl<Range>, Range>; using Base = QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>;
friend class QGenericItemModelImpl<QGenericTableItemModelImpl<Range>, Range>; friend class QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>;
using range_type = typename Base::range_type; using range_type = typename Base::range_type;
using range_features = typename Base::range_features; using range_features = typename Base::range_features;
@ -2011,7 +2011,7 @@ class QGenericTableItemModelImpl
static constexpr bool is_mutable_impl = true; static constexpr bool is_mutable_impl = true;
public: public:
explicit QGenericTableItemModelImpl(Range &&model, QGenericItemModel *itemModel) explicit QGenericTableItemModelImpl(Range &&model, QRangeModel *itemModel)
: Base(std::forward<Range>(model), {}, itemModel) : Base(std::forward<Range>(model), {}, itemModel)
{} {}
@ -2019,10 +2019,10 @@ protected:
QModelIndex indexImpl(int row, int column, const QModelIndex &) const QModelIndex indexImpl(int row, int column, const QModelIndex &) const
{ {
if constexpr (Base::dynamicColumns()) { if constexpr (Base::dynamicColumns()) {
if (column < int(Base::size(*QGenericItemModelDetails::cpos(*this->m_data.model(), row)))) if (column < int(Base::size(*QRangeModelDetails::cpos(*this->m_data.model(), row))))
return this->createIndex(row, column); return this->createIndex(row, column);
// if we got here, then column < columnCount(), but this row is to short // if we got here, then column < columnCount(), but this row is to short
qCritical("QGenericItemModel: Column-range at row %d is not large enough!", row); qCritical("QRangeModel: Column-range at row %d is not large enough!", row);
return {}; return {};
} else { } else {
return this->createIndex(row, column); return this->createIndex(row, column);
@ -2050,7 +2050,7 @@ protected:
if constexpr (Base::dynamicColumns()) { if constexpr (Base::dynamicColumns()) {
return int(Base::size(*this->m_data.model()) == 0 return int(Base::size(*this->m_data.model()) == 0
? 0 ? 0
: Base::size(*QGenericItemModelDetails::cbegin(*this->m_data.model()))); : Base::size(*QRangeModelDetails::cbegin(*this->m_data.model())));
} else if constexpr (Base::one_dimensional_range) { } else if constexpr (Base::one_dimensional_range) {
return row_traits::fixed_size(); return row_traits::fixed_size();
} else { } else {
@ -2096,8 +2096,8 @@ protected:
// dynamically sized rows all have to have the same column count // dynamically sized rows all have to have the same column count
if constexpr (Base::dynamicColumns() && row_features::has_resize) { if constexpr (Base::dynamicColumns() && row_features::has_resize) {
if (QGenericItemModelDetails::isValid(empty_row)) if (QRangeModelDetails::isValid(empty_row))
QGenericItemModelDetails::refTo(empty_row).resize(this->itemModel().columnCount()); QRangeModelDetails::refTo(empty_row).resize(this->itemModel().columnCount());
} }
return empty_row; return empty_row;
@ -2115,13 +2115,13 @@ protected:
decltype(auto) rowDataImpl(const QModelIndex &index) const decltype(auto) rowDataImpl(const QModelIndex &index) const
{ {
Q_ASSERT(index.row() < int(Base::size(*this->m_data.model()))); Q_ASSERT(index.row() < int(Base::size(*this->m_data.model())));
return *QGenericItemModelDetails::cpos(*this->m_data.model(), index.row()); return *QRangeModelDetails::cpos(*this->m_data.model(), index.row());
} }
decltype(auto) rowDataImpl(const QModelIndex &index) decltype(auto) rowDataImpl(const QModelIndex &index)
{ {
Q_ASSERT(index.row() < int(Base::size(*this->m_data.model()))); Q_ASSERT(index.row() < int(Base::size(*this->m_data.model())));
return *QGenericItemModelDetails::pos(*this->m_data.model(), index.row()); return *QRangeModelDetails::pos(*this->m_data.model(), index.row());
} }
auto childRangeImpl(const QModelIndex &) const auto childRangeImpl(const QModelIndex &) const
@ -2149,4 +2149,4 @@ QT_END_NAMESPACE
#endif // Q_QDOC #endif // Q_QDOC
#endif // QGENERICITEMMODEL_IMPL_H #endif // QRANGEMODEL_IMPL_H

View File

@ -2,7 +2,7 @@
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qstringlistmodel) add_subdirectory(qstringlistmodel)
add_subdirectory(qgenericitemmodel) add_subdirectory(qrangemodel)
if(TARGET Qt::Gui) if(TARGET Qt::Gui)
add_subdirectory(qabstractitemmodel) add_subdirectory(qabstractitemmodel)
if(QT_FEATURE_proxymodel) if(QT_FEATURE_proxymodel)

View File

@ -2,18 +2,18 @@
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
##################################################################### #####################################################################
## tst_qgenericitemmodel Test: ## tst_qrangemodel Test:
##################################################################### #####################################################################
if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(tst_qgenericitemmodel LANGUAGES CXX) project(tst_qrangemodel LANGUAGES CXX)
find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
endif() endif()
qt_internal_add_test(tst_qgenericitemmodel qt_internal_add_test(tst_qrangemodel
SOURCES SOURCES
tst_qgenericitemmodel.cpp tst_qrangemodel.cpp
LIBRARIES LIBRARIES
Qt::Gui Qt::Gui
) )
@ -24,6 +24,6 @@ if (
# gcc 10.2.0 chokes in a standard library header # gcc 10.2.0 chokes in a standard library header
(NOT CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.2.0)) (NOT CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.2.0))
if ("${CMAKE_CXX_COMPILE_FEATURES}" MATCHES "cxx_std_20") if ("${CMAKE_CXX_COMPILE_FEATURES}" MATCHES "cxx_std_20")
set_property(TARGET tst_qgenericitemmodel PROPERTY CXX_STANDARD 20) set_property(TARGET tst_qrangemodel PROPERTY CXX_STANDARD 20)
endif() endif()
endif() endif()

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest> #include <QTest>
#include <QtCore/qgenericitemmodel.h> #include <QtCore/qrangemodel.h>
#include <QtCore/qjsondocument.h> #include <QtCore/qjsondocument.h>
#include <QtCore/qjsonarray.h> #include <QtCore/qjsonarray.h>
@ -273,7 +273,7 @@ namespace std {
{ using type = decltype(get<I>(std::declval<tree_row>())); }; { using type = decltype(get<I>(std::declval<tree_row>())); };
} }
class tst_QGenericItemModel : public QObject class tst_QRangeModel : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -459,7 +459,7 @@ private:
{"green", Qt::green, "0x00ff00"}, {"green", Qt::green, "0x00ff00"},
{"blue", Qt::blue, "0x0000ff"}, {"blue", Qt::blue, "0x0000ff"},
}; };
std::vector<QGenericItemModel::SingleColumn<Item>> listOfGadgets = { std::vector<QRangeModel::SingleColumn<Item>> listOfGadgets = {
{{"red", Qt::red, "0xff0000"}}, {{"red", Qt::red, "0xff0000"}},
{{"green", Qt::green, "0x00ff00"}}, {{"green", Qt::green, "0x00ff00"}},
{{"blue", Qt::blue, "0x0000ff"}}, {{"blue", Qt::blue, "0x0000ff"}},
@ -480,7 +480,7 @@ private:
MetaObjectTuple mot1; MetaObjectTuple mot1;
MetaObjectTuple mot2; MetaObjectTuple mot2;
MetaObjectTuple mot3; MetaObjectTuple mot3;
std::vector<QGenericItemModel::SingleColumn<MetaObjectTuple *>> listOfMetaObjectTuple = { std::vector<QRangeModel::SingleColumn<MetaObjectTuple *>> listOfMetaObjectTuple = {
&mot1, &mot1,
&mot2, &mot2,
&mot3, &mot3,
@ -488,7 +488,7 @@ private:
MetaObjectTuple mot4; MetaObjectTuple mot4;
MetaObjectTuple mot5; MetaObjectTuple mot5;
MetaObjectTuple mot6; MetaObjectTuple mot6;
std::vector<QGenericItemModel::MultiColumn<MetaObjectTuple *>> tableOfMetaObjectTuple = { std::vector<QRangeModel::MultiColumn<MetaObjectTuple *>> tableOfMetaObjectTuple = {
{&mot4}, {&mot4},
{&mot5}, {&mot5},
{&mot6}, {&mot6},
@ -613,7 +613,7 @@ public:
Q_DECLARE_FLAGS(ChangeActions, ChangeAction); Q_DECLARE_FLAGS(ChangeActions, ChangeAction);
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(tst_QGenericItemModel::ChangeActions) Q_DECLARE_OPERATORS_FOR_FLAGS(tst_QRangeModel::ChangeActions)
using Factory = std::function<std::unique_ptr<QAbstractItemModel>()>; using Factory = std::function<std::unique_ptr<QAbstractItemModel>()>;
@ -629,7 +629,7 @@ void createBackup(QObject* object, T& model) {
template <typename T, std::enable_if_t<!std::is_copy_assignable_v<T>, bool> = true> template <typename T, std::enable_if_t<!std::is_copy_assignable_v<T>, bool> = true>
void createBackup(QObject* , T& ) {} void createBackup(QObject* , T& ) {}
void tst_QGenericItemModel::createTestData() void tst_QRangeModel::createTestData()
{ {
m_data.reset(new Data); m_data.reset(new Data);
@ -643,7 +643,7 @@ void tst_QGenericItemModel::createTestData()
#define ADD_HELPER(Model, Tag, Policy, ColumnCount, Actions) \ #define ADD_HELPER(Model, Tag, Policy, ColumnCount, Actions) \
{ \ { \
Factory factory = [this]() -> std::unique_ptr<QAbstractItemModel> { \ Factory factory = [this]() -> std::unique_ptr<QAbstractItemModel> { \
auto result = std::make_unique<QGenericItemModel>(Policy(m_data->Model)); \ auto result = std::make_unique<QRangeModel>(Policy(m_data->Model)); \
createBackup(result.get(), m_data->Model); \ createBackup(result.get(), m_data->Model); \
return result; \ return result; \
}; \ }; \
@ -735,7 +735,7 @@ void tst_QGenericItemModel::createTestData()
{"2/0", "2/1", "2/2", "2/3"}, {"2/0", "2/1", "2/2", "2/3"},
{"3/0", "3/1", "3/2", "3/3"}, {"3/0", "3/1", "3/2", "3/3"},
}; };
return std::unique_ptr<QAbstractItemModel>(new QGenericItemModel(std::move(movedTable))); return std::unique_ptr<QAbstractItemModel>(new QRangeModel(std::move(movedTable)));
}) << 4 << 4 << ChangeActions(ChangeAction::All); }) << 4 << 4 << ChangeActions(ChangeAction::All);
// moved list of pointers -> model takes ownership // moved list of pointers -> model takes ownership
@ -746,25 +746,25 @@ void tst_QGenericItemModel::createTestData()
}; };
return std::unique_ptr<QAbstractItemModel>( return std::unique_ptr<QAbstractItemModel>(
new QGenericItemModel(std::move(movedListOfObjects)) new QRangeModel(std::move(movedListOfObjects))
); );
}) << 6 << 2 << (ChangeAction::ChangeRows | ChangeAction::SetData); }) << 6 << 2 << (ChangeAction::ChangeRows | ChangeAction::SetData);
// special case: tree // special case: tree
QTest::addRow("value tree (ref)") << Factory([this]{ QTest::addRow("value tree (ref)") << Factory([this]{
return std::unique_ptr<QAbstractItemModel>(new QGenericItemModel(std::ref(*m_data->m_tree))); return std::unique_ptr<QAbstractItemModel>(new QRangeModel(std::ref(*m_data->m_tree)));
}) << int(std::size(*m_data->m_tree.get())) << int(std::tuple_size_v<tree_row>) }) << int(std::size(*m_data->m_tree.get())) << int(std::tuple_size_v<tree_row>)
<< (ChangeAction::ChangeRows | ChangeAction::SetData); << (ChangeAction::ChangeRows | ChangeAction::SetData);
QTest::addRow("pointer tree") << Factory([this]{ QTest::addRow("pointer tree") << Factory([this]{
return std::unique_ptr<QAbstractItemModel>( return std::unique_ptr<QAbstractItemModel>(
new QGenericItemModel(m_data->m_pointer_tree.get(), tree_row::ProtocolPointerImpl{}) new QRangeModel(m_data->m_pointer_tree.get(), tree_row::ProtocolPointerImpl{})
); );
}) << int(std::size(*m_data->m_pointer_tree.get())) << int(std::tuple_size_v<tree_row>) }) << int(std::size(*m_data->m_pointer_tree.get())) << int(std::tuple_size_v<tree_row>)
<< (ChangeAction::ChangeRows | ChangeAction::SetData); << (ChangeAction::ChangeRows | ChangeAction::SetData);
} }
void tst_QGenericItemModel::basics() void tst_QRangeModel::basics()
{ {
#if QT_CONFIG(itemmodeltester) #if QT_CONFIG(itemmodeltester)
QFETCH(Factory, factory); QFETCH(Factory, factory);
@ -778,25 +778,25 @@ void tst_QGenericItemModel::basics()
using ModelFromData = std::function<std::unique_ptr<QAbstractItemModel>(std::vector<int> &)>; using ModelFromData = std::function<std::unique_ptr<QAbstractItemModel>(std::vector<int> &)>;
void tst_QGenericItemModel::modifies_data() void tst_QRangeModel::modifies_data()
{ {
QTest::addColumn<ModelFromData>("modelFromData"); QTest::addColumn<ModelFromData>("modelFromData");
QTest::addColumn<bool>("modifiesOriginal"); QTest::addColumn<bool>("modifiesOriginal");
QTest::newRow("copy") << ModelFromData([](std::vector<int> &numbers){ QTest::newRow("copy") << ModelFromData([](std::vector<int> &numbers){
return std::unique_ptr<QAbstractItemModel>(new QGenericItemModel(numbers)); return std::unique_ptr<QAbstractItemModel>(new QRangeModel(numbers));
}) << false; }) << false;
QTest::newRow("reference_wrapper") << ModelFromData([](std::vector<int> &numbers){ QTest::newRow("reference_wrapper") << ModelFromData([](std::vector<int> &numbers){
return std::unique_ptr<QAbstractItemModel>(new QGenericItemModel(std::ref(numbers))); return std::unique_ptr<QAbstractItemModel>(new QRangeModel(std::ref(numbers)));
}) << true; }) << true;
QTest::newRow("pointer") << ModelFromData([](std::vector<int> &numbers){ QTest::newRow("pointer") << ModelFromData([](std::vector<int> &numbers){
return std::unique_ptr<QAbstractItemModel>(new QGenericItemModel(&numbers)); return std::unique_ptr<QAbstractItemModel>(new QRangeModel(&numbers));
}) << true; }) << true;
} }
void tst_QGenericItemModel::modifies() void tst_QRangeModel::modifies()
{ {
QFETCH(ModelFromData, modelFromData); QFETCH(ModelFromData, modelFromData);
QFETCH(bool, modifiesOriginal); QFETCH(bool, modifiesOriginal);
@ -824,7 +824,7 @@ void tst_QGenericItemModel::modifies()
} }
} }
void tst_QGenericItemModel::minimalIterator() void tst_QRangeModel::minimalIterator()
{ {
struct Minimal struct Minimal
{ {
@ -861,7 +861,7 @@ void tst_QGenericItemModel::minimalIterator()
int m_size; int m_size;
} minimal{100}; } minimal{100};
QGenericItemModel model(minimal); QRangeModel model(minimal);
QCOMPARE(model.rowCount(), minimal.m_size); QCOMPARE(model.rowCount(), minimal.m_size);
for (int row = model.rowCount() - 1; row >= 0; --row) { for (int row = model.rowCount() - 1; row >= 0; --row) {
const QModelIndex index = model.index(row, 0); const QModelIndex index = model.index(row, 0);
@ -870,12 +870,12 @@ void tst_QGenericItemModel::minimalIterator()
} }
} }
void tst_QGenericItemModel::ranges() void tst_QRangeModel::ranges()
{ {
#if defined(__cpp_lib_ranges) #if defined(__cpp_lib_ranges)
const int lowest = 1; const int lowest = 1;
const int highest = 10; const int highest = 10;
QGenericItemModel model(std::views::iota(lowest, highest)); QRangeModel model(std::views::iota(lowest, highest));
QCOMPARE(model.rowCount(), highest - lowest); QCOMPARE(model.rowCount(), highest - lowest);
QCOMPARE(model.columnCount(), 1); QCOMPARE(model.columnCount(), 1);
#else #else
@ -883,18 +883,18 @@ void tst_QGenericItemModel::ranges()
#endif #endif
} }
void tst_QGenericItemModel::json() void tst_QRangeModel::json()
{ {
QJsonDocument json = QJsonDocument::fromJson(R"([ "one", "two" ])"); QJsonDocument json = QJsonDocument::fromJson(R"([ "one", "two" ])");
QVERIFY(json.isArray()); QVERIFY(json.isArray());
QGenericItemModel model(json.array()); QRangeModel model(json.array());
QCOMPARE(model.rowCount(), 2); QCOMPARE(model.rowCount(), 2);
const QModelIndex index = model.index(1, 0); const QModelIndex index = model.index(1, 0);
QVERIFY(index.isValid()); QVERIFY(index.isValid());
QCOMPARE(index.data().toString(), "two"); QCOMPARE(index.data().toString(), "two");
} }
void tst_QGenericItemModel::ownership() void tst_QRangeModel::ownership()
{ {
{ // a list of pointers to objects { // a list of pointers to objects
Object *object = new Object; Object *object = new Object;
@ -903,22 +903,22 @@ void tst_QGenericItemModel::ownership()
object object
}; };
{ // model takes ownership of its own copy of the vector (!) { // model takes ownership of its own copy of the vector (!)
QGenericItemModel modelOnCopy(objects); QRangeModel modelOnCopy(objects);
} }
QVERIFY(!guard); QVERIFY(!guard);
objects[0] = new Object; objects[0] = new Object;
guard = objects[0]; guard = objects[0];
{ // model does not take ownership { // model does not take ownership
QGenericItemModel modelOnPointer(&objects); QRangeModel modelOnPointer(&objects);
} }
QVERIFY(guard); QVERIFY(guard);
{ // model does not take ownership { // model does not take ownership
QGenericItemModel modelOnRef(std::ref(objects)); QRangeModel modelOnRef(std::ref(objects));
} }
QVERIFY(guard); QVERIFY(guard);
{ // model does take ownership { // model does take ownership
QGenericItemModel movedIntoModel(std::move(objects)); QRangeModel movedIntoModel(std::move(objects));
QCOMPARE(movedIntoModel.columnCount(), 2); QCOMPARE(movedIntoModel.columnCount(), 2);
} }
QVERIFY(!guard); QVERIFY(!guard);
@ -932,25 +932,25 @@ void tst_QGenericItemModel::ownership()
}; };
{ // model does not take ownership { // model does not take ownership
QCOMPARE(objects[0].use_count(), 1); QCOMPARE(objects[0].use_count(), 1);
QGenericItemModel modelOnCopy(objects); QRangeModel modelOnCopy(objects);
QCOMPARE(modelOnCopy.rowCount(), 1); QCOMPARE(modelOnCopy.rowCount(), 1);
QCOMPARE(objects[0].use_count(), 2); QCOMPARE(objects[0].use_count(), 2);
} }
QCOMPARE(objects[0].use_count(), 1); QCOMPARE(objects[0].use_count(), 1);
{ // model does not take ownership { // model does not take ownership
QGenericItemModel modelOnPointer(&objects); QRangeModel modelOnPointer(&objects);
QCOMPARE(objects[0].use_count(), 1); QCOMPARE(objects[0].use_count(), 1);
} }
QCOMPARE(objects[0].use_count(), 1); QCOMPARE(objects[0].use_count(), 1);
QVERIFY(guard); QVERIFY(guard);
{ // model does not take ownership { // model does not take ownership
QGenericItemModel modelOnRef(std::ref(objects)); QRangeModel modelOnRef(std::ref(objects));
QCOMPARE(objects[0].use_count(), 1); QCOMPARE(objects[0].use_count(), 1);
} }
QCOMPARE(objects[0].use_count(), 1); QCOMPARE(objects[0].use_count(), 1);
QVERIFY(guard); QVERIFY(guard);
{ // model owns the last shared copy { // model owns the last shared copy
QGenericItemModel movedIntoModel(std::move(objects)); QRangeModel movedIntoModel(std::move(objects));
} }
QVERIFY(!guard); QVERIFY(!guard);
} }
@ -962,19 +962,19 @@ void tst_QGenericItemModel::ownership()
{object} {object}
}; };
{ // model does not take ownership { // model does not take ownership
QGenericItemModel modelOnCopy(table); QRangeModel modelOnCopy(table);
} }
QVERIFY(guard); QVERIFY(guard);
{ // model does not take ownership { // model does not take ownership
QGenericItemModel modelOnPointer(&table); QRangeModel modelOnPointer(&table);
} }
QVERIFY(guard); QVERIFY(guard);
{ // model does not take ownership { // model does not take ownership
QGenericItemModel modelOnRef(std::ref(table)); QRangeModel modelOnRef(std::ref(table));
} }
QVERIFY(guard); QVERIFY(guard);
{ // model does take ownership of rows, but not of objects within each row { // model does take ownership of rows, but not of objects within each row
QGenericItemModel movedIntoModel(std::move(table)); QRangeModel movedIntoModel(std::move(table));
} }
QVERIFY(guard); QVERIFY(guard);
delete object; delete object;
@ -984,7 +984,7 @@ void tst_QGenericItemModel::ownership()
std::vector<std::shared_ptr<Object>> objects = { std::make_shared<Object>() }; std::vector<std::shared_ptr<Object>> objects = { std::make_shared<Object>() };
{ {
QGenericItemModel model(objects); QRangeModel model(objects);
QCOMPARE(objects.front().use_count(), 2); QCOMPARE(objects.front().use_count(), 2);
} }
@ -998,7 +998,7 @@ void tst_QGenericItemModel::ownership()
}; };
{ {
QGenericItemModel model(table); QRangeModel model(table);
QCOMPARE(table.front().use_count(), 2); QCOMPARE(table.front().use_count(), 2);
QCOMPARE(table.front()->front().use_count(), 1); QCOMPARE(table.front()->front().use_count(), 1);
} }
@ -1008,7 +1008,7 @@ void tst_QGenericItemModel::ownership()
} }
} }
void tst_QGenericItemModel::dimensions() void tst_QRangeModel::dimensions()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1019,7 +1019,7 @@ void tst_QGenericItemModel::dimensions()
QCOMPARE(model->columnCount(), expectedColumnCount); QCOMPARE(model->columnCount(), expectedColumnCount);
} }
void tst_QGenericItemModel::sibling() void tst_QRangeModel::sibling()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1044,7 +1044,7 @@ void tst_QGenericItemModel::sibling()
test(withChildren); test(withChildren);
} }
void tst_QGenericItemModel::flags() void tst_QRangeModel::flags()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1061,7 +1061,7 @@ void tst_QGenericItemModel::flags()
changeActions.testFlags(ChangeAction::SetData)); changeActions.testFlags(ChangeAction::SetData));
} }
void tst_QGenericItemModel::data() void tst_QRangeModel::data()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1077,7 +1077,7 @@ void tst_QGenericItemModel::data()
QVERIFY(last.data().isValid()); QVERIFY(last.data().isValid());
} }
void tst_QGenericItemModel::setData() void tst_QRangeModel::setData()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1099,7 +1099,7 @@ void tst_QGenericItemModel::setData()
QCOMPARE(first.data() == oldValue, !changeActions.testFlag(ChangeAction::SetData)); QCOMPARE(first.data() == oldValue, !changeActions.testFlag(ChangeAction::SetData));
} }
void tst_QGenericItemModel::itemData() void tst_QRangeModel::itemData()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1115,7 +1115,7 @@ void tst_QGenericItemModel::itemData()
} }
} }
void tst_QGenericItemModel::setItemData() void tst_QRangeModel::setItemData()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1171,7 +1171,7 @@ void tst_QGenericItemModel::setItemData()
} }
} }
void tst_QGenericItemModel::clearItemData() void tst_QRangeModel::clearItemData()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1188,7 +1188,7 @@ void tst_QGenericItemModel::clearItemData()
QCOMPARE(index1.data(), oldDataAt1); QCOMPARE(index1.data(), oldDataAt1);
} }
void tst_QGenericItemModel::insertRows() void tst_QRangeModel::insertRows()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1259,7 +1259,7 @@ void tst_QGenericItemModel::insertRows()
verifyPmiList(pmiList); verifyPmiList(pmiList);
} }
void tst_QGenericItemModel::removeRows() void tst_QRangeModel::removeRows()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1282,7 +1282,7 @@ void tst_QGenericItemModel::removeRows()
QCOMPARE(couldRemove, model->rowCount() != newRowCount); QCOMPARE(couldRemove, model->rowCount() != newRowCount);
} }
void tst_QGenericItemModel::moveRows() void tst_QRangeModel::moveRows()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1325,7 +1325,7 @@ void tst_QGenericItemModel::moveRows()
QCOMPARE(model->index(expectedRowCount - 1, 0).data(), last); QCOMPARE(model->index(expectedRowCount - 1, 0).data(), last);
} }
void tst_QGenericItemModel::insertColumns() void tst_QRangeModel::insertColumns()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1344,7 +1344,7 @@ void tst_QGenericItemModel::insertColumns()
changeActions.testFlag(ChangeAction::InsertColumns)); changeActions.testFlag(ChangeAction::InsertColumns));
} }
void tst_QGenericItemModel::removeColumns() void tst_QRangeModel::removeColumns()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1356,7 +1356,7 @@ void tst_QGenericItemModel::removeColumns()
changeActions.testFlag(ChangeAction::RemoveColumns)); changeActions.testFlag(ChangeAction::RemoveColumns));
} }
void tst_QGenericItemModel::moveColumns() void tst_QRangeModel::moveColumns()
{ {
QFETCH(Factory, factory); QFETCH(Factory, factory);
auto model = factory(); auto model = factory();
@ -1401,9 +1401,9 @@ void tst_QGenericItemModel::moveColumns()
} }
} }
void tst_QGenericItemModel::inconsistentColumnCount() void tst_QRangeModel::inconsistentColumnCount()
{ {
QTest::ignoreMessage(QtCriticalMsg, "QGenericItemModel: " QTest::ignoreMessage(QtCriticalMsg, "QRangeModel: "
"Column-range at row 1 is not large enough!"); "Column-range at row 1 is not large enough!");
std::vector<std::vector<int>> fuzzyTable = { std::vector<std::vector<int>> fuzzyTable = {
@ -1411,7 +1411,7 @@ void tst_QGenericItemModel::inconsistentColumnCount()
{}, {},
{2}, {2},
}; };
QGenericItemModel model(fuzzyTable); QRangeModel model(fuzzyTable);
QCOMPARE(model.columnCount(), 1); QCOMPARE(model.columnCount(), 1);
for (int row = 0; row < model.rowCount(); ++row) { for (int row = 0; row < model.rowCount(); ++row) {
auto debug = qScopeGuard([&]{ auto debug = qScopeGuard([&]{
@ -1430,7 +1430,7 @@ void tst_QGenericItemModel::inconsistentColumnCount()
enum class TreeProtocol { ValueImplicit, ValueReadOnly, PointerExplicit, PointerExplicitMoved }; enum class TreeProtocol { ValueImplicit, ValueReadOnly, PointerExplicit, PointerExplicitMoved };
void tst_QGenericItemModel::createTree() void tst_QRangeModel::createTree()
{ {
tree_row root[] = { tree_row root[] = {
{"1", "one"}, {"1", "one"},
@ -1469,7 +1469,7 @@ void tst_QGenericItemModel::createTree()
m_data->m_pointer_tree->at(1)->addChildPointer("2.2", "two.two"); m_data->m_pointer_tree->at(1)->addChildPointer("2.2", "two.two");
} }
void tst_QGenericItemModel::tree_data() void tst_QRangeModel::tree_data()
{ {
m_data.reset(new Data); m_data.reset(new Data);
createTree(); createTree();
@ -1502,7 +1502,7 @@ void tst_QGenericItemModel::tree_data()
<< ChangeActions(ChangeAction::All); << ChangeActions(ChangeAction::All);
} }
std::unique_ptr<QAbstractItemModel> tst_QGenericItemModel::makeTreeModel() std::unique_ptr<QAbstractItemModel> tst_QRangeModel::makeTreeModel()
{ {
createTree(); createTree();
@ -1511,7 +1511,7 @@ std::unique_ptr<QAbstractItemModel> tst_QGenericItemModel::makeTreeModel()
QFETCH(const TreeProtocol, protocol); QFETCH(const TreeProtocol, protocol);
switch (protocol) { switch (protocol) {
case TreeProtocol::ValueImplicit: case TreeProtocol::ValueImplicit:
model.reset(new QGenericItemModel(m_data->m_tree.get())); model.reset(new QRangeModel(m_data->m_tree.get()));
break; break;
case TreeProtocol::ValueReadOnly: { case TreeProtocol::ValueReadOnly: {
struct { // minimal (read-only) implementation of the tree traversal protocol struct { // minimal (read-only) implementation of the tree traversal protocol
@ -1519,11 +1519,11 @@ std::unique_ptr<QAbstractItemModel> tst_QGenericItemModel::makeTreeModel()
const std::optional<value_tree> &childRows(const tree_row &row) const const std::optional<value_tree> &childRows(const tree_row &row) const
{ return row.childRows(); } { return row.childRows(); }
} readOnlyProtocol; } readOnlyProtocol;
model.reset(new QGenericItemModel(m_data->m_tree.get(), readOnlyProtocol)); model.reset(new QRangeModel(m_data->m_tree.get(), readOnlyProtocol));
break; break;
} }
case TreeProtocol::PointerExplicit: case TreeProtocol::PointerExplicit:
model.reset(new QGenericItemModel(m_data->m_pointer_tree.get(), model.reset(new QRangeModel(m_data->m_pointer_tree.get(),
tree_row::ProtocolPointerImpl{})); tree_row::ProtocolPointerImpl{}));
break; break;
case TreeProtocol::PointerExplicitMoved: { case TreeProtocol::PointerExplicitMoved: {
@ -1537,7 +1537,7 @@ std::unique_ptr<QAbstractItemModel> tst_QGenericItemModel::makeTreeModel()
moved_tree.at(1)->addChildPointer("2.1", "two.one"); moved_tree.at(1)->addChildPointer("2.1", "two.one");
moved_tree.at(1)->addChildPointer("2.2", "two.two"); moved_tree.at(1)->addChildPointer("2.2", "two.two");
model.reset(new QGenericItemModel(std::move(moved_tree), model.reset(new QRangeModel(std::move(moved_tree),
tree_row::ProtocolPointerImpl{})); tree_row::ProtocolPointerImpl{}));
break; break;
} }
@ -1546,7 +1546,7 @@ std::unique_ptr<QAbstractItemModel> tst_QGenericItemModel::makeTreeModel()
return model; return model;
} }
void tst_QGenericItemModel::tree() void tst_QRangeModel::tree()
{ {
auto model = makeTreeModel(); auto model = makeTreeModel();
QFETCH(const int, expectedRootRowCount); QFETCH(const int, expectedRootRowCount);
@ -1579,7 +1579,7 @@ void tst_QGenericItemModel::tree()
#endif #endif
} }
void tst_QGenericItemModel::treeModifyBranch() void tst_QRangeModel::treeModifyBranch()
{ {
auto model = makeTreeModel(); auto model = makeTreeModel();
QFETCH(QList<int>, rowsWithChildren); QFETCH(QList<int>, rowsWithChildren);
@ -1641,7 +1641,7 @@ void tst_QGenericItemModel::treeModifyBranch()
#endif #endif
} }
void tst_QGenericItemModel::treeCreateBranch() void tst_QRangeModel::treeCreateBranch()
{ {
auto model = makeTreeModel(); auto model = makeTreeModel();
QFETCH(QList<int>, rowsWithChildren); QFETCH(QList<int>, rowsWithChildren);
@ -1674,7 +1674,7 @@ void tst_QGenericItemModel::treeCreateBranch()
verifyPmiList(pmiList); verifyPmiList(pmiList);
} }
void tst_QGenericItemModel::treeRemoveBranch() void tst_QRangeModel::treeRemoveBranch()
{ {
auto model = makeTreeModel(); auto model = makeTreeModel();
QFETCH(QList<int>, rowsWithChildren); QFETCH(QList<int>, rowsWithChildren);
@ -1701,7 +1701,7 @@ void tst_QGenericItemModel::treeRemoveBranch()
QCOMPARE(model->rowCount(parent), 0); QCOMPARE(model->rowCount(parent), 0);
} }
void tst_QGenericItemModel::treeMoveRows() void tst_QRangeModel::treeMoveRows()
{ {
auto model = makeTreeModel(); auto model = makeTreeModel();
QFETCH(const QList<int>, rowsWithChildren); QFETCH(const QList<int>, rowsWithChildren);
@ -1726,7 +1726,7 @@ void tst_QGenericItemModel::treeMoveRows()
verifyPmiList(pmiList); verifyPmiList(pmiList);
} }
void tst_QGenericItemModel::treeMoveRowBranches() void tst_QRangeModel::treeMoveRowBranches()
{ {
auto model = makeTreeModel(); auto model = makeTreeModel();
QFETCH(const QList<int>, rowsWithChildren); QFETCH(const QList<int>, rowsWithChildren);
@ -1797,5 +1797,5 @@ void tst_QGenericItemModel::treeMoveRowBranches()
verifyPmiList(pmiList); verifyPmiList(pmiList);
} }
QTEST_MAIN(tst_QGenericItemModel) QTEST_MAIN(tst_QRangeModel)
#include "tst_qgenericitemmodel.moc" #include "tst_qrangemodel.moc"