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 using value_type = data_type;
151 using const_value_type = const_data_type;
152 using pointer = QRangeModelDetails::data_pointer_t<const_value_type>;
153
154 explicit DataReference(const QModelIndex &index) noexcept
155 : m_index(index)
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 = std::move(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 std::swap(m_rowIndex, other.m_rowIndex);
296 std::swap(m_column, other.m_column);
297 q_ptr_swap(m_adapter, other.m_adapter);
298 }
299
300 friend Iterator &operator++(Iterator &that)
301 {
302 ++that.m_column;
303 return that;
304 }
305 friend Iterator operator++(Iterator &that, int)
306 {
307 auto copy = that;
308 ++that;
309 return copy;
310 }
311 friend Iterator operator+(const Iterator &that, difference_type n)
312 {
313 return {that.m_rowIndex, that.m_column + n, that.m_adapter};
314 }
315 friend Iterator operator+(difference_type n, const Iterator &that)
316 {
317 return that + n;
318 }
319 friend Iterator &operator+=(Iterator &that, difference_type n)
320 {
321 that.m_column += n;
322 return that;
323 }
324
325 friend Iterator &operator--(Iterator &that)
326 {
327 --that.m_column;
328 return that;
329 }
330 friend Iterator operator--(Iterator &that, int)
331 {
332 auto copy = that;
333 --that;
334 return copy;
335 }
336 friend Iterator operator-(const Iterator &that, difference_type n)
337 {
338 return {that.m_rowIndex, that.m_column - n, that.m_adapter};
339 }
340 friend Iterator operator-(difference_type n, const Iterator &that)
341 {
342 return that - n;
343 }
344 friend Iterator &operator-=(Iterator &that, difference_type n)
345 {
346 that.m_column -= n;
347 return that;
348 }
349
350 friend difference_type operator-(const Iterator &lhs, const Iterator &rhs)
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 private:
390 using Base = ColumnIteratorBase<ConstColumnIterator, const QRangeModelAdapter>;
391 public:
392 using difference_type = typename Base::difference_type;
393 using value_type = data_type;
394 using reference = const_data_type;
395 using pointer = QRangeModelDetails::data_pointer_t<value_type>;
396
397 using Base::Base;
398 using Base::operator=;
399 ~ConstColumnIterator() = default;
400
401 pointer operator->() const
402 {
403 return pointer{operator*()};
404 }
405
406 reference operator*() const
407 {
408 return std::as_const(this->m_adapter)->at(this->m_rowIndex.row(), this->m_column);
409 }
410
411 reference operator[](difference_type n) const
412 {
413 return *(*this + n);
414 }
415 };
416
417 struct ColumnIterator : ColumnIteratorBase<ColumnIterator, QRangeModelAdapter>
418 {
419 private:
420 using Base = ColumnIteratorBase<ColumnIterator, QRangeModelAdapter>;
421 public:
422 using difference_type = typename Base::difference_type;
423 using value_type = DataReference;
424 using reference = DataReference;
425 using pointer = reference;
426
427 using Base::Base;
428 using Base::operator=;
429 ~ColumnIterator() = default;
430
431 operator ConstColumnIterator() const
432 {
433 return ConstColumnIterator{this->m_rowIndex, this->m_column, this->m_adapter};
434 }
435
436 pointer operator->() const
437 {
438 return operator*();
439 }
440
441 reference operator*() const
442 {
443 return reference{this->m_rowIndex.siblingAtColumn(this->m_column)};
444 }
445
446 reference operator[](difference_type n) const
447 {
448 return *(*this + n);
449 }
450 };
451
452 template <typename Reference, typename const_row_type, typename = void>
453 struct RowGetter
454 {
455 const_row_type get() const
456 {
457 const Reference *that = static_cast<const Reference *>(this);
458 const auto *impl = that->m_adapter->storage.implementation();
459 auto *childRange = impl->childRange(that->m_index.parent());
460 if constexpr (std::is_convertible_v<const row_type &, const_row_type>) {
461 return *std::next(QRangeModelDetails::adl_begin(childRange), that->m_index.row());
462 } else {
463 const auto &row = *std::next(QRangeModelDetails::adl_begin(childRange),
464 that->m_index.row());
465 return const_row_type{QRangeModelDetails::adl_begin(row),
466 QRangeModelDetails::adl_end(row)};
467 }
468 }
469
470 const_row_type operator->() const
471 {
472 return {get()};
473 }
474
475 operator const_row_type() const
476 {
477 return get();
478 }
479 };
480
481 template <typename Reference, typename const_row_type>
482 struct RowGetter<Reference, const_row_type,
483 std::enable_if_t<std::is_reference_v<const_row_type>>>
484 {
485 const_row_type get() const
486 {
487 const Reference *that = static_cast<const Reference *>(this);
488 const auto *impl = that->m_adapter->storage.implementation();
489 return *std::next(QRangeModelDetails::begin(
490 QRangeModelDetails::refTo(impl->childRange(that->m_index.parent()))),
491 that->m_index.row());
492 }
493
494 auto operator->() const
495 {
496 return std::addressof(get());
497 }
498
499 operator const_row_type() const
500 {
501 return get();
502 }
503 };
504
505 template <typename Reference, typename const_row_type>
506 struct RowGetter<Reference, const_row_type,
507 std::enable_if_t<std::is_pointer_v<const_row_type>>>
508 {
509 const_row_type get() const
510 {
511 const Reference *that = static_cast<const Reference *>(this);
512 const auto *impl = that->m_adapter->storage.implementation();
513 return *std::next(QRangeModelDetails::begin(
514 QRangeModelDetails::refTo(impl->childRange(that->m_index.parent()))),
515 that->m_index.row());
516 }
517
518 const_row_type operator->() const
519 {
520 return get();
521 }
522
523 operator const_row_type() const
524 {
525 return get();
526 }
527 };
528
529 template <typename Reference, typename Adapter>
530 struct RowReferenceBase : RowGetter<Reference, QRangeModelDetails::asConstRow_t<row_type>>
531 {
532 using const_iterator = ConstColumnIterator;
533 using size_type = int;
534 using difference_type = int;
535 using const_row_type = QRangeModelDetails::asConstRow_t<row_type>;
536
537 RowReferenceBase(const QModelIndex &index, Adapter *adapter) noexcept
538 : m_index(index), m_adapter(adapter)
539 {}
540
541 template <typename I = Impl, if_tree<I> = true>
542 bool hasChildren() const
543 {
544 return m_adapter->model()->hasChildren(m_index);
545 }
546
547 template <typename I = Impl, if_tree<I> = true>
548 auto children() const
549 {
550 using ConstRange = QRangeModelDetails::asConst_t<Range>;
551 return QRangeModelAdapter<ConstRange, Protocol, Model>(m_adapter->storage.m_model,
552 m_index, std::in_place);
553 }
554
555 ConstColumnIterator cbegin() const
556 {
557 return ConstColumnIterator{m_index, 0, m_adapter};
558 }
559 ConstColumnIterator cend() const
560 {
561 return ConstColumnIterator{m_index, m_adapter->columnCount(), m_adapter};
562 }
563
564 ConstColumnIterator begin() const { return cbegin(); }
565 ConstColumnIterator end() const { return cend(); }
566
567 size_type size() const
568 {
569 return m_adapter->columnCount();
570 }
571
572 auto at(int column) const
573 {
574 Q_ASSERT(column >= 0 && column < m_adapter->columnCount());
575 return *ConstColumnIterator{m_index, column, m_adapter};
576 }
577
578 auto operator[](int column) const
579 {
580 return at(column);
581 }
582
583 protected:
584 friend struct RowGetter<Reference, const_row_type>;
585 ~RowReferenceBase() = default;
586 QModelIndex m_index;
587 Adapter *m_adapter;
588
589 private:
590 friend bool comparesEqual(const Reference &lhs, const Reference &rhs)
591 {
592 Q_ASSERT(lhs.m_adapter == rhs.m_adapter);
593 return lhs.m_index == rhs.m_index;
594 }
595 friend Qt::strong_ordering compareThreeWay(const Reference &lhs, const Reference &rhs)
596 {
597 Q_ASSERT(lhs.m_adapter == rhs.m_adapter);
598 return qCompareThreeWay(lhs.m_index, rhs.m_index);
599 }
600
601 Q_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT(Reference)
602
603 friend bool comparesEqual(const Reference &lhs, const row_type &rhs)
604 {
605 return lhs.get() == rhs;
606 }
607 Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(Reference, row_type)
608
609#ifndef QT_NO_DEBUG_STREAM
610 friend inline QDebug operator<<(QDebug dbg, const Reference &ref)
611 {
612 QDebugStateSaver saver(dbg);
613 dbg.nospace();
614 return dbg << "RowReference(" << ref.m_index << ")";
615 }
616#endif
617#ifndef QT_NO_DATASTREAM
618 friend inline QDataStream &operator<<(QDataStream &ds, const Reference &ref)
619 {
620 return ds << ref.get();
621 }
622#endif
623 };
624
625 struct ConstRowReference : RowReferenceBase<ConstRowReference, const QRangeModelAdapter>
626 {
627 private:
628 using Base = RowReferenceBase<ConstRowReference, const QRangeModelAdapter>;
629 public:
630 using Base::Base;
631
632 ConstRowReference() = default;
633 ConstRowReference(const ConstRowReference &) = default;
634 ConstRowReference(ConstRowReference &&) = default;
635 ConstRowReference &operator=(const ConstRowReference &) = default;
636 ConstRowReference &operator=(ConstRowReference &&) = default;
637 ~ConstRowReference() = default;
638 };
639
640 struct RowReference : RowReferenceBase<RowReference, QRangeModelAdapter>
641 {
642 private:
643 using Base = RowReferenceBase<RowReference, QRangeModelAdapter>;
644 public:
645 using iterator = ColumnIterator;
646 using const_iterator = typename Base::const_iterator;
647 using size_type = typename Base::size_type;
648 using difference_type = typename Base::difference_type;
649 using const_row_type = typename Base::const_row_type;
650
651 using Base::Base;
652 RowReference() = delete;
653 ~RowReference() = default;
654 RowReference(const RowReference &other) = default;
655 RowReference(RowReference &&other) = default;
656
657 // assignment has reference (std::reference_wrapper) semantics
658 RowReference &operator=(const ConstRowReference &other)
659 {
660 *this = other.get();
661 return *this;
662 }
663
664 RowReference &operator=(const RowReference &other)
665 {
666 *this = other.get();
667 return *this;
668 }
669
670 RowReference &operator=(const row_type &other)
671 {
672 assign(other);
673 return *this;
674 }
675
676 RowReference &operator=(row_type &&other)
677 {
678 assign(std::move(other));
679 return *this;
680 }
681
682 operator ConstRowReference() const
683 {
684 return ConstRowReference{this->m_index, this->m_adapter};
685 }
686
687 template <typename ConstRowType = const_row_type,
688 std::enable_if_t<!std::is_same_v<ConstRowType, const row_type &>, bool> = true>
689 RowReference &operator=(const ConstRowType &other)
690 {
691 assign(other);
692 return *this;
693 }
694
695 template <typename T, typename It, typename Sentinel>
696 RowReference &operator=(const QRangeModelDetails::RowView<T, It, Sentinel> &other)
697 {
698 *this = row_type{other.begin(), other.end()};
699 return *this;
700 }
701
702 friend inline void swap(RowReference lhs, RowReference rhs)
703 {
704 auto lhsRow = lhs.get();
705 lhs = rhs.get();
706 rhs = std::move(lhsRow);
707 }
708
709 template <typename I = Impl, if_tree<I> = true>
710 auto children()
711 {
712 return QRangeModelAdapter(this->m_adapter->storage.m_model, this->m_index,
713 std::in_place);
714 }
715
716 using Base::begin;
717 ColumnIterator begin()
718 {
719 return ColumnIterator{this->m_index, 0, this->m_adapter};
720 }
721
722 using Base::end;
723 ColumnIterator end()
724 {
725 return ColumnIterator{this->m_index, this->m_adapter->columnCount(), this->m_adapter};
726 }
727
728 using Base::at;
729 auto at(int column)
730 {
731 Q_ASSERT(column >= 0 && column < this->m_adapter->columnCount());
732 return *ColumnIterator{this->m_index, column, this->m_adapter};
733 }
734
735 using Base::operator[];
736 auto operator[](int column)
737 {
738 return at(column);
739 }
740
741 private:
742 template <typename RHS>
743 void verifyRows(const row_type &oldRow, const RHS &newRow)
744 {
745 if constexpr (QRangeModelDetails::test_size<row_type>::value) {
746 // prevent that tables get populated with wrongly sized rows
747 Q_ASSERT_X(Impl::size(newRow) == Impl::size(oldRow),
748 "RowReference::operator=()",
749 "The new row has the wrong size!");
750 }
751
752 if constexpr (is_tree<Impl>) {
753 // we cannot hook invalid rows up to the tree hierarchy
754 Q_ASSERT_X(QRangeModelDetails::isValid(newRow),
755 "RowReference::operator=()",
756 "An invalid row can not inserted into a tree!");
757 }
758 }
759
760 template <typename R>
761 void assign(R &&other)
762 {
763 auto *impl = this->m_adapter->storage.implementation();
764 decltype(auto) oldRow = impl->rowData(this->m_index);
765
766 verifyRows(oldRow, other);
767
768 if constexpr (is_tree<Impl>) {
769 auto &protocol = impl->protocol();
770 auto *oldParent = protocol.parentRow(QRangeModelDetails::refTo(oldRow));
771
772 // the old children will be removed; we don't try to overwrite
773 // them with the new children, we replace them completely
774 if (decltype(auto) oldChildren = protocol.childRows(QRangeModelDetails::refTo(oldRow));
775 QRangeModelDetails::isValid(oldChildren)) {
776 if (int oldChildCount = this->m_adapter->model()->rowCount(this->m_index)) {
777 impl->beginRemoveRows(this->m_index, 0, oldChildCount - 1);
778 impl->deleteRemovedRows(QRangeModelDetails::refTo(oldChildren));
779 // make sure the list is empty before we emit rowsRemoved
780 QRangeModelDetails::refTo(oldChildren) = range_type{};
781 impl->endRemoveRows();
782 }
783 }
784
785 if constexpr (protocol_traits::has_deleteRow)
786 protocol.deleteRow(oldRow);
787 oldRow = std::forward<R>(other);
788 if constexpr (protocol_traits::has_setParentRow) {
789 protocol.setParentRow(QRangeModelDetails::refTo(oldRow),
790 QRangeModelDetails::pointerTo(oldParent));
791 if (decltype(auto) newChildren = protocol.childRows(QRangeModelDetails::refTo(oldRow));
792 QRangeModelDetails::isValid(newChildren)) {
793 impl->beginInsertRows(this->m_index, 0,
794 Impl::size(QRangeModelDetails::refTo(newChildren)) - 1);
795 impl->setParentRow(QRangeModelDetails::refTo(newChildren),
796 QRangeModelDetails::pointerTo(oldRow));
797 impl->endInsertRows();
798 }
799 }
800 } else {
801 oldRow = std::forward<R>(other);
802 }
803 this->m_adapter->emitDataChanged(this->m_index,
804 this->m_index.siblingAtColumn(this->m_adapter->columnCount() - 1));
805 if constexpr (Impl::itemsAreQObjects) {
806 if (this->m_adapter->model()->autoConnectPolicy() == QRangeModel::AutoConnectPolicy::Full) {
807 impl->autoConnectPropertiesInRow(oldRow, this->m_index.row(), this->m_index.parent());
808 if constexpr (is_tree<Impl>)
809 impl->autoConnectProperties(this->m_index);
810 }
811
812 }
813 }
814
815#ifndef QT_NO_DATASTREAM
816 friend inline QDataStream &operator>>(QDataStream &ds, RowReference &ref)
817 {
818 row_type value;
819 ds >> value;
820 ref = value;
821 return ds;
822 }
823#endif
824 };
825
826 template <typename Iterator, typename Adapter>
827 struct RowIteratorBase : QRangeModelDetails::ParentIndex<is_tree<Impl>>
828 {
829 using iterator_category = std::random_access_iterator_tag;
830 using difference_type = int;
831
832 RowIteratorBase() = default;
833 RowIteratorBase(const RowIteratorBase &) = default;
834 RowIteratorBase(RowIteratorBase &&) = default;
835 RowIteratorBase &operator=(const RowIteratorBase &) = default;
836 RowIteratorBase &operator=(RowIteratorBase &&) = default;
837
838 RowIteratorBase(int row, const QModelIndex &parent, Adapter *adapter)
839 : QRangeModelDetails::ParentIndex<is_tree<Impl>>{parent}
840 , m_row(row), m_adapter(adapter)
841 {}
842
843 void swap(RowIteratorBase &other) noexcept
844 {
845 qSwap(m_row, other.m_row);
846 qSwap(this->m_rootIndex, other.m_rootIndex);
847 q_ptr_swap(m_adapter, other.m_adapter);
848 }
849
850 friend Iterator &operator++(Iterator &that)
851 {
852 ++that.m_row;
853 return that;
854 }
855 friend Iterator operator++(Iterator &that, int)
856 {
857 auto copy = that;
858 ++that;
859 return copy;
860 }
861 friend Iterator operator+(const Iterator &that, difference_type n)
862 {
863 return {that.m_row + n, that.root(), that.m_adapter};
864 }
865 friend Iterator operator+(difference_type n, const Iterator &that)
866 {
867 return that + n;
868 }
869 friend Iterator &operator+=(Iterator &that, difference_type n)
870 {
871 that.m_row += n;
872 return that;
873 }
874
875 friend Iterator &operator--(Iterator &that)
876 {
877 --that.m_row;
878 return that;
879 }
880 friend Iterator operator--(Iterator &that, int)
881 {
882 auto copy = that;
883 --that;
884 return copy;
885 }
886 friend Iterator operator-(const Iterator &that, difference_type n)
887 {
888 return {that.m_row - n, that.root(), that.m_adapter};
889 }
890 friend Iterator operator-(difference_type n, const Iterator &that)
891 {
892 return that - n;
893 }
894 friend Iterator &operator-=(Iterator &that, difference_type n)
895 {
896 that.m_row -= n;
897 return that;
898 }
899
900 friend difference_type operator-(const Iterator &lhs, const Iterator &rhs)
901 {
902 return lhs.m_row - rhs.m_row;
903 }
904
905 protected:
906 ~RowIteratorBase() = default;
907 int m_row = -1;
908 Adapter *m_adapter = nullptr;
909
910 private:
911 friend bool comparesEqual(const Iterator &lhs, const Iterator &rhs) noexcept
912 {
913 return lhs.m_row == rhs.m_row && lhs.root() == rhs.root();
914 }
915 friend Qt::strong_ordering compareThreeWay(const Iterator &lhs, const Iterator &rhs) noexcept
916 {
917 if (lhs.root() == rhs.root())
918 return qCompareThreeWay(lhs.m_row, rhs.m_row);
919 return qCompareThreeWay(lhs.root(), rhs.root());
920 }
921
922 Q_DECLARE_STRONGLY_ORDERED(Iterator)
923
924#ifndef QT_NO_DEBUG_STREAM
925 friend inline QDebug operator<<(QDebug dbg, const Iterator &it)
926 {
927 QDebugStateSaver saver(dbg);
928 dbg.nospace();
929 return dbg << "RowIterator(" << it.m_row << it.root() << ")";
930 }
931#endif
932 };
933
934public:
935 struct ConstRowIterator : public RowIteratorBase<ConstRowIterator, const QRangeModelAdapter>
936 {
937 private:
938 using Base = RowIteratorBase<ConstRowIterator, const QRangeModelAdapter>;
939 public:
940 using Base::Base;
941
942 using difference_type = typename Base::difference_type;
943 using value_type = std::conditional_t<is_list<Impl>,
944 const_data_type,
945 ConstRowReference>;
946 using reference = std::conditional_t<is_list<Impl>,
947 const_data_type,
948 ConstRowReference>;
949 using pointer = std::conditional_t<is_list<Impl>,
950 QRangeModelDetails::data_pointer_t<const_data_type>,
951 ConstRowReference>;
952
953 ConstRowIterator(const ConstRowIterator &other) = default;
954 ConstRowIterator(ConstRowIterator &&other) = default;
955 ConstRowIterator &operator=(const ConstRowIterator &other) = default;
956 ConstRowIterator &operator=(ConstRowIterator &&other) = default;
957 ~ConstRowIterator() = default;
958
959 pointer operator->() const
960 {
961 return pointer{operator*()};
962 }
963
964 reference operator*() const
965 {
966 if constexpr (is_list<Impl>) {
967 return this->m_adapter->at(this->m_row);
968 } else {
969 const QModelIndex index = this->m_adapter->model()->index(this->m_row, 0,
970 this->root());
971 return ConstRowReference{index, this->m_adapter};
972 }
973 }
974
975 reference operator[](difference_type n) const
976 {
977 return *(*this + n);
978 }
979 };
980
981 struct RowIterator : public RowIteratorBase<RowIterator, QRangeModelAdapter>
982 {
983 private:
984 using Base = RowIteratorBase<RowIterator, QRangeModelAdapter>;
985 public:
986 using Base::Base;
987
988 using difference_type = typename Base::difference_type;
989 using value_type = std::conditional_t<is_list<Impl>,
990 DataReference,
991 RowReference>;
992 using reference = std::conditional_t<is_list<Impl>,
993 DataReference,
994 RowReference>;
995 using pointer = std::conditional_t<is_list<Impl>,
996 DataReference,
997 RowReference>;
998
999 RowIterator(const RowIterator &other) = default;
1000 RowIterator(RowIterator &&other) = default;
1001 RowIterator &operator=(const RowIterator &other) = default;
1002 RowIterator &operator=(RowIterator &&other) = default;
1003 ~RowIterator() = default;
1004
1005 operator ConstRowIterator() const
1006 {
1007 return ConstRowIterator{this->m_row, this->root(), this->m_adapter};
1008 }
1009
1010 pointer operator->() const
1011 {
1012 return pointer{operator*()};
1013 }
1014
1015 reference operator*() const
1016 {
1017 const QModelIndex index = this->m_adapter->model()->index(this->m_row, 0, this->root());
1018 if constexpr (is_list<Impl>) {
1019 return reference{index};
1020 } else {
1021 return reference{index, this->m_adapter};
1022 }
1023 }
1024
1025 reference operator[](difference_type n) const
1026 {
1027 return *(*this + n);
1028 }
1029 };
1030
1031 using const_iterator = ConstRowIterator;
1032 using iterator = RowIterator;
1033
1034 template <typename R,
1035 typename P,
1036 if_compatible_model_params<R, P> = true>
1037 explicit QRangeModelAdapter(R &&range, P &&protocol)
1038 : QRangeModelAdapter(new Model(QRangeModelDetails::forwardOrConvert<Range>(std::forward<R>(range)),
1039 QRangeModelDetails::forwardOrConvert<Protocol>(std::forward<P>(protocol))))
1040 {}
1041
1042 template <typename R,
1043 typename P = void, // to enable the ctr for void protocols only
1044 if_compatible_model_params<R, P> = true,
1045 unless_adapter<R> = true>
1046 explicit QRangeModelAdapter(R &&range)
1047 : QRangeModelAdapter(new Model(QRangeModelDetails::forwardOrConvert<Range>(std::forward<R>(range))))
1048 {}
1049
1050 // compiler-generated copy/move SMF are fine!
1051
1052 Model *model() const
1053 {
1054 return storage.m_model.get();
1055 }
1056
1057 const range_type &range() const
1058 {
1059 return QRangeModelDetails::refTo(storage.implementation()->childRange(storage.root()));
1060 }
1061
1062 template <typename NewRange = range_type, if_assignable_range<NewRange> = true>
1063 void assign(NewRange &&newRange)
1064 {
1065 assignImpl(qsizetype(Impl::size(QRangeModelDetails::refTo(newRange))),
1066 [&newRange](auto &oldRange) {
1067 oldRange = std::forward<NewRange>(newRange);
1068 });
1069 }
1070
1071 template <typename NewRange = range_type, if_assignable_range<NewRange> = true,
1072 unless_adapter<NewRange> = true>
1073 QRangeModelAdapter &operator=(NewRange &&newRange)
1074 {
1075 assign(std::forward<NewRange>(newRange));
1076 return *this;
1077 }
1078
1079 template <typename Row, if_assignable_range<std::initializer_list<Row>> = true>
1080 void assign(std::initializer_list<Row> newRange)
1081 {
1082 assignImpl(newRange.size(), [&newRange](auto &oldRange) {
1083 oldRange = newRange;
1084 });
1085 }
1086
1087 template <typename Row, if_assignable_range<std::initializer_list<Row>> = true>
1088 QRangeModelAdapter &operator=(std::initializer_list<Row> newRange)
1089 {
1090 assign(newRange);
1091 return *this;
1092 }
1093
1094 template <typename InputIterator, typename Sentinel, typename I = Impl, if_writable<I> = true>
1095 void assign(InputIterator first, Sentinel last)
1096 {
1097 assignImpl(size_t(std::distance(first, last)), [first, last](auto &oldRange) {
1098 oldRange.assign(first, last);
1099 });
1100 }
1101
1102 // iterator API
1103 ConstRowIterator cbegin() const
1104 {
1105 return ConstRowIterator{ 0, storage.root(), this };
1106 }
1107 ConstRowIterator begin() const { return cbegin(); }
1108
1109 ConstRowIterator cend() const
1110 {
1111 return ConstRowIterator{ rowCount(), storage.root(), this };
1112 }
1113 ConstRowIterator end() const { return cend(); }
1114
1115 template <typename I = Impl, if_writable<I> = true>
1116 RowIterator begin()
1117 {
1118 return RowIterator{ 0, storage.root(), this };
1119 }
1120
1121 template <typename I = Impl, if_writable<I> = true>
1122 RowIterator end()
1123 {
1124 return RowIterator{ rowCount(), storage.root(), this };
1125 }
1126
1127 int size() const
1128 {
1129 return rowCount();
1130 }
1131
1132 template <typename I = Impl, if_list<I> = true>
1133 QModelIndex index(int row) const
1134 {
1135 return storage->index(row, 0, storage.root());
1136 }
1137
1138 template <typename I = Impl, unless_list<I> = true>
1139 QModelIndex index(int row, int column) const
1140 {
1141 return storage->index(row, column, storage.root());
1142 }
1143
1144 template <typename I = Impl, if_tree<I> = true>
1145 QModelIndex index(QSpan<const int> path, int col) const
1146 {
1147 QModelIndex result = storage.root();
1148 auto count = path.size();
1149 for (const int r : path) {
1150 if (--count)
1151 result = storage->index(r, 0, result);
1152 else
1153 result = storage->index(r, col, result);
1154 }
1155 return result;
1156 }
1157
1158 int columnCount() const
1159 {
1160 // all rows and tree branches have the same column count
1161 return storage->columnCount({});
1162 }
1163
1164 int rowCount() const
1165 {
1166 return storage->rowCount(storage.root());
1167 }
1168
1169 template <typename I = Impl, if_tree<I> = true>
1170 int rowCount(int row) const
1171 {
1172 return storage->rowCount(index(row, 0));
1173 }
1174
1175 template <typename I = Impl, if_tree<I> = true>
1176 int rowCount(QSpan<const int> path) const
1177 {
1178 return storage->rowCount(index(path, 0));
1179 }
1180
1181 template <typename I = Impl, if_tree<I> = true>
1182 constexpr bool hasChildren(int row) const
1183 {
1184 return storage.m_model->hasChildren(index(row, 0));
1185 }
1186
1187 template <typename I = Impl, if_tree<I> = true>
1188 constexpr bool hasChildren(QSpan<const int> path) const
1189 {
1190 return storage.m_model->hasChildren(index(path, 0));
1191 }
1192
1193 template <typename I = Impl, if_list<I> = true>
1194 QVariant data(int row) const
1195 {
1196 return QRangeModelDetails::dataAtIndex<QVariant>(index(row));
1197 }
1198
1199 template <typename I = Impl, if_list<I> = true>
1200 QVariant data(int row, int role) const
1201 {
1202 return QRangeModelDetails::dataAtIndex<QVariant>(index(row), role);
1203 }
1204
1205 template <typename I = Impl, if_list<I> = true, if_writable<I> = true>
1206 bool setData(int row, const QVariant &value, int role = Qt::EditRole)
1207 {
1208 return storage->setData(index(row), value, role);
1209 }
1210
1211 template <typename I = Impl, unless_list<I> = true>
1212 QVariant data(int row, int column) const
1213 {
1214 return QRangeModelDetails::dataAtIndex<QVariant>(index(row, column));
1215 }
1216
1217 template <typename I = Impl, unless_list<I> = true>
1218 QVariant data(int row, int column, int role) const
1219 {
1220 return QRangeModelDetails::dataAtIndex<QVariant>(index(row, column), role);
1221 }
1222
1223 template <typename I = Impl, unless_list<I> = true, if_writable<I> = true>
1224 bool setData(int row, int column, const QVariant &value, int role = Qt::EditRole)
1225 {
1226 return storage->setData(index(row, column), value, role);
1227 }
1228
1229 template <typename I = Impl, if_tree<I> = true>
1230 QVariant data(QSpan<const int> path, int column) const
1231 {
1232 return QRangeModelDetails::dataAtIndex<QVariant>(index(path, column));
1233 }
1234
1235 template <typename I = Impl, if_tree<I> = true>
1236 QVariant data(QSpan<const int> path, int column, int role) const
1237 {
1238 return QRangeModelDetails::dataAtIndex<QVariant>(index(path, column), role);
1239 }
1240
1241 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1242 bool setData(QSpan<const int> path, int column, const QVariant &value, int role = Qt::EditRole)
1243 {
1244 return storage->setData(index(path, column), value, role);
1245 }
1246
1247 // at/operator[int] for list: returns value at row
1248 // if multi-role value: return the entire object
1249 template <typename I= Impl, if_list<I> = true>
1250 const_data_type at(int row) const
1251 {
1252 return QRangeModelDetails::dataAtIndex<data_type>(index(row));
1253 }
1254 template <typename I = Impl, if_list<I> = true>
1255 const_data_type operator[](int row) const { return at(row); }
1256
1257 template <typename I= Impl, if_list<I> = true, if_writable<I> = true>
1258 auto at(int row) {
1259 const QModelIndex idx = this->index(row);
1260 Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::at", "Index at row is invalid");
1261 return DataReference{idx};
1262 }
1263 template <typename I = Impl, if_list<I> = true, if_writable<I> = true>
1264 auto operator[](int row) {
1265 const QModelIndex idx = this->index(row);
1266 Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::operator[]", "Index at row is invalid");
1267 return DataReference{idx};
1268 }
1269
1270 // at/operator[int] for table or tree: a reference or view of the row
1271 template <typename I = Impl, unless_list<I> = true>
1272 decltype(auto) at(int row) const
1273 {
1274 return ConstRowReference{index(row, 0), this}.get();
1275 }
1276 template <typename I = Impl, unless_list<I> = true>
1277 decltype(auto) operator[](int row) const { return at(row); }
1278
1279 template <typename I = Impl, if_table<I> = true, if_writable<I> = true>
1280 auto at(int row)
1281 {
1282 return RowReference{index(row, 0), this};
1283 }
1284 template <typename I = Impl, if_table<I> = true, if_writable<I> = true>
1285 auto operator[](int row) { return at(row); }
1286
1287 // at/operator[int, int] for table: returns value at row/column
1288 template <typename I = Impl, unless_list<I> = true>
1289 const_data_type at(int row, int column) const
1290 {
1291 return QRangeModelDetails::dataAtIndex<data_type>(index(row, column));
1292 }
1293
1294#ifdef __cpp_multidimensional_subscript
1295 template <typename I = Impl, unless_list<I> = true>
1296 const_data_type operator[](int row, int column) const { return at(row, column); }
1297#endif
1298
1299 template <typename I = Impl, unless_list<I> = true, if_writable<I> = true>
1300 auto at(int row, int column)
1301 {
1302 const QModelIndex idx = this->index(row, column);
1303 Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::at", "Index at cell is invalid");
1304 return DataReference{idx};
1305 }
1306#ifdef __cpp_multidimensional_subscript
1307 template <typename I = Impl, unless_list<I> = true, if_writable<I> = true>
1308 auto operator[](int row, int column)
1309 {
1310 const QModelIndex idx = this->index(row, column);
1311 Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::operator[]", "Index at cell is invalid");
1312 return DataReference{idx};
1313 }
1314#endif
1315
1316 // at/operator[int] for tree: return a wrapper that maintains reference to
1317 // parent.
1318 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1319 auto at(int row)
1320 {
1321 return RowReference{index(row, 0), this};
1322 }
1323 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1324 auto operator[](int row) { return at(row); }
1325
1326 // at/operator[path] for tree: a reference or view of the row
1327 template <typename I = Impl, if_tree<I> = true>
1328 decltype(auto) at(QSpan<const int> path) const
1329 {
1330 return ConstRowReference{index(path, 0), this}.get();
1331 }
1332 template <typename I = Impl, if_tree<I> = true>
1333 decltype(auto) operator[](QSpan<const int> path) const { return at(path); }
1334
1335 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1336 auto at(QSpan<const int> path)
1337 {
1338 return RowReference{index(path, 0), this};
1339 }
1340 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1341 auto operator[](QSpan<const int> path) { return at(path); }
1342
1343 // at/operator[path, column] for tree: return value
1344 template <typename I = Impl, if_tree<I> = true>
1345 const_data_type at(QSpan<const int> path, int column) const
1346 {
1347 Q_PRE(path.size());
1348 return QRangeModelDetails::dataAtIndex<data_type>(index(path, column));
1349 }
1350
1351#ifdef __cpp_multidimensional_subscript
1352 template <typename I = Impl, if_tree<I> = true>
1353 const_data_type operator[](QSpan<const int> path, int column) const { return at(path, column); }
1354#endif
1355
1356 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1357 auto at(QSpan<const int> path, int column)
1358 {
1359 Q_PRE(path.size());
1360 const QModelIndex idx = this->index(path, column);
1361 Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::at", "Index at path is invalid");
1362 return DataReference{idx};
1363 }
1364#ifdef __cpp_multidimensional_subscript
1365 template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1366 auto operator[](QSpan<const int> path, int column)
1367 {
1368 const QModelIndex idx = this->index(path, column);
1369 Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::operator[]", "Index at path is invalid");
1370 return DataReference{idx};
1371 }
1372#endif
1373
1374 template <typename I = Impl, if_canInsertRows<I> = true>
1375 bool insertRow(int before)
1376 {
1377 return storage.m_model->insertRow(before);
1378 }
1379
1380 template <typename I = Impl, if_canInsertRows<I> = true, if_tree<I> = true>
1381 bool insertRow(QSpan<const int> before)
1382 {
1383 Q_PRE(before.size());
1384 return storage.m_model->insertRow(before.back(), this->index(before.first(before.size() - 1), 0));
1385 }
1386
1387 template <typename D = row_type, typename I = Impl,
1388 if_canInsertRows<I> = true, if_compatible_row<D> = true>
1389 bool insertRow(int before, D &&data)
1390 {
1391 return insertRowImpl(before, storage.root(), std::forward<D>(data));
1392 }
1393
1394 template <typename D = row_type, typename I = Impl,
1395 if_canInsertRows<I> = true, if_compatible_row<D> = true, if_tree<I> = true>
1396 bool insertRow(QSpan<const int> before, D &&data)
1397 {
1398 return insertRowImpl(before.back(), this->index(before.sliced(0, before.size() - 1), 0),
1399 std::forward<D>(data));
1400 }
1401
1402 template <typename C, typename I = Impl,
1403 if_canInsertRows<I> = true, if_compatible_row_range<C> = true>
1404 bool insertRows(int before, C &&data)
1405 {
1406 return insertRowsImpl(before, storage.root(), std::forward<C>(data));
1407 }
1408
1409 template <typename C, typename I = Impl,
1410 if_canInsertRows<I> = true, if_compatible_row_range<C> = true, if_tree<I> = true>
1411 bool insertRows(QSpan<const int> before, C &&data)
1412 {
1413 return insertRowsImpl(before.back(), this->index(before.sliced(0, before.size() - 1), 0),
1414 std::forward<C>(data));
1415 }
1416
1417 template <typename I = Impl, if_canRemoveRows<I> = true>
1418 bool removeRow(int row)
1419 {
1420 return removeRows(row, 1);
1421 }
1422
1423 template <typename I = Impl, if_canRemoveRows<I> = true, if_tree<I> = true>
1424 bool removeRow(QSpan<const int> path)
1425 {
1426 return removeRows(path, 1);
1427 }
1428
1429 template <typename I = Impl, if_canRemoveRows<I> = true>
1430 bool removeRows(int row, int count)
1431 {
1432 return storage->removeRows(row, count, storage.root());
1433 }
1434
1435 template <typename I = Impl, if_canRemoveRows<I> = true, if_tree<I> = true>
1436 bool removeRows(QSpan<const int> path, int count)
1437 {
1438 return storage->removeRows(path.back(), count,
1439 this->index(path.first(path.size() - 1), 0));
1440 }
1441
1442 template <typename F = range_features, if_canMoveItems<F> = true>
1443 bool moveRow(int source, int destination)
1444 {
1445 return moveRows(source, 1, destination);
1446 }
1447
1448 template <typename F = range_features, if_canMoveItems<F> = true>
1449 bool moveRows(int source, int count, int destination)
1450 {
1451 return storage->moveRows(storage.root(), source, count, storage.root(), destination);
1452 }
1453
1454 template <typename I = Impl, typename F = range_features,
1455 if_canMoveItems<F> = true, if_tree<I> = true>
1456 bool moveRow(QSpan<const int> source, QSpan<const int> destination)
1457 {
1458 return moveRows(source, 1, destination);
1459 }
1460
1461 template <typename I = Impl, typename F = range_features,
1462 if_canMoveItems<F> = true, if_tree<I> = true>
1463 bool moveRows(QSpan<const int> source, int count, QSpan<const int> destination)
1464 {
1465 return storage->moveRows(this->index(source.first(source.size() - 1), 0),
1466 source.back(),
1467 count,
1468 this->index(destination.first(destination.size() - 1), 0),
1469 destination.back());
1470 }
1471
1472 template <typename I = Impl, if_canInsertColumns<I> = true>
1473 bool insertColumn(int before)
1474 {
1475 return storage.m_model->insertColumn(before);
1476 }
1477
1478 template <typename D, typename I = Impl,
1479 if_canInsertColumns<I> = true, if_compatible_column_data<D> = true>
1480 bool insertColumn(int before, D &&data)
1481 {
1482 return insertColumnImpl(before, storage.root(), std::forward<D>(data));
1483 }
1484
1485 template <typename C, typename I = Impl,
1486 if_canInsertColumns<I> = true, if_compatible_column_range<C> = true>
1487 bool insertColumns(int before, C &&data)
1488 {
1489 return insertColumnsImpl(before, storage.root(), std::forward<C>(data));
1490 }
1491
1492 template <typename I = Impl, if_canRemoveColumns<I> = true>
1493 bool removeColumn(int column)
1494 {
1495 return storage.m_model->removeColumn(column);
1496 }
1497
1498 template <typename I = Impl, if_canRemoveColumns<I> = true>
1499 bool removeColumns(int column, int count)
1500 {
1501 return storage->removeColumns(column, count, {});
1502 }
1503
1504 template <typename F = row_features, if_canMoveItems<F> = true>
1505 bool moveColumn(int from, int to)
1506 {
1507 return moveColumns(from, 1, to);
1508 }
1509
1510 template <typename F = row_features, if_canMoveItems<F> = true>
1511 bool moveColumns(int from, int count, int to)
1512 {
1513 return storage->moveColumns(storage.root(), from, count, storage.root(), to);
1514 }
1515
1516 template <typename I = Impl, typename F = row_features,
1517 if_canMoveItems<F> = true, if_tree<I> = true>
1518 bool moveColumn(QSpan<const int> source, int to)
1519 {
1520 const QModelIndex parent = this->index(source.first(source.size() - 1), 0);
1521 return storage->moveColumns(parent, source.back(), 1, parent, to);
1522 }
1523
1524 template <typename I = Impl, typename F = row_features,
1525 if_canMoveItems<F> = true, if_tree<I> = true>
1526 bool moveColumns(QSpan<const int> source, int count, int destination)
1527 {
1528 const QModelIndex parent = this->index(source.first(source.size() - 1), 0);
1529 return storage->moveColumns(parent, source.back(), count, parent, destination);
1530 }
1531
1532private:
1533 friend inline
1534 bool comparesEqual(const QRangeModelAdapter &lhs, const QRangeModelAdapter &rhs) noexcept
1535 {
1536 return lhs.storage.m_model == rhs.storage.m_model;
1537 }
1538 Q_DECLARE_EQUALITY_COMPARABLE(QRangeModelAdapter)
1539
1540 friend inline
1541 bool comparesEqual(const QRangeModelAdapter &lhs, const range_type &rhs)
1542 {
1543 return lhs.range() == rhs;
1544 }
1545 Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(QRangeModelAdapter, range_type)
1546
1547
1548 void emitDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
1549 {
1550 Q_EMIT storage.implementation()->dataChanged(topLeft, bottomRight, {});
1551 }
1552
1553 void beginAssignImpl(Impl *impl, range_type *oldRange, int newLastRow)
1554 {
1555 const QModelIndex root = storage.root();
1556 const qsizetype oldLastRow = qsizetype(Impl::size(oldRange)) - 1;
1557
1558 if (!root.isValid()) {
1559 impl->beginResetModel();
1560 impl->deleteOwnedRows();
1561 } else if constexpr (is_tree<Impl>) {
1562 if (oldLastRow >= 0) {
1563 impl->beginRemoveRows(root, 0, model()->rowCount(root) - 1);
1564 impl->deleteRemovedRows(QRangeModelDetails::refTo(oldRange));
1565 impl->endRemoveRows();
1566 }
1567 if (newLastRow >= 0)
1568 impl->beginInsertRows(root, 0, newLastRow);
1569 } else {
1570 Q_ASSERT_X(false, "QRangeModelAdapter::assign",
1571 "Internal error: The root index in a table or list must be invalid.");
1572 }
1573 }
1574
1575 void endAssignImpl(Impl *impl, int newLastRow)
1576 {
1577 const QModelIndex root = storage.root();
1578 if (!root.isValid()) {
1579 impl->endResetModel();
1580 } else if constexpr (is_tree<Impl>) {
1581 if (newLastRow >= 0) {
1582 Q_ASSERT(model()->hasChildren(root));
1583 // if it was moved, then newRange is now likely to be empty. Get
1584 // the inserted row.
1585 impl->setParentRow(QRangeModelDetails::refTo(impl->childRange(root)),
1586 QRangeModelDetails::pointerTo(impl->rowData(root)));
1587 impl->endInsertRows();
1588 }
1589 }
1590 }
1591
1592 template <typename Assigner>
1593 void assignImpl(std::size_t newSize, Assigner &&assigner)
1594 {
1595 const auto sz = q26::saturate_cast<int>(newSize);
1596 Q_ASSERT_X(q20::cmp_equal(sz, newSize),
1597 "QRangeModelAdapter::assign", "New range is too large");
1598 const int newLastRow = sz - 1;
1599
1600 auto *impl = storage.implementation();
1601 auto *oldRange = impl->childRange(storage.root());
1602 beginAssignImpl(impl, oldRange, newLastRow);
1603 assigner(QRangeModelDetails::refTo(oldRange));
1604 endAssignImpl(impl, newLastRow);
1605
1606 if constexpr (Impl::itemsAreQObjects) {
1607 if (model()->autoConnectPolicy() == QRangeModel::AutoConnectPolicy::Full) {
1608 const auto begin = QRangeModelDetails::begin(QRangeModelDetails::refTo(oldRange));
1609 const auto end = QRangeModelDetails::end(QRangeModelDetails::refTo(oldRange));
1610 int rowIndex = 0;
1611 for (auto it = begin; it != end; ++it, ++rowIndex)
1612 impl->autoConnectPropertiesInRow(*it, rowIndex, storage.root());
1613 }
1614 }
1615 }
1616
1617
1618 template <typename P, typename Row>
1619 static auto setParentRow(P &protocol, Row &newRow, row_ptr parentRow)
1620 -> decltype(protocol.setParentRow(newRow, parentRow))
1621 {
1622 return protocol.setParentRow(newRow, parentRow);
1623 }
1624 template <typename ...Args> static constexpr void setParentRow(Args &&...)
1625 {
1626 static_assert(!protocol_traits::has_setParentRow,
1627 "Internal error, wrong setParentRow overload called");
1628 }
1629
1630 template <typename D>
1631 bool insertRowImpl(int before, const QModelIndex &parent, D &&data)
1632 {
1633 return storage.implementation()->doInsertRows(before, 1, parent, [&data, this]
1634 (range_type &range, auto *parentRow, int row, int count) {
1635 Q_UNUSED(this);
1636 const auto oldSize = range.size();
1637 auto newRow = range.emplace(QRangeModelDetails::pos(range, row), std::forward<D>(data));
1638 setParentRow(storage->protocol(), QRangeModelDetails::refTo(*newRow),
1639 QRangeModelDetails::pointerTo(parentRow));
1640 return range.size() == oldSize + count;
1641 });
1642 }
1643
1644 template <typename LHS>
1645 static auto selfInsertion(LHS *lhs, LHS *rhs) -> decltype(lhs == rhs)
1646 {
1647 if (lhs == rhs) {
1648#ifndef QT_NO_DEBUG
1649 qCritical("Inserting data into itself is not supported");
1650#endif
1651 return true;
1652 }
1653 return false;
1654 }
1655 template <typename LHS, typename RHS>
1656 static constexpr bool selfInsertion(LHS *, RHS *) { return false; }
1657
1658 template <typename C>
1659 bool insertRowsImpl(int before, const QModelIndex &parent, C &&data)
1660 {
1661 bool result = false;
1662 result = storage->doInsertRows(before, int(std::size(data)), parent, [&data, this]
1663 (range_type &range, auto *parentRow, int row, int count){
1664 Q_UNUSED(parentRow);
1665 Q_UNUSED(this);
1666 const auto pos = QRangeModelDetails::pos(range, row);
1667 const auto oldSize = range.size();
1668
1669 auto dataRange = [&data]{
1670 if constexpr (std::is_rvalue_reference_v<C&&>) {
1671 return std::make_pair(
1672 std::move_iterator(std::begin(data)),
1673 std::move_iterator(std::end(data))
1674 );
1675 } else {
1676 return std::make_pair(std::begin(data), std::end(data));
1677 }
1678 }();
1679
1680 if constexpr (range_features::has_insert_range) {
1681 if (selfInsertion(&range, &data))
1682 return false;
1683 auto start = range.insert(pos, dataRange.first, dataRange.second);
1684 if constexpr (protocol_traits::has_setParentRow) {
1685 while (count) {
1686 setParentRow(storage->protocol(), QRangeModelDetails::refTo(*start),
1687 QRangeModelDetails::pointerTo(parentRow));
1688 ++start;
1689 --count;
1690 }
1691 } else {
1692 Q_UNUSED(start);
1693 }
1694 } else {
1695 auto newRow = range.insert(pos, count, row_type{});
1696 while (dataRange.first != dataRange.second) {
1697 *newRow = *dataRange.first;
1698 setParentRow(storage->protocol(), QRangeModelDetails::refTo(*newRow),
1699 QRangeModelDetails::pointerTo(parentRow));
1700 ++dataRange.first;
1701 ++newRow;
1702 }
1703 }
1704 return range.size() == oldSize + count;
1705 });
1706 return result;
1707 }
1708
1709 template <typename D, typename = void>
1710 struct DataFromList {
1711 static constexpr auto first(D &data) { return &data; }
1712 static constexpr auto next(D &, D *entry) { return entry; }
1713 };
1714
1715 template <typename D>
1716 struct DataFromList<D, std::enable_if_t<QRangeModelDetails::range_traits<D>::value>>
1717 {
1718 static constexpr auto first(D &data) { return std::begin(data); }
1719 static constexpr auto next(D &data, typename D::iterator entry)
1720 {
1721 ++entry;
1722 if (entry == std::end(data))
1723 entry = first(data);
1724 return entry;
1725 }
1726 };
1727
1728 template <typename D, typename = void> struct RowFromTable
1729 {
1730 static constexpr auto first(D &data) { return &data; }
1731 static constexpr auto next(D &, D *entry) { return entry; }
1732 };
1733
1734 template <typename D>
1735 struct RowFromTable<D, std::enable_if_t<std::conjunction_v<
1736 QRangeModelDetails::range_traits<D>,
1737 QRangeModelDetails::range_traits<typename D::value_type>
1738 >>
1739 > : DataFromList<D>
1740 {};
1741
1742 template <typename D>
1743 bool insertColumnImpl(int before, const QModelIndex &parent, D data)
1744 {
1745 auto entry = DataFromList<D>::first(data);
1746
1747 return storage->doInsertColumns(before, 1, parent, [&entry, &data]
1748 (auto &range, auto pos, int count) {
1749 const auto oldSize = range.size();
1750 range.insert(pos, *entry);
1751 entry = DataFromList<D>::next(data, entry);
1752 return range.size() == oldSize + count;
1753 });
1754 }
1755
1756 template <typename C>
1757 bool insertColumnsImpl(int before, const QModelIndex &parent, C data)
1758 {
1759 bool result = false;
1760 auto entries = RowFromTable<C>::first(data);
1761 auto begin = std::begin(*entries);
1762 auto end = std::end(*entries);
1763 result = storage->doInsertColumns(before, int(std::size(*entries)), parent,
1764 [&begin, &end, &entries, &data](auto &range, auto pos, int count) {
1765 const auto oldSize = range.size();
1766 if constexpr (row_features::has_insert_range) {
1767 range.insert(pos, begin, end);
1768 } else {
1769 auto start = range.insert(pos, count, {});
1770 std::copy(begin, end, start);
1771 }
1772 entries = RowFromTable<C>::next(data, entries);
1773 begin = std::begin(*entries);
1774 end = std::end(*entries);
1775 return range.size() == oldSize + count;
1776 });
1777 return result;
1778 }
1779};
1780
1781// Deduction guides are needed to correctly map single-parameter construction
1782// to the void-protocol case, and to disable construction from incompatible
1783// ranges.
1784template <typename Range, typename Protocol,
1785 QRangeModelDetails::if_can_construct<Range, Protocol> = true>
1787
1788template <typename Range,
1789 QRangeModelDetails::if_can_construct<Range> = true>
1790QRangeModelAdapter(Range &&) -> QRangeModelAdapter<Range, void>;
1791
1792QT_END_NAMESPACE
1793
1794#endif // QRANGEMODELADAPTER_H
QRangeModelAdapter(Range &&, Protocol &&) -> QRangeModelAdapter< Range, Protocol >