// Copyright (C) 2025 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause #include #ifndef QT_NO_WIDGETS using namespace Qt::StringLiterals; #include #include #include #include class Book { Q_GADGET Q_PROPERTY(QString title READ title) Q_PROPERTY(QString author READ author) Q_PROPERTY(QString summary MEMBER m_summary) Q_PROPERTY(int rating READ rating WRITE setRating) public: enum Roles { TitleRole = Qt::UserRole, AuthorRole, SummaryRole, RatingRole, }; Book() = default; Book(const QString &title, const QString &author); // C++ rule of 0: destructor, as well as copy/move operations // provided by the compiler. // read-only properties QString title() const { return m_title; } QString author() const { return m_author; } // read/writable property with input validation int rating() const { return m_rating; } void setRating(int rating) { m_rating = qBound(0, rating, 5); } private: QString m_title; QString m_author; QString m_summary; int m_rating = 0; }; template <> struct QRangeModel::RowOptions { static constexpr auto rowCategory = QRangeModel::RowCategory::MultiRoleItem; }; struct TreeRow; using Tree = QList; struct TreeRow { QString firstColumn; int secondColumn = 0; TreeRow() = default; explicit TreeRow(const QString &first, int second, std::optional children = std::nullopt) : firstColumn(first), secondColumn(second), m_children(children) {} TreeRow *parentRow() const { return m_parent; } void setParentRow(TreeRow *parent) { m_parent = parent; } const std::optional &childRows() const { return m_children; } std::optional &childRows() { return m_children; } private: TreeRow *m_parent; std::optional m_children; template friend inline decltype(auto) get(const TreeRow &row) { static_assert(I < 2); return false; } }; namespace std { template<> struct tuple_size : integral_constant {}; template<> struct tuple_element<0, TreeRow> { using type = QString; }; template<> struct tuple_element<1, TreeRow> { using type = int; }; } void construct_and_use() { //! [construct] std::vector data = {1, 2, 3, 4, 5}; QRangeModelAdapter adapter(&data); //! [construct] //! [use-model] QListView listView; listView.setModel(adapter.model()); //! [use-model] } void get_and_set() { QListView tableView; //! [get-range] QList books = { // ... }; QRangeModelAdapter adapter(books); tableView.setModel(adapter.model()); // show UI and where the user can modify the list QList modifiedBooks = adapter; // or modifiedBooks = adapter.range(); //! [get-range] //! [set-range] // reset to the original adapter = books; // or adapter.setRange(books); //! [set-range] } void dataAccess() { int row = 0; int column = 0; int path = 0; int to = 0; int branch = 0; QRangeModelAdapter listAdapter(QList{}); //! [list-data] QVariant listItem = listAdapter.data(row); //! [list-data] QRangeModelAdapter tableAdapter(QList>{}); //! [table-data] QVariant tableItem = tableAdapter.data(row, column); //! [table-data] QRangeModelAdapter treeAdapter(QList{}); //! [tree-data] QVariant treeItem = treeAdapter.data({path, to, branch}, column); //! [tree-data] //! [multirole-data] QRangeModelAdapter listOfBooks(QList{ // ~~~ }); QString bookTitle = listOfBooks.data(0, Book::TitleRole).toString(); Book multiRoleItem = listOfBooks.data(0).value(); //! [multirole-data] } void list_access() { QListView listView; { //! [list-access] QRangeModelAdapter list(std::vector{1, 2, 3, 4, 5}); listView.setModel(list.model()); int firstValue = list.at(0); // == 1 list.at(0) = -1; list.at(1) = list.at(4); //! [list-access] } { //! [list-access-multirole] QRangeModelAdapter books(QList{ // ~~~ }); Book firstBook = books.at(0); Book newBook = {}; books.at(0) = newBook; // dataChanged() emitted //! [list-access-multirole] //! [list-access-multirole-member-access] QString title = books.at(0)->title(); //! [list-access-multirole-member-access] //! [list-access-multirole-write-back] // books.at(0)->setRating(5); - not possible even though 'books' is not const firstBook = books.at(0); firstBook.setRating(5); books.at(0) = firstBook; // dataChanged() emitted //! [list-access-multirole-write-back] } } void table_access() { QTableView tableView; { //! [table-item-access] QRangeModelAdapter table(std::vector>{ {1.0, 2.0, 3.0, 4.0, 5.0}, {6.0, 7.0, 8.0, 9.0, 10.0}, }); tableView.setModel(table.model()); double value = table.at(0, 2); // value == 3.0 table.at(0, 2) = value * 2; // table[0, 2] == 6.0 //! [table-item-access] //! [table-row-const-access] const auto &constTable = table; const std::vector &topRow = constTable.at(0); //! [table-row-const-access] //! [table-row-access] auto lastRow = table.at(table.rowCount() - 1); lastRow = { 6.5, 7.5, 8.0, 9.0, 10 }; // emits dataChanged() for entire row //! [table-row-access] } { //! [table-mixed-type-access] QRangeModelAdapter table(std::vector>{ // ~~~ }); int number = table.at(0, 0)->toInt(); QString text = table.at(0, 1)->toString(); //! [table-mixed-type-access] } } void tree_access() { QTreeView treeView; //! [tree-row-access] QRangeModelAdapter tree = QRangeModelAdapter(Tree{ new TreeRow{"Germany", 357002, Tree{ new TreeRow("Bavaria", 70550) }, }, new TreeRow{"France", 632702}, }); treeView.setModel(tree.model()); auto germanyData = tree.at(0); auto bavariaData = tree.at({0, 0}); //! [tree-row-access] //! [tree-item-access] auto germanyName = tree.at(0, 0); auto bavariaSize = tree.at({0, 0}, 1); //! [tree-item-access] //! [tree-row-write] // deletes the old row - tree was moved in tree.at({0, 0}) = new TreeRow{"Berlin", 892}; //! [tree-row-write] } void read_only() { #if 0 //! [read-only] const QStringList strings = {"On", "Off"}; QRangeModelAdapter adapter(strings); adapter.at(0) = "Undecided"; // compile error: return value of 'at' is const adapter.insertRow(0); // compiler error: requirements not satisfied //! [read-only] #endif } void list_iterate() { QRangeModelAdapter books(QList{ // ~~~ }); QListView view; view.setModel(books.model()); //! [ranged-for-const-list] for (const auto &book : std::as_const(books)) { qDebug() << "The book" << book.title() << "written by" << book.author() << "has" << book.rating() << "stars"; } //! [ranged-for-const-list] //! [ranged-for-mutable-list] for (auto book : books) { qDebug() << "The book" << book->title() << "written by" << book->author() << "has" << book->rating() << "stars"; Book copy = book; copy.setRating(copy.rating() + 1); book = copy; } //! [ranged-for-mutable-list] } void table_iterate() { //! [ranged-for-const-table] QRangeModelAdapter table(std::vector>{ // ~~~ }); for (const auto &row : std::as_const(table)) { qDebug() << "Number is" << row->first << "and string is" << row->second; } //! [ranged-for-const-table] //! [ranged-for-const-table-items] for (const auto &row : std::as_const(table)) { for (const auto &item : row) { qDebug() << item; // item is a QVariant } } //! [ranged-for-const-table-items] //! [ranged-for-mutable-table] for (auto row : table) { qDebug() << "Number is" << row->first << "and string is" << row->second; row = std::make_pair(42, u"forty-two"_s); } //! [ranged-for-mutable-table] //! [ranged-for-mutable-table-items] for (auto row : table) { for (auto item : row) { item = 42; } } //! [ranged-for-mutable-table-items] } void tree_iterate() { QRangeModelAdapter tree = QRangeModelAdapter(Tree{ new TreeRow{"1", 1, Tree{ new TreeRow("1.1", 11) }, }, new TreeRow{"2", 2}, }); static_assert(std::is_same_v); //! [ranged-for-tree] for (auto row : tree) { if (row.hasChildren()) { for (auto child : row.children()) { // ~~~ } } } //! [ranged-for-tree] } #endif