1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
3
4#include <QtCore/qrangemodel.h>
5
6#ifndef QT_NO_WIDGETS
7
8#include <QtWidgets/qapplication.h>
9#include <QtWidgets/qlistview.h>
10#include <QtWidgets/qtableview.h>
11#include <QtWidgets/qtreeview.h>
12
13#include <array>
14#include <vector>
15
16void array()
17{
18 QListView listView;
19
20 //! [array]
21 std::array<int, 5> numbers = {1, 2, 3, 4, 5};
22 QRangeModel model(numbers);
23 listView.setModel(&model);
24 //! [array]
25}
26
27void construct_by()
28{
29 std::vector<int> numbers = {1, 2, 3, 4, 5};
30
31 {
32 //! [value]
33 QRangeModel model(numbers);
34 //! [value]
35 }
36
37 {
38 //! [pointer]
39 QRangeModel model(&numbers);
40 //! [pointer]
41 }
42
43 {
44 //! [reference_wrapper]
45 QRangeModel model(std::ref(t&: numbers));
46 //! [reference_wrapper]
47 }
48
49 {
50 //! [smart_pointer]
51 auto shared_numbers = std::make_shared<std::vector<int>>(args&: numbers);
52 QRangeModel model(shared_numbers);
53 //! [smart_pointer]
54 }
55}
56
57void const_array()
58{
59 //! [const_array]
60 const std::array<int, 5> numbers = {1, 2, 3, 4, 5};
61 //! [const_array]
62 QRangeModel model(numbers);
63}
64
65void const_values()
66{
67 //! [const_values]
68 std::array<const int, 5> numbers = {1, 2, 3, 4, 5};
69 //! [const_values]
70 QRangeModel model(numbers);
71}
72
73void const_ref()
74{
75 std::vector<int> numbers = {1, 2, 3, 4, 5};
76 //! [const_ref]
77 QRangeModel model(std::cref(t: numbers));
78 //! [const_ref]
79}
80
81void list_of_int()
82{
83 //! [list_of_int]
84 QList<int> numbers = {1, 2, 3, 4, 5};
85 QRangeModel model(numbers); // columnCount() == 1
86 QListView listView;
87 listView.setModel(&model);
88 //! [list_of_int]
89}
90
91void grid_of_numbers()
92{
93 //! [grid_of_numbers]
94 std::vector<std::vector<int>> gridOfNumbers = {
95 {1, 2, 3, 4, 5},
96 {6, 7, 8, 9, 10},
97 {11, 12, 13, 14, 15},
98 };
99 QRangeModel model(&gridOfNumbers); // columnCount() == 5
100 QTableView tableView;
101 tableView.setModel(&model);
102 //! [grid_of_numbers]
103}
104
105void pair_int_QString()
106{
107 //! [pair_int_QString]
108 using TableRow = std::tuple<int, QString>;
109 QList<TableRow> numberNames = {
110 {1, "one"},
111 {2, "two"},
112 {3, "three"}
113 };
114 QRangeModel model(&numberNames); // columnCount() == 2
115 QTableView tableView;
116 tableView.setModel(&model);
117 //! [pair_int_QString]
118}
119
120#if defined(__cpp_concepts) && defined(__cpp_lib_forward_like)
121//! [tuple_protocol]
122struct Book
123{
124 QString title;
125 QString author;
126 QString summary;
127 int rating = 0;
128
129 template <size_t I, typename T>
130 requires ((I <= 3) && std::is_same_v<std::remove_cvref_t<T>, Book>)
131 friend inline decltype(auto) get(T &&book)
132 {
133 if constexpr (I == 0)
134 return std::as_const(book.title);
135 else if constexpr (I == 1)
136 return std::as_const(book.author);
137 else if constexpr (I == 2)
138 return std::forward_like<T>(book.summary);
139 else if constexpr (I == 3)
140 return std::forward_like<T>(book.rating);
141 }
142};
143
144namespace std {
145 template <> struct tuple_size<Book> : std::integral_constant<size_t, 4> {};
146 template <size_t I> struct tuple_element<I, Book>
147 { using type = decltype(get<I>(std::declval<Book>())); };
148}
149//! [tuple_protocol]
150#endif // __cpp_concepts && forward_like
151
152namespace gadget {
153//! [gadget]
154class Book
155{
156 Q_GADGET
157 Q_PROPERTY(QString title READ title)
158 Q_PROPERTY(QString author READ author)
159 Q_PROPERTY(QString summary MEMBER m_summary)
160 Q_PROPERTY(int rating READ rating WRITE setRating)
161public:
162 Book(const QString &title, const QString &author);
163
164 // C++ rule of 0: destructor, as well as copy/move operations
165 // provided by the compiler.
166
167 // read-only properties
168 QString title() const { return m_title; }
169 QString author() const { return m_author; }
170
171 // read/writable property with input validation
172 int rating() const { return m_rating; }
173 void setRating(int rating)
174 {
175 m_rating = qBound(min: 0, val: rating, max: 5);
176 }
177
178private:
179 QString m_title;
180 QString m_author;
181 QString m_summary;
182 int m_rating = 0;
183};
184//! [gadget]
185} // namespace gadget
186
187namespace Object
188{
189//! [object_0]
190class Entry : public QObject
191{
192 Q_OBJECT
193 Q_PROPERTY(QString display READ display WRITE setDisplay NOTIFY displayChanged)
194 Q_PROPERTY(QIcon decoration READ decoration WRITE setDecoration NOTIFY decorationChanged)
195 Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip NOTIFY toolTipChanged)
196
197public:
198 Entry() = default;
199
200 QString display() const
201 {
202 return m_display;
203 }
204
205 void setDisplay(const QString &display)
206 {
207 if (m_display == display)
208 return;
209 m_display = display;
210 emit displayChanged(m_display);
211 }
212
213signals:
214 void displayChanged(const QString &);
215//! [object_0]
216
217private:
218 QString m_display;
219
220//! [object_1]
221};
222//! [object_1]
223
224void vector_of_objects()
225{
226 //! [vector_of_objects_0]
227 std::vector<std::shared_ptr<Entry>> entries = {
228 //! [vector_of_objects_0]
229 std::make_shared<Entry>(),
230 //! [vector_of_objects_1]
231 };
232 //! [vector_of_objects_1]
233
234 //! [vector_of_objects_2]
235 QRangeModel model(std::ref(t&: entries));
236 QListView listView;
237 listView.setModel(&model);
238 //! [vector_of_objects_2]
239}
240
241} // namespace object
242
243using Entry = Object::Entry;
244//! [vector_of_multirole_objects_0]
245template <>
246struct QRangeModel::RowOptions<Entry>
247{
248 static constexpr auto rowCategory = QRangeModel::RowCategory::MultiRoleItem;
249};
250//! [vector_of_multirole_objects_0]
251
252namespace Object
253{
254
255void vector_of_multirole_objects()
256{
257 //! [vector_of_multirole_objects_1]
258 std::vector<std::shared_ptr<Entry>> entries = {
259 std::make_shared<Entry>(),
260 //! [vector_of_multirole_objects_1]
261 //! [vector_of_multirole_objects_2]
262 };
263
264 QRangeModel model(std::ref(t&: entries));
265 //! [vector_of_multirole_objects_2]
266}
267
268} // namespace object
269
270namespace Subclass
271{
272
273//! [subclass_header]
274class NumbersModel : public QRangeModel
275{
276 std::vector<int> m_numbers;
277
278public:
279 NumbersModel(const std::vector<int> &numbers)
280 : QRangeModel(std::ref(t&: m_numbers))
281 , m_numbers(numbers)
282 {
283 }
284//! [subclass_header]
285//! [subclass_API]
286 void setNumber(int idx, int number)
287 {
288 setData(index: index(row: idx, column: 0), data: QVariant::fromValue(value: number));
289 }
290
291 int number(int idx) const
292 {
293 return m_numbers.at(n: idx);
294 }
295};
296//! [subclass_API]
297
298} // namespace Subclass
299
300namespace tree_protocol
301{
302//! [tree_protocol_0]
303class TreeRow;
304
305using Tree = std::vector<TreeRow>;
306//! [tree_protocol_0]
307
308//! [tree_protocol_1]
309class TreeRow
310{
311 Q_GADGET
312 // properties
313
314 TreeRow *m_parent;
315 std::optional<Tree> m_children;
316
317public:
318 TreeRow() = default;
319
320 // rule of 0: copy, move, and destructor implicitly defaulted
321//! [tree_protocol_1]
322
323 friend struct TreeTraversal;
324 TreeRow(const QString &) {}
325
326//! [tree_protocol_2]
327 // tree traversal protocol implementation
328 const TreeRow *parentRow() const { return m_parent; }
329 const std::optional<Tree> &childRows() const { return m_children; }
330//! [tree_protocol_2]
331//! [tree_protocol_3]
332 void setParentRow(TreeRow *parent) { m_parent = parent; }
333 std::optional<Tree> &childRows() { return m_children; }
334//! [tree_protocol_3]
335//! [tree_protocol_4]
336 // Helper to assembly a tree of rows, not used by QRangeModel
337 template <typename ...Args>
338 TreeRow &addChild(Args &&...args)
339 {
340 if (!m_children)
341 m_children.emplace(args: Tree{});
342 auto &child = m_children->emplace_back(std::forward<Args>(args)...);
343 child.m_parent = this;
344 return child;
345 }
346};
347//! [tree_protocol_4]
348
349void tree_protocol()
350{
351 //! [tree_protocol_5]
352 Tree tree = {
353 {"..."},
354 {"..."},
355 {"..."},
356 };
357
358 // each toplevel row has three children
359 tree[0].addChild(args: "...");
360 tree[0].addChild(args: "...");
361 tree[0].addChild(args: "...");
362
363 tree[1].addChild(args: "...");
364 tree[1].addChild(args: "...");
365 tree[1].addChild(args: "...");
366
367 tree[2].addChild(args: "...");
368 tree[2].addChild(args: "...");
369 tree[2].addChild(args: "...");
370 //! [tree_protocol_5]
371
372 //! [tree_protocol_6]
373 // instantiate the model with a pointer to the tree, not a copy!
374 QRangeModel model(&tree);
375 QTreeView view;
376 view.setModel(&model);
377 //! [tree_protocol_6]
378}
379
380//! [explicit_tree_protocol_0]
381struct TreeTraversal
382{
383 TreeRow newRow() const { return TreeRow{}; }
384 const TreeRow *parentRow(const TreeRow &row) const { return row.m_parent; }
385 void setParentRow(TreeRow &row, TreeRow *parent) const { row.m_parent = parent; }
386 const std::optional<Tree> &childRows(const TreeRow &row) const { return row.m_children; }
387 std::optional<Tree> &childRows(TreeRow &row) const { return row.m_children; }
388};
389//! [explicit_tree_protocol_0]
390void explicit_tree_protocol()
391{
392 Tree tree;
393 //! [explicit_tree_protocol_1]
394 QRangeModel model(&tree, TreeTraversal{});
395 //! [explicit_tree_protocol_1]
396}
397} // namespace tree_protocol
398
399namespace tree_of_pointers
400{
401//! [tree_of_pointers_0]
402struct TreeRow;
403using Tree = std::vector<TreeRow *>;
404//! [tree_of_pointers_0]
405
406//! [tree_of_pointers_1]
407struct TreeRow
408{
409 Q_GADGET
410public:
411 TreeRow(const QString &value = {})
412 : m_value(value)
413 {}
414 ~TreeRow()
415 {
416 if (m_children)
417 qDeleteAll(c: *m_children);
418 }
419
420 // move-only
421 TreeRow(TreeRow &&) = default;
422 TreeRow &operator=(TreeRow &&) = default;
423
424 // helper to populate
425 template <typename ...Args>
426 TreeRow *addChild(Args &&...args)
427 {
428 if (!m_children)
429 m_children.emplace(args: Tree{});
430 auto *child = m_children->emplace_back(args: new TreeRow(std::forward<Args>(args)...));
431 child->m_parent = this;
432 return child;
433 }
434
435private:
436 friend struct TreeTraversal;
437 QString m_value;
438 std::optional<Tree> m_children;
439 TreeRow *m_parent = nullptr;
440};
441//! [tree_of_pointers_1]
442
443Tree make_tree_of_pointers()
444{
445 //! [tree_of_pointers_2]
446 Tree tree = {
447 new TreeRow("1"),
448 new TreeRow("2"),
449 new TreeRow("3"),
450 new TreeRow("4"),
451 };
452 tree[0]->addChild(args: "1.1");
453 tree[1]->addChild(args: "2.1");
454 tree[2]->addChild(args: "3.1")->addChild(args: "3.1.1");
455 tree[3]->addChild(args: "4.1");
456 //! [tree_of_pointers_2]
457 return tree;
458}
459
460//! [tree_of_pointers_3]
461struct TreeTraversal
462{
463 TreeRow *newRow() const { return new TreeRow; }
464 void deleteRow(TreeRow *row) { delete row; }
465
466 const TreeRow *parentRow(const TreeRow &row) const { return row.m_parent; }
467 void setParentRow(TreeRow &row, TreeRow *parent) { row.m_parent = parent; }
468 const std::optional<Tree> &childRows(const TreeRow &row) const { return row.m_children; }
469 std::optional<Tree> &childRows(TreeRow &row) { return row.m_children; }
470};
471//! [tree_of_pointers_3]
472
473//! [tree_of_pointers_4]
474int main(int argc, char **argv)
475{
476 QApplication app(argc, argv);
477
478 Tree tree = make_tree_of_pointers();
479
480 QRangeModel model(std::move(tree), TreeTraversal{});
481 QTreeView treeView;
482 treeView.setModel(&model);
483 treeView.show();
484
485 return app.exec();
486}
487//! [tree_of_pointers_4]
488
489} // namespace tree_of_pointers
490
491void color_map()
492{
493 //! [color_map]
494 using ColorEntry = QMap<Qt::ItemDataRole, QVariant>;
495
496 const QStringList colorNames = QColor::colorNames();
497 QList<ColorEntry> colors;
498 colors.reserve(asize: colorNames.size());
499 for (const QString &name : colorNames) {
500 const QColor color = QColor::fromString(name);
501 colors << ColorEntry{{Qt::DisplayRole, name},
502 {Qt::DecorationRole, color},
503 {Qt::ToolTipRole, color.name()}};
504 }
505 QRangeModel colorModel(colors);
506 QListView list;
507 list.setModel(&colorModel);
508 //! [color_map]
509}
510
511namespace multirole_gadget {
512//! [color_gadget_decl]
513class ColorEntry
514{
515 Q_GADGET
516 Q_PROPERTY(QString display MEMBER m_colorName)
517 Q_PROPERTY(QColor decoration READ decoration)
518 Q_PROPERTY(QString toolTip READ toolTip)
519public:
520//! [color_gadget_decl]
521//! [color_gadget_impl]
522 ColorEntry(const QString &color = {})
523 : m_colorName(color)
524 {}
525
526 QColor decoration() const
527 {
528 return QColor::fromString(name: m_colorName);
529 }
530 QString toolTip() const
531 {
532 return QColor::fromString(name: m_colorName).name();
533 }
534
535private:
536 QString m_colorName;
537//! [color_gadget_impl]
538//! [color_gadget_end]
539};
540//! [color_gadget_end]
541}
542
543using ColorEntry = multirole_gadget::ColorEntry;
544//! [color_gadget_multi_role_gadget]
545
546template <>
547struct QRangeModel::RowOptions<ColorEntry>
548{
549 static constexpr auto rowCategory = QRangeModel::RowCategory::MultiRoleItem;
550};
551//! [color_gadget_multi_role_gadget]
552
553namespace multirole_gadget {
554void color_table() {
555 //! [color_gadget_table]
556 QList<QList<ColorEntry>> colorTable;
557
558 // ...
559
560 QRangeModel colorModel(colorTable);
561 QTableView table;
562 table.setModel(&colorModel);
563 //! [color_gadget_table]
564}
565
566void color_list_multi_role() {
567 //! [color_gadget_multi_role]
568 const QStringList colorNames = QColor::colorNames();
569 QList<ColorEntry> colors;
570 colors.reserve(asize: colorNames.size());
571 for (const QString &name : colorNames)
572 colors << name;
573
574 QRangeModel colorModel(colors);
575 QListView list;
576 list.setModel(&colorModel);
577 //! [color_gadget_multi_role]
578}
579
580void color_list_single_column() {
581 //! [color_gadget_single_column]
582 const QStringList colorNames = QColor::colorNames();
583 QList<std::tuple<ColorEntry>> colors;
584
585 // ...
586
587 QRangeModel colorModel(colors);
588 QListView list;
589 list.setModel(&colorModel);
590 //! [color_gadget_single_column]
591
592 {
593 //! [color_gadget_single_column_access_get]
594 ColorEntry firstEntry = std::get<0>(t: colors.at(i: 0));
595 //! [color_gadget_single_column_access_get]
596 }
597 {
598 //! [color_gadget_single_column_access_sb]
599 auto [firstEntry] = colors.at(i: 0);
600 //! [color_gadget_single_column_access_sb]
601 }
602}
603} // namespace multirole_gadget
604
605#endif // QT_NO_WIDGETS
606

source code of qtbase/src/corelib/doc/snippets/qrangemodel/main.cpp