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
qrangemodeladapter.h
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#ifndef QRANGEMODELADAPTER_H
6#define QRANGEMODELADAPTER_H
7
8#include <QtCore/qrangemodeladapter_impl.h>
9
10#include <QtCore/q26numeric.h>
11
12QT_BEGIN_NAMESPACE
13
14template <typename Range, typename Protocol = void, typename Model = QRangeModel>
15class QT_TECH_PREVIEW_API QRangeModelAdapter
16{
17 using Impl = QRangeModelDetails::RangeImplementation<Range, Protocol>;
18 using Storage = QRangeModelDetails::AdapterStorage<Model, Impl>;
19
20 Storage storage;
21
22#ifdef Q_QDOC
23 using range_type = Range;
24#else
25 using range_type = QRangeModelDetails::wrapped_t<Range>;
26#endif
27 using const_row_reference = typename Impl::const_row_reference;
28 using row_reference = typename Impl::row_reference;
29 using range_features = typename QRangeModelDetails::range_traits<range_type>;
30 using row_type = std::remove_reference_t<row_reference>;
31 using row_features = QRangeModelDetails::range_traits<typename Impl::wrapped_row_type>;
32 using row_ptr = typename Impl::wrapped_row_type *;
33 using row_traits = typename Impl::row_traits;
34 using item_type = std::remove_reference_t<typename row_traits::item_type>;
35 using data_type = typename QRangeModelDetails::data_type<item_type>::type;
36 using const_data_type = QRangeModelDetails::asConst_t<data_type>;
37 using protocol_traits = typename Impl::protocol_traits;
38
39 template <typename I> static constexpr bool is_list = I::protocol_traits::is_list;
40 template <typename I> static constexpr bool is_table = I::protocol_traits::is_table;
41 template <typename I> static constexpr bool is_tree = I::protocol_traits::is_tree;
42 template <typename I> static constexpr bool canInsertColumns = I::dynamicColumns()
43 && I::isMutable()
44 && row_features::has_insert;
45 template <typename I> static constexpr bool canRemoveColumns = I::dynamicColumns()
46 && I::isMutable()
47 && row_features::has_erase;
48
49 template <typename I> using if_writable = std::enable_if_t<I::isMutable(), bool>;
50 template <typename I> using if_list = std::enable_if_t<is_list<I>, bool>;
51 template <typename I> using unless_list = std::enable_if_t<!is_list<I>, bool>;
52 template <typename I> using if_table = std::enable_if_t<is_table<I>, bool>;
53 template <typename I> using if_tree = std::enable_if_t<is_tree<I>, bool>;
54 template <typename I> using unless_tree = std::enable_if_t<!is_tree<I>, bool>;
55 template <typename I> using if_flat = std::enable_if_t<is_list<I> || is_table<I>, bool>;
56
57 template <typename I>
58 using if_canInsertRows = std::enable_if_t<I::canInsertRows(), bool>;
59 template <typename I>
60 using if_canRemoveRows = std::enable_if_t<I::canRemoveRows(), bool>;
61 template <typename F>
62 using if_canMoveItems = std::enable_if_t<F::has_rotate || F::has_splice, bool>;
63
64 template <typename I>
65 using if_canInsertColumns = std::enable_if_t<canInsertColumns<I>, bool>;
66 template <typename I>
67 using if_canRemoveColumns = std::enable_if_t<canRemoveColumns<I>, bool>;
68
69 template <typename Row>
70 static constexpr bool is_compatible_row = std::is_convertible_v<Row, const_row_reference>;
71 template <typename Row>
72 using if_compatible_row = std::enable_if_t<is_compatible_row<Row>, bool>;
73
74 template <typename C>
75 static constexpr bool is_compatible_row_range = is_compatible_row<
76 decltype(*std::begin(std::declval<C&>()))
77 >;
78 template <typename C>
79 using if_compatible_row_range = std::enable_if_t<is_compatible_row_range<C>, bool>;
80 template <typename Data>
81 static constexpr bool is_compatible_data = std::is_convertible_v<Data, data_type>;
82 template <typename Data>
83 using if_compatible_data = std::enable_if_t<is_compatible_data<Data>, bool>;
84 template <typename C>
85 static constexpr bool is_compatible_data_range = is_compatible_data<
86 typename QRangeModelDetails::data_type<
87 typename QRangeModelDetails::row_traits<
88 decltype(*std::begin(std::declval<C&>()))
89 >::item_type
90 >::type
91 >;
92 template <typename C>
93 using if_compatible_column_data = std::enable_if_t<is_compatible_data<C>
94 || is_compatible_data_range<C>, bool>;
95 template <typename C>
96 using if_compatible_column_range = std::enable_if_t<is_compatible_data_range<C>, bool>;
97
98 template <typename R>
99 using if_assignable_range = std::enable_if_t<std::is_assignable_v<range_type, R>, bool>;
100
101 friend class QRangeModel;
102 template <typename T>
103 static constexpr bool is_adapter = QRangeModelDetails::is_any_of<q20::remove_cvref_t<T>,
104 QRangeModelAdapter>::value;
105 template <typename T>
106 using unless_adapter = std::enable_if_t<!is_adapter<T>, bool>;
107
108 template <typename R, typename P>
109 using if_compatible_model_params =
110 std::enable_if_t<
111 std::conjunction_v<
112 std::disjunction<
113 std::is_convertible<R &&, Range>,
114 std::is_convertible<R &&, Range &&> // for C-arrays
115 >,
116 std::is_convertible<P, Protocol> // note, only void is expected to be convertible to void
117 >, bool>;
118
119#if !defined(Q_OS_VXWORKS) && !defined(Q_OS_INTEGRITY)
120 // An adapter on a mutable range can make itself an adapter on a const
121 // version of that same range. To make the constructor for a sub-range
122 // accessible, befriend the mutable version. We can use more
123 // generic pattern matching here, as we only use as input what asConst
124 // might produce as output.
125 template <typename T> static constexpr T asMutable(const T &);
126 template <typename T> static constexpr T *asMutable(const T *);
127 template <template <typename, typename...> typename U, typename T, typename ...Args>
128 static constexpr U<T, Args...> asMutable(const U<const T, Args...> &);
129
130 template <typename T>
131 using asMutable_t = decltype(asMutable(std::declval<T>()));
132 friend class QRangeModelAdapter<asMutable_t<Range>, Protocol, Model>;
133#else
134 template <typename R, typename P, typename M>
135 friend class QRangeModelAdapter;
136#endif
137
138 explicit QRangeModelAdapter(const std::shared_ptr<QRangeModel> &model, const QModelIndex &root,
139 std::in_place_t) // disambiguate from range/protocol c'tor
140 : storage{model, root}
141 {}
142
143 explicit QRangeModelAdapter(QRangeModel *model)
144 : storage(model)
145 {}
146
147public:
148 struct DataReference
149 {
150#ifdef Q_QDOC
151 using value_type = int;
152 using const_value_type = const int;
153 using pointer = void *;
154#else
155 using value_type = data_type;
156 using const_value_type = const_data_type;
157 using pointer = QRangeModelDetails::data_pointer_t<const_value_type>;
158#endif
159
160 explicit DataReference(const QModelIndex &index) noexcept
161 : m_index(index)
162 {}
163
164 DataReference(const DataReference &other) = default;
165 DataReference(DataReference &&other) = default;
166
167 // reference (not std::reference_wrapper) semantics
168 DataReference &operator=(const DataReference &other)
169 {
170 *this = other.get();
171 return *this;
172 }
173
174 DataReference &operator=(DataReference &&other)
175 {
176 *this = other.get();
177 return *this;
178 }
179
180 ~DataReference() = default;
181
182 DataReference &operator=(const value_type &value)
183 {
184 assign(value);
185 return *this;
186 }
187
188 DataReference &operator=(value_type &&value)
189 {
190 assign(std::move(value));
191 return *this;
192 }
193
194 const_value_type get() const
195 {
196 Q_ASSERT_X(m_index.isValid(), "QRangeModelAdapter::at", "Index at position is invalid");
197 return QRangeModelDetails::dataAtIndex<q20::remove_cvref_t<value_type>>(m_index);
198 }
199
200 operator const_value_type() const
201 {
202 return get();
203 }
204
205 pointer operator->() const
206 {
207 return {get()};
208 }
209
210 bool isValid() const { return m_index.isValid(); }
211
212 private:
213 QModelIndex m_index;
214
215 template <typename Value>
216 void assign(Value &&value)
217 {
218 constexpr Qt::ItemDataRole dataRole = Qt::RangeModelAdapterRole;
219
220 if (m_index.isValid()) {
221 auto model = const_cast<QAbstractItemModel *>(m_index.model());
222 [[maybe_unused]] bool couldWrite = false;
223 if constexpr (std::is_same_v<q20::remove_cvref_t<Value>, QVariant>) {
224 couldWrite = model->setData(m_index, value, dataRole);
225 } else {
226 couldWrite = model->setData(m_index,
227 QVariant::fromValue(std::forward<Value>(value)),
228 dataRole);
229 }
230#ifndef QT_NO_DEBUG
231 if (!couldWrite) {
232 qWarning() << "Writing value of type"
233 << QMetaType::fromType<q20::remove_cvref_t<Value>>().name()
234 << "to role" << dataRole << "at index" << m_index << "failed";
235 }
236 } else {
237 qCritical("Data reference for invalid index, can't write to model");
238#endif
239 }
240 }
241
242 friend inline bool comparesEqual(const DataReference &lhs, const DataReference &rhs)
243 {
244 return lhs.m_index == rhs.m_index
245 || lhs.get() == rhs.get();
246 }
247 Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(DataReference);
248
249 friend inline bool comparesEqual(const DataReference &lhs, const value_type &rhs)
250 {
251 return lhs.get() == rhs;
252 }
253 Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(DataReference, value_type);
254
255 friend inline void swap(DataReference lhs, DataReference rhs)
256 {
257 const value_type lhsValue = lhs.get();
258 lhs = rhs;
259 rhs = lhsValue; // no point in moving, we have to go through QVariant anyway
260 }
261
262#ifndef QT_NO_DEBUG_STREAM
263 friend inline QDebug operator<<(QDebug dbg, const DataReference &ref)
264 {
265 return dbg << ref.get();
266 }
267#endif
268#ifndef QT_NO_DATASTREAM
269 friend inline QDataStream &operator<<(QDataStream &ds, const DataReference &ref)
270 {
271 return ds << ref.get();
272 }
273 friend inline QDataStream &operator>>(QDataStream &ds, DataReference &ref)
274 {
275 value_type value;
276 ds >> value;
277 ref = std::move(value);
278 return ds;
279 }
280#endif
281 };
282 template <typename Iterator, typename Adapter>
283 struct ColumnIteratorBase
284 {
285 using iterator_category = std::random_access_iterator_tag;
286 using difference_type = int;
287
288 ColumnIteratorBase() = default;
289 ColumnIteratorBase(const ColumnIteratorBase &other) = default;
290 ColumnIteratorBase(ColumnIteratorBase &&other) = default;
291 ColumnIteratorBase &operator=(const ColumnIteratorBase &other) = default;
292 ColumnIteratorBase &operator=(ColumnIteratorBase &&other) = default;
293
294 ColumnIteratorBase(const QModelIndex &rowIndex, int column, Adapter *adapter) noexcept
295 : m_rowIndex(rowIndex), m_column(column), m_adapter(adapter)
296 {
297 }
298
299 void swap(ColumnIteratorBase &other) noexcept
300 {
301 std::swap(m_rowIndex, other.m_rowIndex);
302 std::swap(m_column, other.m_column);
303 q_ptr_swap(m_adapter, other.m_adapter);
304 }
305
306 friend Iterator &operator++(Iterator &that)
307 {
308 ++that.m_column;
309 return that;
310 }
311 friend Iterator operator++(Iterator &that, int)
312 {
313 auto copy = that;
314 ++that;
315 return copy;
316 }
317 friend Iterator operator+(const Iterator &that, difference_type n)
318 {
319 return {that.m_rowIndex, that.m_column + n, that.m_adapter};
320 }
321 friend Iterator operator+(difference_type n, const Iterator &that)
322 {
323 return that + n;
324 }
325 friend Iterator &operator+=(Iterator &that, difference_type n)
326 {
327 that.m_column += n;
328 return that;
329 }
330
331 friend Iterator &operator--(Iterator &that)
332 {
333 --that.m_column;
334 return that;
335 }
336 friend Iterator operator--(Iterator &that, int)
337 {
338 auto copy = that;
339 --that;
340 return copy;
341 }
342 friend Iterator operator-(const Iterator &that, difference_type n)
343 {
344 return {that.m_rowIndex, that.m_column - n, that.m_adapter};
345 }
346 friend Iterator operator-(difference_type n, const Iterator &that)
347 {
348 return that - n;
349 }
350 friend Iterator &operator-=(Iterator &that, difference_type n)
351 {
352 that.m_column -= n;
353 return that;
354 }
355
356 friend difference_type operator-(const Iterator &lhs, const Iterator &rhs)
357 {
358 Q_PRE(lhs.m_rowIndex == rhs.m_rowIndex);
359 Q_PRE(lhs.m_adapter == rhs.m_adapter);
360 return lhs.m_column - rhs.m_column;
361 }
362
363 protected:
364 ~ColumnIteratorBase() = default;
365 QModelIndex m_rowIndex;
366 int m_column = -1;
367 Adapter *m_adapter = nullptr;
368
369 private:
370 friend bool comparesEqual(const Iterator &lhs, const Iterator &rhs)
371 {
372 Q_ASSERT(lhs.m_rowIndex == rhs.m_rowIndex);
373 return lhs.m_column == rhs.m_column;
374 }
375 friend Qt::strong_ordering compareThreeWay(const Iterator &lhs, const Iterator &rhs)
376 {
377 Q_ASSERT(lhs.m_rowIndex == rhs.m_rowIndex);
378 return qCompareThreeWay(lhs.m_column, rhs.m_column);
379 }
380
381 Q_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT(Iterator)
382
383#ifndef QT_NO_DEBUG_STREAM
384 friend inline QDebug operator<<(QDebug dbg, const Iterator &it)
385 {
386 QDebugStateSaver saver(dbg);
387 dbg.nospace();
388 return dbg << "ColumnIterator(" << it.m_rowIndex.siblingAtColumn(it.m_column) << ")";
389 }
390#endif
391 };
392
393 struct ConstColumnIterator : ColumnIteratorBase<ConstColumnIterator, const QRangeModelAdapter>
394 {
395 private:
396 using Base = ColumnIteratorBase<ConstColumnIterator, const QRangeModelAdapter>;
397 public:
398 using difference_type = typename Base::difference_type;
399 using value_type = data_type;
400 using reference = const_data_type;
401 using pointer = QRangeModelDetails::data_pointer_t<value_type>;
402
403 using Base::Base;
404 using Base::operator=;
405 ~ConstColumnIterator() = default;
406
407 pointer operator->() const
408 {
409 return pointer{operator*()};
410 }
411
412 reference operator*() const
413 {
414 return std::as_const(this->m_adapter)->at(this->m_rowIndex.row(), this->m_column);
415 }
416
417 reference operator[](difference_type n) const
418 {
419 return *(*this + n);
420 }
421 };
422
423 struct ColumnIterator : ColumnIteratorBase<ColumnIterator, QRangeModelAdapter>
424 {
425 private:
426 using Base = ColumnIteratorBase<ColumnIterator, QRangeModelAdapter>;
427 public:
428 using difference_type = typename Base::difference_type;
429 using value_type = DataReference;
430 using reference = DataReference;
431 using pointer = reference;
432
433 using Base::Base;
434 using Base::operator=;
435 ~ColumnIterator() = default;
436
437 operator ConstColumnIterator() const
438 {
439 return ConstColumnIterator{this->m_rowIndex, this->m_column, this->m_adapter};
440 }
441
442 pointer operator->() const
443 {
444 return operator*();
445 }
446
447 reference operator*() const
448 {
449 return reference{this->m_rowIndex.siblingAtColumn(this->m_column)};
450 }
451
452 reference operator[](difference_type n) const
453 {
454 return *(*this + n);
455 }
456 };
457
458 template <typename Reference, typename const_row_type,
459 bool = std::is_reference_v<const_row_type>,
460 bool = std::is_pointer_v<const_row_type>>
461 struct RowGetter
462 {
463 const_row_type get() const
464 {
465 const Reference *that = static_cast<const Reference *>(this);
466 const auto *impl = that->m_adapter->storage.implementation();
467 auto *childRange = impl->childRange(that->m_index.parent());
468 if constexpr (std::is_convertible_v<const row_type &, const_row_type>) {
469 return *std::next(QRangeModelDetails::adl_begin(childRange), that->m_index.row());
470 } else {
471 const auto &row = *std::next(QRangeModelDetails::adl_begin(childRange),
472 that->m_index.row());
473 return const_row_type{QRangeModelDetails::adl_begin(row),
474 QRangeModelDetails::adl_end(row)};
475 }
476 }
477
478 const_row_type operator->() const
479 {
480 return {get()};
481 }
482
483 operator const_row_type() const
484 {
485 return get();
486 }
487 };
488
489 template <typename Reference, typename const_row_type>
490 struct RowGetter<Reference, const_row_type, true, false>
491 {
492 const_row_type get() const
493 {
494 const Reference *that = static_cast<const Reference *>(this);
495 const auto *impl = that->m_adapter->storage.implementation();
496 return *std::next(QRangeModelDetails::begin(
497 QRangeModelDetails::refTo(impl->childRange(that->m_index.parent()))),
498 that->m_index.row());
499 }
500
501 auto operator->() const
502 {
503 return std::addressof(get());
504 }
505
506 operator const_row_type() const
507 {
508 return get();
509 }
510 };
511
512 template <typename Reference, typename const_row_type>
513 struct RowGetter<Reference, const_row_type, false, true>
514 {
515 const_row_type get() const
516 {
517 const Reference *that = static_cast<const Reference *>(this);
518 const auto *impl = that->m_adapter->storage.implementation();
519 return *std::next(QRangeModelDetails::begin(
520 QRangeModelDetails::refTo(impl->childRange(that->m_index.parent()))),
521 that->m_index.row());
522 }
523
524 const_row_type operator->() const
525 {
526 return get();
527 }
528
529 operator const_row_type() const
530 {
531 return get();
532 }
533 };
534
535 template <typename Reference, typename Adapter>
536 struct RowReferenceBase : RowGetter<Reference, QRangeModelDetails::asConstRow_t<row_type>>
537 {
538 using const_iterator = ConstColumnIterator;
539 using size_type = int;
540 using difference_type = int;
541 using const_row_type = QRangeModelDetails::asConstRow_t<row_type>;
542
543 RowReferenceBase(const QModelIndex &index, Adapter *adapter) noexcept
544 : m_index(index), m_adapter(adapter)
545 {}
546
547 template <typename I = Impl, if_tree<I> = true>
548 bool hasChildren() const
549 {
550 return m_adapter->model()->hasChildren(m_index);
551 }
552
553 template <typename I = Impl, if_tree<I> = true>
554 auto children() const
555 {
556 using ConstRange = QRangeModelDetails::asConst_t<Range>;
557 return QRangeModelAdapter<ConstRange, Protocol, Model>(m_adapter->storage.m_model,
558 m_index, std::in_place);
559 }
560
561 ConstColumnIterator cbegin() const
562 {
563 return ConstColumnIterator{m_index, 0, m_adapter};
564 }
565 ConstColumnIterator cend() const
566 {
567 return ConstColumnIterator{m_index, m_adapter->columnCount(), m_adapter};
568 }
569
570 ConstColumnIterator begin() const { return cbegin(); }
571 ConstColumnIterator end() const { return cend(); }
572
573 size_type size() const
574 {
575 return m_adapter->columnCount();
576 }
577
578 auto at(int column) const
579 {
580 Q_ASSERT(column >= 0 && column < m_adapter->columnCount());
581 return *ConstColumnIterator{m_index, column, m_adapter};
582 }
583
584 auto operator[](int column) const
585 {
586 return at(column);
587 }
588
589 protected:
590 friend struct RowGetter<Reference, const_row_type>;
591 ~RowReferenceBase() = default;
592 QModelIndex m_index;
593 Adapter *m_adapter;
594
595 private:
596 friend bool comparesEqual(const Reference &lhs, const Reference &rhs)
597 {
598 Q_ASSERT(lhs.m_adapter == rhs.m_adapter);
599 return lhs.m_index == rhs.m_index;
600 }
601 friend Qt::strong_ordering compareThreeWay(const Reference &lhs, const Reference &rhs)
602 {
603 Q_ASSERT(lhs.m_adapter == rhs.m_adapter);
604 return qCompareThreeWay(lhs.m_index, rhs.m_index);
605 }
606
607 Q_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT(Reference)
608
609 friend bool comparesEqual(const Reference &lhs, const row_type &rhs)
610 {
611 return lhs.get() == rhs;
612 }
613 Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(Reference, row_type)
614
615#ifndef QT_NO_DEBUG_STREAM
616 friend inline QDebug operator<<(QDebug dbg, const Reference &ref)
617 {
618 QDebugStateSaver saver(dbg);
619 dbg.nospace();
620 return dbg << "RowReference(" << ref.m_index << ")";
621 }
622#endif
623#ifndef QT_NO_DATASTREAM
624 friend inline QDataStream &operator<<(QDataStream &ds, const Reference &ref)
625 {
626 return ds << ref.get();
627 }
628#endif
629 };
630
631 struct ConstRowReference : RowReferenceBase<ConstRowReference, const QRangeModelAdapter>
632 {
633 private:
634 using Base = RowReferenceBase<ConstRowReference, const QRangeModelAdapter>;
635 public:
636 using Base::Base;
637
638 ConstRowReference() = default;
639 ConstRowReference(const ConstRowReference &) = default;
640 ConstRowReference(ConstRowReference &&) = default;
641 ConstRowReference &operator=(const ConstRowReference &) = default;
642 ConstRowReference &operator=(ConstRowReference &&) = default;
643 ~ConstRowReference() = default;
644 };
645
646 struct RowReference : RowReferenceBase<RowReference, QRangeModelAdapter>
647 {
648 private:
649 using Base = RowReferenceBase<RowReference, QRangeModelAdapter>;
650 public:
651 using iterator = ColumnIterator;
652 using const_iterator = typename Base::const_iterator;
653 using size_type = typename Base::size_type;
654 using difference_type = typename Base::difference_type;
655#ifdef Q_QDOC
656 using row_type = int;
657#endif
658 using const_row_type = typename Base::const_row_type;
659
660 using Base::Base;
661 RowReference() = delete;
662 ~RowReference() = default;
663 RowReference(const RowReference &other) = default;
664 RowReference(RowReference &&other) = default;
665
666 // assignment has reference (std::reference_wrapper) semantics
667 RowReference &operator=(const ConstRowReference &other)
668 {
669 *this = other.get();
670 return *this;
671 }
672
673 RowReference &operator=(const RowReference &other)
674 {
675 *this = other.get();
676 return *this;
677 }
678
679 RowReference &operator=(const row_type &other)
680 {
681 assign(other);
682 return *this;
683 }
684
685 RowReference &operator=(row_type &&other)
686 {
687 assign(std::move(other));
688 return *this;
689 }
690
691 operator ConstRowReference() const
692 {
693 return ConstRowReference{this->m_index, this->m_adapter};
694 }
695
696 template <typename ConstRowType = const_row_type,
697 std::enable_if_t<!std::is_same_v<ConstRowType, const row_type &>, bool> = true>
698 RowReference &operator=(const ConstRowType &other)
699 {
700 assign(other);
701 return *this;
702 }
703
704 template <typename T, typename It, typename Sentinel>
705 RowReference &operator=(const QRangeModelDetails::RowView<T, It, Sentinel> &other)
706 {
707 *this = row_type{other.begin(), other.end()};
708 return *this;
709 }
710
711 friend inline void swap(RowReference lhs, RowReference rhs)
712 {
713 auto lhsRow = lhs.get();
714 lhs = rhs.get();
715 rhs = std::move(lhsRow);
716 }
717
718 template <typename I = Impl, if_tree<I> = true>
719 auto children()
720 {
721 return QRangeModelAdapter(this->m_adapter->storage.m_model, this->m_index,
722 std::in_place);
723 }
724
725 using Base::begin;
726 ColumnIterator begin()
727 {
728 return ColumnIterator{this->m_index, 0, this->m_adapter};
729 }
730
731 using Base::end;
732 ColumnIterator end()
733 {
734 return ColumnIterator{this->m_index, this->m_adapter->columnCount(), this->m_adapter};
735 }
736
737 using Base::at;
738 auto at(int column)
739 {
740 Q_ASSERT(column >= 0 && column < this->m_adapter->columnCount());
741 return *ColumnIterator{this->m_index, column, this->m_adapter};
742 }
743
744 using Base::operator[];
745 auto operator[](int column)
746 {
747 return at(column);
748 }
749
750 private:
751 template <typename RHS>
752 void verifyRows(const row_type &oldRow, const RHS &newRow)
753 {
754 if constexpr (QRangeModelDetails::test_size<row_type>::value) {
755 // prevent that tables get populated with wrongly sized rows
756 Q_ASSERT_X(Impl::size(newRow) == Impl::size(oldRow),
757 "RowReference::operator=()",
758 "The new row has the wrong size!");
759 }
760
761 if constexpr (is_tree<Impl>) {
762 // we cannot hook invalid rows up to the tree hierarchy
763 Q_ASSERT_X(QRangeModelDetails::isValid(newRow),
764 "RowReference::operator=()",
765 "An invalid row can not inserted into a tree!");
766 }
767 }
768
769 template <typename R>
770 void assign(R &&other)
771 {
772 auto *impl = this->m_adapter->storage.implementation();
773 decltype(auto) oldRow = impl->rowData(this->m_index);
774
775 verifyRows(oldRow, other);
776
777 if constexpr (is_tree<Impl>) {
778 auto &protocol = impl->protocol();
779 auto *oldParent = protocol.parentRow(QRangeModelDetails::refTo(oldRow));
780
781 // the old children will be removed; we don't try to overwrite
782 // them with the new children, we replace them completely
783 if (decltype(auto) oldChildren = protocol.childRows(QRangeModelDetails::refTo(oldRow));
784 QRangeModelDetails::isValid(oldChildren)) {
785 if (int oldChildCount = this->m_adapter->model()->rowCount(this->m_index)) {
786 impl->beginRemoveRows(this->m_index, 0, oldChildCount - 1);
787 impl->deleteRemovedRows(QRangeModelDetails::refTo(oldChildren));
788 // make sure the list is empty before we emit rowsRemoved
789 QRangeModelDetails::refTo(oldChildren) = range_type{};
790 impl->endRemoveRows();
791 }
792 }
793
794 if constexpr (protocol_traits::has_deleteRow)
795 protocol.deleteRow(oldRow);
796 oldRow = std::forward<R>(other);
797 if constexpr (protocol_traits::has_setParentRow) {
798 protocol.setParentRow(QRangeModelDetails::refTo(oldRow),
799 QRangeModelDetails::pointerTo(oldParent));
800 if (decltype(auto) newChildren = protocol.childRows(QRangeModelDetails::refTo(oldRow));
801 QRangeModelDetails::isValid(newChildren)) {
802 impl->beginInsertRows(this->m_index, 0,
803 Impl::size(QRangeModelDetails::refTo(newChildren)) - 1);
804 impl->setParentRow(QRangeModelDetails::refTo(newChildren),
805 QRangeModelDetails::pointerTo(oldRow));
806 impl->endInsertRows();
807 }
808 }
809 } else {
810 oldRow = std::forward<R>(other);
811 }
812 this->m_adapter->emitDataChanged(this->m_index,
813 this->m_index.siblingAtColumn(this->m_adapter->columnCount() - 1));
814 if constexpr (Impl::itemsAreQObjects) {
815 if (this->m_adapter->model()->autoConnectPolicy() == QRangeModel::AutoConnectPolicy::Full) {
816 impl->autoConnectPropertiesInRow(oldRow, this->m_index.row(), this->m_index.parent());
817 if constexpr (is_tree<Impl>)
818 impl->autoConnectProperties(this->m_index);
819 }
820
821 }
822 }
823
824#ifndef QT_NO_DATASTREAM
825 friend inline QDataStream &operator>>(QDataStream &ds, RowReference &ref)
826 {
827 row_type value;
828 ds >> value;
829 ref = value;
830 return ds;
831 }
832#endif
833 };
834
835 template <typename Iterator, typename Adapter>
836 struct RowIteratorBase : QRangeModelDetails::ParentIndex<is_tree<Impl>>
837 {
838 using iterator_category = std::random_access_iterator_tag;
839 using difference_type = int;
840
841 RowIteratorBase() = default;
842 RowIteratorBase(const RowIteratorBase &) = default;
843 RowIteratorBase(RowIteratorBase &&) = default;
844 RowIteratorBase &operator=(const RowIteratorBase &) = default;
845 RowIteratorBase &operator=(RowIteratorBase &&) = default;
846
847 RowIteratorBase(int row, const QModelIndex &parent, Adapter *adapter)
848 : QRangeModelDetails::ParentIndex<is_tree<Impl>>{parent}
849 , m_row(row), m_adapter(adapter)
850 {}
851
852 void swap(RowIteratorBase &other) noexcept
853 {
854 qSwap(m_row, other.m_row);
855 qSwap(this->m_rootIndex, other.m_rootIndex);
856 q_ptr_swap(m_adapter, other.m_adapter);
857 }
858
859 friend Iterator &operator++(Iterator &that)
860 {
861 ++that.m_row;
862 return that;
863 }
864 friend Iterator operator++(Iterator &that, int)
865 {
866 auto copy = that;
867 ++that;
868 return copy;
869 }
870 friend Iterator operator+(const Iterator &that, difference_type n)
871 {
872 return {that.m_row + n, that.root(), that.m_adapter};
873 }
874 friend Iterator operator+(difference_type n, const Iterator &that)
875 {
876 return that + n;
877 }
878 friend Iterator &operator+=(Iterator &that, difference_type n)
879 {
880 that.m_row += n;
881 return that;
882 }
883
884 friend Iterator &operator--(Iterator &that)
885 {
886 --that.m_row;
887 return that;
888 }
889 friend Iterator operator--(Iterator &that, int)
890 {
891 auto copy = that;
892 --that;
893 return copy;
894 }
895 friend Iterator operator-(const Iterator &that, difference_type n)
896 {
897 return {that.m_row - n, that.root(), that.m_adapter};
898 }
899 friend Iterator operator-(difference_type n, const Iterator &that)
900 {
901 return that - n;
902 }
903 friend Iterator &operator-=(Iterator &that, difference_type n)
904 {
905 that.m_row -= n;
906 return that;
907 }
908
909 friend difference_type operator-(const Iterator &lhs, const Iterator &rhs)
910 {
911 return lhs.m_row - rhs.m_row;
912 }
913
914 protected:
915 ~RowIteratorBase() = default;
916 int m_row = -1;
917 Adapter *m_adapter = nullptr;
918
919 private:
920 friend bool comparesEqual(const Iterator &lhs, const Iterator &rhs) noexcept
921 {
922 return lhs.m_row == rhs.m_row && lhs.root() == rhs.root();
923 }
924 friend Qt::strong_ordering compareThreeWay(const Iterator &lhs, const Iterator &rhs) noexcept
925 {
926 if (lhs.root() == rhs.root())
927 return qCompareThreeWay(lhs.m_row, rhs.m_row);
928 return qCompareThreeWay(lhs.root(), rhs.root());
929 }
930
931 Q_DECLARE_STRONGLY_ORDERED(Iterator)
932
933#ifndef QT_NO_DEBUG_STREAM
934 friend inline QDebug operator<<(QDebug dbg, const Iterator &it)
935 {
936 QDebugStateSaver saver(dbg);
937 dbg.nospace();
938 return dbg << "RowIterator(" << it.m_row << it.root() << ")";
939 }
940#endif
941 };
942
943public:
944 struct ConstRowIterator : public RowIteratorBase<ConstRowIterator, const QRangeModelAdapter>
945 {
946 private:
947 using Base = RowIteratorBase<ConstRowIterator, const QRangeModelAdapter>;
948 public:
949 using Base::Base;
950
951 using difference_type = typename Base::difference_type;
952 using value_type = std::conditional_t<is_list<Impl>,
953 const_data_type,
954 ConstRowReference>;
955 using reference = std::conditional_t<is_list<Impl>,
956 const_data_type,
957 ConstRowReference>;
958 using pointer = std::conditional_t<is_list<Impl>,
959 QRangeModelDetails::data_pointer_t<const_data_type>,
960 ConstRowReference>;
961
962 ConstRowIterator(const ConstRowIterator &other) = default;
963 ConstRowIterator(ConstRowIterator &&other) = default;
964 ConstRowIterator &operator=(const ConstRowIterator &other) = default;
965 ConstRowIterator &operator=(ConstRowIterator &&other) = default;
966 ~ConstRowIterator() = default;
967
968 pointer operator->() const
969 {
970 return pointer{operator*()};
971 }
972
973 reference operator*() const
974 {
975 if constexpr (is_list<Impl>) {
976 return this->m_adapter->at(this->m_row);
977 } else {
978 const QModelIndex index = this->m_adapter->model()->index(this->m_row, 0,
979 this->root());
980 return ConstRowReference{index, this->m_adapter};
981 }
982 }
983
984 reference operator[](difference_type n) const
985 {
986 return *(*this + n);
987 }
988 };
989
990 struct RowIterator : public RowIteratorBase<RowIterator, QRangeModelAdapter>
991 {
992 private:
993 using Base = RowIteratorBase<RowIterator, QRangeModelAdapter>;
994 public:
995 using Base::Base;
996
997 using difference_type = typename Base::difference_type;
998 using value_type = std::conditional_t<is_list<Impl>,
999 DataReference,
1000 RowReference>;
1001 using reference = std::conditional_t<is_list<Impl>,
1002 DataReference,
1003 RowReference>;
1004 using pointer = std::conditional_t<is_list<Impl>,
1005 DataReference,
1006 RowReference>;
1007
1008 RowIterator(const RowIterator &other) = default;
1009 RowIterator(RowIterator &&other) = default;
1010 RowIterator &operator=(const RowIterator &other) = default;
1011 RowIterator &operator=(RowIterator &&other) = default;
1012 ~RowIterator() = default;
1013
1014 operator ConstRowIterator() const
1015 {
1016 return ConstRowIterator{this->m_row, this->root(), this->m_adapter};
1017 }
1018
1019 pointer operator->() const
1020 {
1021 return pointer{operator*()};
1022 }
1023
1024 reference operator*() const
1025 {
1026 const QModelIndex index = this->m_adapter->model()->index(this->m_row, 0, this->root());
1027 if constexpr (is_list<Impl>) {
1028 return reference{index};
1029 } else {
1030 return reference{index, this->m_adapter};
1031 }
1032 }
1033
1034 reference operator[](difference_type n) const
1035 {
1036 return *(*this + n);
1037 }
1038 };
1039
1040 using const_iterator = ConstRowIterator;
1041 using iterator = RowIterator;
1042
1043 template <typename R,
1044 typename P,
1045 if_compatible_model_params<R, P> = true>
1046 explicit QRangeModelAdapter(R &&range, P &&protocol)
1047 : QRangeModelAdapter(new Model(QRangeModelDetails::forwardOrConvert<Range>(std::forward<R>(range)),
1048 QRangeModelDetails::forwardOrConvert<Protocol>(std::forward<P>(protocol))))
1049 {}
1050
1051 template <typename R,
1052 typename P = void, // to enable the ctr for void protocols only
1053 if_compatible_model_params<R, P> = true,
1054 unless_adapter<R> = true>
1055 explicit QRangeModelAdapter(R &&range)
1056 : QRangeModelAdapter(new Model(QRangeModelDetails::forwardOrConvert<Range>(std::forward<R>(range))))
1057 {}
1058
1059 // compiler-generated copy/move SMF are fine!
1060
1061 Model *model() const
1062 {
1063 return storage.m_model.get();
1064 }
1065
1066 const range_type &range() const
1067 {
1068 return QRangeModelDetails::refTo(storage.implementation()->childRange(storage.root()));
1069 }
1070
1071 template <typename NewRange = range_type, if_assignable_range<NewRange> = true>
1072 void assign(NewRange &&newRange)
1073 {
1074 assignImpl(qsizetype(Impl::size(QRangeModelDetails::refTo(newRange))),
1075 [&newRange](auto &oldRange) {
1076 oldRange = std::forward<NewRange>(newRange);
1077 });
1078 }
1079
1080 template <typename NewRange = range_type, if_assignable_range<NewRange> = true,
1081 unless_adapter<NewRange> = true>
1082 QRangeModelAdapter &operator=(NewRange &&newRange)
1083 {
1084 assign(std::forward<NewRange>(newRange));
1085 return *this;
1086 }
1087
1088 template <typename Row, if_assignable_range<std::initializer_list<Row>> = true>
1089 void assign(std::initializer_list<Row> newRange)
1090 {
1091 assignImpl(newRange.size(), [&newRange](auto &oldRange) {
1092 oldRange = newRange;
1093 });
1094 }
1095
1096 template <typename Row, if_assignable_range<std::initializer_list<Row>> = true>
1097 QRangeModelAdapter &operator=(std::initializer_list<Row> newRange)
1098 {
1099 assign(newRange);
1100 return *this;
1101 }
1102
1103 template <typename InputIterator, typename Sentinel, typename I = Impl, if_writable<I> = true>
1104 void assign(InputIterator first, Sentinel last)
1105 {
1106 assignImpl(size_t(std::distance(first, last)), [first, last](auto &oldRange) {
1107 oldRange.assign(first, last);
1108 });
1109 }
1110
1111 // iterator API
1112 ConstRowIterator cbegin() const
1113 {
1114 return ConstRowIterator{ 0, storage.root(), this };
1115 }
1116 ConstRowIterator begin() const { return cbegin(); }
1117
1118 ConstRowIterator cend() const
1119 {
1120 return ConstRowIterator{ rowCount(), storage.root(), this };
1121 }
1122 ConstRowIterator end() const { return cend(); }
1123
1124 template <typename I = Impl, if_writable<I> = true>
1125 RowIterator begin()
1126 {
1127 return RowIterator{ 0, storage.root(), this };
1128 }
1129
1130 template <typename I = Impl, if_writable<I> = true>
1131 RowIterator end()
1132 {
1133 return RowIterator{ rowCount(), storage.root(), this };
1134 }
1135
1136 int size() const
1137 {
1138 return rowCount();
1139 }
1140
1141 template <typename I = Impl, if_list<I> = true>
1142 QModelIndex index(int row) const
1143 {
1144 return storage->index(row, 0, storage.root());
1145 }
1146
1147 template <typename I = Impl, unless_list<I> = true>
1148 QModelIndex index(int row, int column) const
1149 {
1150 return storage->index(row, column, storage.root());
1151 }
1152
1153 template <typename I = Impl, if_tree<I> = true>
1154 QModelIndex index(QSpan<const int> path, int col) const
1155 {
1156 QModelIndex result = storage.root();
1157 auto count = path.size();
1158 for (const int r : path) {
1159 if (--count)
1160 result = storage->index(r, 0, result);
1161 else
1162 result = storage->index(r, col, result);
1163 }
1164 return result;
1165 }
1166
1167 int columnCount() const
1168 {
1169 // all rows and tree branches have the same column count
1170 return storage->columnCount({});
1171 }
1172
1173 int rowCount() const
1174 {
1175 return storage->rowCount(storage.root());
1176 }
1177
1178 template <typename I = Impl, if_tree<I> = true>
1179 int rowCount(int row) const
1180 {
1181 return rowCount(index(row, 0));
1182 }
1183
1184 template <typename I = Impl, if_tree<I> = true>
1185 int rowCount(QSpan<const int> path) const
1186 {
1187 return rowCount(index(path, 0));
1188 }
1189
1190 template <typename I = Impl, if_tree<I> = true>
1191 int rowCount(const QModelIndex &index) const
1192 {
1193 return storage->rowCount(index);
1194 }
1195
1196 template <typename I = Impl, if_tree<I> = true>
1197 constexpr bool hasChildren(int row) const
1198 {
1199 return hasChildren(index(row, 0));
1200 }
1201
1202 template <typename I = Impl, if_tree<I> = true>
1203 constexpr bool hasChildren(QSpan<const int> path) const
1204 {
1205 return hasChildren(index(path, 0));
1206 }
1207
1208 template <typename I = Impl, if_tree<I> = true>
1209 constexpr bool hasChildren(const QModelIndex &index) const
1210 {
1211 return storage.m_model->hasChildren(index);
1212 }
1213
1214 template <typename I = Impl, if_list<I> = true>
1215 QVariant data(int row) const
1216 {
1217 return data(index(row));
1218 }
1219
1220 template <typename I = Impl, if_list<I> = true>
1221 QVariant data(int row, int role) const
1222 {
1223 return data(index(row), role);
1224 }
1225
1226 template <typename I = Impl, if_list<I> = true, if_writable<I> = true>
1227 bool setData(int row, const QVariant &value, int role = Qt::EditRole)
1228 {
1229 return setData(index(row), value, role);
1230 }
1231
1232 template <typename I = Impl, unless_list<I> = true>
1233 QVariant data(int row, int column) const
1234 {
1235 return data(index(row, column));
1236 }
1237
1238 template <typename I = Impl, unless_list<I> = true>
1239 QVariant data(int row, int column, int role) const
1240 {
1241 return data(index(row, column), role);
1242 }
1243
1244 template <typename I = Impl, unless_list<I> = true, if_writable<I> = true>
1245 bool setData(int row, int column, const QVariant &value, int role = Qt::EditRole)
1246 {
1247 return setData(index(row, column), value, role);
1248 }
1249
1250 template <typename I = Impl, if_tree<I> = true>
1251 QVariant data(QSpan<const int> path, int column) const
1252 {
1253 return data(index(path, column));
1254 }
1255
1256 template <typename I = Impl, if_tree<I> = true>
1257 QVariant data(QSpan<const int> path, int column, int role) const
1258 {
1259 return data(index(path, column), role);
1260 }
1261
1262 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1263 bool setData(QSpan<const int> path, int column, const QVariant &value, int role = Qt::EditRole)
1264 {
1265 return setData(index(path, column), value, role);
1266 }
1267
1268 QVariant data(const QModelIndex &index) const
1269 {
1270 return QRangeModelDetails::dataAtIndex<QVariant>(index);
1271 }
1272
1273 QVariant data(const QModelIndex &index, int role) const
1274 {
1275 return QRangeModelDetails::dataAtIndex<QVariant>(index, role);
1276 }
1277
1278 template <typename I = Impl, if_writable<I> = true>
1279 bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)
1280 {
1281 return storage->setData(index, value, role);
1282 }
1283
1284 // at/operator[int] for list: returns value at row
1285 // if multi-role value: return the entire object
1286 template <typename I= Impl, if_list<I> = true>
1287 const_data_type at(int row) const
1288 {
1289 return QRangeModelDetails::dataAtIndex<data_type>(index(row));
1290 }
1291 template <typename I = Impl, if_list<I> = true>
1292 const_data_type operator[](int row) const { return at(row); }
1293
1294 template <typename I= Impl, if_list<I> = true, if_writable<I> = true>
1295 auto at(int row) {
1296 const QModelIndex idx = this->index(row);
1297 Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::at", "Index at row is invalid");
1298 return DataReference{idx};
1299 }
1300 template <typename I = Impl, if_list<I> = true, if_writable<I> = true>
1301 auto operator[](int row) {
1302 const QModelIndex idx = this->index(row);
1303 Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::operator[]", "Index at row is invalid");
1304 return DataReference{idx};
1305 }
1306
1307 // at/operator[int] for table or tree: a reference or view of the row
1308 template <typename I = Impl, unless_list<I> = true>
1309 decltype(auto) at(int row) const
1310 {
1311 return ConstRowReference{index(row, 0), this}.get();
1312 }
1313 template <typename I = Impl, unless_list<I> = true>
1314 decltype(auto) operator[](int row) const { return at(row); }
1315
1316 template <typename I = Impl, if_table<I> = true, if_writable<I> = true>
1317 auto at(int row)
1318 {
1319 return RowReference{index(row, 0), this};
1320 }
1321 template <typename I = Impl, if_table<I> = true, if_writable<I> = true>
1322 auto operator[](int row) { return at(row); }
1323
1324 // at/operator[int, int] for table: returns value at row/column
1325 template <typename I = Impl, unless_list<I> = true>
1326 const_data_type at(int row, int column) const
1327 {
1328 return QRangeModelDetails::dataAtIndex<data_type>(index(row, column));
1329 }
1330
1331#ifdef __cpp_multidimensional_subscript
1332 template <typename I = Impl, unless_list<I> = true>
1333 const_data_type operator[](int row, int column) const { return at(row, column); }
1334#endif
1335
1336 template <typename I = Impl, unless_list<I> = true, if_writable<I> = true>
1337 auto at(int row, int column)
1338 {
1339 const QModelIndex idx = this->index(row, column);
1340 Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::at", "Index at cell is invalid");
1341 return DataReference{idx};
1342 }
1343#ifdef __cpp_multidimensional_subscript
1344 template <typename I = Impl, unless_list<I> = true, if_writable<I> = true>
1345 auto operator[](int row, int column)
1346 {
1347 const QModelIndex idx = this->index(row, column);
1348 Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::operator[]", "Index at cell is invalid");
1349 return DataReference{idx};
1350 }
1351#endif
1352
1353 // at/operator[int] for tree: return a wrapper that maintains reference to
1354 // parent.
1355 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1356 auto at(int row)
1357 {
1358 return RowReference{index(row, 0), this};
1359 }
1360 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1361 auto operator[](int row) { return at(row); }
1362
1363 // at/operator[path] for tree: a reference or view of the row
1364 template <typename I = Impl, if_tree<I> = true>
1365 decltype(auto) at(QSpan<const int> path) const
1366 {
1367 return ConstRowReference{index(path, 0), this}.get();
1368 }
1369 template <typename I = Impl, if_tree<I> = true>
1370 decltype(auto) operator[](QSpan<const int> path) const { return at(path); }
1371
1372 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1373 auto at(QSpan<const int> path)
1374 {
1375 return RowReference{index(path, 0), this};
1376 }
1377 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1378 auto operator[](QSpan<const int> path) { return at(path); }
1379
1380 // at/operator[path, column] for tree: return value
1381 template <typename I = Impl, if_tree<I> = true>
1382 const_data_type at(QSpan<const int> path, int column) const
1383 {
1384 Q_PRE(path.size());
1385 return QRangeModelDetails::dataAtIndex<data_type>(index(path, column));
1386 }
1387
1388#ifdef __cpp_multidimensional_subscript
1389 template <typename I = Impl, if_tree<I> = true>
1390 const_data_type operator[](QSpan<const int> path, int column) const { return at(path, column); }
1391#endif
1392
1393 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1394 auto at(QSpan<const int> path, int column)
1395 {
1396 Q_PRE(path.size());
1397 const QModelIndex idx = this->index(path, column);
1398 Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::at", "Index at path is invalid");
1399 return DataReference{idx};
1400 }
1401#ifdef __cpp_multidimensional_subscript
1402 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1403 auto operator[](QSpan<const int> path, int column)
1404 {
1405 const QModelIndex idx = this->index(path, column);
1406 Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::operator[]", "Index at path is invalid");
1407 return DataReference{idx};
1408 }
1409#endif
1410
1411 const_data_type at(const QModelIndex &index) const
1412 {
1413 Q_ASSERT_X(index.isValid(), "QRangeModelAdapter::at", "Index is invalid");
1414 return QRangeModelDetails::dataAtIndex<data_type>(index);
1415 }
1416
1417 template <typename I = Impl, if_writable<I> = true>
1418 auto at(const QModelIndex &index)
1419 {
1420 Q_ASSERT_X(index.isValid(), "QRangeModelAdapter::at", "Index is invalid");
1421 return DataReference{index};
1422 }
1423
1424 template <typename I = Impl, if_canInsertRows<I> = true>
1425 bool insertRow(int before)
1426 {
1427 return storage.m_model->insertRow(before);
1428 }
1429
1430 template <typename I = Impl, if_canInsertRows<I> = true, if_tree<I> = true>
1431 bool insertRow(QSpan<const int> before)
1432 {
1433 Q_PRE(before.size());
1434 return insertRow(before.back(), this->index(before.first(before.size() - 1), 0));
1435 }
1436
1437 template <typename I = Impl, if_canInsertRows<I> = true, if_tree<I> = true>
1438 bool insertRow(int before, const QModelIndex &parent)
1439 {
1440 return storage.m_model->insertRow(before, parent);
1441 }
1442
1443 template <typename D = row_type, typename I = Impl,
1444 if_canInsertRows<I> = true, if_compatible_row<D> = true>
1445 bool insertRow(int before, D &&data)
1446 {
1447 return insertRowImpl(before, storage.root(), std::forward<D>(data));
1448 }
1449
1450 template <typename D = row_type, typename I = Impl,
1451 if_canInsertRows<I> = true, if_compatible_row<D> = true, if_tree<I> = true>
1452 bool insertRow(QSpan<const int> before, D &&data)
1453 {
1454 return insertRow(before.back(), this->index(before.sliced(0, before.size() - 1), 0),
1455 std::forward<D>(data));
1456 }
1457
1458 template <typename D = row_type, typename I = Impl,
1459 if_canInsertRows<I> = true, if_compatible_row<D> = true, if_tree<I> = true>
1460 bool insertRow(int before, const QModelIndex &parent, D &&data)
1461 {
1462 return insertRowImpl(before, parent, std::forward<D>(data));
1463 }
1464
1465 template <typename C, typename I = Impl,
1466 if_canInsertRows<I> = true, if_compatible_row_range<C> = true>
1467 bool insertRows(int before, C &&data)
1468 {
1469 return insertRowsImpl(before, storage.root(), std::forward<C>(data));
1470 }
1471
1472 template <typename C, typename I = Impl,
1473 if_canInsertRows<I> = true, if_compatible_row_range<C> = true, if_tree<I> = true>
1474 bool insertRows(QSpan<const int> before, C &&data)
1475 {
1476 return insertRows(before.back(), this->index(before.sliced(0, before.size() - 1), 0),
1477 std::forward<C>(data));
1478 }
1479
1480 template <typename C, typename I = Impl,
1481 if_canInsertRows<I> = true, if_compatible_row_range<C> = true, if_tree<I> = true>
1482 bool insertRows(int before, const QModelIndex &parent, C &&data)
1483 {
1484 return insertRowsImpl(before, parent, std::forward<C>(data));
1485 }
1486
1487 template <typename I = Impl, if_canRemoveRows<I> = true>
1488 bool removeRow(int row)
1489 {
1490 return removeRows(row, 1);
1491 }
1492
1493 template <typename I = Impl, if_canRemoveRows<I> = true, if_tree<I> = true>
1494 bool removeRow(QSpan<const int> path)
1495 {
1496 return removeRows(path, 1);
1497 }
1498
1499 template <typename I = Impl, if_canRemoveRows<I> = true, if_tree<I> = true>
1500 bool removeRow(int row, const QModelIndex &parent)
1501 {
1502 return removeRows(row, 1, parent);
1503 }
1504
1505 template <typename I = Impl, if_canRemoveRows<I> = true>
1506 bool removeRows(int row, int count)
1507 {
1508 return storage->removeRows(row, count, storage.root());
1509 }
1510
1511 template <typename I = Impl, if_canRemoveRows<I> = true, if_tree<I> = true>
1512 bool removeRows(QSpan<const int> path, int count)
1513 {
1514 return removeRows(path.back(), count, this->index(path.first(path.size() - 1), 0));
1515 }
1516
1517 template <typename I = Impl, if_canRemoveRows<I> = true, if_tree<I> = true>
1518 bool removeRows(int row, int count, const QModelIndex &parent)
1519 {
1520 return storage->removeRows(row, count, parent);
1521 }
1522
1523 template <typename F = range_features, if_canMoveItems<F> = true>
1524 bool moveRow(int source, int destination)
1525 {
1526 return moveRows(source, 1, destination);
1527 }
1528
1529 template <typename F = range_features, if_canMoveItems<F> = true>
1530 bool moveRows(int source, int count, int destination)
1531 {
1532 return storage->moveRows(storage.root(), source, count, storage.root(), destination);
1533 }
1534
1535 template <typename I = Impl, typename F = range_features,
1536 if_canMoveItems<F> = true, if_tree<I> = true>
1537 bool moveRow(QSpan<const int> source, QSpan<const int> destination)
1538 {
1539 return moveRows(source, 1, destination);
1540 }
1541
1542 template <typename I = Impl, typename F = range_features,
1543 if_canMoveItems<F> = true, if_tree<I> = true>
1544 bool moveRow(const QModelIndex &sourceParent, int sourceRow,
1545 const QModelIndex &destinationParent, int destinationChild)
1546 {
1547 return moveRows(sourceParent, sourceRow, 1, destinationParent, destinationChild);
1548 }
1549
1550 template <typename I = Impl, typename F = range_features,
1551 if_canMoveItems<F> = true, if_tree<I> = true>
1552 bool moveRows(QSpan<const int> source, int count, QSpan<const int> destination)
1553 {
1554 return moveRows(this->index(source.first(source.size() - 1), 0),
1555 source.back(),
1556 count,
1557 this->index(destination.first(destination.size() - 1), 0),
1558 destination.back());
1559 }
1560
1561 template <typename I = Impl, typename F = range_features,
1562 if_canMoveItems<F> = true, if_tree<I> = true>
1563 bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
1564 const QModelIndex &destinationParent, int destinationChild)
1565 {
1566 return storage->moveRows(sourceParent, sourceRow, count,
1567 destinationParent, destinationChild);
1568 }
1569
1570 template <typename I = Impl, if_canInsertColumns<I> = true>
1571 bool insertColumn(int before)
1572 {
1573 return storage.m_model->insertColumn(before);
1574 }
1575
1576 template <typename D, typename I = Impl,
1577 if_canInsertColumns<I> = true, if_compatible_column_data<D> = true>
1578 bool insertColumn(int before, D &&data)
1579 {
1580 return insertColumnImpl(before, storage.root(), std::forward<D>(data));
1581 }
1582
1583 template <typename C, typename I = Impl,
1584 if_canInsertColumns<I> = true, if_compatible_column_range<C> = true>
1585 bool insertColumns(int before, C &&data)
1586 {
1587 return insertColumnsImpl(before, storage.root(), std::forward<C>(data));
1588 }
1589
1590 template <typename I = Impl, if_canRemoveColumns<I> = true>
1591 bool removeColumn(int column)
1592 {
1593 return storage.m_model->removeColumn(column);
1594 }
1595
1596 template <typename I = Impl, if_canRemoveColumns<I> = true>
1597 bool removeColumns(int column, int count)
1598 {
1599 return storage->removeColumns(column, count, {});
1600 }
1601
1602 template <typename F = row_features, if_canMoveItems<F> = true>
1603 bool moveColumn(int from, int to)
1604 {
1605 return moveColumns(from, 1, to);
1606 }
1607
1608 template <typename F = row_features, if_canMoveItems<F> = true>
1609 bool moveColumns(int from, int count, int to)
1610 {
1611 return storage->moveColumns(storage.root(), from, count, storage.root(), to);
1612 }
1613
1614 template <typename I = Impl, typename F = row_features,
1615 if_canMoveItems<F> = true, if_tree<I> = true>
1616 bool moveColumn(QSpan<const int> source, int to)
1617 {
1618 const QModelIndex parent = this->index(source.first(source.size() - 1), 0);
1619 return storage->moveColumns(parent, source.back(), 1, parent, to);
1620 }
1621
1622 template <typename I = Impl, typename F = row_features,
1623 if_canMoveItems<F> = true, if_tree<I> = true>
1624 bool moveColumns(QSpan<const int> source, int count, int destination)
1625 {
1626 const QModelIndex parent = this->index(source.first(source.size() - 1), 0);
1627 return storage->moveColumns(parent, source.back(), count, parent, destination);
1628 }
1629
1630private:
1631 friend inline
1632 bool comparesEqual(const QRangeModelAdapter &lhs, const QRangeModelAdapter &rhs) noexcept
1633 {
1634 return lhs.storage.m_model == rhs.storage.m_model;
1635 }
1636 Q_DECLARE_EQUALITY_COMPARABLE(QRangeModelAdapter)
1637
1638 friend inline
1639 bool comparesEqual(const QRangeModelAdapter &lhs, const range_type &rhs)
1640 {
1641 return lhs.range() == rhs;
1642 }
1643 Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(QRangeModelAdapter, range_type)
1644
1645
1646 void emitDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
1647 {
1648 Q_EMIT storage.implementation()->dataChanged(topLeft, bottomRight, {});
1649 }
1650
1651 void beginAssignImpl(Impl *impl, range_type *oldRange, int newLastRow)
1652 {
1653 const QModelIndex root = storage.root();
1654 const qsizetype oldLastRow = qsizetype(Impl::size(oldRange)) - 1;
1655
1656 if (!root.isValid()) {
1657 impl->beginResetModel();
1658 impl->deleteOwnedRows();
1659 } else if constexpr (is_tree<Impl>) {
1660 if (oldLastRow >= 0) {
1661 impl->beginRemoveRows(root, 0, model()->rowCount(root) - 1);
1662 impl->deleteRemovedRows(QRangeModelDetails::refTo(oldRange));
1663 impl->endRemoveRows();
1664 }
1665 if (newLastRow >= 0)
1666 impl->beginInsertRows(root, 0, newLastRow);
1667 } else {
1668 Q_ASSERT_X(false, "QRangeModelAdapter::assign",
1669 "Internal error: The root index in a table or list must be invalid.");
1670 }
1671 }
1672
1673 void endAssignImpl(Impl *impl, int newLastRow)
1674 {
1675 const QModelIndex root = storage.root();
1676 if (!root.isValid()) {
1677 impl->endResetModel();
1678 } else if constexpr (is_tree<Impl>) {
1679 if (newLastRow >= 0) {
1680 Q_ASSERT(model()->hasChildren(root));
1681 // if it was moved, then newRange is now likely to be empty. Get
1682 // the inserted row.
1683 impl->setParentRow(QRangeModelDetails::refTo(impl->childRange(root)),
1684 QRangeModelDetails::pointerTo(impl->rowData(root)));
1685 impl->endInsertRows();
1686 }
1687 }
1688 }
1689
1690 template <typename Assigner>
1691 void assignImpl(std::size_t newSize, Assigner &&assigner)
1692 {
1693 const auto sz = q26::saturating_cast<int>(newSize);
1694 Q_ASSERT_X(q20::cmp_equal(sz, newSize),
1695 "QRangeModelAdapter::assign", "New range is too large");
1696 const int newLastRow = sz - 1;
1697
1698 auto *impl = storage.implementation();
1699 auto *oldRange = impl->childRange(storage.root());
1700 beginAssignImpl(impl, oldRange, newLastRow);
1701 assigner(QRangeModelDetails::refTo(oldRange));
1702 endAssignImpl(impl, newLastRow);
1703
1704 if constexpr (Impl::itemsAreQObjects) {
1705 if (model()->autoConnectPolicy() == QRangeModel::AutoConnectPolicy::Full) {
1706 const auto begin = QRangeModelDetails::begin(QRangeModelDetails::refTo(oldRange));
1707 const auto end = QRangeModelDetails::end(QRangeModelDetails::refTo(oldRange));
1708 int rowIndex = 0;
1709 for (auto it = begin; it != end; ++it, ++rowIndex)
1710 impl->autoConnectPropertiesInRow(*it, rowIndex, storage.root());
1711 }
1712 }
1713 }
1714
1715
1716 template <typename P, typename Row>
1717 static auto setParentRow(P &protocol, Row &newRow, row_ptr parentRow)
1718 -> decltype(protocol.setParentRow(newRow, parentRow))
1719 {
1720 return protocol.setParentRow(newRow, parentRow);
1721 }
1722 template <typename ...Args> static constexpr void setParentRow(Args &&...)
1723 {
1724 static_assert(!protocol_traits::has_setParentRow,
1725 "Internal error, wrong setParentRow overload called");
1726 }
1727
1728 template <typename D>
1729 bool insertRowImpl(int before, const QModelIndex &parent, D &&data)
1730 {
1731 return storage.implementation()->doInsertRows(before, 1, parent, [&data, this]
1732 (range_type &range, auto *parentRow, int row, int count) {
1733 Q_UNUSED(this);
1734 const auto oldSize = range.size();
1735 auto newRow = range.emplace(QRangeModelDetails::pos(range, row), std::forward<D>(data));
1736 setParentRow(storage->protocol(), QRangeModelDetails::refTo(*newRow),
1737 QRangeModelDetails::pointerTo(parentRow));
1738 return range.size() == oldSize + count;
1739 });
1740 }
1741
1742 template <typename LHS>
1743 static auto selfInsertion(LHS *lhs, LHS *rhs) -> decltype(lhs == rhs)
1744 {
1745 if (lhs == rhs) {
1746#ifndef QT_NO_DEBUG
1747 qCritical("Inserting data into itself is not supported");
1748#endif
1749 return true;
1750 }
1751 return false;
1752 }
1753 template <typename LHS, typename RHS>
1754 static constexpr bool selfInsertion(LHS *, RHS *) { return false; }
1755
1756 template <typename C>
1757 bool insertRowsImpl(int before, const QModelIndex &parent, C &&data)
1758 {
1759 bool result = false;
1760 result = storage->doInsertRows(before, int(std::size(data)), parent, [&data, this]
1761 (range_type &range, auto *parentRow, int row, int count){
1762 Q_UNUSED(parentRow);
1763 Q_UNUSED(this);
1764 const auto pos = QRangeModelDetails::pos(range, row);
1765 const auto oldSize = range.size();
1766
1767 auto dataRange = [&data]{
1768 if constexpr (std::is_rvalue_reference_v<C&&>) {
1769 return std::make_pair(
1770 std::move_iterator(std::begin(data)),
1771 std::move_iterator(std::end(data))
1772 );
1773 } else {
1774 return std::make_pair(std::begin(data), std::end(data));
1775 }
1776 }();
1777
1778 if constexpr (range_features::has_insert_range) {
1779 if (selfInsertion(&range, &data))
1780 return false;
1781 auto start = range.insert(pos, dataRange.first, dataRange.second);
1782 if constexpr (protocol_traits::has_setParentRow) {
1783 while (count) {
1784 setParentRow(storage->protocol(), QRangeModelDetails::refTo(*start),
1785 QRangeModelDetails::pointerTo(parentRow));
1786 ++start;
1787 --count;
1788 }
1789 } else {
1790 Q_UNUSED(start);
1791 }
1792 } else {
1793 auto newRow = range.insert(pos, count, row_type{});
1794 while (dataRange.first != dataRange.second) {
1795 *newRow = *dataRange.first;
1796 setParentRow(storage->protocol(), QRangeModelDetails::refTo(*newRow),
1797 QRangeModelDetails::pointerTo(parentRow));
1798 ++dataRange.first;
1799 ++newRow;
1800 }
1801 }
1802 return range.size() == oldSize + count;
1803 });
1804 return result;
1805 }
1806
1807 template <typename D, typename = void>
1808 struct DataFromList {
1809 static constexpr auto first(D &data) { return &data; }
1810 static constexpr auto next(D &, D *entry) { return entry; }
1811 };
1812
1813 template <typename D>
1814 struct DataFromList<D, std::enable_if_t<QRangeModelDetails::range_traits<D>::value>>
1815 {
1816 static constexpr auto first(D &data) { return std::begin(data); }
1817 static constexpr auto next(D &data, typename D::iterator entry)
1818 {
1819 ++entry;
1820 if (entry == std::end(data))
1821 entry = first(data);
1822 return entry;
1823 }
1824 };
1825
1826 template <typename D, typename = void> struct RowFromTable
1827 {
1828 static constexpr auto first(D &data) { return &data; }
1829 static constexpr auto next(D &, D *entry) { return entry; }
1830 };
1831
1832 template <typename D>
1833 struct RowFromTable<D, std::enable_if_t<std::conjunction_v<
1834 QRangeModelDetails::range_traits<D>,
1835 QRangeModelDetails::range_traits<typename D::value_type>
1836 >>
1837 > : DataFromList<D>
1838 {};
1839
1840 template <typename D>
1841 bool insertColumnImpl(int before, const QModelIndex &parent, D data)
1842 {
1843 auto entry = DataFromList<D>::first(data);
1844
1845 return storage->doInsertColumns(before, 1, parent, [&entry, &data]
1846 (auto &range, auto pos, int count) {
1847 const auto oldSize = range.size();
1848 range.insert(pos, *entry);
1849 entry = DataFromList<D>::next(data, entry);
1850 return range.size() == oldSize + count;
1851 });
1852 }
1853
1854 template <typename C>
1855 bool insertColumnsImpl(int before, const QModelIndex &parent, C data)
1856 {
1857 bool result = false;
1858 auto entries = RowFromTable<C>::first(data);
1859 auto begin = std::begin(*entries);
1860 auto end = std::end(*entries);
1861 result = storage->doInsertColumns(before, int(std::size(*entries)), parent,
1862 [&begin, &end, &entries, &data](auto &range, auto pos, int count) {
1863 const auto oldSize = range.size();
1864 if constexpr (row_features::has_insert_range) {
1865 range.insert(pos, begin, end);
1866 } else {
1867 auto start = range.insert(pos, count, {});
1868 std::copy(begin, end, start);
1869 }
1870 entries = RowFromTable<C>::next(data, entries);
1871 begin = std::begin(*entries);
1872 end = std::end(*entries);
1873 return range.size() == oldSize + count;
1874 });
1875 return result;
1876 }
1877};
1878
1879// Deduction guides are needed to correctly map single-parameter construction
1880// to the void-protocol case, and to disable construction from incompatible
1881// ranges.
1882template <typename Range, typename Protocol,
1883 QRangeModelDetails::if_can_construct<Range, Protocol> = true>
1885
1886template <typename Range,
1887 QRangeModelDetails::if_can_construct<Range> = true>
1888QRangeModelAdapter(Range &&) -> QRangeModelAdapter<Range, void>;
1889
1890QT_END_NAMESPACE
1891
1892#endif // QRANGEMODELADAPTER_H
QRangeModelAdapter(Range &&, Protocol &&) -> QRangeModelAdapter< Range, Protocol >