Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qrangemodel.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qrangemodel.h"
6#include <QtCore/qcollator.h>
7#include <QtCore/qmimedata.h>
8#include <QtCore/qpoint.h>
9#include <QtCore/qsize.h>
10
11#include <QtCore/private/qabstractitemmodel_p.h>
12
13#include <variant>
14
15QT_BEGIN_NAMESPACE
16
17class QRangeModelPrivate : QAbstractItemModelPrivate
18{
19 Q_DECLARE_PUBLIC(QRangeModel)
20
21public:
22 explicit QRangeModelPrivate(std::unique_ptr<QRangeModelImplBase, QRangeModelImplBase::Deleter> impl)
23 : impl(std::move(impl))
24 {
25 this->impl->call<QRangeModelImplBase::InterfaceVersion>(m_interfaceVersion);
26 if (m_interfaceVersion >= QT_VERSION_CHECK(6, 12, 0)) {
27 m_supportedDropActions = this->impl->call<QRangeModelImplBase::AdjustSupportedDropActions>(
28 m_supportedDropActions
29 );
30 }
31 }
32
33 std::unique_ptr<QRangeModelImplBase, QRangeModelImplBase::Deleter> impl;
34 friend class QRangeModelImplBase;
35
36 static QRangeModelPrivate *get(QRangeModel *model) { return model->d_func(); }
37 static const QRangeModelPrivate *get(const QRangeModel *model) { return model->d_func(); }
38
39 mutable QHash<int, QByteArray> m_roleNames;
40 QRangeModel::AutoConnectPolicy m_autoConnectPolicy = QRangeModel::AutoConnectPolicy::None;
41 bool m_dataChangedDispatchBlocked = false;
42 int m_interfaceVersion = -1;
43 int m_sortRole = Qt::DisplayRole;
44 std::optional<QCollator> m_sortCollator;
45 mutable std::optional<QStringList> m_mimeTypes;
46 Qt::DropActions m_supportedDragActions = Qt::CopyAction;
47 Qt::DropActions m_supportedDropActions = Qt::CopyAction;
48
49 static void emitDataChanged(const QModelIndex &index, int role)
50 {
51 const auto *model = static_cast<const QRangeModel *>(index.model());
52 if (!get(model)->m_dataChangedDispatchBlocked)
53 const_cast<QRangeModel *>(model)->dataChanged(index, index, {role});
54 }
55
56 static bool compareModelIndex(const QModelIndex &left, const QModelIndex &right);
57};
58
60{
61 PropertyChangedHandler(const QPersistentModelIndex &index, int role)
63 {}
64
65 // move-only
69 {
70 Q_ASSERT(std::holds_alternative<Data>(storage));
71 // A moved-from handler is essentially a reference to the moved-to
72 // handler (which lives inside QSlotObject/QCallableObject). This
73 // way we can update the stored handler with the created connection.
74 other.storage = this;
75 }
79
80 // we can assign a connection to a moved-from handler to update the
81 // handler stored in the QSlotObject/QCallableObject.
82 PropertyChangedHandler &operator=(QMetaObject::Connection &&connection)
83 {
84 Q_ASSERT(std::holds_alternative<PropertyChangedHandler *>(storage));
85 std::get<PropertyChangedHandler *>(storage)->connection = std::move(connection);
86 return *this;
87 }
88
89 void operator()();
90
91private:
92 QMetaObject::Connection connection;
93 struct Data
94 {
95 QPersistentModelIndex index;
96 int role = -1;
97 };
98 std::variant<PropertyChangedHandler *, Data> storage;
99};
100
102{
103 Q_ASSERT(std::holds_alternative<Data>(storage));
104 const auto &data = std::get<Data>(storage);
105 if (!data.index.isValid()) {
106 if (!QObject::disconnect(connection))
107 qWarning() << "Failed to break connection for" << Qt::ItemDataRole(data.role);
108 } else {
109 QRangeModelPrivate::emitDataChanged(data.index, data.role);
110 }
111}
112
114{
115 ConstPropertyChangedHandler(const QModelIndex &index, int role)
116 : index(index), role(role)
117 {}
118
119 // move-only
122
123 void operator()() { QRangeModelPrivate::emitDataChanged(index, role); }
124
125private:
126 QModelIndex index;
127 int role = -1;
128};
129
130QRangeModel::QRangeModel(QRangeModelImplBase *impl, QObject *parent)
131 : QAbstractItemModel(*new QRangeModelPrivate({impl, {}}), parent)
132{
133}
134
135QRangeModelImplBase *QRangeModelImplBase::getImplementation(QRangeModel *model)
136{
137 return model->d_func()->impl.get();
138}
139
140const QRangeModelImplBase *QRangeModelImplBase::getImplementation(const QRangeModel *model)
141{
142 return model->d_func()->impl.get();
143}
144
145QScopedValueRollback<bool> QRangeModelImplBase::blockDataChangedDispatch()
146{
147 return QScopedValueRollback(m_rangeModel->d_func()->m_dataChangedDispatchBlocked, true);
148}
149
150int QRangeModelImplBase::sortRole() const
151{
152 return m_rangeModel->sortRole();
153}
154
155const QCollator *QRangeModelImplBase::sortCollator() const
156{
157 const QRangeModelPrivate *d = QRangeModelPrivate::get(m_rangeModel);
158 return d->m_sortCollator ? &d->m_sortCollator.value() : nullptr;
159}
160
161QVariant QRangeModelImplBase::convertMatchValue(const QVariant &value, Qt::MatchFlags flags)
162{
163 QVariant matchValue = value;
164 const Qt::CaseSensitivity cs = flags & Qt::MatchCaseSensitive
165 ? Qt::CaseSensitive : Qt::CaseInsensitive;
166 switch ((flags & Qt::MatchTypeMask).toInt()) {
167#if QT_CONFIG(regularexpression)
168 case Qt::MatchRegularExpression:
169 case Qt::MatchWildcard:
170 if (value.metaType() != QMetaType::fromType<QRegularExpression>()) {
171 QRegularExpression rx;
172 if (flags & Qt::MatchWildcard) {
173 rx.setPattern(QRegularExpression::wildcardToRegularExpression(
174 value.toString(), QRegularExpression::NonPathWildcardConversion));
175 } else {
176 rx.setPattern(value.toString());
177 }
178 if (cs == Qt::CaseInsensitive)
179 rx.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
180 matchValue = rx;
181 }
182 break;
183#endif // QT_CONFIG(regularexpression)
184 case Qt::MatchStartsWith:
185 case Qt::MatchEndsWith:
186 case Qt::MatchFixedString:
187 case Qt::MatchContains:
188 matchValue.convert(QMetaType::fromType<QString>());
189 break;
190 default:
191 break;
192 }
193 return matchValue;
194}
195
196bool QRangeModelImplBase::matchValue(const QString &itemData, const QVariant &value,
197 Qt::MatchFlags flags)
198{
199 // QString or regular expression based matching
200 const uint matchType = (flags & Qt::MatchTypeMask).toInt();
201 const Qt::CaseSensitivity cs = flags & Qt::MatchCaseSensitive
202 ? Qt::CaseSensitive : Qt::CaseInsensitive;
203 switch (matchType) {
204#if QT_CONFIG(regularexpression)
205 case Qt::MatchRegularExpression:
206 case Qt::MatchWildcard:
207 return itemData.contains(value.toRegularExpression());
208#endif // QT_CONFIG(regularexpression)
209 case Qt::MatchStartsWith:
210 return itemData.startsWith(value.toString(), cs);
211 case Qt::MatchEndsWith:
212 return itemData.endsWith(value.toString(), cs);
213 case Qt::MatchFixedString:
214 return itemData.compare(value.toString(), cs) == 0;
215 case Qt::MatchContains:
216 return itemData.contains(value.toString(), cs);
217 default:
218 return false;
219 }
220}
221
222/*!
223 \internal
224
225 Using \a metaObject, return a mapping of roles to the matching QMetaProperties.
226*/
227QHash<int, QMetaProperty> QRangeModelImplBase::roleProperties(const QAbstractItemModel &model,
228 const QMetaObject &metaObject)
229{
230 const auto roles = model.roleNames();
231 QHash<int, QMetaProperty> result;
232 for (auto &&[role, roleName] : roles.asKeyValueRange()) {
233 if (role == Qt::RangeModelDataRole)
234 continue;
235 result[role] = metaObject.property(metaObject.indexOfProperty(roleName));
236 }
237 return result;
238}
239
240QHash<int, QMetaProperty> QRangeModelImplBase::columnProperties(const QMetaObject &metaObject)
241{
242 QHash<int, QMetaProperty> result;
243 const int propertyOffset = metaObject.propertyOffset();
244 for (int p = propertyOffset; p < metaObject.propertyCount(); ++p)
245 result[p - propertyOffset] = metaObject.property(p);
246 return result;
247}
248
249QRangeModelDetails::AutoConnectContext::~AutoConnectContext() = default;
250
251template <auto Handler>
252static bool connectPropertiesHelper(const QModelIndex &index, const QObject *item,
253 QRangeModelDetails::AutoConnectContext *context,
254 const QHash<int, QMetaProperty> &properties)
255{
256 if (!item)
257 return true;
258
259 auto connect = [item, context](const QModelIndex &cell, int role, const QMetaProperty &property) {
260 if (property.hasNotifySignal()) {
261 if (!Handler(cell, item, context, role, property))
262 return false;
263 } else {
264 qWarning() << "Property" << property.name() << "for" << Qt::ItemDataRole(role)
265 << "at" << cell << "has no notify signal";
266 }
267 return true;
268 };
269
270 if (context->mapping == QRangeModelDetails::AutoConnectContext::AutoConnectMapping::Roles) {
271 for (auto &&[role, property] : properties.asKeyValueRange())
272 connect(index, role, property);
273 } else {
274 for (auto &&[column, property] : properties.asKeyValueRange())
275 connect(index.siblingAtColumn(column), Qt::DisplayRole, property);
276 }
277 return true;
278}
279
280bool QRangeModelImplBase::connectProperty(const QModelIndex &index, const QObject *item,
281 QRangeModelDetails::AutoConnectContext *context,
282 int role, const QMetaProperty &property)
283{
284 if (!item)
285 return true; // nothing to do, continue
286 PropertyChangedHandler handler{index, role};
287 auto connection = property.enclosingMetaObject()->connect(item, property.notifySignal(),
288 context, std::move(handler));
289 if (!connection) {
290 qWarning() << "Failed to connect to" << item << property.name();
291 return false;
292 } else {
293 // handler is now in moved-from state, and acts like a reference to
294 // the handler that is stored in the QSlotObject/QCallableObject.
295 // This assignment updates the stored handler's connection with the
296 // QMetaObject::Connection handle, and should look harmless for
297 // static analyzers.
298 handler = std::move(connection);
299 }
300 return true;
301}
302
303bool QRangeModelImplBase::connectProperties(const QModelIndex &index, const QObject *item,
304 QRangeModelDetails::AutoConnectContext *context,
305 const QHash<int, QMetaProperty> &properties)
306{
307 return connectPropertiesHelper<QRangeModelImplBase::connectProperty>(index, item, context, properties);
308}
309
310bool QRangeModelImplBase::connectPropertyConst(const QModelIndex &index, const QObject *item,
311 QRangeModelDetails::AutoConnectContext *context,
312 int role, const QMetaProperty &property)
313{
314 if (!item)
315 return true; // nothing to do, continue
316 ConstPropertyChangedHandler handler{index, role};
317 if (!property.enclosingMetaObject()->connect(item, property.notifySignal(),
318 context, std::move(handler))) {
319 qWarning() << "Failed to connect to" << item << property.name();
320 return false;
321 } else {
322 return true;
323 }
324}
325
326bool QRangeModelImplBase::connectPropertiesConst(const QModelIndex &index, const QObject *item,
327 QRangeModelDetails::AutoConnectContext *context,
328 const QHash<int, QMetaProperty> &properties)
329{
330 return connectPropertiesHelper<QRangeModelImplBase::connectPropertyConst>(index, item, context, properties);
331}
332
334{
335Q_CORE_EXPORT QVariant qVariantAtIndex(const QModelIndex &index)
336{
341 };
344 size_t r = 0;
345 do {
346 variant = result[r].data();
347 ++r;
348 } while (!variant.isValid() && r < std::size(result));
349
350 return variant;
351}
352}
353
354/*!
355 \class QRangeModel
356 \inmodule QtCore
357 \since 6.10
358 \ingroup model-view
359 \brief QRangeModel implements QAbstractItemModel for any C++ range.
360 \reentrant
361
362 QRangeModel can make the data in any sequentially iterable C++ type
363 available to the \l{Model/View Programming}{model/view framework} of Qt.
364 This makes it easy to display existing data structures in the Qt Widgets
365 and Qt Quick item views, and to allow the user of the application to
366 manipulate the data using a graphical user interface.
367
368 To use QRangeModel, instantiate it with a C++ range and set it as
369 the model of one or more views:
370
371 \snippet qrangemodel/main.cpp array
372
373 \section1 Constructing the model
374
375 The range can be any C++ type for which the standard methods
376 \c{std::begin} and \c{std::end} are implemented, and for which the
377 returned iterator type satisfies \c{std::forward_iterator}. Certain model
378 operations will perform better if \c{std::size} is available, and if the
379 iterator satisfies \c{std::random_access_iterator}.
380
381 The range must be provided when constructing the model and can be provided
382 by value, reference wrapper, or pointer. How the model was constructed
383 defines whether changes through the model API will modify the original
384 data. Use QRangeModelAdapter to implicitly construct a model while also
385 having direct, type-safe, and convenient access to the model as a range.
386
387 When constructed by value, the model makes a copy of the range, and
388 QAbstractItemModel APIs that modify the model, such as setData() or
389 insertRows(), have no impact on the original range.
390
391 \snippet qrangemodel/main.cpp value
392
393 Changes made to the data can be monitored by connecting to the signals
394 emitted by the model, such as \l{QAbstractItemModel}{dataChanged()}.
395
396 To make modifications of the model affect the original range, provide the
397 range either by pointer:
398
399 \snippet qrangemodel/main.cpp pointer
400
401 or through a reference wrapper:
402
403 \snippet qrangemodel/main.cpp reference_wrapper
404
405 In this case, QAbstractItemModel APIs that modify the model also modify the
406 range. Methods that modify the structure of the range, such as insertRows()
407 or removeColumns(), use standard C++ container APIs \c{resize()},
408 \c{insert()}, \c{erase()}, in addition to dereferencing a mutating iterator
409 to set or clear the data.
410
411 \note Once the model has been constructed and passed on to a view, the
412 range that the model operates on must no longer be modified directly. Views
413 on the model wouldn't be informed about the changes, and structural changes
414 are likely to corrupt instances of QPersistentModelIndex that the model
415 maintains. Use QRangeModelAdapter to safely interact with the underlying
416 range while keeping the model updated.
417
418 The caller must make sure that the range's lifetime exceeds the lifetime of
419 the model.
420
421 Use smart pointers to make sure that the range is only deleted when all
422 clients are done with it.
423
424 \snippet qrangemodel/main.cpp smart_pointer
425
426 QRangeModel supports both shared and unique pointers.
427
428 \section2 Read-only or mutable
429
430 For ranges that are const objects, for which access always yields constant
431 values, or where the required container APIs are not available,
432 QRangeModel implements write-access APIs to do nothing and return
433 \c{false}. In the example using \c{std::array}, the model cannot add or
434 remove rows, as the number of entries in a C++ array is fixed. But the
435 values can be changed using setData(), and the user can trigger editing of
436 the values in the list view. By making the array const, the values also
437 become read-only.
438
439 \snippet qrangemodel/main.cpp const_array
440
441 The values are also read-only if the element type is const, like in
442
443 \snippet qrangemodel/main.cpp const_values
444
445 In the above examples using \c{std::vector}, the model can add or remove
446 rows, and the data can be changed. Passing the range as a constant
447 reference will make the model read-only.
448
449 \snippet qrangemodel/main.cpp const_ref
450
451 \note If the values in the range are const, then it's also not possible
452 to remove or insert columns and rows through the QAbstractItemModel API.
453 For more granular control, implement \l{the C++ tuple protocol}.
454
455 \section1 Rows and columns
456
457 The elements in the range are interpreted as rows of the model. Depending
458 on the type of these row elements, QRangeModel exposes the range as a
459 list, a table, or a tree.
460
461 If the row elements are simple values, then the range gets represented as a
462 list.
463
464 \snippet qrangemodel/main.cpp list_of_int
465
466 If the type of the row elements is an iterable range, such as a vector,
467 list, or array, then the range gets represented as a table.
468
469 \snippet qrangemodel/main.cpp grid_of_numbers
470
471 If the row type provides the standard C++ container APIs \c{resize()},
472 \c{insert()}, \c{erase()}, then columns can be added and removed via
473 insertColumns() and removeColumns(). All rows are required to have
474 the same number of columns.
475
476 \section2 Structs and gadgets as rows
477
478 If the row type implements \l{the C++ tuple protocol}, then the range gets
479 represented as a table with a fixed number of columns.
480
481 \snippet qrangemodel/main.cpp pair_int_QString
482
483 An easier and more flexible alternative to implementing the tuple protocol
484 for a C++ type is to use Qt's \l{Meta-Object System}{meta-object system} to
485 declare a type with \l{Qt's Property System}{properties}. This can be a
486 value type that is declared as a \l{Q_GADGET}{gadget}, or a QObject subclass.
487
488 \snippet qrangemodel/main.cpp gadget
489
490 Using QObject subclasses allows properties to be \l{Qt Bindable Properties}
491 {bindable}, or to have change notification signals. However, using QObject
492 instances for items has significant memory overhead.
493
494 Using Qt gadgets or objects is more convenient and can be more flexible
495 than implementing the tuple protocol. Those types are also directly
496 accessible from within QML. However, the access through \l{the property system}
497 comes with some runtime overhead. For performance critical models, consider
498 implementing the tuple protocol for compile-time generation of the access
499 code.
500
501 \section2 Multi-role items
502
503 The type of the items that the implementations of data(), setData(),
504 clearItemData() etc. operate on can be the same across the entire model -
505 like in the \c{gridOfNumbers} example above. But the range can also have
506 different item types for different columns, like in the \c{numberNames}
507 case.
508
509 By default, the value gets used for the Qt::DisplayRole and Qt::EditRole
510 roles. Most views expect the value to be
511 \l{QVariant::canConvert}{convertible to and from a QString} (but a custom
512 delegate might provide more flexibility).
513
514 \section3 Associative containers with multiple roles
515
516 If the item is an associative container that uses \c{int},
517 \l{Qt::ItemDataRole}, or QString as the key type, and QVariant as the
518 mapped type, then QRangeModel interprets that container as the storage
519 of the data for multiple roles. The data() and setData() functions return
520 and modify the mapped value in the container, and setItemData() modifies all
521 provided values, itemData() returns all stored values, and clearItemData()
522 clears the entire container.
523
524 \snippet qrangemodel/main.cpp color_map
525
526 The most efficient data type to use as the key is Qt::ItemDataRole or
527 \c{int}. When using \c{int}, itemData() returns the container as is, and
528 doesn't have to create a copy of the data.
529
530 \section3 Gadgets and Objects as multi-role items
531
532 Gadgets and QObject types can also be represented as multi-role items. The
533 \l{The Property System}{properties} of those items will be used for the
534 role for which the \l{roleNames()}{name of a role} matches. If all items
535 hold the same type of gadget or QObject, then the \l{roleNames()}
536 implementation in QRangeModel will return the list of properties of that
537 type.
538
539 \snippet qrangemodel/specialize.cpp color_gadget_decl
540 \snippet qrangemodel/specialize.cpp color_gadget_impl
541 \snippet qrangemodel/specialize.cpp color_gadget_end
542
543 When used in a table, this is the default representation for gadgets:
544
545 \snippet qrangemodel/specialize.cpp color_gadget_table
546
547 When used in a list, these types are however by default represented as
548 multi-column rows, with each property represented as a separate column. To
549 force a gadget to be represented as a multi-role item in a list, declare
550 the gadget as a multi-role type by specializing QRoleModel::RowOptions,
551 with a \c{static constexpr auto rowCategory} member variable set to
552 MultiRoleItem.
553
554 \snippet qrangemodel/specialize.cpp color_gadget_decl
555 \dots
556 \snippet qrangemodel/specialize.cpp color_gadget_end
557 \snippet qrangemodel/specialize.cpp color_gadget_row_options_decl
558 \snippet qrangemodel/specialize.cpp color_gadget_row_options_rowCategory
559 \snippet qrangemodel/specialize.cpp color_gadget_row_options_end_decl
560
561 You can also wrap such types into a single-element tuple, turning the list
562 into a table with a single column:
563
564 \snippet qrangemodel/specialize.cpp color_gadget_single_column
565
566 In this case, note that direct access to the elements in the list data
567 needs to use \c{std::get}:
568
569 \snippet qrangemodel/specialize.cpp color_gadget_single_column_access_get
570
571 or alternatively a structured binding:
572
573 \snippet qrangemodel/specialize.cpp color_gadget_single_column_access_sb
574
575 \section2 Rows as values or pointers
576
577 In the examples so far, we have always used QRangeModel with ranges that
578 hold values. QRangeModel can also operate on ranges that hold pointers,
579 including smart pointers. This allows QRangeModel to operate on ranges of
580 polymorph types, such as QObject subclasses.
581
582 \snippet qrangemodel/main.cpp object_0
583 \dots
584 \snippet qrangemodel/main.cpp object_1
585
586 \snippet qrangemodel/main.cpp vector_of_objects_0
587 \dots
588 \snippet qrangemodel/main.cpp vector_of_objects_1
589 \snippet qrangemodel/main.cpp vector_of_objects_2
590
591 As with values, the type of the row defines whether the range is
592 represented as a list, table, or tree. Rows that are QObjects will present
593 each property as a column, unless the QRangeModel::RowOptions template is
594 specialized to declare the type as a multi-role item.
595
596 \snippet qrangemodel/main.cpp vector_of_multirole_objects_0
597 \snippet qrangemodel/main.cpp vector_of_multirole_objects_1
598 \dots
599 \snippet qrangemodel/main.cpp vector_of_multirole_objects_2
600
601 \note If the range holds raw pointers, then you have to construct
602 QRangeModel from a pointer or reference wrapper of the range. Otherwise the
603 ownership of the data becomes ambiguous, and a copy of the range would
604 still be operating on the same actual row data, resulting in unexpected
605 side effects.
606
607 \section2 Subclassing QRangeModel
608
609 Subclassing QRangeModel makes it possible to add convenient APIs that take
610 the data type and structure of the range into account.
611
612 \snippet qrangemodel/main.cpp subclass_header
613
614 When doing so, add the range as a private member, and call the QRangeModel
615 constructor with a reference wrapper or pointer to that member. This
616 properly encapsulates the data and avoids direct access.
617
618 \snippet qrangemodel/main.cpp subclass_API
619
620 Add member functions to provide type-safe access to the data, using the
621 QAbstractItemModel API to perform any operation that modifies the range.
622 Read-only access can directly operate on the data structure.
623
624 \section1 Trees of data
625
626 QRangeModel can represent a data structure as a tree model. Such a
627 tree data structure needs to be homomorphic: on all levels of the tree, the
628 list of child rows needs to use the exact same representation as the tree
629 itself. In addition, the row type needs be of a static size: either a gadget
630 or QObject type, or a type that implements \l{the C++ tuple protocol}.
631
632 To represent such data as a tree, QRangeModel has to be able to traverse the
633 data structure: for any given row, the model needs to be able to retrieve
634 the parent row, and the optional span of children. These traversal functions
635 can be provided implicitly through the row type, or through an explicit
636 protocol type.
637
638 \section2 Implicit tree traversal protocol
639
640 \snippet qrangemodel/main.cpp tree_protocol_0
641
642 The tree itself is a vector of \c{TreeRow} values. See \l{Tree Rows as
643 pointers or values} for the considerations on whether to use values or
644 pointers of items for the rows.
645
646 \snippet qrangemodel/main.cpp tree_protocol_1
647
648 The row class can be of any fixed-size type described above: a type that
649 implements the tuple protocol, a gadget, or a QObject. In this example, we
650 use a gadget.
651
652 Each row item needs to maintain a pointer to the parent row, as well as an
653 optional range of child rows. That range has to be identical to the range
654 structure used for the tree itself.
655
656 Making the row type default constructible is optional, and allows the model
657 to construct new row data elements, for instance in the insertRow() or
658 moveRows() implementations.
659
660 \snippet qrangemodel/main.cpp tree_protocol_2
661
662 The tree traversal protocol can then be implemented as member functions of
663 the row data type. A const \c{parentRow()} function has to return a pointer
664 to a row item; and the \c{childRows()} function has to return a reference
665 to a const \c{std::optional} that can hold the optional child range.
666
667 These two functions are sufficient for the model to navigate the tree as a
668 read-only data structure. To allow the user to edit data in a view, and the
669 model to implement mutating model APIs such as insertRows(), removeRows(),
670 and moveRows(), we have to implement additional functions for write-access:
671
672 \snippet qrangemodel/main.cpp tree_protocol_3
673
674 The model calls the \c{setParentRow()} function and mutable \c{childRows()}
675 overload to move or insert rows into an existing tree branch, and to update
676 the parent pointer should the old value have become invalid. The non-const
677 overload of \c{childRows()} provides in addition write-access to the row
678 data.
679
680 \note The model performs setting the parent of a row, removing that row
681 from the old parent, and adding it to the list of the new parent's children,
682 as separate steps. This keeps the protocol interface small.
683
684 \dots
685 \snippet qrangemodel/main.cpp tree_protocol_4
686
687 The rest of the class implementation is not relevant for the model, but
688 a \c{addChild()} helper provides us with a convenient way to construct the
689 initial state of the tree.
690
691 \snippet qrangemodel/main.cpp tree_protocol_5
692
693 A QRangeModel instantiated with an instance of such a range will
694 represent the data as a tree.
695
696 \snippet qrangemodel/main.cpp tree_protocol_6
697
698 \section2 Tree traversal protocol in a separate class
699
700 The tree traversal protocol can also be implemented in a separate class.
701
702 \snippet qrangemodel/main.cpp explicit_tree_protocol_0
703
704 Pass an instance of this protocol implementation to the QRangeModel
705 constructor:
706
707 \snippet qrangemodel/main.cpp explicit_tree_protocol_1
708
709 \section2 Tree Rows as pointers or values
710
711 The row type of the data range can be either a value, or a pointer. In
712 the code above we have been using the tree rows as values in a vector,
713 which avoids that we have to deal with explicit memory management. However,
714 a vector as a contiguous block of memory invalidates all iterators and
715 references when it has to reallocate the storage, or when inserting or
716 removing elements. This impacts the pointer to the parent item, which is
717 the location of the parent row within the vector. Making sure that this
718 parent (and QPersistentModelIndex instances referring to items within it)
719 stays valid can incurr substantial performance overhead. The
720 QRangeModel implementation has to assume that all references into the
721 range become invalid when modifying the range.
722
723 Alternatively, we can also use a range of row pointers as the tree type:
724
725 \snippet qrangemodel/main.cpp tree_of_pointers_0
726
727 In this case, we have to allocate all TreeRow instances explicitly using
728 operator \c{new}, and implement the destructor to \c{delete} all items in
729 the vector of children.
730
731 \snippet qrangemodel/main.cpp tree_of_pointers_1
732 \snippet qrangemodel/main.cpp tree_of_pointers_2
733
734 Before we can construct a model that represents this data as a tree, we need
735 to also implement the tree traversal protocol.
736
737 \snippet qrangemodel/main.cpp tree_of_pointers_3
738
739 An explicit protocol implementation for mutable trees of pointers has to
740 provide two additional member functions, \c{newRow()} and
741 \c{deleteRow(RowType *)}.
742
743 \snippet qrangemodel/main.cpp tree_of_pointers_4
744
745 The model will call those functions when creating new rows in insertRows(),
746 and when removing rows in removeRows(). In addition, if the model has
747 ownership of the data, then it will also delete all top-level rows upon
748 destruction. Note how in this example, we move the tree into the model, so
749 we must no longer perform any operations on it. QRangeModel, when
750 constructed by moving tree-data with row-pointers into it, will take
751 ownership of the data, and delete the row pointers in it's destructor.
752
753 Using pointers as rows comes with some memory allocation and management
754 overhead. However, the references to the row items remain stable, even when
755 they are moved around in the range, or when the range reallocates. This can
756 significantly reduce the cost of making modifications to the model's
757 structure when using insertRows(), removeRows(), or moveRows().
758
759 Each choice has different performance and memory overhead trade-offs. The
760 best option depends on the exact use case and data structure used.
761
762 \section1 Customization by template specialization
763
764 QRangeModel declares two nested templates types that you can specialize to
765 override default behavior.
766
767 The RowOptions template we have already introduced above is for customizing
768 functionality that is specific to the row-type, such as header data, or
769 that should apply uniformly to all items in a row, such as default flags.
770 The ItemAccess template allows customizing item type specific behavior,
771 such as reading or writing role data.
772
773 These two templates always need to be specialized for the underlying type,
774 so even if the range holds rows of type \c{Row} as
775 \c{std::unique_ptr<Row>}, or items of type \c{Item} as
776 \c{std::shared_ptr<Item>}, the specialization needs to be for \c{Row} and
777 \c{Item}.
778
779 \snippet qrangemodel/specialize.cpp color_gadget_item_access_decl
780 \dots
781 \snippet qrangemodel/specialize.cpp color_gadget_item_access_end_decl
782
783 \snippet qrangemodel/specialize.cpp color_gadget_item_access_use
784
785 \note In C++ you should only ever specialize templates for types that you
786 own, and not for standard or Qt types. Create subclasses or aggregates for
787 types you don't control if you need to customize behavior for those types.
788 Note that a type alias is not a distinct type, and you should not
789 specialize templates for alias types. However, it is allowed to create a
790 specialization of a standard or Qt container with a type that you own, such
791 as a \c{std::vector<MyGadget>}.
792
793 \section2 Row and item specific flags
794
795 The default implementation of flags() returns a combination of
796 Qt::ItemIsSelectable, Qt::ItemIsEnabled, and - except for items at column 0
797 of a tree model - Qt::ItemNeverHasChildren. The Qt::ItemIsEditable and
798 Qt::ItemIsDropEnabled flags are set for all items in models that are not
799 read-only, and Qt::ItemIsDragEnabled is set as long as the model supports
800 at least one \l{mimeTypes()}{mime type}.
801
802 To customize the default behavior for all items in a row, specialize the
803 RowOptions template. To access per-item flag data, specialize the
804 ItemAccess template. You can do both: RowOptions can set flags that are
805 common for all items in a row, and ItemAccess can set flags for items
806 backed by a specific type.
807
808 \section2 Drag'n'drop handling
809
810 Since Qt 6.12, QRangeModel implements the flags() virtual function to set
811 the Qt::ItemIsDragEnabled flag for all valid items in a model, as long as
812 the model supports at least one \l{mimeTypes()}{mime type}. This is the
813 default, as QAbstractItemModel provides the Qt-internal
814 "application/x-qabstractitemmodeldatalist" mime type. In addition, the
815 Qt::ItemIsDropEnabled flag is set for items in such a model as long as that
816 model is not read-only. This includes the non-existent item at the invalid
817 index, so users can drop data into empty areas of a view to append the
818 data.
819
820 Implementing support for additional mime types can be done without
821 subclassing QRangeModel and overriding the respective virtual functions.
822 QRangeModel will detect and use functions in the ItemAccess and RowOptions
823 customization templates to encode rows or items as \l{ItemAccess::mimeData()}
824 {mime data}, and to \l{ItemAccess::dropMimeData()}{decode mime data} into
825 sequences of rows or items. These customization functions can operate
826 directly on the row and item types, without taking detours through QModelIndex
827 and QVariant.
828
829 This way, the code for serializing data can be type-safe, and can stay with
830 the implementation of the type that is used to store the data.
831
832 In addition, \l{supportedDragActions} and \l{supportedDropActions} are
833 properties that can be configured for each QRangeModel instance.
834
835 \section1 Advanced C++ topics
836
837 \section2 The C++ tuple protocol
838
839 As seen in the \c{numberNames} example above, the row type can be a tuple,
840 and in fact any type that implements the tuple protocol. This protocol is
841 implemented by specializing \c{std::tuple_size} and \c{std::tuple_element},
842 and overloading the unqualified \c{get} function. Do so for your custom row
843 type to make existing structured data available to the model/view framework
844 in Qt.
845
846 \snippet qrangemodel/main.cpp tuple_protocol
847
848 In the above implementation, the \c{title} and \c{author} values of the
849 \c{Book} type are returned as \c{const}, so the model flags items in those
850 two columns as read-only. The user won't be able to trigger editing, and
851 setData() does nothing and returns false. For \c{summary} and \c{rating}
852 the implementation returns the same value category as the book, so when
853 \c{get} is called with a mutable reference to a \c{Book}, then it will
854 return a mutable reference of the respective variable. The model makes
855 those columns editable, both for the user and for programmatic access.
856
857 \note The implementation of \c{get} above requires C++23.
858
859 \section2 Binary compatibility considerations
860
861 QRangeModel is not a template class. Passing QRangeModel instances (by
862 pointer or reference, as with all QObject classes) through library APIs, or
863 storing QRangeModel by value in a public class of a library, is safe.
864
865 However, the QRangeModel constructor is a template and inline, and the
866 internal implementation that is specialized on the type of the range the
867 model operates on is instantiated in the constructor. You should not call
868 the constructor in an inline-implementation of a library API. It results in
869 ODR violations, and might break binary compatibility of that library if the
870 Qt version it gets built against is different from the Qt version an
871 application using that library is built against.
872
873 New and optimized implementations of virtual functions introduced in later
874 version of Qt might also not be used if QRangeModel detects that the
875 implementation was compiled against an older version of Qt. For instance,
876 the implementations of sort() and match() are new in Qt 6.12, but will not
877 be called by an application that was compiled against Qt 6.11, even if the
878 Qt library used is Qt 6.12. To benefit from such new overrides, recompile
879 your application.
880
881 \sa {Model/View Programming}
882*/
883
884/*!
885 \class QRangeModel::RowOptions
886 \inmodule QtCore
887 \ingroup model-view
888 \brief The RowOptions template provides a customization point to control
889 how QRangeModel represents types used as rows.
890 \since 6.10
891
892 RowOptions<T> is a struct template where \a T specifies the row type.
893 Specialize this template for the type used in your range, and add the
894 relevant members.
895
896 \snippet qrangemodel/specialize.cpp color_gadget_row_options_decl
897 \dots
898 \snippet qrangemodel/specialize.cpp color_gadget_row_options_end_decl
899
900 \sa ItemAccess
901*/
902
903/*!
904 \variable QRangeModel::RowOptions::rowCategory
905
906 Set this static compile-time constant to one of the values in the
907 RowCategory enumerator to define how QRangeModel should interpret the
908 elements of the range. Not providing this constant is the equivalent of
909 RowCategory::Default.
910
911 \snippet qrangemodel/specialize.cpp color_gadget_decl
912 \dots
913 \snippet qrangemodel/specialize.cpp color_gadget_end
914
915 \snippet qrangemodel/specialize.cpp color_gadget_row_options_decl
916 \snippet qrangemodel/specialize.cpp color_gadget_row_options_rowCategory
917 \snippet qrangemodel/specialize.cpp color_gadget_row_options_end_decl
918
919 If the \c{rowCategory} is set to \l{QRangeModel::RowCategory}{MultiRoleItem},
920 then none of the other members will have any effect.
921
922 \sa ItemAccess
923*/
924
925/*!
926 \fn template <typename T> QVariant QRangeModel::RowOptions<T>::headerData(int section, int role)
927 \since 6.12
928
929 Implement this class member to return the header data QRangeModel should
930 return for the \a role of the \a section in the horizontal header.
931
932 \snippet qrangemodel/specialize.cpp color_gadget_row_options_decl
933 \snippet qrangemodel/specialize.cpp color_gadget_row_options_headerData
934 \snippet qrangemodel/specialize.cpp color_gadget_row_options_end_decl
935
936 If this member is not provided, then QRangeModel returns type-specific default
937 values from the headerData() implementation.
938
939 \sa QAbstractItemModel::headerData()
940*/
941
942/*!
943 \fn template <typename T> Qt::ItemFlags QRangeModel::RowOptions<T>::flags(const T &row)
944 \since 6.12
945
946 Implement this class member to return the \l{QAbstractItemModel::flags}{flags}
947 for all items in \a row.
948
949 \snippet qrangemodel/specialize.cpp color_gadget_row_options_decl
950 \snippet qrangemodel/specialize.cpp color_gadget_row_options_flags
951 \snippet qrangemodel/specialize.cpp color_gadget_row_options_end_decl
952
953 This will be overwritten by a customization of \l{ItemAccess}{ItemAccess::flags}.
954
955 If this member is not provided, then QRangeModel computes the flags based
956 on the range it was constructed from.
957
958 \sa QAbstractItemModel::flags()
959*/
960
961/*!
962 \fn template <typename T> static QStringList QRangeModel::RowOptions<T>::mimeTypes()
963 \since 6.12
964
965 Implement this class member to return the list of \l{QAbstractItemModel::mimeTypes}
966 {mime types} that a model holding rows of type \a T can use to represent the
967 model data during drag'n'drop operations.
968
969 \snippet qrangemodel/specialize.cpp color_gadget_row_options_decl
970 \snippet qrangemodel/specialize.cpp color_gadget_row_options_mimeTypes
971 \snippet qrangemodel/specialize.cpp color_gadget_row_options_end_decl
972
973 If this member is not provided, then QRangeModel returns the default mime
974 type, "application/x-qabstractitemmodeldatalist", as supported by
975 QAbstractItemModel. If the returned list does not include that mime type,
976 then it will not be supported.
977
978 \sa QAbstractItemModel::mimeTypes()
979*/
980
981/*!
982 \fn template <typename T> QMimeData *QRangeModel::RowOptions<T>::mimeData(const auto &range)
983 \fn template <typename T> QMimeData *QRangeModel::RowOptions<T>::mimeData(const QModelIndex &range)
984 \since 6.12
985
986 Implement one of these class members to return the \l{QAbstractItemModel::mimeData()}
987 {mime data} for the rows in the provided \a range.
988
989 If the generic version is provided, then the iterator over \a range is
990 bidirectional, and dereferences to a pair of a row of type \a T and the
991 corresponding QModelIndex.
992
993 \snippet qrangemodel/specialize.cpp color_gadget_row_options_decl
994 \snippet qrangemodel/specialize.cpp color_gadget_row_options_mimeData
995 \snippet qrangemodel/specialize.cpp color_gadget_row_options_end_decl
996 \code
997 for (const auto &[row, index] : range) {
998 // ...
999 }
1000 \endcode
1001
1002 Fully selected rows will be included in the range only once, paired with an
1003 \c index that holds the row number and parent, and a column of -1.
1004 Partially selected rows are included in the range multiple times, once for
1005 each selected column.
1006
1007 The entries in \a range are sorted in logical order, from top-most to last
1008 row, and from left-most column to last column.
1009
1010 \sa QAbstractItemModel::mimeData()
1011*/
1012
1013/*!
1014 \fn template <typename T> bool QRangeModel::RowOptions<T>::canDropMimeData(const QMimeData *data)
1015 \fn template <typename T> bool QRangeModel::RowOptions<T>::canDropMimeData(const QMimeData *data, Qt::DragAction action, int row, int column, const QModelIndex &parent)
1016 \since 6.12
1017
1018//! [specialize-canDropMimeData]
1019 Implement one of these class members to return whether \c data can be dropped
1020 into the model. If the simplified version is implemented, then QRangeModel will
1021 validate that \a action is one of the \l{QRangeModel::supportedDropActions}
1022 {supported drop actions}. In the full version the implementation can return
1023 different results based on the position of the drop as specified by \a row,
1024 \a column, and \a parent.
1025
1026 This member is optional and not required for drag'n'drop customization.
1027 The default behavior returns whether \c data holds one of the supported mime
1028 types.
1029//! [specialize-canDropMimeData]
1030
1031 \sa QAbstractItemModel::canDropMimeData()
1032*/
1033
1034/*!
1035 \fn template <typename T> auto QRangeModel::RowOptions<T>::dropMimeData(const QMimeData *data, auto inserter)
1036 \fn template <typename T> auto QRangeModel::RowOptions<T>::dropMimeData(const QMimeData *data, Qt::DragAction action, int row, int column, const QModelIndex &parent, auto inserter)
1037 \since 6.12
1038
1039 Implement one of these class members to decode the relevant entries in \a
1040 data into a sequence of rows of type \a T, and drop these rows into the
1041 model by assigning each to the provided \a inserter. Return whether the
1042 operation was successful.
1043
1044 \snippet qrangemodel/specialize.cpp color_gadget_row_options_decl
1045 \snippet qrangemodel/specialize.cpp color_gadget_row_options_dropMimeData
1046 \snippet qrangemodel/specialize.cpp color_gadget_row_options_end_decl
1047
1048 The \a inserter behaves like a \l{https://cppreference.com/cpp/iterator/back_insert_iterator}
1049 {std::back_insert_iterator} and can be used with e.g. \c{std::copy}. The
1050 above snippets omits error handling, which perhaps would require storing the
1051 decoded items in a separate list that can be discarded in case of an error.
1052 The following would efficiently move the decoded rows into the model:
1053
1054 \code
1055 static bool dropMimeData(const QMimeData *mimeData, auto inserter)
1056 {
1057 QList<ColorEntry> decodedEntries;
1058 // read stream and populate decodedEntries
1059
1060 if (stream.hasError())
1061 return false;
1062 std::copy(std::move_iterator(decodedRows.begin()), std::move_iterator(decodedRows.end()),
1063 inserter);
1064 return true;
1065 }
1066 \endcode
1067
1068 Optionally, decoded rows can be paired with the relative row number it
1069 should have in the inserted range of rows.
1070
1071 \code
1072 int row = 0;
1073 for (const auto &decodedRow : decodedRows) {
1074 inserter = {decodedRow, row};
1075 row += 2;
1076 }
1077 \endcode
1078
1079 This implementation keeps an empty row between each decoded row.
1080
1081//! [specialize-dropMimeData-return]
1082 Return one of the \l{QRangeModel::}{DropOperation} values to provide a hint
1083 to QRangeModel for how the dropped rows should be applied to the model.
1084 Alternatively, simply return \c{true} (the equivalent of
1085 \l{QRangeModel::}{DropOperation::Automatic}) or \c{false} (the equivalent of
1086 \l{QRangeModel::}{DropOperation::DontDrop}).
1087//! [specialize-dropMimeData-return]
1088
1089 \sa QAbstractItemModel::dropMimeData()
1090*/
1091
1092/*!
1093 \enum QRangeModel::RowCategory
1094
1095 This enum describes how QRangeModel should present the elements of the
1096 range it was constructed with.
1097
1098 \value Default
1099 QRangeModel decides how to present the rows.
1100 \value MultiRoleItem
1101 QRangeModel will present items with a meta object as multi-role
1102 items, also when used in a one-dimensional range.
1103
1104 Specialize the RowOptions template for your type, and add a public member
1105 variable \c{static constexpr auto rowCategory} with one of the values from
1106 this enum.
1107
1108 \sa RowOptions
1109*/
1110
1111/*!
1112 \class QRangeModel::ItemAccess
1113 \inmodule QtCore
1114 \ingroup model-view
1115 \brief The ItemAccess template provides a customization point to control
1116 how QRangeModel accesses role data of individual items.
1117 \since 6.11
1118
1119 ItemAccess<T> is a struct template where \a T specifies the item type.
1120 Specialize this template for the type used in your data structure, and
1121 implement the relevant class member functions.
1122
1123 \snippet qrangemodel/specialize.cpp color_gadget_item_access_decl
1124 \snippet qrangemodel/specialize.cpp color_gadget_item_access_flags
1125 \snippet qrangemodel/specialize.cpp color_gadget_item_access_readRole
1126 \snippet qrangemodel/specialize.cpp color_gadget_item_access_writeRole
1127 \dots
1128 \snippet qrangemodel/specialize.cpp color_gadget_item_access_end_decl
1129
1130 A specialization of this type will take precedence over any predefined
1131 behavior, and over a corresponding specialization of \l{QRangeModel::}{RowOptions}.
1132
1133 \note Do not specialize this template for types you do not own.
1134*/
1135
1136/*!
1137 \fn template <typename T> QVariant QRangeModel::ItemAccess<T>::readRole(const T &item, int role)
1138
1139 Implement this class member to return the data in \a item for the requested
1140 \a role.
1141
1142 \snippet qrangemodel/specialize.cpp color_gadget_item_access_decl
1143 \snippet qrangemodel/specialize.cpp color_gadget_item_access_readRole
1144 \snippet qrangemodel/specialize.cpp color_gadget_item_access_end_decl
1145
1146 Types for which ItemAccess is specialized with a \c{readRole} implementation
1147 are implicitly interpreted as \l{RowCategory}{multi-role items}.
1148
1149 \sa QAbstractItemModel::data()
1150*/
1151
1152/*!
1153 \fn template <typename T> bool QRangeModel::ItemAccess<T>::writeRole(T &item, const QVariant &value, int role)
1154
1155 Implement this class member to set the data of \a item for the requested
1156 \a role to the provided \a value, and return whether the change was
1157 successful.
1158
1159 \snippet qrangemodel/specialize.cpp color_gadget_item_access_decl
1160 \snippet qrangemodel/specialize.cpp color_gadget_item_access_writeRole
1161 \snippet qrangemodel/specialize.cpp color_gadget_item_access_end_decl
1162
1163 \sa QAbstractItemModel::setData()
1164*/
1165
1166/*!
1167 \fn template <typename T> Qt::ItemFlags QRangeModel::ItemAccess<T>::flags(const T &item)
1168 \since 6.12
1169
1170 Implement this class member to return the \l{QAbstractItemModel::flags}{flags}
1171 for \a item.
1172
1173 \snippet qrangemodel/specialize.cpp color_gadget_item_access_decl
1174 \snippet qrangemodel/specialize.cpp color_gadget_item_access_flags
1175 \snippet qrangemodel/specialize.cpp color_gadget_item_access_end_decl
1176
1177 \sa QAbstractItemModel::flags()
1178*/
1179
1180/*!
1181 \fn template <typename T> static QStringList QRangeModel::ItemAccess<T>::mimeTypes()
1182 \since 6.12
1183
1184 Implement this class member to return the list of \l{QAbstractItemModel::mimeTypes}
1185 {mime types} that a model holding items of type \a T can use to represent the
1186 model data during drag'n'drop operations.
1187
1188 \snippet qrangemodel/specialize.cpp color_gadget_item_access_decl
1189 \snippet qrangemodel/specialize.cpp color_gadget_item_access_mimeTypes
1190 \snippet qrangemodel/specialize.cpp color_gadget_item_access_end_decl
1191
1192 If the list includes the \l{QAbstractItemModel::mimeTypes()}{default mime type}
1193 that Qt uses for drag'n'drop data, then QRangeModel will take care of the
1194 encoding and decoding of data for that mime type automatically.
1195
1196//! [specialize-ItemAccess-dragdrop]
1197 \note This specialization will only be considered when all items in the
1198 model are backed by items of type \a T. For heterogenous models where
1199 different columns provide different data types, specialize
1200 \l{QRangeModel::}{RowOptions} instead.
1201//! [specialize-ItemAccess-dragdrop]
1202
1203 \sa QAbstractItemModel::mimeTypes()
1204*/
1205
1206/*!
1207 \fn template <typename T> QMimeData *QRangeModel::ItemAccess<T>::mimeData(const auto &range)
1208 \fn template <typename T> QMimeData *QRangeModel::ItemAccess<T>::mimeData(const QModelIndex &range)
1209 \since 6.12
1210
1211 Implement one of these class members to return the \l{QAbstractItemModel::mimeData()}
1212 {mime data} for the items in the provided \a range.
1213
1214 If the generic version is provided, then the iterator over \a range is
1215 bidirectional, and dereferences to a pair with an item of type \a T and the
1216 corresponding QModelIndex.
1217
1218 \snippet qrangemodel/specialize.cpp color_gadget_item_access_decl
1219 \snippet qrangemodel/specialize.cpp color_gadget_item_access_mimeData
1220 \snippet qrangemodel/specialize.cpp color_gadget_item_access_end_decl
1221
1222 The entries in \a range are sorted in logical order, from top-most to last row,
1223 and from left-most column to last column.
1224
1225 \include qrangemodel.cpp specialize-ItemAccess-dragdrop
1226
1227 \sa QAbstractItemModel::mimeData()
1228*/
1229
1230/*!
1231 \fn template <typename T> bool QRangeModel::ItemAccess<T>::canDropMimeData(const QMimeData *data)
1232 \fn template <typename T> bool QRangeModel::ItemAccess<T>::canDropMimeData(const QMimeData *data, Qt::DragAction action, int row, int column, const QModelIndex &parent)
1233 \since 6.12
1234
1235 \include qrangemodel.cpp specialize-canDropMimeData
1236
1237 \include qrangemodel.cpp specialize-ItemAccess-dragdrop
1238
1239 \sa QAbstractItemModel::canDropMimeData()
1240*/
1241
1242/*!
1243 \fn template <typename T> auto QRangeModel::ItemAccess<T>::dropMimeData(const QMimeData *data, auto inserter)
1244 \fn template <typename T> auto QRangeModel::ItemAccess<T>::dropMimeData(const QMimeData *data, Qt::DragAction action, int row, int column, const QModelIndex &parent, auto inserter)
1245 \since 6.12
1246
1247 Implement one of these class members to decode the relevant entries in \a data
1248 into a sequence of items of type \a T, and drop these rows into the
1249 model by assigning each to the provided \a inserter. Return whether the
1250 operation was successful.
1251
1252 \snippet qrangemodel/specialize.cpp color_gadget_item_access_decl
1253 \snippet qrangemodel/specialize.cpp color_gadget_item_access_dropMimeData
1254 \snippet qrangemodel/specialize.cpp color_gadget_item_access_end_decl
1255
1256 Optionally, decoded items can be paired with a row and column value relative
1257 to the drop location. If the mime data includes positional information, then
1258 this makes it possible to maintain the "shape" of the items.
1259
1260 \code
1261 for (const auto &decodedItem: decodedItems) {
1262 inserter = {
1263 decodedItem,
1264 {
1265 relativeRow,
1266 relativeColumn
1267 }
1268 };
1269 }
1270 \endcode
1271
1272 Implement the version with \a action, \a row, \a column, and \a parent
1273 parameters for full control over the operation.
1274
1275 \include qrangemodel.cpp specialize-dropMimeData-return
1276
1277 \include qrangemodel.cpp specialize-ItemAccess-dragdrop
1278
1279 \sa QAbstractItemModel::dropMimeData()
1280*/
1281
1282/*!
1283 \fn template <typename Range, QRangeModelDetails::if_table_range<Range>> QRangeModel::QRangeModel(Range &&range, QObject *parent)
1284 \fn template <typename Range, QRangeModelDetails::if_tree_range<Range>> QRangeModel::QRangeModel(Range &&range, QObject *parent)
1285 \fn template <typename Range, typename Protocol, QRangeModelDetails::if_tree_range<Range, Protocol>> QRangeModel::QRangeModel(Range &&range, Protocol &&protocol, QObject *parent)
1286
1287 Constructs a QRangeModel instance that operates on the data in \a range.
1288 The \a range has to be a sequential range for which the compiler finds
1289 \c{begin} and \c{end} overloads through
1290 \l{https://en.cppreference.com/w/cpp/language/adl.html}{argument dependent
1291 lookup}, or for which \c{std::begin} and \c{std::end} are implemented. If
1292 \a protocol is provided, then the model will represent the range as a tree
1293 using the protocol implementation. The model instance becomes a child of \a
1294 parent.
1295
1296 The \a range can be a pointer or reference wrapper, in which case mutating
1297 model APIs (such as \l{setData()} or \l{insertRow()}) will modify the data
1298 in the referenced range instance. If \a range is a value (or moved into the
1299 model), then connect to the signals emitted by the model to respond to
1300 changes to the data.
1301
1302 QRangeModel will not access the \a range while being constructed. This
1303 makes it legal to pass a pointer or reference to a range object that is not
1304 fully constructed yet to this constructor, for example when \l{Subclassing
1305 QRangeModel}{subclassing QRangeModel}.
1306
1307 If the \a range was moved into the model, then the range and all data in it
1308 will be destroyed upon destruction of the model.
1309
1310 \note While the model does not take ownership of the range object otherwise,
1311 you must not modify the \a range directly once the model has been constructed
1312 and and passed on to a view. Such modifications will not emit signals
1313 necessary to keep model users (other models or views) synchronized with the
1314 model, resulting in inconsistent results, undefined behavior, and crashes.
1315 Use QRangeModelAdapter to safely interact with the underlying range while
1316 keeping the model updated.
1317
1318 \sa QRangeModelAdapter
1319*/
1320
1321/*!
1322 Destroys the QRangeModel.
1323
1324 The range that the model was constructed from is not accessed, and only
1325 destroyed if the model was constructed from a moved-in range.
1326*/
1327QRangeModel::~QRangeModel() = default;
1328
1329/*!
1330 \reimp
1331
1332 Returns the index of the model item at \a row and \a column in \a parent.
1333
1334 Passing a valid parent produces an invalid index for models that operate on
1335 list and table ranges.
1336
1337 \sa parent()
1338*/
1339QModelIndex QRangeModel::index(int row, int column, const QModelIndex &parent) const
1340{
1341 Q_D(const QRangeModel);
1342 return d->impl->call<QRangeModelImplBase::Index>(row, column, parent);
1343}
1344
1345/*!
1346 \reimp
1347
1348 Returns the parent of the item at the \a child index.
1349
1350 This function always produces an invalid index for models that operate on
1351 list and table ranges. For models operation on a tree, this function
1352 returns the index for the row item returned by the parent() implementation
1353 of the tree traversal protocol.
1354
1355 \sa index(), hasChildren()
1356*/
1357QModelIndex QRangeModel::parent(const QModelIndex &child) const
1358{
1359 Q_D(const QRangeModel);
1360 return d->impl->call<QRangeModelImplBase::Parent>(child);
1361}
1362
1363/*!
1364 \reimp
1365
1366 Returns the sibling at \a row and \a column for the item at \a index, or an
1367 invalid QModelIndex if there is no sibling at that location.
1368
1369 This implementation is significantly faster than going through the parent()
1370 of the \a index.
1371
1372 \sa index(), QModelIndex::row(), QModelIndex::column()
1373*/
1374QModelIndex QRangeModel::sibling(int row, int column, const QModelIndex &index) const
1375{
1376 Q_D(const QRangeModel);
1377 return d->impl->call<QRangeModelImplBase::Sibling>(row, column, index);
1378}
1379
1380/*!
1381 \reimp
1382
1383 Returns the number of rows under the given \a parent. This is the number of
1384 items in the root range for an invalid \a parent index.
1385
1386 If the \a parent index is valid, then this function always returns 0 for
1387 models that operate on list and table ranges. For trees, this returns the
1388 size of the range returned by the childRows() implementation of the tree
1389 traversal protocol.
1390
1391 \sa columnCount(), insertRows(), hasChildren()
1392*/
1393int QRangeModel::rowCount(const QModelIndex &parent) const
1394{
1395 Q_D(const QRangeModel);
1396 return d->impl->call<QRangeModelImplBase::RowCount>(parent);
1397}
1398
1399/*!
1400 \reimp
1401
1402 Returns the number of columns of the model. This function returns the same
1403 value for all \a parent indexes.
1404
1405 For models operating on a statically sized row type, this returned value is
1406 always the same throughout the lifetime of the model. For models operating
1407 on dynamically sized row type, the model returns the number of items in the
1408 first row, or 0 if the model has no rows.
1409
1410 \sa rowCount, insertColumns()
1411*/
1412int QRangeModel::columnCount(const QModelIndex &parent) const
1413{
1414 Q_D(const QRangeModel);
1415 return d->impl->call<QRangeModelImplBase::ColumnCount>(parent);
1416}
1417
1418/*!
1419 \reimp
1420
1421 Returns the item flags for the given \a index.
1422
1423 The implementation returns a combination of flags that enables the item
1424 (\c ItemIsEnabled) and allows it to be selected (\c ItemIsSelectable). For
1425 models operating on a range with mutable data, it also sets the flag
1426 that allows the item to be editable (\c ItemIsEditable).
1427
1428 Models that return a non-empty list of \l{mimeTypes()}{mimeTypes()} also
1429 set the Qt::ItemIsDragEnabled, and - unless read-only - the
1430 Qt::ItemIsDropEnabled flag.
1431
1432 Flat models set the Qt::ItemNeverHasChildren for all items, while
1433 hierarchical models set that flag for all items in columns above 0.
1434
1435 To customize the flags for your own data types, provide a specialization
1436 of RowOptions and/or ItemAccess for your row or item types and implement a
1437 \l{ItemAccess::}{flags()} static member function:
1438
1439 \snippet qrangemodel/specialize.cpp color_gadget_item_access_decl
1440 \snippet qrangemodel/specialize.cpp color_gadget_item_access_flags
1441 \snippet qrangemodel/specialize.cpp color_gadget_item_access_end_decl
1442
1443 \sa Qt::ItemFlags, RowOptions, ItemAccess
1444*/
1445Qt::ItemFlags QRangeModel::flags(const QModelIndex &index) const
1446{
1447 Q_D(const QRangeModel);
1448 return d->impl->call<QRangeModelImplBase::Flags>(index);
1449}
1450
1451/*!
1452 \reimp
1453
1454 Returns the data for the given \a role and \a section in the header with
1455 the specified \a orientation.
1456
1457 For horizontal headers, the section number corresponds to the column
1458 number. Similarly, for vertical headers, the section number corresponds to
1459 the row number.
1460
1461 For the horizontal header and the Qt::DisplayRole \a role, models that
1462 operate on a range that uses an array as the row type return \a section. If
1463 the row type is a tuple, then the implementation returns the name of the
1464 type at \a section. For rows that are a gadget or QObject type, this
1465 function returns the name of the property at the index of \a section.
1466
1467 To customize the horizontal header data for your own range, provide a
1468 specialization of RowOptions for your row types and implement a
1469 \l{RowOptions::}{headerData()} class member function:
1470
1471 \snippet qrangemodel/specialize.cpp color_gadget_row_options_decl
1472 \snippet qrangemodel/specialize.cpp color_gadget_row_options_headerData
1473 \snippet qrangemodel/specialize.cpp color_gadget_row_options_end_decl
1474
1475 For the vertical header, this function always returns the result of the
1476 default implementation in QAbstractItemModel.
1477
1478 \sa Qt::ItemDataRole, setHeaderData(), QHeaderView, RowOptions
1479*/
1480QVariant QRangeModel::headerData(int section, Qt::Orientation orientation, int role) const
1481{
1482 Q_D(const QRangeModel);
1483 return d->impl->call<QRangeModelImplBase::HeaderData>(section, orientation, role);
1484}
1485
1486/*!
1487 \reimp
1488*/
1489bool QRangeModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &data,
1490 int role)
1491{
1492 return QAbstractItemModel::setHeaderData(section, orientation, data, role);
1493}
1494
1495/*!
1496 \reimp
1497
1498 Returns the data stored under the given \a role for the value in the
1499 range referred to by the \a index.
1500
1501 If the item type for that index is an associative container that maps from
1502 either \c{int}, Qt::ItemDataRole, or QString to a QVariant, then the role
1503 data is looked up in that container and returned.
1504
1505 If the item is a gadget or QObject, then the implementation returns the
1506 value of the item's property matching the \a role entry in the roleNames()
1507 mapping.
1508
1509 Otherwise, the implementation returns a QVariant constructed from the item
1510 via \c{QVariant::fromValue()} for \c{Qt::DisplayRole} or \c{Qt::EditRole}.
1511 For other roles, the implementation returns an \b invalid
1512 (default-constructed) QVariant.
1513
1514 \sa Qt::ItemDataRole, setData(), headerData()
1515*/
1516QVariant QRangeModel::data(const QModelIndex &index, int role) const
1517{
1518 Q_D(const QRangeModel);
1519 return d->impl->call<QRangeModelImplBase::Data>(index, role);
1520}
1521
1522/*!
1523 \reimp
1524
1525 Sets the \a role data for the item at \a index to \a data.
1526
1527 If the item type for that \a index is an associative container that maps
1528 from either \c{int}, Qt::ItemDataRole, or QString to a QVariant, then
1529 \a data is stored in that container for the key specified by \a role.
1530
1531 If the item is a gadget or QObject, then \a data is written to the item's
1532 property matching the \a role entry in the the roleNames() mapping. The
1533 function returns \c{true} if a property was found and if \a data stored a
1534 value that could be converted to the required type, otherwise returns
1535 \c{false}.
1536
1537 Otherwise, this implementation assigns the value in \a data to the item at
1538 the \a index in the range for \c{Qt::DisplayRole} and \c{Qt::EditRole},
1539 and returns \c{true}. For other roles, the implementation returns
1540 \c{false}.
1541
1542//! [read-only-setData]
1543 For models operating on a read-only range, or on a read-only column in
1544 a row type that implements \l{the C++ tuple protocol}, this implementation
1545 returns \c{false} immediately.
1546//! [read-only-setData]
1547*/
1548bool QRangeModel::setData(const QModelIndex &index, const QVariant &data, int role)
1549{
1550 Q_D(QRangeModel);
1551 return d->impl->call<QRangeModelImplBase::SetData>(index, data, role);
1552}
1553
1554/*!
1555 \reimp
1556
1557 Returns a map with values for all predefined roles in the model for the
1558 item at the given \a index.
1559
1560 If the item type for that \a index is an associative container that maps
1561 from either \c{int}, Qt::ItemDataRole, or QString to a QVariant, then the
1562 data from that container is returned.
1563
1564 If the item type is a gadget or QObject subclass, then the values of those
1565 properties that match a \l{roleNames()}{role name} are returned.
1566
1567 If the item is not an associative container, gadget, or QObject subclass,
1568 then this calls the base class implementation.
1569
1570 \sa setItemData(), Qt::ItemDataRole, data()
1571*/
1572QMap<int, QVariant> QRangeModel::itemData(const QModelIndex &index) const
1573{
1574 Q_D(const QRangeModel);
1575 return d->impl->call<QRangeModelImplBase::ItemData>(index);
1576}
1577
1578/*!
1579 \reimp
1580
1581 If the item type for that \a index is an associative container that maps
1582 from either \c{int} or Qt::ItemDataRole to a QVariant, then the entries in
1583 \a data are stored in that container. If the associative container maps from
1584 QString to QVariant, then only those values in \a data are stored for which
1585 there is a mapping in the \l{roleNames()}{role names} table.
1586
1587 If the item type is a gadget or QObject subclass, then those properties that
1588 match a \l{roleNames()}{role name} are set to the corresponding value in
1589 \a data.
1590
1591 Roles for which there is no entry in \a data are not modified.
1592
1593 For item types that can be copied, this implementation is transactional,
1594 and returns true if all the entries from \a data could be stored. If any
1595 entry could not be updated, then the original container is not modified at
1596 all, and the function returns false.
1597
1598 If the item is not an associative container, gadget, or QObject subclass,
1599 then this calls the base class implementation, which calls setData() for
1600 each entry in \a data.
1601
1602 \sa itemData(), setData(), Qt::ItemDataRole
1603*/
1604bool QRangeModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &data)
1605{
1606 Q_D(QRangeModel);
1607 return d->impl->call<QRangeModelImplBase::SetItemData>(index, data);
1608}
1609
1610/*!
1611 \reimp
1612
1613 Replaces the value stored in the range at \a index with a default-
1614 constructed value.
1615
1616 \include qrangemodel.cpp read-only-setData
1617*/
1618bool QRangeModel::clearItemData(const QModelIndex &index)
1619{
1620 Q_D(QRangeModel);
1621 return d->impl->call<QRangeModelImplBase::ClearItemData>(index);
1622}
1623
1624/*
1625//! [column-change-requirement]
1626 \note A dynamically sized row type needs to provide a \c{\1} member function.
1627
1628 For models operating on a read-only range, or on a range with a
1629 statically sized row type (such as a tuple, array, or struct), this
1630 implementation does nothing and returns \c{false} immediately. This is
1631 always the case for tree models.
1632//! [column-change-requirement]
1633*/
1634
1635/*!
1636 \reimp
1637
1638 Inserts \a count empty columns before the item at \a column in all rows
1639 of the range at \a parent. Returns \c{true} if successful; otherwise
1640 returns \c{false}.
1641
1642 \include qrangemodel.cpp {column-change-requirement} {insert(const_iterator, size_t, value_type)}
1643*/
1644bool QRangeModel::insertColumns(int column, int count, const QModelIndex &parent)
1645{
1646 Q_D(QRangeModel);
1647 return d->impl->call<QRangeModelImplBase::InsertColumns>(column, count, parent);
1648}
1649
1650/*!
1651 \reimp
1652
1653 Removes \a count columns from the item at \a column on in all rows of the
1654 range at \a parent. Returns \c{true} if successful, otherwise returns
1655 \c{false}.
1656
1657 \include qrangemodel.cpp {column-change-requirement} {erase(const_iterator, size_t)}
1658*/
1659bool QRangeModel::removeColumns(int column, int count, const QModelIndex &parent)
1660{
1661 Q_D(QRangeModel);
1662 return d->impl->call<QRangeModelImplBase::RemoveColumns>(column, count, parent);
1663}
1664
1665/*!
1666 \reimp
1667
1668 Moves \a count columns starting with the given \a sourceColumn under parent
1669 \a sourceParent to column \a destinationColumn under parent \a destinationParent.
1670
1671 Returns \c{true} if the columns were successfully moved; otherwise returns
1672 \c{false}.
1673*/
1674bool QRangeModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count,
1675 const QModelIndex &destinationParent, int destinationColumn)
1676{
1677 Q_D(QRangeModel);
1678 return d->impl->call<QRangeModelImplBase::MoveColumns>(
1679 sourceParent, sourceColumn, count,
1680 destinationParent, destinationColumn);
1681}
1682
1683/*
1684//! [row-change-requirement]
1685 \note The range needs to be dynamically sized and provide a \c{\1}
1686 member function.
1687
1688 For models operating on a read-only or statically-sized range (such as
1689 an array), this implementation does nothing and returns \c{false}
1690 immediately.
1691//! [row-change-requirement]
1692*/
1693
1694/*!
1695 \reimp
1696
1697 Inserts \a count empty rows before the given \a row into the range at
1698 \a parent. Returns \c{true} if successful; otherwise returns \c{false}.
1699
1700 \include qrangemodel.cpp {row-change-requirement} {insert(const_iterator, size_t, value_type)}
1701
1702 \note For ranges with a dynamically sized column type, the column needs
1703 to provide a \c{resize(size_t)} member function.
1704*/
1705bool QRangeModel::insertRows(int row, int count, const QModelIndex &parent)
1706{
1707 Q_D(QRangeModel);
1708 return d->impl->call<QRangeModelImplBase::InsertRows>(row, count, parent);
1709}
1710
1711/*!
1712 \reimp
1713
1714 Removes \a count rows from the range at \a parent, starting with the
1715 given \a row. Returns \c{true} if successful, otherwise returns \c{false}.
1716
1717 \include qrangemodel.cpp {row-change-requirement} {erase(const_iterator, size_t)}
1718*/
1719bool QRangeModel::removeRows(int row, int count, const QModelIndex &parent)
1720{
1721 Q_D(QRangeModel);
1722 return d->impl->call<QRangeModelImplBase::RemoveRows>(row, count, parent);
1723}
1724
1725/*!
1726 \reimp
1727
1728 Moves \a count rows starting with the given \a sourceRow under parent
1729 \a sourceParent to row \a destinationRow under parent \a destinationParent.
1730
1731 Returns \c{true} if the rows were successfully moved; otherwise returns
1732 \c{false}.
1733*/
1734bool QRangeModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
1735 const QModelIndex &destinationParent, int destinationRow)
1736{
1737 Q_D(QRangeModel);
1738 return d->impl->call<QRangeModelImplBase::MoveRows>(
1739 sourceParent, sourceRow, count,
1740 destinationParent, destinationRow);
1741}
1742
1743/*!
1744 \reimp
1745*/
1746bool QRangeModel::canFetchMore(const QModelIndex &parent) const
1747{
1748 return QAbstractItemModel::canFetchMore(parent);
1749}
1750
1751/*!
1752 \reimp
1753*/
1754void QRangeModel::fetchMore(const QModelIndex &parent)
1755{
1756 QAbstractItemModel::fetchMore(parent);
1757}
1758
1759/*!
1760 \reimp
1761*/
1762bool QRangeModel::hasChildren(const QModelIndex &parent) const
1763{
1764 return QAbstractItemModel::hasChildren(parent);
1765}
1766
1767/*!
1768 \reimp
1769*/
1770QModelIndex QRangeModel::buddy(const QModelIndex &index) const
1771{
1772 return QAbstractItemModel::buddy(index);
1773}
1774
1775/*!
1776 \enum QRangeModel::DropOperation
1777 \since 6.12
1778
1779 This enum defines how data decoded in a dropMimeData() customization gets
1780 written to the model.
1781
1782 \value DontDrop The data should not be added to the model.
1783 \value Automatic Qt determines how data gets added to the model.
1784 \value OverwriteAndIgnore Overwrite the dropped-on item and following items,
1785 and discard any dropped data that doesn't fit.
1786 \value OverwriteAndExtend Overwrite the dropped-on item and following items,
1787 and grow the model to fit all dropped data.
1788 \value InsertAsSiblings Insert all dropped data as siblings of the dropped-on
1789 item.
1790 \value InsertAsChildren Insert all dropped data as children of the dropped-on
1791 item.
1792
1793 A dropMimeData() customization can return a bool value instead, in which
1794 case \c{false} maps to the DontDrop value, and \c{true} to Automatic.
1795
1796 \sa canDropMimeData(), dropMimeData()
1797*/
1798
1799/*
1800//! [override-calls-specialization]
1801 If a customization of ItemAccess is available for the item type stored in
1802 the range, and if that customization implements a suitable
1803 \l{ItemAccess::}{\1()} class member function, then this implementation
1804 calls that function and returns the result.
1805
1806 \snippet qrangemodel/specialize.cpp color_gadget_item_access_decl
1807 \snippet qrangemodel/specialize.cpp color_gadget_item_access_\1
1808 \snippet qrangemodel/specialize.cpp color_gadget_item_access_end_decl
1809
1810 Otherwise, if a customization of RowOptions is available for the row type
1811 in the range with a suitable \l{RowOptions::}{\1()} class member function,
1812 then this implementation returns the result of calling that function.
1813
1814 \snippet qrangemodel/specialize.cpp color_gadget_row_options_decl
1815 \snippet qrangemodel/specialize.cpp color_gadget_row_options_\1
1816 \snippet qrangemodel/specialize.cpp color_gadget_row_options_end_decl
1817
1818 If neither customization is available, then this returns the result of the
1819 default QAbstractItemModel implementation.
1820
1821 \sa {QRangeModel#Drag'n'drop handling}{Drag'n'drop handling},
1822 RowOptions::\1(), ItemAccess::\1()
1823//! [override-calls-specialization]
1824*/
1825
1826/*!
1827 \reimp
1828
1829 \include qrangemodel.cpp {override-calls-specialization} {canDropMimeData}
1830
1831 \sa dropMimeData(), mimeTypes(), mimeData()
1832*/
1833bool QRangeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action,
1834 int row, int column, const QModelIndex &parent) const
1835{
1836 Q_D(const QRangeModel);
1837 if (d->m_interfaceVersion < QT_VERSION_CHECK(6, 12, 0))
1838 return QAbstractItemModel::canDropMimeData(data, action, row, column, parent);
1839 return d->impl->call<QRangeModelImplBase::CanDropMimeData>(data, action, row, column, parent);
1840}
1841
1842/*!
1843 \reimp
1844
1845 \include qrangemodel.cpp {override-calls-specialization} {dropMimeData}
1846
1847 \sa canDropMimeData(), mimeTypes(), mimeData()
1848*/
1849bool QRangeModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
1850 int row, int column, const QModelIndex &parent)
1851{
1852 if (!data)
1853 return false;
1854 if (action == Qt::IgnoreAction)
1855 return true;
1856
1857 Q_D(QRangeModel);
1858 if (d->m_interfaceVersion < QT_VERSION_CHECK(6, 12, 0))
1859 return QAbstractItemModel::dropMimeData(data, action, row, column, parent);
1860 if (d->impl->call<QRangeModelImplBase::DropMimeData>(data, action, row, column, parent))
1861 return true;
1862
1863 // failing that, insert the data as new indexes. A row of -1 indicates
1864 // that data should be appended to the model
1865 if (row == -1)
1866 row = rowCount(parent);
1867#if !defined(QT_NO_DATASTREAM)
1868 const QString defaultFormat = QAbstractItemModel::mimeTypes().at(0);
1869 if (data->hasFormat(defaultFormat)) {
1870 QByteArray encoded = data->data(defaultFormat);
1871 QDataStream stream(&encoded, QDataStream::ReadOnly);
1872 return decodeData(row, column, parent, stream);
1873 }
1874#endif
1875 return false;
1876}
1877
1878bool QRangeModelImplBase::dropDataOnItem(const QMimeData *data, const QModelIndex &index)
1879{
1880#if !defined(QT_NO_DATASTREAM)
1881 const QString defaultFormat = m_rangeModel->QAbstractItemModel::mimeTypes().at(0);
1882 if (data->hasFormat(defaultFormat)) {
1883 QByteArray encoded = data->data(defaultFormat);
1884 QDataStream stream(&encoded, QDataStream::ReadOnly);
1885 return m_rangeModel->d_func()->dropOnItem(index, stream);
1886 }
1887#endif
1888 return false;
1889}
1890
1891// QModelIndex::operator< is not useful as it compares the internal data pointer.
1892// We need to compare indexes based on the row path, taking into account
1893// that only items at column zero can have children.
1894bool QRangeModelPrivate::compareModelIndex(const QModelIndex &left, const QModelIndex &right)
1895{
1896 if (!left.isValid())
1897 return right.isValid();
1898 if (!right.isValid())
1899 return false;
1900 const QModelIndex leftCol0 = left.column() ? left.siblingAtColumn(0) : left;
1901 const QModelIndex rightCol0 = right.column() ? right.siblingAtColumn(0) : right;
1902 const QModelIndex leftParent = leftCol0.parent();
1903 const QModelIndex rightParent = rightCol0.parent();
1904 if (leftParent == rightParent) {
1905 if (left.row() == right.row())
1906 return left.column() < right.column();
1907 return left.row() < right.row();
1908 }
1909 // parents come before their children
1910 if (leftCol0 == rightParent)
1911 return true;
1912 if (rightCol0 == leftParent)
1913 return false;
1914
1915 // indexes are not directly related, so generate and compare their paths
1916 auto makePath = [](const QModelIndex &index) {
1917 // we call with col0 indexes and a parent can never be at another column
1918 Q_ASSERT(index.column() == 0);
1919 QVarLengthArray<int, 32> path{index.row()};
1920 QModelIndex parent = index.parent();
1921 while (parent.isValid()) {
1922 path.append(parent.row());
1923 parent = parent.parent();
1924 }
1925 std::reverse(path.begin(), path.end());
1926 return path;
1927 };
1928 const auto leftPath = makePath(leftCol0);
1929 const auto rightPath = makePath(rightCol0);
1930 return leftPath < rightPath;
1931}
1932
1933/*!
1934 \reimp
1935
1936 \include qrangemodel.cpp {override-calls-specialization} {mimeData}
1937
1938 \sa canDropMimeData(), dropMimeData(), mimeTypes()
1939*/
1940QMimeData *QRangeModel::mimeData(const QModelIndexList &indexes) const
1941{
1942 Q_D(const QRangeModel);
1943 if (indexes.isEmpty())
1944 return nullptr;
1945
1946 if (d->m_interfaceVersion < QT_VERSION_CHECK(6, 12, 0))
1947 return QAbstractItemModel::mimeData(indexes);
1948
1949 // sort the indexes so that all indexes in the same row are in sequence.
1950 QModelIndexList groupedList = indexes;
1951 std::sort(groupedList.begin(), groupedList.end(), QRangeModelPrivate::compareModelIndex);
1952 QMimeData *data = d->impl->call<QRangeModelImplBase::MimeData>(groupedList);
1953
1954 // finalize with default mime type
1955 const QString defaultFormat = QAbstractItemModel::mimeTypes().at(0);
1956 if (!mimeTypes().contains(defaultFormat))
1957 return data;
1958
1959 std::unique_ptr<QMimeData> defaultMimeData(QAbstractItemModel::mimeData(indexes));
1960 if (!data)
1961 return defaultMimeData.release();
1962 // add default mime data into the custom data
1963 if (defaultMimeData) {
1964 const QStringList defaultTypes = defaultMimeData->formats();
1965 for (const auto &defaultType : defaultTypes)
1966 data->setData(defaultType, defaultMimeData->data(defaultType));
1967 }
1968 return data;
1969}
1970
1971/*!
1972 \reimp
1973
1974 \include qrangemodel.cpp {override-calls-specialization} {mimeTypes}
1975
1976 \sa canDropMimeData(), dropMimeData(), mimeData()
1977*/
1978QStringList QRangeModel::mimeTypes() const
1979{
1980 Q_D(const QRangeModel);
1981 if (!d->m_mimeTypes) {
1982 d->m_mimeTypes = d->m_interfaceVersion < QT_VERSION_CHECK(6, 12, 0)
1983 ? QAbstractItemModel::mimeTypes()
1984 : d->impl->call<QRangeModelImplBase::MimeTypes>();
1985 }
1986 return *d->m_mimeTypes;
1987}
1988
1989/*!
1990 \reimp
1991
1992 Returns a list of indexes for the items in the column of \a start where
1993 the data stored under \a role matches \a value, using the match criteria
1994 defined by \a flags. Use \a hits = -1 to find all matching items.
1995
1996 \note This implementation reads data directly from the underlying C++
1997 range and does not dispatch through overrides of data().
1998*/
1999QModelIndexList QRangeModel::match(const QModelIndex &start, int role, const QVariant &value,
2000 int hits, Qt::MatchFlags flags) const
2001{
2002 Q_D(const QRangeModel);
2003 if (d->m_interfaceVersion < QT_VERSION_CHECK(6, 12, 0))
2004 return QAbstractItemModel::match(start, role, value, hits, flags);
2005 return d->impl->call<QRangeModelImplBase::Match>(start, role, value, hits, flags);
2006}
2007
2008/*!
2009 \reimp
2010*/
2011void QRangeModel::multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const
2012{
2013 Q_D(const QRangeModel);
2014 if (d->m_interfaceVersion < QT_VERSION_CHECK(6, 11, 0))
2015 return QAbstractItemModel::multiData(index, roleDataSpan);
2016 d->impl->call<QRangeModelImplBase::MultiData>(index, roleDataSpan);
2017}
2018
2019
2020/*!
2021 \property QRangeModel::roleNames
2022 \brief the role names for the model.
2023
2024 If all columns in the range are of the same type, and if that type provides
2025 a meta object (i.e., it is a gadget, or a QObject subclass), then this
2026 property holds the names of the properties of that type, mapped to values of
2027 Qt::ItemDataRole values from Qt::UserRole and up. In addition, a role
2028 "modelData" provides access to the gadget or QObject instance.
2029
2030 Override this default behavior by setting this property explicitly to a non-
2031 empty mapping. Setting this property to an empty mapping, or using
2032 resetRoleNames(), restores the default behavior.
2033
2034 \sa QAbstractItemModel::roleNames()
2035*/
2036
2037QHash<int, QByteArray> QRangeModelImplBase::roleNamesForMetaObject(const QAbstractItemModel &model,
2038 const QMetaObject &metaObject)
2039{
2040 const auto defaults = model.QAbstractItemModel::roleNames();
2041 QHash<int, QByteArray> result = {{Qt::RangeModelDataRole, "modelData"}};
2042 int offset = metaObject.propertyOffset();
2043 for (int i = offset; i < metaObject.propertyCount(); ++i) {
2044 const auto name = metaObject.property(i).name();
2045 const int defaultRole = defaults.key(name, -1);
2046 if (defaultRole != -1) {
2047 ++offset;
2048 result[defaultRole] = name;
2049 } else {
2050 result[Qt::UserRole + i - offset] = name;
2051 }
2052 }
2053 return result;
2054}
2055
2056QHash<int, QByteArray> QRangeModelImplBase::roleNamesForSimpleType()
2057{
2058 // just a plain value
2059 return QHash<int, QByteArray>{
2060 {Qt::DisplayRole, "display"},
2061 {Qt::EditRole, "edit"},
2062 {Qt::RangeModelDataRole, "modelData"},
2063 };
2064}
2065
2066/*!
2067 \reimp
2068
2069 \note Overriding this function in a QRangeModel subclass is possible,
2070 but might break the behavior of the property.
2071*/
2072QHash<int, QByteArray> QRangeModel::roleNames() const
2073{
2074 Q_D(const QRangeModel);
2075 if (d->m_roleNames.isEmpty())
2076 d->m_roleNames = d->impl->call<QRangeModelImplBase::RoleNames>();
2077
2078 return d->m_roleNames;
2079}
2080
2081void QRangeModel::setRoleNames(const QHash<int, QByteArray> &names)
2082{
2083 Q_D(QRangeModel);
2084 if (d->m_roleNames == names)
2085 return;
2086 beginResetModel();
2087 d->impl->call<QRangeModelImplBase::InvalidateCaches>();
2088 if (d->m_autoConnectPolicy != AutoConnectPolicy::None)
2089 d->impl->call<QRangeModelImplBase::SetAutoConnectPolicy>();
2090
2091 d->m_roleNames = names;
2092 endResetModel();
2093 Q_EMIT roleNamesChanged();
2094}
2095
2096void QRangeModel::resetRoleNames()
2097{
2098 setRoleNames({});
2099}
2100
2101/*!
2102 \enum QRangeModel::AutoConnectPolicy
2103 \since 6.11
2104
2105 This enum defines if and when QRangeModel auto-connects changed-signals for
2106 properties to the \l{QAbstractItemModel::}{dataChanged()} signal of the
2107 model. Only properties that match one of the \l{roleNames()}{role names}
2108 are connected.
2109
2110 \value None No connections are made automatically.
2111 \value Full The signals for all relevant properties are connected
2112 automatically, for all QObject items. This includes QObject
2113 items that are added to newly inserted rows and columns.
2114 \value OnRead Signals for relevant properties are connected the first time
2115 the model reads the property.
2116
2117 The memory overhead of making automatic connections can be substantial. A
2118 Full auto-connection does not require any book-keeping in addition to the
2119 connection itself, but each connection takes memory, and connecting all
2120 properties of all objects can be very costly, especially if only a few
2121 properties of a subset of objects will ever change.
2122
2123 The OnRead connection policy will not connect to objects or properties that
2124 are never read from (for instance, never rendered in a view), but remembering
2125 which connections have been made requires some book-keeping overhead, and
2126 unpredictable memory growth over time. For instance, scrolling down a long
2127 list of items can easily result in thousands of new connections being made.
2128
2129 \sa autoConnectPolicy, roleNames()
2130*/
2131
2132/*!
2133 \property QRangeModel::autoConnectPolicy
2134 \since 6.11
2135 \brief if and when the model auto-connects to property changed notifications.
2136
2137 If QRangeModel operates on a data structure that holds the same type of
2138 QObject subclass as its row or item type, then it can automatically connect
2139 the properties of the QObjects to the dataChanged() signal. For QObject
2140 rows, this is done for each column, mapping to the Qt::DisplayRole
2141 property. For items, this is done for those properties that match one of
2142 the \l{roleNames()}{role names}.
2143
2144 By default, the value of this property is \l{QRangeModel::AutoConnectPolicy::}
2145 {None}, so no such connections are made. Changing the value of this property
2146 always breaks all existing connections.
2147
2148 \note Connections are not broken or created if QObjects in the data
2149 structure that QRangeModel operates on are swapped out.
2150
2151 \sa roleNames()
2152*/
2153
2154QRangeModel::AutoConnectPolicy QRangeModel::autoConnectPolicy() const
2155{
2156 Q_D(const QRangeModel);
2157 return d->m_autoConnectPolicy;
2158}
2159
2160void QRangeModel::setAutoConnectPolicy(QRangeModel::AutoConnectPolicy policy)
2161{
2162 Q_D(QRangeModel);
2163 if (d->m_autoConnectPolicy == policy)
2164 return;
2165
2166 d->m_autoConnectPolicy = policy;
2167 d->impl->call<QRangeModelImplBase::SetAutoConnectPolicy>();
2168 Q_EMIT autoConnectPolicyChanged(policy);
2169}
2170
2171/*!
2172 \reimp
2173
2174 Sorts the the underlying range in the given \a order, based on the data for
2175 the \l{sortRole} (Qt::DisplayRole by default) of the items in \a column.
2176
2177 \note This implementation uses a member function \c{sort(Compare comp)} of
2178 the C++ range if available (such as in \c{std::list}), or otherwise
2179 \c{std::stable_sort()} if the range provides random-access iterators. If
2180 neither is available then the implementation does nothing and returns
2181 immediately.
2182
2183 \note Accessing the item does not dispatch the reading of data through
2184 overrides of data().
2185
2186 \sa sortRole, QSortFilterProxyModel
2187*/
2188void QRangeModel::sort(int column, Qt::SortOrder order)
2189{
2190 Q_D(QRangeModel);
2191 if (d->m_interfaceVersion < QT_VERSION_CHECK(6, 12, 0))
2192 return QAbstractItemModel::sort(column, order);
2193 QT_TRY {
2194 d->impl->call<QRangeModelImplBase::Sort>(column, order);
2195 } QT_CATCH(const std::bad_alloc &) {
2196 qCritical("QRangeModel::sort ran out of memory, sort likely incomplete.");
2197 }
2198}
2199
2200/*!
2201 \property QRangeModel::sortRole
2202 \since 6.12
2203 \brief the data role used when sorting items.
2204
2205 The default value is Qt::DisplayRole.
2206
2207 \sa sort(), sortCollator, QSortFilterProxyModel
2208*/
2209int QRangeModel::sortRole() const
2210{
2211 Q_D(const QRangeModel);
2212 return d->m_sortRole;
2213}
2214
2215void QRangeModel::setSortRole(int role)
2216{
2217 Q_D(QRangeModel);
2218 if (d->m_sortRole == role)
2219 return;
2220 d->m_sortRole = role;
2221 Q_EMIT sortRoleChanged(d->m_sortRole);
2222}
2223
2224void QRangeModel::resetSortRole()
2225{
2226 setSortRole(Qt::DisplayRole);
2227}
2228
2229/*!
2230 \property QRangeModel::sortCollator
2231 \since 6.12
2232 \brief the collator that will be used when sorting the model
2233
2234 The default value of this property is a QCollator for the C-locale.
2235 Sorting will not be locale aware, and case sensitive. Setting a collator
2236 will make the sorting locale-aware.
2237
2238 \sa sort(), sortRole, QSortFilterProxyModel
2239*/
2240QCollator QRangeModel::sortCollator() const
2241{
2242 Q_D(const QRangeModel);
2243 return d->m_sortCollator.value_or(QCollator(QLocale::C));
2244}
2245
2246void QRangeModel::setSortCollator(const QCollator &collator)
2247{
2248 Q_D(QRangeModel);
2249 if (sortCollator() == collator)
2250 return;
2251 d->m_sortCollator = collator;
2252 Q_EMIT sortCollatorChanged(*d->m_sortCollator);
2253}
2254
2255void QRangeModel::resetSortCollator()
2256{
2257 Q_D(QRangeModel);
2258 if (!d->m_sortCollator)
2259 return;
2260 d->m_sortCollator = std::nullopt;
2261 Q_EMIT sortCollatorChanged(sortCollator());
2262}
2263
2264/*!
2265 \reimp
2266*/
2267QSize QRangeModel::span(const QModelIndex &index) const
2268{
2269 return QAbstractItemModel::span(index);
2270}
2271
2272/*!
2273 \property QRangeModel::supportedDragActions
2274 \since 6.12
2275 \brief the drag-actions supported by this model.
2276
2277 Actions that the model cannot support, such as moving data out of a
2278 read-only model, will be removed when setting the actions.
2279
2280 \note Overriding this function in a QRangeModel subclass is possible,
2281 but might break the behavior of the property.
2282
2283 \sa supportedDropActions
2284*/
2285Qt::DropActions QRangeModel::supportedDragActions() const
2286{
2287 Q_D(const QRangeModel);
2288 return d->m_supportedDragActions;
2289}
2290
2291void QRangeModel::setSupportedDragActions(Qt::DropActions actions)
2292{
2293 Q_D(QRangeModel);
2294 actions = d->impl->call<QRangeModelImplBase::AdjustSupportedDragActions>(actions);
2295 if (actions == d->m_supportedDragActions)
2296 return;
2297 d->m_supportedDragActions = actions;
2298 Q_EMIT supportedDragActionsChanged(d->m_supportedDragActions);
2299}
2300
2301void QRangeModel::resetSupportedDragActions()
2302{
2303 setSupportedDragActions(Qt::CopyAction);
2304}
2305
2306/*!
2307 \property QRangeModel::supportedDropActions
2308 \since 6.12
2309 \brief the drop-actions supported by this model.
2310
2311 Read-only models cannot support any drop-actions.
2312
2313 \note Overriding this function in a QRangeModel subclass is possible,
2314 but might break the behavior of the property.
2315
2316 \sa supportedDragActions
2317*/
2318Qt::DropActions QRangeModel::supportedDropActions() const
2319{
2320 Q_D(const QRangeModel);
2321 return d->m_supportedDropActions;
2322}
2323
2324void QRangeModel::setSupportedDropActions(Qt::DropActions actions)
2325{
2326 Q_D(QRangeModel);
2327 actions = d->impl->call<QRangeModelImplBase::AdjustSupportedDropActions>(actions);
2328 if (actions == d->m_supportedDropActions)
2329 return;
2330 d->m_supportedDropActions = actions;
2331 Q_EMIT supportedDropActionsChanged(d->m_supportedDropActions);
2332}
2333
2334void QRangeModel::resetSupportedDropActions()
2335{
2336 setSupportedDropActions(Qt::CopyAction);
2337}
2338
2339/*!
2340 \reimp
2341*/
2342void QRangeModel::resetInternalData()
2343{
2344 QAbstractItemModel::resetInternalData();
2345}
2346
2347/*!
2348 \reimp
2349*/
2350bool QRangeModel::event(QEvent *event)
2351{
2352 return QAbstractItemModel::event(event);
2353}
2354
2355/*!
2356 \reimp
2357*/
2358bool QRangeModel::eventFilter(QObject *object, QEvent *event)
2359{
2360 return QAbstractItemModel::eventFilter(object, event);
2361}
2362
2363QT_END_NAMESPACE
2364
2365#include "moc_qrangemodel.cpp"
static bool connectPropertiesHelper(const QModelIndex &index, const QObject *item, QRangeModelDetails::AutoConnectContext *context, const QHash< int, QMetaProperty > &properties)
~ConstPropertyChangedHandler()=default
ConstPropertyChangedHandler(ConstPropertyChangedHandler &&other) noexcept=default
ConstPropertyChangedHandler(const QModelIndex &index, int role)
PropertyChangedHandler & operator=(PropertyChangedHandler &&)=delete
PropertyChangedHandler(PropertyChangedHandler &&other) noexcept
PropertyChangedHandler(const PropertyChangedHandler &)=delete
PropertyChangedHandler & operator=(const PropertyChangedHandler &)=delete
~PropertyChangedHandler()=default
PropertyChangedHandler(const QPersistentModelIndex &index, int role)
PropertyChangedHandler & operator=(QMetaObject::Connection &&connection)