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