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