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.
1437
1438 \sa Qt::ItemFlags, RowOptions, ItemAccess
1439*/
1440Qt::ItemFlags QRangeModel::flags(const QModelIndex &index) const
1441{
1442 Q_D(const QRangeModel);
1443 return d->impl->call<QRangeModelImplBase::Flags>(index);
1444}
1445
1446/*!
1447 \reimp
1448
1449 Returns the data for the given \a role and \a section in the header with
1450 the specified \a orientation.
1451
1452 For horizontal headers, the section number corresponds to the column
1453 number. Similarly, for vertical headers, the section number corresponds to
1454 the row number.
1455
1456 For the horizontal header and the Qt::DisplayRole \a role, models that
1457 operate on a range that uses an array as the row type return \a section. If
1458 the row type is a tuple, then the implementation returns the name of the
1459 type at \a section. For rows that are a gadget or QObject type, this
1460 function returns the name of the property at the index of \a section.
1461
1462 For the vertical header, this function always returns the result of the
1463 default implementation in QAbstractItemModel.
1464
1465 \sa Qt::ItemDataRole, setHeaderData(), QHeaderView
1466*/
1467QVariant QRangeModel::headerData(int section, Qt::Orientation orientation, int role) const
1468{
1469 Q_D(const QRangeModel);
1470 return d->impl->call<QRangeModelImplBase::HeaderData>(section, orientation, role);
1471}
1472
1473/*!
1474 \reimp
1475*/
1476bool QRangeModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &data,
1477 int role)
1478{
1479 return QAbstractItemModel::setHeaderData(section, orientation, data, role);
1480}
1481
1482/*!
1483 \reimp
1484
1485 Returns the data stored under the given \a role for the value in the
1486 range referred to by the \a index.
1487
1488 If the item type for that index is an associative container that maps from
1489 either \c{int}, Qt::ItemDataRole, or QString to a QVariant, then the role
1490 data is looked up in that container and returned.
1491
1492 If the item is a gadget or QObject, then the implementation returns the
1493 value of the item's property matching the \a role entry in the roleNames()
1494 mapping.
1495
1496 Otherwise, the implementation returns a QVariant constructed from the item
1497 via \c{QVariant::fromValue()} for \c{Qt::DisplayRole} or \c{Qt::EditRole}.
1498 For other roles, the implementation returns an \b invalid
1499 (default-constructed) QVariant.
1500
1501 \sa Qt::ItemDataRole, setData(), headerData()
1502*/
1503QVariant QRangeModel::data(const QModelIndex &index, int role) const
1504{
1505 Q_D(const QRangeModel);
1506 return d->impl->call<QRangeModelImplBase::Data>(index, role);
1507}
1508
1509/*!
1510 \reimp
1511
1512 Sets the \a role data for the item at \a index to \a data.
1513
1514 If the item type for that \a index is an associative container that maps
1515 from either \c{int}, Qt::ItemDataRole, or QString to a QVariant, then
1516 \a data is stored in that container for the key specified by \a role.
1517
1518 If the item is a gadget or QObject, then \a data is written to the item's
1519 property matching the \a role entry in the the roleNames() mapping. The
1520 function returns \c{true} if a property was found and if \a data stored a
1521 value that could be converted to the required type, otherwise returns
1522 \c{false}.
1523
1524 Otherwise, this implementation assigns the value in \a data to the item at
1525 the \a index in the range for \c{Qt::DisplayRole} and \c{Qt::EditRole},
1526 and returns \c{true}. For other roles, the implementation returns
1527 \c{false}.
1528
1529//! [read-only-setData]
1530 For models operating on a read-only range, or on a read-only column in
1531 a row type that implements \l{the C++ tuple protocol}, this implementation
1532 returns \c{false} immediately.
1533//! [read-only-setData]
1534*/
1535bool QRangeModel::setData(const QModelIndex &index, const QVariant &data, int role)
1536{
1537 Q_D(QRangeModel);
1538 return d->impl->call<QRangeModelImplBase::SetData>(index, data, role);
1539}
1540
1541/*!
1542 \reimp
1543
1544 Returns a map with values for all predefined roles in the model for the
1545 item at the given \a index.
1546
1547 If the item type for that \a index is an associative container that maps
1548 from either \c{int}, Qt::ItemDataRole, or QString to a QVariant, then the
1549 data from that container is returned.
1550
1551 If the item type is a gadget or QObject subclass, then the values of those
1552 properties that match a \l{roleNames()}{role name} are returned.
1553
1554 If the item is not an associative container, gadget, or QObject subclass,
1555 then this calls the base class implementation.
1556
1557 \sa setItemData(), Qt::ItemDataRole, data()
1558*/
1559QMap<int, QVariant> QRangeModel::itemData(const QModelIndex &index) const
1560{
1561 Q_D(const QRangeModel);
1562 return d->impl->call<QRangeModelImplBase::ItemData>(index);
1563}
1564
1565/*!
1566 \reimp
1567
1568 If the item type for that \a index is an associative container that maps
1569 from either \c{int} or Qt::ItemDataRole to a QVariant, then the entries in
1570 \a data are stored in that container. If the associative container maps from
1571 QString to QVariant, then only those values in \a data are stored for which
1572 there is a mapping in the \l{roleNames()}{role names} table.
1573
1574 If the item type is a gadget or QObject subclass, then those properties that
1575 match a \l{roleNames()}{role name} are set to the corresponding value in
1576 \a data.
1577
1578 Roles for which there is no entry in \a data are not modified.
1579
1580 For item types that can be copied, this implementation is transactional,
1581 and returns true if all the entries from \a data could be stored. If any
1582 entry could not be updated, then the original container is not modified at
1583 all, and the function returns false.
1584
1585 If the item is not an associative container, gadget, or QObject subclass,
1586 then this calls the base class implementation, which calls setData() for
1587 each entry in \a data.
1588
1589 \sa itemData(), setData(), Qt::ItemDataRole
1590*/
1591bool QRangeModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &data)
1592{
1593 Q_D(QRangeModel);
1594 return d->impl->call<QRangeModelImplBase::SetItemData>(index, data);
1595}
1596
1597/*!
1598 \reimp
1599
1600 Replaces the value stored in the range at \a index with a default-
1601 constructed value.
1602
1603 \include qrangemodel.cpp read-only-setData
1604*/
1605bool QRangeModel::clearItemData(const QModelIndex &index)
1606{
1607 Q_D(QRangeModel);
1608 return d->impl->call<QRangeModelImplBase::ClearItemData>(index);
1609}
1610
1611/*
1612//! [column-change-requirement]
1613 \note A dynamically sized row type needs to provide a \c{\1} member function.
1614
1615 For models operating on a read-only range, or on a range with a
1616 statically sized row type (such as a tuple, array, or struct), this
1617 implementation does nothing and returns \c{false} immediately. This is
1618 always the case for tree models.
1619//! [column-change-requirement]
1620*/
1621
1622/*!
1623 \reimp
1624
1625 Inserts \a count empty columns before the item at \a column in all rows
1626 of the range at \a parent. Returns \c{true} if successful; otherwise
1627 returns \c{false}.
1628
1629 \include qrangemodel.cpp {column-change-requirement} {insert(const_iterator, size_t, value_type)}
1630*/
1631bool QRangeModel::insertColumns(int column, int count, const QModelIndex &parent)
1632{
1633 Q_D(QRangeModel);
1634 return d->impl->call<QRangeModelImplBase::InsertColumns>(column, count, parent);
1635}
1636
1637/*!
1638 \reimp
1639
1640 Removes \a count columns from the item at \a column on in all rows of the
1641 range at \a parent. Returns \c{true} if successful, otherwise returns
1642 \c{false}.
1643
1644 \include qrangemodel.cpp {column-change-requirement} {erase(const_iterator, size_t)}
1645*/
1646bool QRangeModel::removeColumns(int column, int count, const QModelIndex &parent)
1647{
1648 Q_D(QRangeModel);
1649 return d->impl->call<QRangeModelImplBase::RemoveColumns>(column, count, parent);
1650}
1651
1652/*!
1653 \reimp
1654
1655 Moves \a count columns starting with the given \a sourceColumn under parent
1656 \a sourceParent to column \a destinationColumn under parent \a destinationParent.
1657
1658 Returns \c{true} if the columns were successfully moved; otherwise returns
1659 \c{false}.
1660*/
1661bool QRangeModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count,
1662 const QModelIndex &destinationParent, int destinationColumn)
1663{
1664 Q_D(QRangeModel);
1665 return d->impl->call<QRangeModelImplBase::MoveColumns>(
1666 sourceParent, sourceColumn, count,
1667 destinationParent, destinationColumn);
1668}
1669
1670/*
1671//! [row-change-requirement]
1672 \note The range needs to be dynamically sized and provide a \c{\1}
1673 member function.
1674
1675 For models operating on a read-only or statically-sized range (such as
1676 an array), this implementation does nothing and returns \c{false}
1677 immediately.
1678//! [row-change-requirement]
1679*/
1680
1681/*!
1682 \reimp
1683
1684 Inserts \a count empty rows before the given \a row into the range at
1685 \a parent. Returns \c{true} if successful; otherwise returns \c{false}.
1686
1687 \include qrangemodel.cpp {row-change-requirement} {insert(const_iterator, size_t, value_type)}
1688
1689 \note For ranges with a dynamically sized column type, the column needs
1690 to provide a \c{resize(size_t)} member function.
1691*/
1692bool QRangeModel::insertRows(int row, int count, const QModelIndex &parent)
1693{
1694 Q_D(QRangeModel);
1695 return d->impl->call<QRangeModelImplBase::InsertRows>(row, count, parent);
1696}
1697
1698/*!
1699 \reimp
1700
1701 Removes \a count rows from the range at \a parent, starting with the
1702 given \a row. Returns \c{true} if successful, otherwise returns \c{false}.
1703
1704 \include qrangemodel.cpp {row-change-requirement} {erase(const_iterator, size_t)}
1705*/
1706bool QRangeModel::removeRows(int row, int count, const QModelIndex &parent)
1707{
1708 Q_D(QRangeModel);
1709 return d->impl->call<QRangeModelImplBase::RemoveRows>(row, count, parent);
1710}
1711
1712/*!
1713 \reimp
1714
1715 Moves \a count rows starting with the given \a sourceRow under parent
1716 \a sourceParent to row \a destinationRow under parent \a destinationParent.
1717
1718 Returns \c{true} if the rows were successfully moved; otherwise returns
1719 \c{false}.
1720*/
1721bool QRangeModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
1722 const QModelIndex &destinationParent, int destinationRow)
1723{
1724 Q_D(QRangeModel);
1725 return d->impl->call<QRangeModelImplBase::MoveRows>(
1726 sourceParent, sourceRow, count,
1727 destinationParent, destinationRow);
1728}
1729
1730/*!
1731 \reimp
1732*/
1733bool QRangeModel::canFetchMore(const QModelIndex &parent) const
1734{
1735 return QAbstractItemModel::canFetchMore(parent);
1736}
1737
1738/*!
1739 \reimp
1740*/
1741void QRangeModel::fetchMore(const QModelIndex &parent)
1742{
1743 QAbstractItemModel::fetchMore(parent);
1744}
1745
1746/*!
1747 \reimp
1748*/
1749bool QRangeModel::hasChildren(const QModelIndex &parent) const
1750{
1751 return QAbstractItemModel::hasChildren(parent);
1752}
1753
1754/*!
1755 \reimp
1756*/
1757QModelIndex QRangeModel::buddy(const QModelIndex &index) const
1758{
1759 return QAbstractItemModel::buddy(index);
1760}
1761
1762/*!
1763 \enum QRangeModel::DropOperation
1764 \since 6.12
1765
1766 This enum defines how data decoded in a dropMimeData() customization gets
1767 written to the model.
1768
1769 \value DontDrop The data should not be added to the model.
1770 \value Automatic Qt determines how data gets added to the model.
1771 \value OverwriteAndIgnore Overwrite the dropped-on item and following items,
1772 and discard any dropped data that doesn't fit.
1773 \value OverwriteAndExtend Overwrite the dropped-on item and following items,
1774 and grow the model to fit all dropped data.
1775 \value InsertAsSiblings Insert all dropped data as siblings of the dropped-on
1776 item.
1777 \value InsertAsChildren Insert all dropped data as children of the dropped-on
1778 item.
1779
1780 A dropMimeData() customization can return a bool value instead, in which
1781 case \c{false} maps to the DontDrop value, and \c{true} to Automatic.
1782
1783 \sa canDropMimeData(), dropMimeData()
1784*/
1785
1786/*!
1787 \reimp
1788
1789 \sa RowOptions::canDropMimeData() ItemAccess::canDropMimeData()
1790*/
1791bool QRangeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action,
1792 int row, int column, const QModelIndex &parent) const
1793{
1794 Q_D(const QRangeModel);
1795 if (d->m_interfaceVersion < QT_VERSION_CHECK(6, 12, 0))
1796 return QAbstractItemModel::canDropMimeData(data, action, row, column, parent);
1797 return d->impl->call<QRangeModelImplBase::CanDropMimeData>(data, action, row, column, parent);
1798}
1799
1800/*!
1801 \reimp
1802
1803 \sa RowOptions::dropMimeData() ItemAccess::dropMimeData()
1804*/
1805bool QRangeModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
1806 int row, int column, const QModelIndex &parent)
1807{
1808 if (!data)
1809 return false;
1810 if (action == Qt::IgnoreAction)
1811 return true;
1812
1813 Q_D(QRangeModel);
1814 if (d->m_interfaceVersion < QT_VERSION_CHECK(6, 12, 0))
1815 return QAbstractItemModel::dropMimeData(data, action, row, column, parent);
1816 if (d->impl->call<QRangeModelImplBase::DropMimeData>(data, action, row, column, parent))
1817 return true;
1818
1819 // failing that, insert the data as new indexes. A row of -1 indicates
1820 // that data should be appended to the model
1821 if (row == -1)
1822 row = rowCount(parent);
1823#if !defined(QT_NO_DATASTREAM)
1824 const QString defaultFormat = QAbstractItemModel::mimeTypes().at(0);
1825 if (data->hasFormat(defaultFormat)) {
1826 QByteArray encoded = data->data(defaultFormat);
1827 QDataStream stream(&encoded, QDataStream::ReadOnly);
1828 return decodeData(row, column, parent, stream);
1829 }
1830#endif
1831 return false;
1832}
1833
1834bool QRangeModelImplBase::dropDataOnItem(const QMimeData *data, const QModelIndex &index)
1835{
1836#if !defined(QT_NO_DATASTREAM)
1837 const QString defaultFormat = m_rangeModel->QAbstractItemModel::mimeTypes().at(0);
1838 if (data->hasFormat(defaultFormat)) {
1839 QByteArray encoded = data->data(defaultFormat);
1840 QDataStream stream(&encoded, QDataStream::ReadOnly);
1841 return m_rangeModel->d_func()->dropOnItem(index, stream);
1842 }
1843#endif
1844 return false;
1845}
1846
1847// QModelIndex::operator< is not useful as it compares the internal data pointer.
1848// We need to compare indexes based on the row path, taking into account
1849// that only items at column zero can have children.
1850bool QRangeModelPrivate::compareModelIndex(const QModelIndex &left, const QModelIndex &right)
1851{
1852 if (!left.isValid())
1853 return right.isValid();
1854 if (!right.isValid())
1855 return false;
1856 const QModelIndex leftCol0 = left.column() ? left.siblingAtColumn(0) : left;
1857 const QModelIndex rightCol0 = right.column() ? right.siblingAtColumn(0) : right;
1858 const QModelIndex leftParent = leftCol0.parent();
1859 const QModelIndex rightParent = rightCol0.parent();
1860 if (leftParent == rightParent) {
1861 if (left.row() == right.row())
1862 return left.column() < right.column();
1863 return left.row() < right.row();
1864 }
1865 // parents come before their children
1866 if (leftCol0 == rightParent)
1867 return true;
1868 if (rightCol0 == leftParent)
1869 return false;
1870
1871 // indexes are not directly related, so generate and compare their paths
1872 auto makePath = [](const QModelIndex &index) {
1873 // we call with col0 indexes and a parent can never be at another column
1874 Q_ASSERT(index.column() == 0);
1875 QVarLengthArray<int, 32> path{index.row()};
1876 QModelIndex parent = index.parent();
1877 while (parent.isValid()) {
1878 path.append(parent.row());
1879 parent = parent.parent();
1880 }
1881 std::reverse(path.begin(), path.end());
1882 return path;
1883 };
1884 const auto leftPath = makePath(leftCol0);
1885 const auto rightPath = makePath(rightCol0);
1886 return leftPath < rightPath;
1887}
1888
1889/*!
1890 \reimp
1891
1892 \sa RowOptions::mimeData() ItemAccess::mimeData()
1893*/
1894QMimeData *QRangeModel::mimeData(const QModelIndexList &indexes) const
1895{
1896 Q_D(const QRangeModel);
1897 if (indexes.isEmpty())
1898 return nullptr;
1899
1900 if (d->m_interfaceVersion < QT_VERSION_CHECK(6, 12, 0))
1901 return QAbstractItemModel::mimeData(indexes);
1902
1903 // sort the indexes so that all indexes in the same row are in sequence.
1904 QModelIndexList groupedList = indexes;
1905 std::sort(groupedList.begin(), groupedList.end(), QRangeModelPrivate::compareModelIndex);
1906 QMimeData *data = d->impl->call<QRangeModelImplBase::MimeData>(groupedList);
1907
1908 // finalize with default mime type
1909 const QString defaultFormat = QAbstractItemModel::mimeTypes().at(0);
1910 if (!mimeTypes().contains(defaultFormat))
1911 return data;
1912
1913 std::unique_ptr<QMimeData> defaultMimeData(QAbstractItemModel::mimeData(indexes));
1914 if (!data)
1915 return defaultMimeData.release();
1916 // add default mime data into the custom data
1917 if (defaultMimeData) {
1918 const QStringList defaultTypes = defaultMimeData->formats();
1919 for (const auto &defaultType : defaultTypes)
1920 data->setData(defaultType, defaultMimeData->data(defaultType));
1921 }
1922 return data;
1923}
1924
1925/*!
1926 \reimp
1927
1928 \sa RowOptions::mimeTypes() ItemAccess::mimeTypes()
1929*/
1930QStringList QRangeModel::mimeTypes() const
1931{
1932 Q_D(const QRangeModel);
1933 if (!d->m_mimeTypes) {
1934 d->m_mimeTypes = d->m_interfaceVersion < QT_VERSION_CHECK(6, 12, 0)
1935 ? QAbstractItemModel::mimeTypes()
1936 : d->impl->call<QRangeModelImplBase::MimeTypes>();
1937 }
1938 return *d->m_mimeTypes;
1939}
1940
1941/*!
1942 \reimp
1943
1944 Returns a list of indexes for the items in the column of \a start where
1945 the data stored under \a role matches \a value, using the match criteria
1946 defined by \a flags. Use \a hits = -1 to find all matching items.
1947
1948 \note This implementation reads data directly from the underlying C++
1949 range and does not dispatch through overrides of data().
1950*/
1951QModelIndexList QRangeModel::match(const QModelIndex &start, int role, const QVariant &value,
1952 int hits, Qt::MatchFlags flags) const
1953{
1954 Q_D(const QRangeModel);
1955 if (d->m_interfaceVersion < QT_VERSION_CHECK(6, 12, 0))
1956 return QAbstractItemModel::match(start, role, value, hits, flags);
1957 return d->impl->call<QRangeModelImplBase::Match>(start, role, value, hits, flags);
1958}
1959
1960/*!
1961 \reimp
1962*/
1963void QRangeModel::multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const
1964{
1965 Q_D(const QRangeModel);
1966 if (d->m_interfaceVersion < QT_VERSION_CHECK(6, 11, 0))
1967 return QAbstractItemModel::multiData(index, roleDataSpan);
1968 d->impl->call<QRangeModelImplBase::MultiData>(index, roleDataSpan);
1969}
1970
1971
1972/*!
1973 \property QRangeModel::roleNames
1974 \brief the role names for the model.
1975
1976 If all columns in the range are of the same type, and if that type provides
1977 a meta object (i.e., it is a gadget, or a QObject subclass), then this
1978 property holds the names of the properties of that type, mapped to values of
1979 Qt::ItemDataRole values from Qt::UserRole and up. In addition, a role
1980 "modelData" provides access to the gadget or QObject instance.
1981
1982 Override this default behavior by setting this property explicitly to a non-
1983 empty mapping. Setting this property to an empty mapping, or using
1984 resetRoleNames(), restores the default behavior.
1985
1986 \sa QAbstractItemModel::roleNames()
1987*/
1988
1989QHash<int, QByteArray> QRangeModelImplBase::roleNamesForMetaObject(const QAbstractItemModel &model,
1990 const QMetaObject &metaObject)
1991{
1992 const auto defaults = model.QAbstractItemModel::roleNames();
1993 QHash<int, QByteArray> result = {{Qt::RangeModelDataRole, "modelData"}};
1994 int offset = metaObject.propertyOffset();
1995 for (int i = offset; i < metaObject.propertyCount(); ++i) {
1996 const auto name = metaObject.property(i).name();
1997 const int defaultRole = defaults.key(name, -1);
1998 if (defaultRole != -1) {
1999 ++offset;
2000 result[defaultRole] = name;
2001 } else {
2002 result[Qt::UserRole + i - offset] = name;
2003 }
2004 }
2005 return result;
2006}
2007
2008QHash<int, QByteArray> QRangeModelImplBase::roleNamesForSimpleType()
2009{
2010 // just a plain value
2011 return QHash<int, QByteArray>{
2012 {Qt::DisplayRole, "display"},
2013 {Qt::EditRole, "edit"},
2014 {Qt::RangeModelDataRole, "modelData"},
2015 };
2016}
2017
2018/*!
2019 \reimp
2020
2021 \note Overriding this function in a QRangeModel subclass is possible,
2022 but might break the behavior of the property.
2023*/
2024QHash<int, QByteArray> QRangeModel::roleNames() const
2025{
2026 Q_D(const QRangeModel);
2027 if (d->m_roleNames.isEmpty())
2028 d->m_roleNames = d->impl->call<QRangeModelImplBase::RoleNames>();
2029
2030 return d->m_roleNames;
2031}
2032
2033void QRangeModel::setRoleNames(const QHash<int, QByteArray> &names)
2034{
2035 Q_D(QRangeModel);
2036 if (d->m_roleNames == names)
2037 return;
2038 beginResetModel();
2039 d->impl->call<QRangeModelImplBase::InvalidateCaches>();
2040 if (d->m_autoConnectPolicy != AutoConnectPolicy::None)
2041 d->impl->call<QRangeModelImplBase::SetAutoConnectPolicy>();
2042
2043 d->m_roleNames = names;
2044 endResetModel();
2045 Q_EMIT roleNamesChanged();
2046}
2047
2048void QRangeModel::resetRoleNames()
2049{
2050 setRoleNames({});
2051}
2052
2053/*!
2054 \enum QRangeModel::AutoConnectPolicy
2055 \since 6.11
2056
2057 This enum defines if and when QRangeModel auto-connects changed-signals for
2058 properties to the \l{QAbstractItemModel::}{dataChanged()} signal of the
2059 model. Only properties that match one of the \l{roleNames()}{role names}
2060 are connected.
2061
2062 \value None No connections are made automatically.
2063 \value Full The signals for all relevant properties are connected
2064 automatically, for all QObject items. This includes QObject
2065 items that are added to newly inserted rows and columns.
2066 \value OnRead Signals for relevant properties are connected the first time
2067 the model reads the property.
2068
2069 The memory overhead of making automatic connections can be substantial. A
2070 Full auto-connection does not require any book-keeping in addition to the
2071 connection itself, but each connection takes memory, and connecting all
2072 properties of all objects can be very costly, especially if only a few
2073 properties of a subset of objects will ever change.
2074
2075 The OnRead connection policy will not connect to objects or properties that
2076 are never read from (for instance, never rendered in a view), but remembering
2077 which connections have been made requires some book-keeping overhead, and
2078 unpredictable memory growth over time. For instance, scrolling down a long
2079 list of items can easily result in thousands of new connections being made.
2080
2081 \sa autoConnectPolicy, roleNames()
2082*/
2083
2084/*!
2085 \property QRangeModel::autoConnectPolicy
2086 \since 6.11
2087 \brief if and when the model auto-connects to property changed notifications.
2088
2089 If QRangeModel operates on a data structure that holds the same type of
2090 QObject subclass as its row or item type, then it can automatically connect
2091 the properties of the QObjects to the dataChanged() signal. For QObject
2092 rows, this is done for each column, mapping to the Qt::DisplayRole
2093 property. For items, this is done for those properties that match one of
2094 the \l{roleNames()}{role names}.
2095
2096 By default, the value of this property is \l{QRangeModel::AutoConnectPolicy::}
2097 {None}, so no such connections are made. Changing the value of this property
2098 always breaks all existing connections.
2099
2100 \note Connections are not broken or created if QObjects in the data
2101 structure that QRangeModel operates on are swapped out.
2102
2103 \sa roleNames()
2104*/
2105
2106QRangeModel::AutoConnectPolicy QRangeModel::autoConnectPolicy() const
2107{
2108 Q_D(const QRangeModel);
2109 return d->m_autoConnectPolicy;
2110}
2111
2112void QRangeModel::setAutoConnectPolicy(QRangeModel::AutoConnectPolicy policy)
2113{
2114 Q_D(QRangeModel);
2115 if (d->m_autoConnectPolicy == policy)
2116 return;
2117
2118 d->m_autoConnectPolicy = policy;
2119 d->impl->call<QRangeModelImplBase::SetAutoConnectPolicy>();
2120 Q_EMIT autoConnectPolicyChanged(policy);
2121}
2122
2123/*!
2124 \reimp
2125
2126 Sorts the the underlying range in the given \a order, based on the data for
2127 the \l{sortRole} (Qt::DisplayRole by default) of the items in \a column.
2128
2129 \note This implementation uses a member function \c{sort(Compare comp)} of
2130 the C++ range if available (such as in \c{std::list}), or otherwise
2131 \c{std::stable_sort()} if the range provides random-access iterators. If
2132 neither is available then the implementation does nothing and returns
2133 immediately.
2134
2135 \note Accessing the item does not dispatch the reading of data through
2136 overrides of data().
2137
2138 \sa sortRole, QSortFilterProxyModel
2139*/
2140void QRangeModel::sort(int column, Qt::SortOrder order)
2141{
2142 Q_D(QRangeModel);
2143 if (d->m_interfaceVersion < QT_VERSION_CHECK(6, 12, 0))
2144 return QAbstractItemModel::sort(column, order);
2145 QT_TRY {
2146 d->impl->call<QRangeModelImplBase::Sort>(column, order);
2147 } QT_CATCH(const std::bad_alloc &) {
2148 qCritical("QRangeModel::sort ran out of memory, sort likely incomplete.");
2149 }
2150}
2151
2152/*!
2153 \property QRangeModel::sortRole
2154 \since 6.12
2155 \brief the data role used when sorting items.
2156
2157 The default value is Qt::DisplayRole.
2158
2159 \sa sort(), sortCollator, QSortFilterProxyModel
2160*/
2161int QRangeModel::sortRole() const
2162{
2163 Q_D(const QRangeModel);
2164 return d->m_sortRole;
2165}
2166
2167void QRangeModel::setSortRole(int role)
2168{
2169 Q_D(QRangeModel);
2170 if (d->m_sortRole == role)
2171 return;
2172 d->m_sortRole = role;
2173 Q_EMIT sortRoleChanged(d->m_sortRole);
2174}
2175
2176void QRangeModel::resetSortRole()
2177{
2178 setSortRole(Qt::DisplayRole);
2179}
2180
2181/*!
2182 \property QRangeModel::sortCollator
2183 \since 6.12
2184 \brief the collator that will be used when sorting the model
2185
2186 The default value of this property is a QCollator for the C-locale.
2187 Sorting will not be locale aware, and case sensitive. Setting a collator
2188 will make the sorting locale-aware.
2189
2190 \sa sort(), sortRole, QSortFilterProxyModel
2191*/
2192QCollator QRangeModel::sortCollator() const
2193{
2194 Q_D(const QRangeModel);
2195 return d->m_sortCollator.value_or(QCollator(QLocale::C));
2196}
2197
2198void QRangeModel::setSortCollator(const QCollator &collator)
2199{
2200 Q_D(QRangeModel);
2201 if (sortCollator() == collator)
2202 return;
2203 d->m_sortCollator = collator;
2204 Q_EMIT sortCollatorChanged(*d->m_sortCollator);
2205}
2206
2207void QRangeModel::resetSortCollator()
2208{
2209 Q_D(QRangeModel);
2210 if (!d->m_sortCollator)
2211 return;
2212 d->m_sortCollator = std::nullopt;
2213 Q_EMIT sortCollatorChanged(sortCollator());
2214}
2215
2216/*!
2217 \reimp
2218*/
2219QSize QRangeModel::span(const QModelIndex &index) const
2220{
2221 return QAbstractItemModel::span(index);
2222}
2223
2224/*!
2225 \property QRangeModel::supportedDragActions
2226 \since 6.12
2227 \brief the drag-actions supported by this model.
2228
2229 Actions that the model cannot support, such as moving data out of a
2230 read-only model, will be removed when setting the actions.
2231
2232 \note Overriding this function in a QRangeModel subclass is possible,
2233 but might break the behavior of the property.
2234
2235 \sa supportedDropActions
2236*/
2237Qt::DropActions QRangeModel::supportedDragActions() const
2238{
2239 Q_D(const QRangeModel);
2240 return d->m_supportedDragActions;
2241}
2242
2243void QRangeModel::setSupportedDragActions(Qt::DropActions actions)
2244{
2245 Q_D(QRangeModel);
2246 actions = d->impl->call<QRangeModelImplBase::AdjustSupportedDragActions>(actions);
2247 if (actions == d->m_supportedDragActions)
2248 return;
2249 d->m_supportedDragActions = actions;
2250 Q_EMIT supportedDragActionsChanged(d->m_supportedDragActions);
2251}
2252
2253void QRangeModel::resetSupportedDragActions()
2254{
2255 setSupportedDragActions(Qt::CopyAction);
2256}
2257
2258/*!
2259 \property QRangeModel::supportedDropActions
2260 \since 6.12
2261 \brief the drop-actions supported by this model.
2262
2263 Read-only models cannot support any drop-actions.
2264
2265 \note Overriding this function in a QRangeModel subclass is possible,
2266 but might break the behavior of the property.
2267
2268 \sa supportedDragActions
2269*/
2270Qt::DropActions QRangeModel::supportedDropActions() const
2271{
2272 Q_D(const QRangeModel);
2273 return d->m_supportedDropActions;
2274}
2275
2276void QRangeModel::setSupportedDropActions(Qt::DropActions actions)
2277{
2278 Q_D(QRangeModel);
2279 actions = d->impl->call<QRangeModelImplBase::AdjustSupportedDropActions>(actions);
2280 if (actions == d->m_supportedDropActions)
2281 return;
2282 d->m_supportedDropActions = actions;
2283 Q_EMIT supportedDropActionsChanged(d->m_supportedDropActions);
2284}
2285
2286void QRangeModel::resetSupportedDropActions()
2287{
2288 setSupportedDropActions(Qt::CopyAction);
2289}
2290
2291/*!
2292 \reimp
2293*/
2294void QRangeModel::resetInternalData()
2295{
2296 QAbstractItemModel::resetInternalData();
2297}
2298
2299/*!
2300 \reimp
2301*/
2302bool QRangeModel::event(QEvent *event)
2303{
2304 return QAbstractItemModel::event(event);
2305}
2306
2307/*!
2308 \reimp
2309*/
2310bool QRangeModel::eventFilter(QObject *object, QEvent *event)
2311{
2312 return QAbstractItemModel::eventFilter(object, event);
2313}
2314
2315QT_END_NAMESPACE
2316
2317#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)