Revision control

++ // Copyright (C) 2025 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
++
++ #include <QtCore/qrangemodel.h>
++
++ #ifndef QT_NO_WIDGETS
++
++ #include <QtWidgets/qapplication.h>
++ #include <QtWidgets/qlistview.h>
++ #include <QtWidgets/qtableview.h>
++ #include <QtWidgets/qtreeview.h>
++
++ #include <array>
++ #include <vector>
++
++ void array()
++ {
++ QListView listView;
++
++ //! [array]
++ std::array<int, 5> numbers = {1, 2, 3, 4, 5};
++ QRangeModel model(numbers);
++ listView.setModel(&model);
++ //! [array]
++ }
++
++ void construct_by()
++ {
++ std::vector<int> numbers = {1, 2, 3, 4, 5};
++
++ {
++ //! [value]
++ QRangeModel model(numbers);
++ //! [value]
++ }
++
++ {
++ //! [pointer]
++ QRangeModel model(&numbers);
++ //! [pointer]
++ }
++
++ {
++ //! [reference_wrapper]
++ QRangeModel model(std::ref(numbers));
++ //! [reference_wrapper]
++ }
++
++ {
++ //! [smart_pointer]
++ auto shared_numbers = std::make_shared<std::vector<int>>(numbers);
++ QRangeModel model(shared_numbers);
++ //! [smart_pointer]
++ }
++ }
++
++ void const_array()
++ {
++ //! [const_array]
++ const std::array<int, 5> numbers = {1, 2, 3, 4, 5};
++ //! [const_array]
++ QRangeModel model(numbers);
++ }
++
++ void const_values()
++ {
++ //! [const_values]
++ std::array<const int, 5> numbers = {1, 2, 3, 4, 5};
++ //! [const_values]
++ QRangeModel model(numbers);
++ }
++
++ void const_ref()
++ {
++ std::vector<int> numbers = {1, 2, 3, 4, 5};
++ //! [const_ref]
++ QRangeModel model(std::cref(numbers));
++ //! [const_ref]
++ }
++
++ void list_of_int()
++ {
++ //! [list_of_int]
++ QList<int> numbers = {1, 2, 3, 4, 5};
++ QRangeModel model(numbers); // columnCount() == 1
++ QListView listView;
++ listView.setModel(&model);
++ //! [list_of_int]
++ }
++
++ void grid_of_numbers()
++ {
++ //! [grid_of_numbers]
++ std::vector<std::vector<int>> gridOfNumbers = {
++ {1, 2, 3, 4, 5},
++ {6, 7, 8, 9, 10},
++ {11, 12, 13, 14, 15},
++ };
++ QRangeModel model(&gridOfNumbers); // columnCount() == 5
++ QTableView tableView;
++ tableView.setModel(&model);
++ //! [grid_of_numbers]
++ }
++
++ void pair_int_QString()
++ {
++ //! [pair_int_QString]
++ using TableRow = std::tuple<int, QString>;
++ QList<TableRow> numberNames = {
++ {1, "one"},
++ {2, "two"},
++ {3, "three"}
++ };
++ QRangeModel model(&numberNames); // columnCount() == 2
++ QTableView tableView;
++ tableView.setModel(&model);
++ //! [pair_int_QString]
++ }
++
++ #if defined(__cpp_concepts) && defined(__cpp_lib_forward_like)
++ //! [tuple_protocol]
++ struct Book
++ {
++ QString title;
++ QString author;
++ QString summary;
++ int rating = 0;
++
++ template <size_t I, typename T>
++ requires ((I <= 3) && std::is_same_v<std::remove_cvref_t<T>, Book>)
++ friend inline decltype(auto) get(T &&book)
++ {
++ if constexpr (I == 0)
++ return std::as_const(book.title);
++ else if constexpr (I == 1)
++ return std::as_const(book.author);
++ else if constexpr (I == 2)
++ return std::forward_like<T>(book.summary);
++ else if constexpr (I == 3)
++ return std::forward_like<T>(book.rating);
++ }
++ };
++
++ namespace std {
++ template <> struct tuple_size<Book> : std::integral_constant<size_t, 4> {};
++ template <size_t I> struct tuple_element<I, Book>
++ { using type = decltype(get<I>(std::declval<Book>())); };
++ }
++ //! [tuple_protocol]
++ #endif // __cpp_concepts && forward_like
++
++ namespace gadget {
++ //! [gadget]
++ 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:
++ 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;
++ };
++ //! [gadget]
++ } // namespace gadget
++
++ namespace Object
++ {
++ //! [object_0]
++ class Entry : public QObject
++ {
++ Q_OBJECT
++ Q_PROPERTY(QString display READ display WRITE setDisplay NOTIFY displayChanged)
++ Q_PROPERTY(QIcon decoration READ decoration WRITE setDecoration NOTIFY decorationChanged)
++ Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip NOTIFY toolTipChanged)
++
++ public:
++ Entry() = default;
++
++ QString display() const
++ {
++ return m_display;
++ }
++
++ void setDisplay(const QString &display)
++ {
++ if (m_display == display)
++ return;
++ m_display = display;
++ emit displayChanged(m_display);
++ }
++
++ signals:
++ void displayChanged(const QString &);
++ //! [object_0]
++
++ private:
++ QString m_display;
++
++ //! [object_1]
++ };
++ //! [object_1]
++
++ void vector_of_objects()
++ {
++ //! [vector_of_objects_0]
++ std::vector<std::shared_ptr<Entry>> entries = {
++ //! [vector_of_objects_0]
++ std::make_shared<Entry>(),
++ //! [vector_of_objects_1]
++ };
++ //! [vector_of_objects_1]
++
++ //! [vector_of_objects_2]
++ QRangeModel model(std::ref(entries));
++ QListView listView;
++ listView.setModel(&model);
++ //! [vector_of_objects_2]
++ }
++
++ } // namespace object
++
++ using Entry = Object::Entry;
++ //! [vector_of_multirole_objects_0]
++ template <>
++ struct QRangeModel::RowOptions<Entry>
++ {
++ static constexpr auto rowCategory = QRangeModel::RowCategory::MultiRoleItem;
++ };
++ //! [vector_of_multirole_objects_0]
++
++ namespace Object
++ {
++
++ void vector_of_multirole_objects()
++ {
++ //! [vector_of_multirole_objects_1]
++ std::vector<std::shared_ptr<Entry>> entries = {
++ std::make_shared<Entry>(),
++ //! [vector_of_multirole_objects_1]
++ //! [vector_of_multirole_objects_2]
++ };
++
++ QRangeModel model(std::ref(entries));
++ //! [vector_of_multirole_objects_2]
++ }
++
++ } // namespace object
++
++ namespace Subclass
++ {
++
++ //! [subclass_header]
++ class NumbersModel : public QRangeModel
++ {
++ std::vector<int> m_numbers;
++
++ public:
++ NumbersModel(const std::vector<int> &numbers)
++ : QRangeModel(std::ref(m_numbers))
++ , m_numbers(numbers)
++ {
++ }
++ //! [subclass_header]
++ //! [subclass_API]
++ void setNumber(int idx, int number)
++ {
++ setData(index(idx, 0), QVariant::fromValue(number));
++ }
++
++ int number(int idx) const
++ {
++ return m_numbers.at(idx);
++ }
++ };
++ //! [subclass_API]
++
++ } // namespace Subclass
++
++ namespace tree_protocol
++ {
++ //! [tree_protocol_0]
++ class TreeRow;
++
++ using Tree = std::vector<TreeRow>;
++ //! [tree_protocol_0]
++
++ //! [tree_protocol_1]
++ class TreeRow
++ {
++ Q_GADGET
++ // properties
++
++ TreeRow *m_parent;
++ std::optional<Tree> m_children;
++
++ public:
++ TreeRow() = default;
++
++ // rule of 0: copy, move, and destructor implicitly defaulted
++ //! [tree_protocol_1]
++
++ friend struct TreeTraversal;
++ TreeRow(const QString &) {}
++
++ //! [tree_protocol_2]
++ // tree traversal protocol implementation
++ const TreeRow *parentRow() const { return m_parent; }
++ const std::optional<Tree> &childRows() const { return m_children; }
++ //! [tree_protocol_2]
++ //! [tree_protocol_3]
++ void setParentRow(TreeRow *parent) { m_parent = parent; }
++ std::optional<Tree> &childRows() { return m_children; }
++ //! [tree_protocol_3]
++ //! [tree_protocol_4]
++ // Helper to assembly a tree of rows, not used by QRangeModel
++ template <typename ...Args>
++ TreeRow &addChild(Args &&...args)
++ {
++ if (!m_children)
++ m_children.emplace(Tree{});
++ auto &child = m_children->emplace_back(std::forward<Args>(args)...);
++ child.m_parent = this;
++ return child;
++ }
++ };
++ //! [tree_protocol_4]
++
++ void tree_protocol()
++ {
++ //! [tree_protocol_5]
++ Tree tree = {
++ {"..."},
++ {"..."},
++ {"..."},
++ };
++
++ // each toplevel row has three children
++ tree[0].addChild("...");
++ tree[0].addChild("...");
++ tree[0].addChild("...");
++
++ tree[1].addChild("...");
++ tree[1].addChild("...");
++ tree[1].addChild("...");
++
++ tree[2].addChild("...");
++ tree[2].addChild("...");
++ tree[2].addChild("...");
++ //! [tree_protocol_5]
++
++ //! [tree_protocol_6]
++ // instantiate the model with a pointer to the tree, not a copy!
++ QRangeModel model(&tree);
++ QTreeView view;
++ view.setModel(&model);
++ //! [tree_protocol_6]
++ }
++
++ //! [explicit_tree_protocol_0]
++ struct TreeTraversal
++ {
++ TreeRow newRow() const { return TreeRow{}; }
++ const TreeRow *parentRow(const TreeRow &row) const { return row.m_parent; }
++ void setParentRow(TreeRow &row, TreeRow *parent) const { row.m_parent = parent; }
++ const std::optional<Tree> &childRows(const TreeRow &row) const { return row.m_children; }
++ std::optional<Tree> &childRows(TreeRow &row) const { return row.m_children; }
++ };
++ //! [explicit_tree_protocol_0]
++ void explicit_tree_protocol()
++ {
++ Tree tree;
++ //! [explicit_tree_protocol_1]
++ QRangeModel model(&tree, TreeTraversal{});
++ //! [explicit_tree_protocol_1]
++ }
++ } // namespace tree_protocol
++
++ namespace tree_of_pointers
++ {
++ //! [tree_of_pointers_0]
++ struct TreeRow;
++ using Tree = std::vector<TreeRow *>;
++ //! [tree_of_pointers_0]
++
++ //! [tree_of_pointers_1]
++ struct TreeRow
++ {
++ Q_GADGET
++ public:
++ TreeRow(const QString &value = {})
++ : m_value(value)
++ {}
++ ~TreeRow()
++ {
++ if (m_children)
++ qDeleteAll(*m_children);
++ }
++
++ // move-only
++ TreeRow(TreeRow &&) = default;
++ TreeRow &operator=(TreeRow &&) = default;
++
++ // helper to populate
++ template <typename ...Args>
++ TreeRow *addChild(Args &&...args)
++ {
++ if (!m_children)
++ m_children.emplace(Tree{});
++ auto *child = m_children->emplace_back(new TreeRow(std::forward<Args>(args)...));
++ child->m_parent = this;
++ return child;
++ }
++
++ private:
++ friend struct TreeTraversal;
++ QString m_value;
++ std::optional<Tree> m_children;
++ TreeRow *m_parent = nullptr;
++ };
++ //! [tree_of_pointers_1]
++
++ Tree make_tree_of_pointers()
++ {
++ //! [tree_of_pointers_2]
++ Tree tree = {
++ new TreeRow("1"),
++ new TreeRow("2"),
++ new TreeRow("3"),
++ new TreeRow("4"),
++ };
++ tree[0]->addChild("1.1");
++ tree[1]->addChild("2.1");
++ tree[2]->addChild("3.1")->addChild("3.1.1");
++ tree[3]->addChild("4.1");
++ //! [tree_of_pointers_2]
++ return tree;
++ }
++
++ //! [tree_of_pointers_3]
++ struct TreeTraversal
++ {
++ TreeRow *newRow() const { return new TreeRow; }
++ void deleteRow(TreeRow *row) { delete row; }
++
++ const TreeRow *parentRow(const TreeRow &row) const { return row.m_parent; }
++ void setParentRow(TreeRow &row, TreeRow *parent) { row.m_parent = parent; }
++ const std::optional<Tree> &childRows(const TreeRow &row) const { return row.m_children; }
++ std::optional<Tree> &childRows(TreeRow &row) { return row.m_children; }
++ };
++ //! [tree_of_pointers_3]
++
++ //! [tree_of_pointers_4]
++ int main(int argc, char **argv)
++ {
++ QApplication app(argc, argv);
++
++ Tree tree = make_tree_of_pointers();
++
++ QRangeModel model(std::move(tree), TreeTraversal{});
++ QTreeView treeView;
++ treeView.setModel(&model);
++ treeView.show();
++
++ return app.exec();
++ }
++ //! [tree_of_pointers_4]
++
++ } // namespace tree_of_pointers
++
++ void color_map()
++ {
++ //! [color_map]
++ using ColorEntry = QMap<Qt::ItemDataRole, QVariant>;
++
++ const QStringList colorNames = QColor::colorNames();
++ QList<ColorEntry> colors;
++ colors.reserve(colorNames.size());
++ for (const QString &name : colorNames) {
++ const QColor color = QColor::fromString(name);
++ colors << ColorEntry{{Qt::DisplayRole, name},
++ {Qt::DecorationRole, color},
++ {Qt::ToolTipRole, color.name()}};
++ }
++ QRangeModel colorModel(colors);
++ QListView list;
++ list.setModel(&colorModel);
++ //! [color_map]
++ }
++
++ #endif // QT_NO_WIDGETS