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 QRANGEMODEL_IMPL_H
6#define QRANGEMODEL_IMPL_H
7
8#ifndef Q_QDOC
9
10#ifndef QRANGEMODEL_H
11#error Do not include qrangemodel_impl.h directly
12#endif
13
14#if 0
15#pragma qt_sync_skip_header_check
16#pragma qt_sync_stop_processing
17#endif
18
19#include <QtCore/qabstractitemmodel.h>
20#include <QtCore/qmetaobject.h>
21#include <QtCore/qvariant.h>
22#include <QtCore/qmap.h>
23
24#include <algorithm>
25#include <functional>
26#include <iterator>
27#include <type_traits>
28#include <QtCore/q20type_traits.h>
29#include <tuple>
30#include <QtCore/q23utility.h>
31
32QT_BEGIN_NAMESPACE
33
34namespace QtPrivate {
35
36template <typename Applier, size_t ...Is>
37void applyIndexSwitch(size_t index, Applier&& applier, std::index_sequence<Is...>)
38{
39 // Performance considerations:
40 // The folding expression used here represents the same logic as a sequence of
41 // linear if/else if/... statements. Experiments show that Clang, GCC, and MSVC
42 // optimize it to essentially the same bytecode as a normal C++ switch,
43 // ensuring O(1) lookup complexity.
44 static_cast<void>(((Is == index ? (applier(std::integral_constant<size_t, Is>{}), true) : false)
45 || ...));
46}
47
48template <size_t IndexCount, typename Applier>
49void applyIndexSwitch(size_t index, Applier&& applier)
50{
51 applyIndexSwitch(index, std::forward<Applier>(applier), std::make_index_sequence<IndexCount>());
52}
53
54// TODO: move to a separate header in Qt 6.11
55template <typename Interface>
56class QQuasiVirtualInterface
57{
58private:
59 template <typename Arg>
60 static constexpr bool passArgAsValue = sizeof(Arg) <= sizeof(size_t)
61 && std::is_trivially_destructible_v<Arg>;
62
63 template <typename ...>
64 struct MethodImpl;
65
66 template <typename M, typename R, typename I, typename... Args>
67 struct MethodImpl<M, R, I, Args...>
68 {
69 static_assert(std::is_base_of_v<I, Interface>, "The method must belong to the interface");
70 using return_type = R;
71 using call_args = std::tuple<std::conditional_t<passArgAsValue<Args>, Args, Args&&>...>;
72
73 static constexpr size_t index()
74 {
75 return index(std::make_index_sequence<std::tuple_size_v<Methods<>>>());
76 }
77
78 private:
79 template <size_t Ix>
80 static constexpr bool matchesAt()
81 {
82 return std::is_base_of_v<M, std::tuple_element_t<Ix, Methods<>>>;
83 }
84
85 template <size_t... Is>
86 static constexpr size_t index(std::index_sequence<Is...>)
87 {
88 constexpr size_t matchesCount = (size_t(matchesAt<Is>()) + ...);
89 static_assert(matchesCount == 1, "Expected exactly one match");
90 return ((size_t(matchesAt<Is>()) * Is) + ...);
91 }
92
93 static R invoke(I &intf /*const validation*/, Args... args)
94 {
95 Q_ASSERT(intf.m_callFN);
96
97 auto& baseIntf = static_cast<base_interface&>(const_cast<std::remove_const_t<I>&>(intf));
98 call_args callArgs(std::forward<Args>(args)...);
99 if constexpr (std::is_void_v<R>) {
100 intf.m_callFN(index(), baseIntf, nullptr, &callArgs);
101 } else {
102 alignas(R) std::byte buf[sizeof(R)];
103 intf.m_callFN(index(), baseIntf, buf, &callArgs);
104
105 R* result = std::launder(reinterpret_cast<R*>(buf));
106 QScopeGuard destroyBuffer([result]() { std::destroy_at(result); });
107 return std::forward<R>(*result);
108 }
109 }
110
111 friend class QQuasiVirtualInterface<Interface>;
112 };
113
114 template <typename M, typename R, typename I, typename... Args>
115 struct MethodImpl<M, R(I::*)(Args...)> : MethodImpl<M, R, I, Args...> {
116 template <typename Subclass>
117 using Overridden = R(Subclass::*)(Args...);
118 };
119
120 template <typename M, typename R, typename I, typename... Args>
121 struct MethodImpl<M, R(I::*)(Args...) const> : MethodImpl<M, R, const I, Args...> {
122 template <typename Subclass>
123 using Overridden = R(Subclass::*)(Args...) const;
124 };
125
126 template <typename C = Interface> using Methods = typename C::template MethodTemplates<C>;
127
128public:
129 template <auto prototype>
130 struct Method : MethodImpl<Method<prototype>, decltype(prototype)> {};
131
132 template <typename Method, typename... Args>
133 auto call(Args &&... args) const
134 {
135 return Method::invoke(static_cast<const Interface &>(*this), std::forward<Args>(args)...);
136 }
137
138 template <typename Method, typename... Args>
139 auto call(Args &&... args)
140 {
141 return Method::invoke(static_cast<Interface &>(*this), std::forward<Args>(args)...);
142 }
143
144 void destroy(); // quasi-virtual pure destructor
145 using Destroy = Method<&QQuasiVirtualInterface::destroy>;
146
147 struct Deleter
148 {
149 void operator () (QQuasiVirtualInterface* self) const { self->call<Destroy>(); }
150 };
151
152protected:
153 using base_interface = QQuasiVirtualInterface<Interface>;
154 using CallFN = void (*)(size_t index, base_interface &intf, void *ret, void *args);
155 void initCallFN(CallFN func) { m_callFN = func; }
156
157 QQuasiVirtualInterface() = default;
158 ~QQuasiVirtualInterface() = default;
159
160private:
161 Q_DISABLE_COPY_MOVE(QQuasiVirtualInterface)
162 CallFN m_callFN = nullptr;
163};
164
165template <typename Subclass, typename Interface>
166class QQuasiVirtualSubclass : public Interface
167{
168private:
169 template <typename C = Subclass> using Methods = typename C::template MethodTemplates<C>;
170
171 template <size_t OverriddenIndex>
172 static constexpr size_t interfaceMethodIndex() {
173 return std::tuple_element_t<OverriddenIndex, Methods<>>::index();
174 }
175
176 template <size_t... Is>
177 static void callImpl(size_t index, Subclass &subclass, void *ret, void *args, std::index_sequence<Is...>)
178 {
179 // TODO: come up with more sophisticated check if methods count becomes more than 64
180 static constexpr std::uint64_t methodIndexMask = ((uint64_t(1)
181 << interfaceMethodIndex<Is>()) | ...);
182 static_assert(sizeof...(Is) == std::tuple_size_v<Methods<Interface>>,
183 "Base and overridden methods count are different");
184 static_assert(methodIndexMask == (uint64_t(1) << sizeof...(Is)) - 1,
185 "Mapping between base and overridden methods is not unique");
186
187 auto doInvoke = [&](auto idxConstant) {
188 std::tuple_element_t<idxConstant.value, Methods<>>::doInvoke(subclass, ret, args);
189 };
190 applyIndexSwitch(index, doInvoke, std::index_sequence<interfaceMethodIndex<Is>()...>{});
191 }
192
193 static void callImpl(size_t index, typename Interface::base_interface &intf, void *ret, void *args)
194 {
195 constexpr auto seq = std::make_index_sequence<std::tuple_size_v<Methods<>>>();
196 callImpl(index, static_cast<Subclass&>(intf), ret, args, seq);
197 }
198
199 template <typename BaseMethod>
200 using OverridenSignature = typename BaseMethod::template Overridden<Subclass>;
201
202protected:
203 template <typename... Args>
204 QQuasiVirtualSubclass(Args &&... args)
205 : Interface(std::forward<Args>(args)...)
206 {
207 Interface::initCallFN(&QQuasiVirtualSubclass::callImpl);
208 }
209
210public:
211 template <typename BaseMethod, OverridenSignature<BaseMethod> overridden>
212 struct Override : BaseMethod
213 {
214 private:
215 static constexpr void doInvoke(Subclass &subclass, void *ret, void *args)
216 {
217 using Return = typename BaseMethod::return_type;
218 using PackedArgs = typename BaseMethod::call_args;
219
220 Q_ASSERT(args);
221 Q_ASSERT(std::is_void_v<Return> == !ret);
222
223 auto invoke = [&subclass](auto &&...params)
224 {
225 return std::invoke(overridden, &subclass, std::forward<decltype(params)>(params)...);
226 };
227
228 if constexpr (std::is_void_v<Return>) {
229 std::apply(invoke, std::move(*static_cast<PackedArgs *>(args)));
230 } else {
231 // Note, that ::new Return(...) fails on Integrity.
232 // TODO: use std::construct_at for c++20
233 using Alloc = std::allocator<Return>;
234 Alloc alloc;
235 std::allocator_traits<Alloc>::construct(alloc, static_cast<Return *>(ret),
236 std::apply(invoke, std::move(*static_cast<PackedArgs *>(args))));
237 }
238
239 }
240
241 friend class QQuasiVirtualSubclass<Subclass, Interface>;
242 };
243};
244
245}
246
247namespace QRangeModelDetails
248{
249 template <typename T, template <typename...> typename... Templates>
250 struct is_any_of_impl : std::false_type {};
251
252 template <template <typename...> typename Template,
253 typename... Params,
254 template <typename...> typename... Templates>
255 struct is_any_of_impl<Template<Params...>, Template, Templates...> : std::true_type {};
256
257 template <typename T,
258 template <typename...> typename Template,
259 template <typename...> typename... Templates>
260 struct is_any_of_impl<T, Template, Templates...> : is_any_of_impl<T, Templates...> {};
261
262 template <typename T, template <typename...> typename... Templates>
263 using is_any_of = is_any_of_impl<std::remove_cv_t<T>, Templates...>;
264
265 template <typename T, typename = void>
266 struct is_validatable : std::false_type {};
267
268 template <typename T>
269 struct is_validatable<T, std::void_t<decltype(*std::declval<T>())>>
270 : std::is_constructible<bool, T> {};
271
272 template <typename T, typename = void>
273 struct is_smart_ptr : std::false_type {};
274
275 template <typename T>
276 struct is_smart_ptr<T,
277 std::enable_if_t<std::conjunction_v<
278 std::is_pointer<decltype(std::declval<T&>().get())>,
279 std::is_same<decltype(*std::declval<T&>().get()), decltype(*std::declval<T&>())>,
280 is_validatable<T>
281 >>>
282 : std::true_type
283 {};
284
285 // TODO: shouldn't we check is_smart_ptr && !is_copy_constructible && !is_copy_assignable
286 // to support users-specific ptrs?
287 template <typename T>
288 using is_any_unique_ptr = is_any_of<T,
289#ifndef QT_NO_SCOPED_POINTER
290 QScopedPointer,
291#endif
292 std::unique_ptr
293 >;
294
295 template <typename T>
296 using is_any_shared_ptr = is_any_of<T, std::shared_ptr, QSharedPointer,
297 QExplicitlySharedDataPointer, QSharedDataPointer>;
298
299 template <typename T>
300 using is_owning_or_raw_pointer = std::disjunction<is_any_shared_ptr<T>, is_any_unique_ptr<T>,
301 std::is_pointer<T>>;
302
303 template <typename T>
304 static auto pointerTo(T&& t) {
305 using Type = q20::remove_cvref_t<T>;
306 if constexpr (is_any_of<Type, std::optional>())
307 return t ? std::addressof(*std::forward<T>(t)) : nullptr;
308 else if constexpr (std::is_pointer<Type>())
309 return t;
310 else if constexpr (is_smart_ptr<Type>())
311 return t.get();
312 else if constexpr (is_any_of<Type, std::reference_wrapper>())
313 return std::addressof(t.get());
314 else
315 return std::addressof(std::forward<T>(t));
316 }
317
318 template <typename T>
319 using wrapped_t = std::remove_pointer_t<decltype(pointerTo(std::declval<T&>()))>;
320
321 template <typename T>
322 using is_wrapped = std::negation<std::is_same<wrapped_t<T>, std::remove_reference_t<T>>>;
323
324 template <typename T, typename = void>
325 struct tuple_like : std::false_type {};
326 template <typename T, std::size_t N>
327 struct tuple_like<std::array<T, N>> : std::false_type {};
328 template <typename T>
329 struct tuple_like<T, std::void_t<std::tuple_element_t<0, wrapped_t<T>>>> : std::true_type {};
330 template <typename T>
331 [[maybe_unused]] static constexpr bool tuple_like_v = tuple_like<T>::value;
332
333 template <typename T, typename = void>
334 struct array_like : std::false_type {};
335 template <typename T, std::size_t N>
336 struct array_like<std::array<T, N>> : std::true_type {};
337 template <typename T, std::size_t N>
338 struct array_like<T[N]> : std::true_type {};
339 template <typename T>
340 [[maybe_unused]] static constexpr bool array_like_v = array_like<T>::value;
341
342 template <typename T, typename = void>
343 struct has_metaobject : std::false_type {};
344 template <typename T>
345 struct has_metaobject<T, std::void_t<decltype(wrapped_t<T>::staticMetaObject)>>
346 : std::true_type {};
347 template <typename T>
348 [[maybe_unused]] static constexpr bool has_metaobject_v = has_metaobject<T>::value;
349
350 template <typename T>
351 static constexpr bool isValid(const T &t) noexcept
352 {
353 if constexpr (is_validatable<T>())
354 return bool(t);
355 else
356 return true;
357 }
358
359 template <typename T>
360 static decltype(auto) refTo(T&& t) {
361 Q_ASSERT(isValid(t));
362 // it's allowed to move only if the object holds unique ownership of the wrapped data
363 using Type = q20::remove_cvref_t<T>;
364 if constexpr (is_any_of<T, std::optional>())
365 return *std::forward<T>(t); // let std::optional resolve dereferencing
366 if constexpr (!is_wrapped<Type>() || is_any_unique_ptr<Type>())
367 return q23::forward_like<T>(*pointerTo(t));
368 else
369 return *pointerTo(t);
370 }
371
372 template <typename It>
373 auto key(It&& it) -> decltype(it.key()) { return std::forward<It>(it).key(); }
374 template <typename It>
375 auto key(It&& it) -> decltype((it->first)) { return std::forward<It>(it)->first; }
376
377 template <typename It>
378 auto value(It&& it) -> decltype(it.value()) { return std::forward<It>(it).value(); }
379 template <typename It>
380 auto value(It&& it) -> decltype((it->second)) { return std::forward<It>(it)->second; }
381
382 // use our own version of begin/end so that we can overload for pointers
383 template <typename C>
384 static auto begin(C &&c) -> decltype(std::begin(refTo(std::forward<C>(c))))
385 { return std::begin(refTo(std::forward<C>(c))); }
386 template <typename C>
387 static auto end(C &&c) -> decltype(std::end(refTo(std::forward<C>(c))))
388 { return std::end(refTo(std::forward<C>(c))); }
389 template <typename C>
390 static auto pos(C &&c, int i)
391 { return std::next(QRangeModelDetails::begin(std::forward<C>(c)), i); }
392
393 // Test if a type is a range, and whether we can modify it using the
394 // standard C++ container member functions insert, erase, and resize.
395 // For the sake of QAIM, we cannot modify a range if it holds const data
396 // even if the range itself is not const; we'd need to initialize new rows
397 // and columns, and move old row and column data.
398 template <typename C, typename = void>
399 struct test_insert : std::false_type {};
400
401 template <typename C>
402 struct test_insert<C, std::void_t<decltype(std::declval<C>().insert(
403 std::declval<typename C::const_iterator>(),
404 std::declval<typename C::size_type>(),
405 std::declval<typename C::value_type>()
406 ))>>
407 : std::true_type
408 {};
409
410 // Can we insert from another (identical) range? Required to support
411 // move-only types
412 template <typename C, typename = void>
413 struct test_insert_range : std::false_type {};
414
415 template <typename C>
416 struct test_insert_range<C, std::void_t<decltype(std::declval<C&>().insert(
417 std::declval<typename C::const_iterator&>(),
418 std::declval<std::move_iterator<typename C::iterator>&>(),
419 std::declval<std::move_iterator<typename C::iterator>&>()
420 ))>>
421 : std::true_type
422 {};
423
424 template <typename C, typename = void>
425 struct test_erase : std::false_type {};
426
427 template <typename C>
428 struct test_erase<C, std::void_t<decltype(std::declval<C>().erase(
429 std::declval<typename C::const_iterator>(),
430 std::declval<typename C::const_iterator>()
431 ))>>
432 : std::true_type
433 {};
434
435 template <typename C, typename = void>
436 struct test_resize : std::false_type {};
437
438 template <typename C>
439 struct test_resize<C, std::void_t<decltype(std::declval<C>().resize(
440 std::declval<typename C::size_type>(),
441 std::declval<typename C::value_type>()
442 ))>>
443 : std::true_type
444 {};
445
446 // we use std::rotate in moveRows/Columns, which requires std::swap
447 template <typename It, typename = void>
448 struct test_rotate : std::false_type {};
449
450 template <typename It>
451 struct test_rotate<It, std::void_t<decltype(std::swap(*std::declval<It>(),
452 *std::declval<It>()))>>
453 : std::true_type
454 {};
455
456 // Test if a type is an associative container that we can use for multi-role
457 // data, i.e. has a key_type and a mapped_type typedef, and maps from int,
458 // Qt::ItemDataRole, or QString to QVariant. This excludes std::set (and
459 // unordered_set), which are not useful for us anyway even though they are
460 // considered associative containers.
461 template <typename C, typename = void> struct is_multi_role : std::false_type
462 {
463 static constexpr bool int_key = false;
464 };
465 template <typename C> // Qt::ItemDataRole -> QVariant, or QString -> QVariant, int -> QVariant
466 struct is_multi_role<C, std::void_t<typename C::key_type, typename C::mapped_type>>
467 : std::conjunction<std::disjunction<std::is_same<typename C::key_type, int>,
468 std::is_same<typename C::key_type, Qt::ItemDataRole>,
469 std::is_same<typename C::key_type, QString>>,
470 std::is_same<typename C::mapped_type, QVariant>>
471 {
472 static constexpr bool int_key = !std::is_same_v<typename C::key_type, QString>;
473 };
474 template <typename C>
475 [[maybe_unused]]
476 static constexpr bool is_multi_role_v = is_multi_role<C>::value;
477
478 template <typename C, typename = void>
479 struct test_size : std::false_type {};
480 template <typename C>
481 struct test_size<C, std::void_t<decltype(std::size(std::declval<C&>()))>> : std::true_type {};
482
483 template <typename C, typename = void>
484 struct range_traits : std::false_type {
485 static constexpr bool is_mutable = !std::is_const_v<C>;
486 static constexpr bool has_insert = false;
487 static constexpr bool has_insert_range = false;
488 static constexpr bool has_erase = false;
489 static constexpr bool has_resize = false;
490 static constexpr bool has_rotate = false;
491 };
492 template <typename C>
493 struct range_traits<C, std::void_t<decltype(begin(std::declval<C&>())),
494 decltype(end(std::declval<C&>())),
495 std::enable_if_t<!is_multi_role_v<C>>
496 >> : std::true_type
497 {
498 using iterator = decltype(begin(std::declval<C&>()));
499 using value_type = std::remove_reference_t<decltype(*std::declval<iterator&>())>;
500 static constexpr bool is_mutable = !std::is_const_v<C> && !std::is_const_v<value_type>;
501 static constexpr bool has_insert = test_insert<C>();
502 static constexpr bool has_insert_range = test_insert_range<C>();
503 static constexpr bool has_erase = test_erase<C>();
504 static constexpr bool has_resize = test_resize<C>();
505 static constexpr bool has_rotate = test_rotate<iterator>();
506 };
507
508 // Specializations for types that look like ranges, but should be
509 // treated as values.
510 enum class Mutable { Yes, No };
511 template <Mutable IsMutable>
512 struct iterable_value : std::false_type {
513 static constexpr bool is_mutable = IsMutable == Mutable::Yes;
514 static constexpr bool has_insert = false;
515 static constexpr bool has_erase = false;
516 static constexpr bool has_resize = false;
517 static constexpr bool has_rotate = false;
518 };
519 template <> struct range_traits<QByteArray> : iterable_value<Mutable::Yes> {};
520 template <> struct range_traits<QString> : iterable_value<Mutable::Yes> {};
521 template <class CharT, class Traits, class Allocator>
522 struct range_traits<std::basic_string<CharT, Traits, Allocator>> : iterable_value<Mutable::Yes>
523 {};
524
525 // const T * and views are read-only
526 template <typename T> struct range_traits<const T *> : iterable_value<Mutable::No> {};
527 template <> struct range_traits<QLatin1StringView> : iterable_value<Mutable::No> {};
528
529 template <typename C>
530 using is_range = range_traits<C>;
531 template <typename C>
532 [[maybe_unused]] static constexpr bool is_range_v = is_range<C>();
533
534 // Detect which options are set to override default heuristics. Since
535 // QRangeModel is not yet defined we need to delay the evaluation.
536 template <typename T> struct QRangeModelRowOptions;
537
538 template <typename T, typename = void>
539 struct row_category : std::false_type
540 {
541 static constexpr bool isMultiRole = false;
542 };
543
544 template <typename T>
545 struct row_category<T, std::void_t<decltype(QRangeModelRowOptions<T>::rowCategory)>>
546 : std::true_type
547 {
548 static constexpr auto rowCategory = QRangeModelRowOptions<T>::rowCategory;
549 using RowCategory = decltype(rowCategory);
550 static constexpr bool isMultiRole = rowCategory == RowCategory::MultiRoleItem;
551 };
552
553 // Find out how many fixed elements can be retrieved from a row element.
554 // main template for simple values and ranges. Specializing for ranges
555 // is ambiguous with arrays, as they are also ranges
556 template <typename T, typename = void>
557 struct row_traits {
558 static constexpr bool is_range = is_range_v<q20::remove_cvref_t<T>>;
559 // A static size of -1 indicates dynamically sized range
560 // A static size of 0 indicates that the specified type doesn't
561 // represent static or dynamic range.
562 static constexpr int static_size = is_range ? -1 : 0;
563 using item_type = std::conditional_t<is_range, typename range_traits<T>::value_type, T>;
564 static constexpr int fixed_size() { return 1; }
565 static constexpr bool hasMetaObject = false;
566 };
567
568 // Specialization for tuple-like semantics (prioritized over metaobject)
569 template <typename T>
570 struct row_traits<T, std::enable_if_t<tuple_like_v<T>>>
571 {
572 static constexpr std::size_t size64 = std::tuple_size_v<T>;
573 static_assert(q20::in_range<int>(t: size64));
574 static constexpr int static_size = int(size64);
575
576 // are the types in a tuple all the same
577 template <std::size_t ...I>
578 static constexpr bool allSameTypes(std::index_sequence<I...>)
579 {
580 return (std::is_same_v<std::tuple_element_t<0, T>,
581 std::tuple_element_t<I, T>> && ...);
582 }
583
584 using item_type = std::conditional_t<allSameTypes(std::make_index_sequence<size64>{}),
585 std::tuple_element_t<0, T>, void>;
586 static constexpr int fixed_size() { return 0; }
587 static constexpr bool hasMetaObject = false;
588 };
589
590 // Specialization for C arrays and std::array
591 template <typename T, std::size_t N>
592 struct row_traits<std::array<T, N>>
593 {
594 static_assert(q20::in_range<int>(t: N));
595 static constexpr int static_size = int(N);
596 using item_type = T;
597 static constexpr int fixed_size() { return 0; }
598 static constexpr bool hasMetaObject = false;
599 };
600
601 template <typename T, std::size_t N>
602 struct row_traits<T[N]> : row_traits<std::array<T, N>> {};
603
604 // prioritize tuple-like over metaobject
605 template <typename T>
606 struct row_traits<T, std::enable_if_t<has_metaobject_v<T> && !tuple_like_v<T>>>
607 {
608 static constexpr int static_size = 0;
609 using item_type = std::conditional_t<row_category<T>::isMultiRole, T, void>;
610 static int fixed_size() {
611 if constexpr (row_category<T>::isMultiRole) {
612 return 1;
613 } else {
614 // Interpret a gadget in a list as a multi-column row item. To make
615 // a list of multi-role items, wrap it into SingleColumn.
616 static const int columnCount = []{
617 const QMetaObject &mo = T::staticMetaObject;
618 return mo.propertyCount() - mo.propertyOffset();
619 }();
620 return columnCount;
621 }
622 }
623 static constexpr bool hasMetaObject = true;
624 };
625
626 template <typename T>
627 [[maybe_unused]] static constexpr int static_size_v =
628 row_traits<std::remove_cv_t<wrapped_t<T>>>::static_size;
629
630 template <typename Range>
631 struct ListProtocol
632 {
633 using row_type = typename range_traits<wrapped_t<Range>>::value_type;
634
635 template <typename R = row_type>
636 auto newRow() -> decltype(R{}) { return R{}; }
637 };
638
639 template <typename Range>
640 struct TableProtocol
641 {
642 using row_type = typename range_traits<wrapped_t<Range>>::value_type;
643
644 template <typename R = row_type,
645 std::enable_if_t<std::conjunction_v<std::is_destructible<wrapped_t<R>>,
646 is_owning_or_raw_pointer<R>>, bool> = true>
647 auto newRow() -> decltype(R(new wrapped_t<R>)) {
648 if constexpr (is_any_of<R, std::shared_ptr>())
649 return std::make_shared<wrapped_t<R>>();
650 else
651 return R(new wrapped_t<R>);
652 }
653
654 template <typename R = row_type,
655 std::enable_if_t<!is_owning_or_raw_pointer<R>::value, bool> = true>
656 auto newRow() -> decltype(R{}) { return R{}; }
657
658 template <typename R = row_type,
659 std::enable_if_t<std::is_pointer_v<std::remove_reference_t<R>>, bool> = true>
660 auto deleteRow(R&& row) -> decltype(delete row) { delete row; }
661 };
662
663 template <typename Range, typename R = typename range_traits<wrapped_t<Range>>::value_type>
664 using table_protocol_t = std::conditional_t<static_size_v<R> == 0 && !has_metaobject_v<R>,
665 ListProtocol<Range>, TableProtocol<Range>>;
666
667 // Default tree traversal protocol implementation for row types that have
668 // the respective member functions. The trailing return type implicitly
669 // removes those functions that are not available.
670 template <typename Range>
671 struct DefaultTreeProtocol : TableProtocol<Range>
672 {
673 template <typename R /*wrapped_row_type*/>
674 auto parentRow(const R& row) const -> decltype(row.parentRow())
675 {
676 return row.parentRow();
677 }
678
679 template <typename R /* = wrapped_row_type*/>
680 auto setParentRow(R &row, R* parent) -> decltype(row.setParentRow(parent))
681 {
682 row.setParentRow(parent);
683 }
684
685 template <typename R /* = wrapped_row_type*/>
686 auto childRows(const R &row) const -> decltype(row.childRows())
687 {
688 return row.childRows();
689 }
690
691 template <typename R /* = wrapped_row_type*/>
692 auto childRows(R &row) -> decltype(row.childRows())
693 {
694 return row.childRows();
695 }
696 };
697
698 template <typename P, typename R, typename = void>
699 struct protocol_parentRow : std::false_type {};
700 template <typename P, typename R>
701 struct protocol_parentRow<P, R,
702 std::void_t<decltype(std::declval<P&>().parentRow(std::declval<wrapped_t<R>&>()))>>
703 : std::true_type {};
704
705 template <typename P, typename R, typename = void>
706 struct protocol_childRows : std::false_type {};
707 template <typename P, typename R>
708 struct protocol_childRows<P, R,
709 std::void_t<decltype(std::declval<P&>().childRows(std::declval<wrapped_t<R>&>()))>>
710 : std::true_type {};
711
712 template <typename P, typename R, typename = void>
713 struct protocol_setParentRow : std::false_type {};
714 template <typename P, typename R>
715 struct protocol_setParentRow<P, R,
716 std::void_t<decltype(std::declval<P&>().setParentRow(std::declval<wrapped_t<R>&>(),
717 std::declval<wrapped_t<R>*>()))>>
718 : std::true_type {};
719
720 template <typename P, typename R, typename = void>
721 struct protocol_mutable_childRows : std::false_type {};
722 template <typename P, typename R>
723 struct protocol_mutable_childRows<P, R,
724 std::void_t<decltype(refTo(std::declval<P&>().childRows(std::declval<wrapped_t<R>&>()))
725 = {}) >>
726 : std::true_type {};
727
728 template <typename P, typename = void>
729 struct protocol_newRow : std::false_type {};
730 template <typename P>
731 struct protocol_newRow<P, std::void_t<decltype(std::declval<P&>().newRow())>>
732 : std::true_type {};
733
734 template <typename P, typename R, typename = void>
735 struct protocol_deleteRow : std::false_type {};
736 template <typename P, typename R>
737 struct protocol_deleteRow<P, R,
738 std::void_t<decltype(std::declval<P&>().deleteRow(std::declval<R&&>()))>>
739 : std::true_type {};
740
741 template <typename Range,
742 typename Protocol = DefaultTreeProtocol<Range>,
743 typename R = typename range_traits<Range>::value_type,
744 typename = void>
745 struct is_tree_range : std::false_type {};
746
747 template <typename Range, typename Protocol, typename R>
748 struct is_tree_range<Range, Protocol, R,
749 std::enable_if_t<std::conjunction_v<
750 protocol_parentRow<Protocol, R>, protocol_childRows<Protocol, R>>>
751 > : std::true_type {};
752
753 template <typename Range>
754 using if_table_range = std::enable_if_t<std::conjunction_v<is_range<wrapped_t<Range>>,
755 std::negation<is_tree_range<wrapped_t<Range>>>>,
756 bool>;
757
758 template <typename Range, typename Protocol = DefaultTreeProtocol<Range>>
759 using if_tree_range = std::enable_if_t<std::conjunction_v<is_range<wrapped_t<Range>>,
760 is_tree_range<wrapped_t<Range>, wrapped_t<Protocol>>>,
761 bool>;
762
763 template <typename Range, typename Protocol>
764 struct protocol_traits
765 {
766 using protocol = wrapped_t<Protocol>;
767 using row = typename range_traits<wrapped_t<Range>>::value_type;
768
769 static constexpr bool has_newRow = protocol_newRow<protocol>();
770 static constexpr bool has_deleteRow = protocol_deleteRow<protocol, row>();
771 static constexpr bool has_setParentRow = protocol_setParentRow<protocol, row>();
772 static constexpr bool has_mutable_childRows = protocol_mutable_childRows<protocol, row>();
773
774 static constexpr bool is_default = is_any_of<protocol, ListProtocol, TableProtocol, DefaultTreeProtocol>();
775 };
776
777 template <bool cacheProperties>
778 struct PropertyData {
779 static constexpr bool cachesProperties = false;
780
781 void invalidateCaches() {}
782 };
783
784 template <>
785 struct PropertyData<true>
786 {
787 static constexpr bool cachesProperties = true;
788 mutable QHash<int, QMetaProperty> properties;
789
790 void invalidateCaches()
791 {
792 properties.clear();
793 }
794 };
795
796 // The storage of the model data. We might store it as a pointer, or as a
797 // (copied- or moved-into) value (or smart pointer). But we always return a
798 // raw pointer.
799 template <typename ModelStorage, typename ItemType>
800 struct ModelData : PropertyData<has_metaobject_v<ItemType>>
801 {
802 auto model() { return pointerTo(m_model); }
803 auto model() const { return pointerTo(m_model); }
804
805 template <typename Model = ModelStorage>
806 ModelData(Model &&model)
807 : m_model(std::forward<Model>(model))
808 {}
809 ModelStorage m_model;
810 };
811} // namespace QRangeModelDetails
812
813class QRangeModel;
814
815class QRangeModelImplBase : public QtPrivate::QQuasiVirtualInterface<QRangeModelImplBase>
816{
817private:
818 using Self = QRangeModelImplBase;
819 using QtPrivate::QQuasiVirtualInterface<Self>::Method;
820protected:
821 // Helper for calling a lambda with the element of a statically
822 // sized range (tuple or array) with a runtime index.
823 template <typename StaticContainer, typename F>
824 static auto for_element_at(StaticContainer &&container, std::size_t idx, F &&function)
825 {
826 using type = std::remove_cv_t<QRangeModelDetails::wrapped_t<StaticContainer>>;
827 static_assert(QRangeModelDetails::array_like_v<type> || QRangeModelDetails::tuple_like_v<type>,
828 "Internal error: expected an array-like or a tuple-like type");
829
830 if (QRangeModelDetails::isValid(container)) {
831 auto& ref = QRangeModelDetails::refTo(std::forward<StaticContainer>(container));
832 if constexpr (QRangeModelDetails::array_like_v<type>) {
833 Q_ASSERT(idx < std::size(ref));
834 function(ref[idx]);
835 } else {
836 constexpr size_t size = std::tuple_size_v<type>;
837 Q_ASSERT(idx < std::tuple_size_v<type>);
838 QtPrivate::applyIndexSwitch<size>(idx, [&](auto idxConstant) {
839 function(get<idxConstant>(ref));
840 });
841 }
842 }
843 }
844
845 // Get the QMetaType for a tuple-element at a runtime index.
846 // Used in the headerData implementation.
847 template <typename T>
848 static constexpr QMetaType meta_type_at(size_t idx)
849 {
850 using type = QRangeModelDetails::wrapped_t<T>;
851 if constexpr (QRangeModelDetails::array_like_v<type>) {
852 Q_UNUSED(idx);
853 return QMetaType::fromType<std::tuple_element_t<0, type>>();
854 } else {
855 constexpr auto size = std::tuple_size_v<type>;
856 Q_ASSERT(idx < size);
857 QMetaType metaType;
858 QtPrivate::applyIndexSwitch<size>(idx, [&metaType](auto idxConstant) {
859 using ElementType = std::tuple_element_t<idxConstant.value, type>;
860 metaType = QMetaType::fromType<QRangeModelDetails::wrapped_t<ElementType>>();
861 });
862 return metaType;
863 }
864 }
865
866public:
867 // overridable prototypes (quasi-pure-virtual methods)
868
869 void invalidateCaches();
870 bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &data, int role);
871 bool setData(const QModelIndex &index, const QVariant &data, int role);
872 bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &data);
873 bool clearItemData(const QModelIndex &index);
874 bool insertColumns(int column, int count, const QModelIndex &parent);
875 bool removeColumns(int column, int count, const QModelIndex &parent);
876 bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destParent, int destColumn);
877 bool insertRows(int row, int count, const QModelIndex &parent);
878 bool removeRows(int row, int count, const QModelIndex &parent);
879 bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destParent, int destRow);
880
881 QModelIndex index(int row, int column, const QModelIndex &parent) const;
882 QModelIndex sibling(int row, int column, const QModelIndex &index) const;
883 int rowCount(const QModelIndex &parent) const;
884 int columnCount(const QModelIndex &parent) const;
885 Qt::ItemFlags flags(const QModelIndex &index) const;
886 QVariant headerData(int section, Qt::Orientation orientation, int role) const;
887 QVariant data(const QModelIndex &index, int role) const;
888 QMap<int, QVariant> itemData(const QModelIndex &index) const;
889 QHash<int, QByteArray> roleNames() const;
890 QModelIndex parent(const QModelIndex &child) const;
891
892 // bindings for overriding
893
894 using InvalidateCaches = Method<&Self::invalidateCaches>;
895 using SetHeaderData = Method<&Self::setHeaderData>;
896 using SetData = Method<&Self::setData>;
897 using SetItemData = Method<&Self::setItemData>;
898 using ClearItemData = Method<&Self::clearItemData>;
899 using InsertColumns = Method<&Self::insertColumns>;
900 using RemoveColumns = Method<&Self::removeColumns>;
901 using MoveColumns = Method<&Self::moveColumns>;
902 using InsertRows = Method<&Self::insertRows>;
903 using RemoveRows = Method<&Self::removeRows>;
904 using MoveRows = Method<&Self::moveRows>;
905
906 using Index = Method<&Self::index>;
907 using Sibling = Method<&Self::sibling>;
908 using RowCount = Method<&Self::rowCount>;
909 using ColumnCount = Method<&Self::columnCount>;
910 using Flags = Method<&Self::flags>;
911 using HeaderData = Method<&Self::headerData>;
912 using Data = Method<&Self::data>;
913 using ItemData = Method<&Self::itemData>;
914 using RoleNames = Method<&Self::roleNames>;
915 using Parent = Method<&Self::parent>;
916
917 template <typename C>
918 using MethodTemplates = std::tuple<
919 typename C::Destroy,
920 typename C::InvalidateCaches,
921 typename C::SetHeaderData,
922 typename C::SetData,
923 typename C::SetItemData,
924 typename C::ClearItemData,
925 typename C::InsertColumns,
926 typename C::RemoveColumns,
927 typename C::MoveColumns,
928 typename C::InsertRows,
929 typename C::RemoveRows,
930 typename C::MoveRows,
931 typename C::Index,
932 typename C::Parent,
933 typename C::Sibling,
934 typename C::RowCount,
935 typename C::ColumnCount,
936 typename C::Flags,
937 typename C::HeaderData,
938 typename C::Data,
939 typename C::ItemData,
940 typename C::RoleNames
941 >;
942
943private:
944 friend class QRangeModelPrivate;
945 QRangeModel *m_rangeModel;
946
947protected:
948 explicit QRangeModelImplBase(QRangeModel *itemModel)
949 : m_rangeModel(itemModel)
950 {}
951
952 inline QModelIndex createIndex(int row, int column, const void *ptr = nullptr) const;
953 inline void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to);
954 inline void dataChanged(const QModelIndex &from, const QModelIndex &to,
955 const QList<int> &roles);
956 inline void beginInsertColumns(const QModelIndex &parent, int start, int count);
957 inline void endInsertColumns();
958 inline void beginRemoveColumns(const QModelIndex &parent, int start, int count);
959 inline void endRemoveColumns();
960 inline bool beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst, int sourceLast,
961 const QModelIndex &destParent, int destRow);
962 inline void endMoveColumns();
963 inline void beginInsertRows(const QModelIndex &parent, int start, int count);
964 inline void endInsertRows();
965 inline void beginRemoveRows(const QModelIndex &parent, int start, int count);
966 inline void endRemoveRows();
967 inline bool beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast,
968 const QModelIndex &destParent, int destRow);
969 inline void endMoveRows();
970 inline QAbstractItemModel &itemModel();
971 inline const QAbstractItemModel &itemModel() const;
972
973 // implemented in qrangemodel.cpp
974 Q_CORE_EXPORT static QHash<int, QByteArray> roleNamesForMetaObject(const QAbstractItemModel &model,
975 const QMetaObject &metaObject);
976 Q_CORE_EXPORT static QHash<int, QByteArray> roleNamesForSimpleType();
977};
978
979template <typename Structure, typename Range,
980 typename Protocol = QRangeModelDetails::table_protocol_t<Range>>
981class QRangeModelImpl
982 : public QtPrivate::QQuasiVirtualSubclass<QRangeModelImpl<Structure, Range, Protocol>,
983 QRangeModelImplBase>
984{
985public:
986 using range_type = QRangeModelDetails::wrapped_t<Range>;
987 using row_reference = decltype(*QRangeModelDetails::begin(std::declval<range_type&>()));
988 using const_row_reference = decltype(*QRangeModelDetails::begin(std::declval<const range_type&>()));
989 using row_type = std::remove_reference_t<row_reference>;
990 using protocol_type = QRangeModelDetails::wrapped_t<Protocol>;
991
992 static_assert(!QRangeModelDetails::is_any_of<range_type, std::optional>() &&
993 !QRangeModelDetails::is_any_of<row_type, std::optional>(),
994 "Currently, std::optional is not supported for ranges and rows, as "
995 "it has range semantics in c++26. Once the required behavior is clarified, "
996 "std::optional for ranges and rows will be supported.");
997
998protected:
999
1000 using Self = QRangeModelImpl<Structure, Range, Protocol>;
1001 using Ancestor = QtPrivate::QQuasiVirtualSubclass<Self, QRangeModelImplBase>;
1002
1003 Structure& that() { return static_cast<Structure &>(*this); }
1004 const Structure& that() const { return static_cast<const Structure &>(*this); }
1005
1006 template <typename C>
1007 static constexpr int size(const C &c)
1008 {
1009 if (!QRangeModelDetails::isValid(c))
1010 return 0;
1011
1012 if constexpr (QRangeModelDetails::test_size<C>()) {
1013 return int(std::size(c));
1014 } else {
1015#if defined(__cpp_lib_ranges)
1016 return int(std::ranges::distance(QRangeModelDetails::begin(c),
1017 QRangeModelDetails::end(c)));
1018#else
1019 return int(std::distance(QRangeModelDetails::begin(c),
1020 QRangeModelDetails::end(c)));
1021#endif
1022 }
1023 }
1024
1025 using range_features = QRangeModelDetails::range_traits<range_type>;
1026 using wrapped_row_type = QRangeModelDetails::wrapped_t<row_type>;
1027 using row_features = QRangeModelDetails::range_traits<wrapped_row_type>;
1028 using row_traits = QRangeModelDetails::row_traits<std::remove_cv_t<wrapped_row_type>>;
1029 using protocol_traits = QRangeModelDetails::protocol_traits<Range, protocol_type>;
1030
1031 static constexpr bool isMutable()
1032 {
1033 return range_features::is_mutable && row_features::is_mutable
1034 && std::is_reference_v<row_reference>
1035 && Structure::is_mutable_impl;
1036 }
1037
1038 static constexpr int static_row_count = QRangeModelDetails::static_size_v<range_type>;
1039 static constexpr bool rows_are_raw_pointers = std::is_pointer_v<row_type>;
1040 static constexpr bool rows_are_owning_or_raw_pointers =
1041 QRangeModelDetails::is_owning_or_raw_pointer<row_type>();
1042 static constexpr int static_column_count = QRangeModelDetails::static_size_v<row_type>;
1043 static constexpr bool one_dimensional_range = static_column_count == 0;
1044
1045 static constexpr bool dynamicRows() { return isMutable() && static_row_count < 0; }
1046 static constexpr bool dynamicColumns() { return static_column_count < 0; }
1047
1048 // A row might be a value (or range of values), or a pointer.
1049 // row_ptr is always a pointer, and const_row_ptr is a pointer to const.
1050 using row_ptr = wrapped_row_type *;
1051 using const_row_ptr = const wrapped_row_type *;
1052
1053 template <typename T>
1054 static constexpr bool has_metaobject = QRangeModelDetails::has_metaobject_v<
1055 std::remove_pointer_t<std::remove_reference_t<T>>>;
1056
1057 using ModelData = QRangeModelDetails::ModelData<std::conditional_t<
1058 std::is_pointer_v<Range>,
1059 Range, std::remove_reference_t<Range>
1060 >,
1061 typename row_traits::item_type
1062 >;
1063
1064 // A iterator type to use as the input iterator with the
1065 // range_type::insert(pos, start, end) overload if available (it is in
1066 // std::vector, but not in QList). Generates a prvalue when dereferenced,
1067 // which then gets moved into the newly constructed row, which allows us to
1068 // implement insertRows() for move-only row types.
1069 struct EmptyRowGenerator
1070 {
1071 using value_type = row_type;
1072 using reference = value_type;
1073 using pointer = value_type *;
1074 using iterator_category = std::input_iterator_tag;
1075 using difference_type = int;
1076
1077 value_type operator*() { return impl->makeEmptyRow(*parent); }
1078 EmptyRowGenerator &operator++() { ++n; return *this; }
1079 friend bool operator==(const EmptyRowGenerator &lhs, const EmptyRowGenerator &rhs) noexcept
1080 { return lhs.n == rhs.n; }
1081 friend bool operator!=(const EmptyRowGenerator &lhs, const EmptyRowGenerator &rhs) noexcept
1082 { return !(lhs == rhs); }
1083
1084 difference_type n = 0;
1085 Structure *impl = nullptr;
1086 const QModelIndex* parent = nullptr;
1087 };
1088
1089 // If we have a move-only row_type and can add/remove rows, then the range
1090 // must have an insert-from-range overload.
1091 static_assert(static_row_count || range_features::has_insert_range
1092 || std::is_copy_constructible_v<row_type>,
1093 "The range holding a move-only row-type must support insert(pos, start, end)");
1094
1095public:
1096 explicit QRangeModelImpl(Range &&model, Protocol&& protocol, QRangeModel *itemModel)
1097 : Ancestor(itemModel)
1098 , m_data{std::forward<Range>(model)}
1099 , m_protocol(std::forward<Protocol>(protocol))
1100 {
1101 }
1102
1103
1104 // static interface, called by QRangeModelImplBase
1105
1106 void invalidateCaches() { m_data.invalidateCaches(); }
1107
1108 // Not implemented
1109 bool setHeaderData(int , Qt::Orientation , const QVariant &, int ) { return false; }
1110
1111 // actual implementations
1112 QModelIndex index(int row, int column, const QModelIndex &parent) const
1113 {
1114 if (row < 0 || column < 0 || column >= columnCount(parent)
1115 || row >= rowCount(parent)) {
1116 return {};
1117 }
1118
1119 return that().indexImpl(row, column, parent);
1120 }
1121
1122 QModelIndex sibling(int row, int column, const QModelIndex &index) const
1123 {
1124 if (row == index.row() && column == index.column())
1125 return index;
1126
1127 if (column < 0 || column >= this->itemModel().columnCount())
1128 return {};
1129
1130 if (row == index.row())
1131 return this->createIndex(row, column, index.constInternalPointer());
1132
1133 const_row_ptr parentRow = static_cast<const_row_ptr>(index.constInternalPointer());
1134 const auto siblingCount = size(that().childrenOf(parentRow));
1135 if (row < 0 || row >= int(siblingCount))
1136 return {};
1137 return this->createIndex(row, column, parentRow);
1138 }
1139
1140 Qt::ItemFlags flags(const QModelIndex &index) const
1141 {
1142 if (!index.isValid())
1143 return Qt::NoItemFlags;
1144
1145 Qt::ItemFlags f = Structure::defaultFlags();
1146
1147 if constexpr (isMutable()) {
1148 if constexpr (row_traits::hasMetaObject) {
1149 if (index.column() < row_traits::fixed_size()) {
1150 const QMetaObject mo = wrapped_row_type::staticMetaObject;
1151 const QMetaProperty prop = mo.property(index: index.column() + mo.propertyOffset());
1152 if (prop.isWritable())
1153 f |= Qt::ItemIsEditable;
1154 }
1155 } else if constexpr (static_column_count <= 0) {
1156 f |= Qt::ItemIsEditable;
1157 } else if constexpr (std::is_reference_v<row_reference> && !std::is_const_v<row_reference>) {
1158 // we want to know if the elements in the tuple are const; they'd always be, if
1159 // we didn't remove the const of the range first.
1160 const_row_reference row = rowData(index);
1161 row_reference mutableRow = const_cast<row_reference>(row);
1162 if (QRangeModelDetails::isValid(mutableRow)) {
1163 QRangeModelImplBase::for_element_at(mutableRow, index.column(), [&f](auto &&ref){
1164 using target_type = decltype(ref);
1165 if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
1166 f &= ~Qt::ItemIsEditable;
1167 else if constexpr (std::is_lvalue_reference_v<target_type>)
1168 f |= Qt::ItemIsEditable;
1169 });
1170 } else {
1171 // If there's no usable value stored in the row, then we can't
1172 // do anything with this item.
1173 f &= ~Qt::ItemIsEditable;
1174 }
1175 }
1176 }
1177 return f;
1178 }
1179
1180 QVariant headerData(int section, Qt::Orientation orientation, int role) const
1181 {
1182 QVariant result;
1183 if (role != Qt::DisplayRole || orientation != Qt::Horizontal
1184 || section < 0 || section >= columnCount(parent: {})) {
1185 return this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1186 }
1187
1188 if constexpr (row_traits::hasMetaObject) {
1189 if (row_traits::fixed_size() == 1) {
1190 const QMetaType metaType = QMetaType::fromType<wrapped_row_type>();
1191 result = QString::fromUtf8(utf8: metaType.name());
1192 } else if (section <= row_traits::fixed_size()) {
1193 const QMetaProperty prop = wrapped_row_type::staticMetaObject.property(
1194 section + wrapped_row_type::staticMetaObject.propertyOffset());
1195 result = QString::fromUtf8(utf8: prop.name());
1196 }
1197 } else if constexpr (static_column_count >= 1) {
1198 if constexpr (QRangeModelDetails::array_like_v<wrapped_row_type>) {
1199 return section;
1200 } else {
1201 const QMetaType metaType = QRangeModelImplBase::meta_type_at<wrapped_row_type>(section);
1202 if (metaType.isValid())
1203 result = QString::fromUtf8(utf8: metaType.name());
1204 }
1205 }
1206 if (!result.isValid())
1207 result = this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1208 return result;
1209 }
1210
1211 QVariant data(const QModelIndex &index, int role) const
1212 {
1213 QVariant result;
1214 const auto readData = [this, column = index.column(), &result, role](const auto &value) {
1215 Q_UNUSED(this);
1216 using value_type = q20::remove_cvref_t<decltype(value)>;
1217 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1218 if constexpr (has_metaobject<value_type>) {
1219 if (row_traits::fixed_size() <= 1) {
1220 if (role == Qt::RangeModelDataRole) {
1221 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1222 // Qt QML support: "modelData" role returns the entire multi-role item.
1223 // QML can only use raw pointers to QObject (so we unwrap), and gadgets
1224 // only by value (so we take the reference).
1225 if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
1226 result = QVariant::fromValue(QRangeModelDetails::refTo(value));
1227 else
1228 result = QVariant::fromValue(QRangeModelDetails::pointerTo(value));
1229 } else {
1230 result = readRole(role, QRangeModelDetails::pointerTo(value));
1231 }
1232 } else if (column <= row_traits::fixed_size()
1233 && (role == Qt::DisplayRole || role == Qt::EditRole)) {
1234 result = readProperty(column, QRangeModelDetails::pointerTo(value));
1235 }
1236 } else if constexpr (multi_role::value) {
1237 const auto it = [this, &value, role]{
1238 Q_UNUSED(this);
1239 if constexpr (multi_role::int_key)
1240 return std::as_const(value).find(Qt::ItemDataRole(role));
1241 else
1242 return std::as_const(value).find(this->itemModel().roleNames().value(role));
1243 }();
1244 if (it != QRangeModelDetails::end(value))
1245 result = QRangeModelDetails::value(it);
1246 } else if (role == Qt::DisplayRole || role == Qt::EditRole
1247 || role == Qt::RangeModelDataRole) {
1248 result = read(value);
1249 }
1250 };
1251
1252 if (index.isValid())
1253 readAt(index, readData);
1254
1255 return result;
1256 }
1257
1258 QMap<int, QVariant> itemData(const QModelIndex &index) const
1259 {
1260 QMap<int, QVariant> result;
1261 bool tried = false;
1262 const auto readItemData = [this, &result, &tried](const auto &value){
1263 Q_UNUSED(this);
1264 using value_type = q20::remove_cvref_t<decltype(value)>;
1265 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1266 if constexpr (multi_role()) {
1267 tried = true;
1268 if constexpr (std::is_convertible_v<value_type, decltype(result)>) {
1269 result = value;
1270 } else {
1271 const auto roleNames = [this]() -> QHash<int, QByteArray> {
1272 Q_UNUSED(this);
1273 if constexpr (!multi_role::int_key)
1274 return this->itemModel().roleNames();
1275 else
1276 return {};
1277 }();
1278 for (auto it = std::begin(value); it != std::end(value); ++it) {
1279 const int role = [&roleNames, key = QRangeModelDetails::key(it)]() {
1280 Q_UNUSED(roleNames);
1281 if constexpr (multi_role::int_key)
1282 return int(key);
1283 else
1284 return roleNames.key(key.toUtf8(), -1);
1285 }();
1286
1287 if (role != -1 && role != Qt::RangeModelDataRole)
1288 result.insert(role, QRangeModelDetails::value(it));
1289 }
1290 }
1291 } else if constexpr (has_metaobject<value_type>) {
1292 if (row_traits::fixed_size() <= 1) {
1293 tried = true;
1294 const auto roleNames = this->itemModel().roleNames();
1295 const auto end = roleNames.keyEnd();
1296 for (auto it = roleNames.keyBegin(); it != end; ++it) {
1297 const int role = *it;
1298 if (role == Qt::RangeModelDataRole)
1299 continue;
1300 QVariant data = readRole(role, QRangeModelDetails::pointerTo(value));
1301 if (data.isValid())
1302 result[role] = std::move(data);
1303 }
1304 }
1305 }
1306 };
1307
1308 if (index.isValid()) {
1309 readAt(index, readItemData);
1310
1311 if (!tried) // no multi-role item found
1312 result = this->itemModel().QAbstractItemModel::itemData(index);
1313 }
1314 return result;
1315 }
1316
1317 bool setData(const QModelIndex &index, const QVariant &data, int role)
1318 {
1319 if (!index.isValid())
1320 return false;
1321
1322 bool success = false;
1323 if constexpr (isMutable()) {
1324 auto emitDataChanged = qScopeGuard([&success, this, &index, role]{
1325 if (success) {
1326 Q_EMIT this->dataChanged(index, index,
1327 role == Qt::EditRole || role == Qt::RangeModelDataRole
1328 ? QList<int>{} : QList<int>{role});
1329 }
1330 });
1331
1332 const auto writeData = [this, column = index.column(), &data, role](auto &&target) -> bool {
1333 using value_type = q20::remove_cvref_t<decltype(target)>;
1334 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1335 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1336 if constexpr (has_metaobject<value_type>) {
1337 if (role == Qt::RangeModelDataRole) {
1338 auto &targetRef = QRangeModelDetails::refTo(target);
1339 constexpr auto targetMetaType = QMetaType::fromType<value_type>();
1340 const auto dataMetaType = data.metaType();
1341 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>) {
1342 // This covers move-only types, but also polymorph types like QObject.
1343 // We don't support replacing a stored object with another one, as this
1344 // makes object ownership very messy.
1345 // fall through to error handling
1346 } else if constexpr (QRangeModelDetails::is_wrapped<value_type>()) {
1347 if (QRangeModelDetails::isValid(target)) {
1348 // we need to get a wrapped value type out of the QVariant, which
1349 // might carry a pointer. We have to try all alternatives.
1350 if (const auto mt = QMetaType::fromType<wrapped_value_type>();
1351 data.canConvert(mt)) {
1352 targetRef = data.value<wrapped_value_type>();
1353 return true;
1354 } else if (const auto mtp = QMetaType::fromType<wrapped_value_type *>();
1355 data.canConvert(mtp)) {
1356 targetRef = *data.value<wrapped_value_type *>();
1357 return true;
1358 }
1359 }
1360 } else if (targetMetaType == dataMetaType) {
1361 targetRef = data.value<value_type>();
1362 return true;
1363 } else if (dataMetaType.flags() & QMetaType::PointerToGadget) {
1364 targetRef = *data.value<value_type *>();
1365 return true;
1366 }
1367#ifndef QT_NO_DEBUG
1368 qCritical("Not able to assign %s to %s",
1369 qPrintable(QDebug::toString(data)), targetMetaType.name());
1370#endif
1371 return false;
1372 } else if (row_traits::fixed_size() <= 1) {
1373 return writeRole(role, QRangeModelDetails::pointerTo(target), data);
1374 } else if (column <= row_traits::fixed_size()
1375 && (role == Qt::DisplayRole || role == Qt::EditRole)) {
1376 return writeProperty(column, QRangeModelDetails::pointerTo(target), data);
1377 }
1378 } else if constexpr (multi_role::value) {
1379 Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role);
1380 // If there is an entry for EditRole, overwrite that; otherwise,
1381 // set the entry for DisplayRole.
1382 const auto roleNames = [this]() -> QHash<int, QByteArray> {
1383 Q_UNUSED(this);
1384 if constexpr (!multi_role::int_key)
1385 return this->itemModel().roleNames();
1386 else
1387 return {};
1388 }();
1389 if (role == Qt::EditRole) {
1390 if constexpr (multi_role::int_key) {
1391 if (target.find(roleToSet) == target.end())
1392 roleToSet = Qt::DisplayRole;
1393 } else {
1394 if (target.find(roleNames.value(roleToSet)) == target.end())
1395 roleToSet = Qt::DisplayRole;
1396 }
1397 }
1398 if constexpr (multi_role::int_key)
1399 return write(target[roleToSet], data);
1400 else
1401 return write(target[roleNames.value(roleToSet)], data);
1402 } else if (role == Qt::DisplayRole || role == Qt::EditRole
1403 || role == Qt::RangeModelDataRole) {
1404 return write(target, data);
1405 }
1406 return false;
1407 };
1408
1409 success = writeAt(index, writeData);
1410 }
1411 return success;
1412 }
1413
1414 bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &data)
1415 {
1416 if (!index.isValid() || data.isEmpty())
1417 return false;
1418
1419 bool success = false;
1420 if constexpr (isMutable()) {
1421 auto emitDataChanged = qScopeGuard([&success, this, &index, &data]{
1422 if (success)
1423 Q_EMIT this->dataChanged(index, index, data.keys());
1424 });
1425
1426 bool tried = false;
1427 auto writeItemData = [this, &tried, &data](auto &target) -> bool {
1428 Q_UNUSED(this);
1429 using value_type = q20::remove_cvref_t<decltype(target)>;
1430 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1431 if constexpr (multi_role()) {
1432 using key_type = typename value_type::key_type;
1433 tried = true;
1434 const auto roleName = [map = this->itemModel().roleNames()](int role) {
1435 return map.value(role);
1436 };
1437
1438 // transactional: only update target if all values from data
1439 // can be stored. Storing never fails with int-keys.
1440 if constexpr (!multi_role::int_key)
1441 {
1442 auto invalid = std::find_if(data.keyBegin(), data.keyEnd(),
1443 [&roleName](int role) { return roleName(role).isEmpty(); }
1444 );
1445
1446 if (invalid != data.keyEnd()) {
1447#ifndef QT_NO_DEBUG
1448 qWarning("No role name set for %d", *invalid);
1449#endif
1450 return false;
1451 }
1452 }
1453
1454 for (auto &&[role, value] : data.asKeyValueRange()) {
1455 if constexpr (multi_role::int_key)
1456 target[static_cast<key_type>(role)] = value;
1457 else
1458 target[QString::fromUtf8(roleName(role))] = value;
1459 }
1460 return true;
1461 } else if constexpr (has_metaobject<value_type>) {
1462 if (row_traits::fixed_size() <= 1) {
1463 tried = true;
1464 using wrapped_type = QRangeModelDetails::wrapped_t<value_type>;
1465 // transactional: if possible, modify a copy and only
1466 // update target if all values from data could be stored.
1467 auto targetCopy = [](auto &&origin) {
1468 if constexpr (!std::is_copy_assignable_v<wrapped_type>)
1469 return QRangeModelDetails::pointerTo(origin); // no transaction support
1470 else if constexpr (std::is_pointer_v<decltype(target)>)
1471 return *origin;
1472 else if constexpr (std::is_copy_assignable_v<value_type>)
1473 return origin;
1474 else
1475 return QRangeModelDetails::pointerTo(origin);
1476 }(target);
1477 const auto roleNames = this->itemModel().roleNames();
1478 for (auto &&[role, value] : data.asKeyValueRange()) {
1479 if (role == Qt::RangeModelDataRole)
1480 continue;
1481 if (!writeRole(role, QRangeModelDetails::pointerTo(targetCopy), value)) {
1482 const QByteArray roleName = roleNames.value(role);
1483#ifndef QT_NO_DEBUG
1484 qWarning(msg: "Failed to write value '%s' to role '%s'",
1485 qPrintable(QDebug::toString(value)), roleName.data());
1486#endif
1487 return false;
1488 }
1489 }
1490 if constexpr (std::is_pointer_v<decltype(targetCopy)>)
1491 ; // couldn't copy
1492 else if constexpr (std::is_pointer_v<decltype(target)>)
1493 qSwap(*target, targetCopy);
1494 else
1495 qSwap(target, targetCopy);
1496 return true;
1497 }
1498 }
1499 return false;
1500 };
1501
1502 success = writeAt(index, writeItemData);
1503
1504 if (!tried) {
1505 // setItemData will emit the dataChanged signal
1506 Q_ASSERT(!success);
1507 emitDataChanged.dismiss();
1508 success = this->itemModel().QAbstractItemModel::setItemData(index, data);
1509 }
1510 }
1511 return success;
1512 }
1513
1514 bool clearItemData(const QModelIndex &index)
1515 {
1516 if (!index.isValid())
1517 return false;
1518
1519 bool success = false;
1520 if constexpr (isMutable()) {
1521 auto emitDataChanged = qScopeGuard([&success, this, &index]{
1522 if (success)
1523 Q_EMIT this->dataChanged(index, index, {});
1524 });
1525
1526 auto clearData = [column = index.column()](auto &&target) {
1527 if constexpr (row_traits::hasMetaObject) {
1528 if (row_traits::fixed_size() <= 1) {
1529 // multi-role object/gadget: reset all properties
1530 return resetProperty(-1, QRangeModelDetails::pointerTo(target));
1531 } else if (column <= row_traits::fixed_size()) {
1532 return resetProperty(column, QRangeModelDetails::pointerTo(target));
1533 }
1534 } else { // normal structs, values, associative containers
1535 target = {};
1536 return true;
1537 }
1538 return false;
1539 };
1540
1541 success = writeAt(index, clearData);
1542 }
1543 return success;
1544 }
1545
1546 QHash<int, QByteArray> roleNames() const
1547 {
1548 // will be 'void' if columns don't all have the same type
1549 using item_type = typename row_traits::item_type;
1550 if constexpr (QRangeModelDetails::has_metaobject_v<item_type>) {
1551 return QRangeModelImplBase::roleNamesForMetaObject(model: this->itemModel(),
1552 metaObject: QRangeModelDetails::wrapped_t<item_type>::staticMetaObject);
1553 } else if constexpr (std::negation_v<std::disjunction<std::is_void<item_type>,
1554 QRangeModelDetails::is_multi_role<item_type>>>) {
1555 return QRangeModelImplBase::roleNamesForSimpleType();
1556 }
1557
1558 return this->itemModel().QAbstractItemModel::roleNames();
1559 }
1560
1561 bool insertColumns(int column, int count, const QModelIndex &parent)
1562 {
1563 if constexpr (dynamicColumns() && isMutable() && row_features::has_insert) {
1564 if (count == 0)
1565 return false;
1566 range_type * const children = childRange(parent);
1567 if (!children)
1568 return false;
1569
1570 this->beginInsertColumns(parent, column, column + count - 1);
1571 for (auto &child : *children) {
1572 auto it = QRangeModelDetails::pos(child, column);
1573 QRangeModelDetails::refTo(child).insert(it, count, {});
1574 }
1575 this->endInsertColumns();
1576 return true;
1577 }
1578 return false;
1579 }
1580
1581 bool removeColumns(int column, int count, const QModelIndex &parent)
1582 {
1583 if constexpr (dynamicColumns() && isMutable() && row_features::has_erase) {
1584 if (column < 0 || column + count > columnCount(parent))
1585 return false;
1586
1587 range_type * const children = childRange(parent);
1588 if (!children)
1589 return false;
1590
1591 this->beginRemoveColumns(parent, column, column + count - 1);
1592 for (auto &child : *children) {
1593 const auto start = QRangeModelDetails::pos(child, column);
1594 QRangeModelDetails::refTo(child).erase(start, std::next(start, count));
1595 }
1596 this->endRemoveColumns();
1597 return true;
1598 }
1599 return false;
1600 }
1601
1602 bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count,
1603 const QModelIndex &destParent, int destColumn)
1604 {
1605 // we only support moving columns within the same parent
1606 if (sourceParent != destParent)
1607 return false;
1608 if constexpr (isMutable() && row_features::has_rotate) {
1609 if (!Structure::canMoveColumns(sourceParent, destParent))
1610 return false;
1611
1612 if constexpr (dynamicColumns()) {
1613 // we only support ranges as columns, as other types might
1614 // not have the same data type across all columns
1615 range_type * const children = childRange(sourceParent);
1616 if (!children)
1617 return false;
1618
1619 if (!this->beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1,
1620 destParent, destColumn)) {
1621 return false;
1622 }
1623
1624 for (auto &child : *children) {
1625 const auto first = QRangeModelDetails::pos(child, sourceColumn);
1626 const auto middle = std::next(first, count);
1627 const auto last = QRangeModelDetails::pos(child, destColumn);
1628
1629 if (sourceColumn < destColumn) // moving right
1630 std::rotate(first, middle, last);
1631 else // moving left
1632 std::rotate(last, first, middle);
1633 }
1634
1635 this->endMoveColumns();
1636 return true;
1637 }
1638 }
1639 return false;
1640 }
1641
1642 bool insertRows(int row, int count, const QModelIndex &parent)
1643 {
1644 if constexpr (canInsertRows()) {
1645 range_type *children = childRange(parent);
1646 if (!children)
1647 return false;
1648
1649 EmptyRowGenerator generator{0, &that(), &parent};
1650
1651 this->beginInsertRows(parent, row, row + count - 1);
1652
1653 const auto pos = QRangeModelDetails::pos(children, row);
1654 if constexpr (range_features::has_insert_range) {
1655 children->insert(pos, generator, EmptyRowGenerator{count});
1656 } else if constexpr (rows_are_owning_or_raw_pointers) {
1657 auto start = children->insert(pos, count, row_type{});
1658 std::copy(generator, EmptyRowGenerator{count}, start);
1659 } else {
1660 children->insert(pos, count, *generator);
1661 }
1662
1663 // fix the parent in all children of the modified row, as the
1664 // references back to the parent might have become invalid.
1665 that().resetParentInChildren(children);
1666
1667 this->endInsertRows();
1668 return true;
1669 } else {
1670 return false;
1671 }
1672 }
1673
1674 bool removeRows(int row, int count, const QModelIndex &parent = {})
1675 {
1676 if constexpr (canRemoveRows()) {
1677 const int prevRowCount = rowCount(parent);
1678 if (row < 0 || row + count > prevRowCount)
1679 return false;
1680
1681 range_type *children = childRange(parent);
1682 if (!children)
1683 return false;
1684
1685 this->beginRemoveRows(parent, row, row + count - 1);
1686 [[maybe_unused]] bool callEndRemoveColumns = false;
1687 if constexpr (dynamicColumns()) {
1688 // if we remove the last row in a dynamic model, then we no longer
1689 // know how many columns we should have, so they will be reported as 0.
1690 if (prevRowCount == count) {
1691 if (const int columns = columnCount(parent)) {
1692 callEndRemoveColumns = true;
1693 this->beginRemoveColumns(parent, 0, columns - 1);
1694 }
1695 }
1696 }
1697 { // erase invalidates iterators
1698 const auto begin = QRangeModelDetails::pos(children, row);
1699 const auto end = std::next(begin, count);
1700 that().deleteRemovedRows(begin, end);
1701 children->erase(begin, end);
1702 }
1703 // fix the parent in all children of the modified row, as the
1704 // references back to the parent might have become invalid.
1705 that().resetParentInChildren(children);
1706
1707 if constexpr (dynamicColumns()) {
1708 if (callEndRemoveColumns) {
1709 Q_ASSERT(columnCount(parent) == 0);
1710 this->endRemoveColumns();
1711 }
1712 }
1713 this->endRemoveRows();
1714 return true;
1715 } else {
1716 return false;
1717 }
1718 }
1719
1720 bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
1721 const QModelIndex &destParent, int destRow)
1722 {
1723 if constexpr (isMutable() && range_features::has_rotate) {
1724 if (!Structure::canMoveRows(sourceParent, destParent))
1725 return false;
1726
1727 if (sourceParent != destParent) {
1728 return that().moveRowsAcross(sourceParent, sourceRow, count,
1729 destParent, destRow);
1730 }
1731
1732 if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0
1733 || sourceRow < 0 || sourceRow + count - 1 >= this->itemModel().rowCount(sourceParent)
1734 || destRow < 0 || destRow > this->itemModel().rowCount(destParent)) {
1735 return false;
1736 }
1737
1738 range_type *source = childRange(sourceParent);
1739 // moving within the same range
1740 if (!this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow))
1741 return false;
1742
1743 const auto first = QRangeModelDetails::pos(source, sourceRow);
1744 const auto middle = std::next(first, count);
1745 const auto last = QRangeModelDetails::pos(source, destRow);
1746
1747 if (sourceRow < destRow) // moving down
1748 std::rotate(first, middle, last);
1749 else // moving up
1750 std::rotate(last, first, middle);
1751
1752 that().resetParentInChildren(source);
1753
1754 this->endMoveRows();
1755 return true;
1756 } else {
1757 return false;
1758 }
1759 }
1760
1761 QModelIndex parent(const QModelIndex &child) const { return that().parent(child); }
1762
1763 int rowCount(const QModelIndex &parent) const { return that().rowCount(parent); }
1764
1765 int columnCount(const QModelIndex &parent) const { return that().columnCount(parent); }
1766
1767 void destroy() { delete std::addressof(that()); }
1768
1769 template <typename BaseMethod, typename BaseMethod::template Overridden<Self> overridden>
1770 using Override = typename Ancestor::template Override<BaseMethod, overridden>;
1771
1772 using Destroy = Override<QRangeModelImplBase::Destroy, &Self::destroy>;
1773 using Index = Override<QRangeModelImplBase::Index, &Self::index>;
1774 using Parent = Override<QRangeModelImplBase::Parent, &Self::parent>;
1775 using Sibling = Override<QRangeModelImplBase::Sibling, &Self::sibling>;
1776 using RowCount = Override<QRangeModelImplBase::RowCount, &Self::rowCount>;
1777 using ColumnCount = Override<QRangeModelImplBase::ColumnCount, &Self::columnCount>;
1778 using Flags = Override<QRangeModelImplBase::Flags, &Self::flags>;
1779 using HeaderData = Override<QRangeModelImplBase::HeaderData, &Self::headerData>;
1780
1781 using Data = Override<QRangeModelImplBase::Data, &Self::data>;
1782 using ItemData = Override<QRangeModelImplBase::ItemData, &Self::itemData>;
1783 using RoleNames = Override<QRangeModelImplBase::RoleNames, &Self::roleNames>;
1784 using InvalidateCaches = Override<QRangeModelImplBase::InvalidateCaches, &Self::invalidateCaches>;
1785 using SetHeaderData = Override<QRangeModelImplBase::SetHeaderData, &Self::setHeaderData>;
1786 using SetData = Override<QRangeModelImplBase::SetData, &Self::setData>;
1787 using SetItemData = Override<QRangeModelImplBase::SetItemData, &Self::setItemData>;
1788 using ClearItemData = Override<QRangeModelImplBase::ClearItemData, &Self::clearItemData>;
1789 using InsertColumns = Override<QRangeModelImplBase::InsertColumns, &Self::insertColumns>;
1790 using RemoveColumns = Override<QRangeModelImplBase::RemoveColumns, &Self::removeColumns>;
1791 using MoveColumns = Override<QRangeModelImplBase::MoveColumns, &Self::moveColumns>;
1792 using InsertRows = Override<QRangeModelImplBase::InsertRows, &Self::insertRows>;
1793 using RemoveRows = Override<QRangeModelImplBase::RemoveRows, &Self::removeRows>;
1794 using MoveRows = Override<QRangeModelImplBase::MoveRows, &Self::moveRows>;
1795
1796protected:
1797 ~QRangeModelImpl()
1798 {
1799 // We delete row objects if we are not operating on a reference or pointer
1800 // to a range, as in that case, the owner of the referenced/pointed to
1801 // range also owns the row entries.
1802 // ### Problem: if we get a copy of a range (no matter if shared or not),
1803 // then adding rows will create row objects in the model's copy, and the
1804 // client can never delete those. But copied rows will be the same pointer,
1805 // which we must not delete (as we didn't create them).
1806
1807 static constexpr bool modelCopied = !QRangeModelDetails::is_wrapped<Range>() &&
1808 (std::is_reference_v<Range> || std::is_const_v<std::remove_reference_t<Range>>);
1809
1810 static constexpr bool modelShared = QRangeModelDetails::is_any_shared_ptr<Range>();
1811
1812 static constexpr bool default_row_deleter = protocol_traits::is_default &&
1813 protocol_traits::has_deleteRow;
1814
1815 static constexpr bool ambiguousRowOwnership = (modelCopied || modelShared) &&
1816 rows_are_raw_pointers && default_row_deleter;
1817
1818 static_assert(!ambiguousRowOwnership,
1819 "Using of copied and shared tree and table models with rows as raw pointers, "
1820 "and the default protocol is not allowed due to ambiguity of rows ownership. "
1821 "Move the model in, use another row type, or implement a custom tree protocol.");
1822
1823 if constexpr (protocol_traits::has_deleteRow && !std::is_pointer_v<Range>
1824 && !QRangeModelDetails::is_any_of<Range, std::reference_wrapper>()) {
1825 const auto begin = QRangeModelDetails::begin(*m_data.model());
1826 const auto end = QRangeModelDetails::end(*m_data.model());
1827 that().deleteRemovedRows(begin, end);
1828 }
1829 }
1830
1831 static constexpr bool canInsertRows()
1832 {
1833 if constexpr (dynamicColumns() && !row_features::has_resize) {
1834 // If we operate on dynamic columns and cannot resize a newly
1835 // constructed row, then we cannot insert.
1836 return false;
1837 } else if constexpr (!protocol_traits::has_newRow) {
1838 // We also cannot insert if we cannot create a new row element
1839 return false;
1840 } else if constexpr (!range_features::has_insert_range
1841 && !std::is_copy_constructible_v<row_type>) {
1842 // And if the row is a move-only type, then the range needs to be
1843 // backed by a container that can move-insert default-constructed
1844 // row elements.
1845 return false;
1846 } else {
1847 return Structure::canInsertRowsImpl();
1848 }
1849 }
1850
1851 static constexpr bool canRemoveRows()
1852 {
1853 return Structure::canRemoveRowsImpl();
1854 }
1855
1856 template <typename F>
1857 bool writeAt(const QModelIndex &index, F&& writer)
1858 {
1859 bool result = false;
1860 row_reference row = rowData(index);
1861
1862 if constexpr (one_dimensional_range) {
1863 result = writer(row);
1864 } else if (QRangeModelDetails::isValid(row)) {
1865 if constexpr (dynamicColumns()) {
1866 result = writer(*QRangeModelDetails::pos(row, index.column()));
1867 } else {
1868 QRangeModelImplBase::for_element_at(row, index.column(), [&writer, &result](auto &&target) {
1869 using target_type = decltype(target);
1870 // we can only assign to an lvalue reference
1871 if constexpr (std::is_lvalue_reference_v<target_type>
1872 && !std::is_const_v<std::remove_reference_t<target_type>>) {
1873 result = writer(std::forward<target_type>(target));
1874 }
1875 });
1876 }
1877 }
1878
1879 return result;
1880 }
1881
1882 template <typename F>
1883 void readAt(const QModelIndex &index, F&& reader) const {
1884 const_row_reference row = rowData(index);
1885 if constexpr (one_dimensional_range) {
1886 return reader(row);
1887 } else if (QRangeModelDetails::isValid(row)) {
1888 if constexpr (dynamicColumns())
1889 reader(*QRangeModelDetails::pos(row, index.column()));
1890 else
1891 QRangeModelImplBase::for_element_at(row, index.column(), std::forward<F>(reader));
1892 }
1893 }
1894
1895 template <typename Value>
1896 static QVariant read(const Value &value)
1897 {
1898 if constexpr (std::is_constructible_v<QVariant, Value>)
1899 return QVariant(value);
1900 else
1901 return QVariant::fromValue(value);
1902 }
1903 template <typename Value>
1904 static QVariant read(Value *value)
1905 {
1906 if (value) {
1907 if constexpr (std::is_constructible_v<QVariant, Value *>)
1908 return QVariant(value);
1909 else
1910 return read(*value);
1911 }
1912 return {};
1913 }
1914
1915 template <typename Target>
1916 static bool write(Target &target, const QVariant &value)
1917 {
1918 using Type = std::remove_reference_t<Target>;
1919 if constexpr (std::is_constructible_v<Target, QVariant>) {
1920 target = value;
1921 return true;
1922 } else if (value.canConvert<Type>()) {
1923 target = value.value<Type>();
1924 return true;
1925 }
1926 return false;
1927 }
1928 template <typename Target>
1929 static bool write(Target *target, const QVariant &value)
1930 {
1931 if (target)
1932 return write(*target, value);
1933 return false;
1934 }
1935
1936 template <typename ItemType>
1937 QMetaProperty roleProperty(int role) const
1938 {
1939 struct {
1940 operator QMetaProperty() const {
1941 const QByteArray roleName = that.itemModel().roleNames().value(role);
1942 const QMetaObject &mo = ItemType::staticMetaObject;
1943 if (const int index = mo.indexOfProperty(name: roleName.data());
1944 index >= 0) {
1945 return mo.property(index);
1946 }
1947 return {};
1948 }
1949 const QRangeModelImpl &that;
1950 const int role;
1951 } findProperty{*this, role};
1952
1953 if constexpr (ModelData::cachesProperties)
1954 return *m_data.properties.tryEmplace(role, findProperty).iterator;
1955 else
1956 return findProperty;
1957 }
1958
1959 template <typename ItemType>
1960 QVariant readRole(int role, ItemType *gadget) const
1961 {
1962 using item_type = std::remove_pointer_t<ItemType>;
1963 QVariant result;
1964 QMetaProperty prop = roleProperty<item_type>(role);
1965 if (!prop.isValid() && role == Qt::EditRole)
1966 prop = roleProperty<item_type>(Qt::DisplayRole);
1967
1968 if (prop.isValid())
1969 result = readProperty(prop, gadget);
1970 return result;
1971 }
1972
1973 template <typename ItemType>
1974 QVariant readRole(int role, const ItemType &gadget) const
1975 {
1976 return readRole(role, &gadget);
1977 }
1978
1979 template <typename ItemType>
1980 static QVariant readProperty(const QMetaProperty &prop, ItemType *gadget)
1981 {
1982 if constexpr (std::is_base_of_v<QObject, ItemType>)
1983 return prop.read(obj: gadget);
1984 else
1985 return prop.readOnGadget(gadget);
1986 }
1987 template <typename ItemType>
1988 static QVariant readProperty(int property, ItemType *gadget)
1989 {
1990 using item_type = std::remove_pointer_t<ItemType>;
1991 const QMetaObject &mo = item_type::staticMetaObject;
1992 const QMetaProperty prop = mo.property(index: property + mo.propertyOffset());
1993 return readProperty(prop, gadget);
1994 }
1995
1996 template <typename ItemType>
1997 static QVariant readProperty(int property, const ItemType &gadget)
1998 {
1999 return readProperty(property, &gadget);
2000 }
2001
2002 template <typename ItemType>
2003 bool writeRole(int role, ItemType *gadget, const QVariant &data)
2004 {
2005 using item_type = std::remove_pointer_t<ItemType>;
2006 auto prop = roleProperty<item_type>(role);
2007 if (!prop.isValid() && role == Qt::EditRole)
2008 prop = roleProperty<item_type>(Qt::DisplayRole);
2009
2010 return prop.isValid() ? writeProperty(prop, gadget, data) : false;
2011 }
2012
2013 template <typename ItemType>
2014 bool writeRole(int role, ItemType &&gadget, const QVariant &data)
2015 {
2016 return writeRole(role, &gadget, data);
2017 }
2018
2019 template <typename ItemType>
2020 static bool writeProperty(const QMetaProperty &prop, ItemType *gadget, const QVariant &data)
2021 {
2022 if constexpr (std::is_base_of_v<QObject, ItemType>)
2023 return prop.write(gadget, data);
2024 else
2025 return prop.writeOnGadget(gadget, data);
2026 }
2027 template <typename ItemType>
2028 static bool writeProperty(int property, ItemType *gadget, const QVariant &data)
2029 {
2030 using item_type = std::remove_pointer_t<ItemType>;
2031 const QMetaObject &mo = item_type::staticMetaObject;
2032 return writeProperty(mo.property(index: property + mo.propertyOffset()), gadget, data);
2033 }
2034
2035 template <typename ItemType>
2036 static bool writeProperty(int property, ItemType &&gadget, const QVariant &data)
2037 {
2038 return writeProperty(property, &gadget, data);
2039 }
2040
2041 template <typename ItemType>
2042 static bool resetProperty(int property, ItemType *object)
2043 {
2044 using item_type = std::remove_pointer_t<ItemType>;
2045 const QMetaObject &mo = item_type::staticMetaObject;
2046 bool success = true;
2047 if (property == -1) {
2048 // reset all properties
2049 if constexpr (std::is_base_of_v<QObject, item_type>) {
2050 for (int p = mo.propertyOffset(); p < mo.propertyCount(); ++p)
2051 success = writeProperty(mo.property(index: p), object, {}) && success;
2052 } else { // reset a gadget by assigning a default-constructed
2053 *object = {};
2054 }
2055 } else {
2056 success = writeProperty(mo.property(index: property + mo.propertyOffset()), object, {});
2057 }
2058 return success;
2059 }
2060
2061 template <typename ItemType>
2062 static bool resetProperty(int property, ItemType &&object)
2063 {
2064 return resetProperty(property, &object);
2065 }
2066
2067 // helpers
2068 const_row_reference rowData(const QModelIndex &index) const
2069 {
2070 Q_ASSERT(index.isValid());
2071 return that().rowDataImpl(index);
2072 }
2073
2074 row_reference rowData(const QModelIndex &index)
2075 {
2076 Q_ASSERT(index.isValid());
2077 return that().rowDataImpl(index);
2078 }
2079
2080 const range_type *childRange(const QModelIndex &index) const
2081 {
2082 if (!index.isValid())
2083 return m_data.model();
2084 if (index.column()) // only items at column 0 can have children
2085 return nullptr;
2086 return that().childRangeImpl(index);
2087 }
2088
2089 range_type *childRange(const QModelIndex &index)
2090 {
2091 if (!index.isValid())
2092 return m_data.model();
2093 if (index.column()) // only items at column 0 can have children
2094 return nullptr;
2095 return that().childRangeImpl(index);
2096 }
2097
2098
2099 const protocol_type& protocol() const { return QRangeModelDetails::refTo(m_protocol); }
2100 protocol_type& protocol() { return QRangeModelDetails::refTo(m_protocol); }
2101
2102 ModelData m_data;
2103 Protocol m_protocol;
2104};
2105
2106// Implementations that depends on the model structure (flat vs tree) that will
2107// be specialized based on a protocol type. The main template implements tree
2108// support through a protocol type.
2109template <typename Range, typename Protocol>
2110class QGenericTreeItemModelImpl
2111 : public QRangeModelImpl<QGenericTreeItemModelImpl<Range, Protocol>, Range, Protocol>
2112{
2113 using Base = QRangeModelImpl<QGenericTreeItemModelImpl<Range, Protocol>, Range, Protocol>;
2114 friend class QRangeModelImpl<QGenericTreeItemModelImpl<Range, Protocol>, Range, Protocol>;
2115
2116 using range_type = typename Base::range_type;
2117 using range_features = typename Base::range_features;
2118 using row_type = typename Base::row_type;
2119 using row_ptr = typename Base::row_ptr;
2120 using const_row_ptr = typename Base::const_row_ptr;
2121
2122 using tree_traits = typename Base::protocol_traits;
2123 static constexpr bool is_mutable_impl = tree_traits::has_mutable_childRows;
2124
2125 static constexpr bool rows_are_any_refs_or_pointers = Base::rows_are_raw_pointers ||
2126 QRangeModelDetails::is_smart_ptr<row_type>() ||
2127 QRangeModelDetails::is_any_of<row_type, std::reference_wrapper>();
2128 static_assert(!Base::dynamicColumns(), "A tree must have a static number of columns!");
2129
2130public:
2131 QGenericTreeItemModelImpl(Range &&model, Protocol &&p, QRangeModel *itemModel)
2132 : Base(std::forward<Range>(model), std::forward<Protocol>(p), itemModel)
2133 {};
2134
2135protected:
2136 QModelIndex indexImpl(int row, int column, const QModelIndex &parent) const
2137 {
2138 if (!parent.isValid())
2139 return this->createIndex(row, column);
2140 // only items at column 0 can have children
2141 if (parent.column())
2142 return QModelIndex();
2143
2144 const_row_ptr grandParent = static_cast<const_row_ptr>(parent.constInternalPointer());
2145 const auto &parentSiblings = childrenOf(grandParent);
2146 const auto it = QRangeModelDetails::pos(parentSiblings, parent.row());
2147 return this->createIndex(row, column, QRangeModelDetails::pointerTo(*it));
2148 }
2149
2150 QModelIndex parent(const QModelIndex &child) const
2151 {
2152 if (!child.isValid())
2153 return {};
2154
2155 // no pointer to parent row - no parent
2156 const_row_ptr parentRow = static_cast<const_row_ptr>(child.constInternalPointer());
2157 if (!parentRow)
2158 return {};
2159
2160 // get the siblings of the parent via the grand parent
2161 auto &&grandParent = this->protocol().parentRow(QRangeModelDetails::refTo(parentRow));
2162 const range_type &parentSiblings = childrenOf(QRangeModelDetails::pointerTo(grandParent));
2163 // find the index of parentRow
2164 const auto begin = QRangeModelDetails::begin(parentSiblings);
2165 const auto end = QRangeModelDetails::end(parentSiblings);
2166 const auto it = std::find_if(begin, end, [parentRow](auto &&s){
2167 return QRangeModelDetails::pointerTo(std::forward<decltype(s)>(s)) == parentRow;
2168 });
2169 if (it != end)
2170 return this->createIndex(std::distance(begin, it), 0,
2171 QRangeModelDetails::pointerTo(grandParent));
2172 return {};
2173 }
2174
2175 int rowCount(const QModelIndex &parent) const
2176 {
2177 return Base::size(this->childRange(parent));
2178 }
2179
2180 int columnCount(const QModelIndex &) const
2181 {
2182 // all levels of a tree have to have the same, static, column count
2183 if constexpr (Base::one_dimensional_range)
2184 return 1;
2185 else
2186 return Base::static_column_count; // if static_column_count is -1, static assert fires
2187 }
2188
2189 static constexpr Qt::ItemFlags defaultFlags()
2190 {
2191 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
2192 }
2193
2194 static constexpr bool canInsertRowsImpl()
2195 {
2196 // We must not insert rows if we cannot adjust the parents of the
2197 // children of the following rows. We don't have to do that if the
2198 // range operates on pointers.
2199 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2200 && Base::dynamicRows() && range_features::has_insert;
2201 }
2202
2203 static constexpr bool canRemoveRowsImpl()
2204 {
2205 // We must not remove rows if we cannot adjust the parents of the
2206 // children of the following rows. We don't have to do that if the
2207 // range operates on pointers.
2208 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2209 && Base::dynamicRows() && range_features::has_erase;
2210 }
2211
2212 static constexpr bool canMoveColumns(const QModelIndex &, const QModelIndex &)
2213 {
2214 return true;
2215 }
2216
2217 static constexpr bool canMoveRows(const QModelIndex &, const QModelIndex &)
2218 {
2219 return true;
2220 }
2221
2222 bool moveRowsAcross(const QModelIndex &sourceParent, int sourceRow, int count,
2223 const QModelIndex &destParent, int destRow)
2224 {
2225 // If rows are pointers, then reference to the parent row don't
2226 // change, so we can move them around freely. Otherwise we need to
2227 // be able to explicitly update the parent pointer.
2228 if constexpr (!rows_are_any_refs_or_pointers && !tree_traits::has_setParentRow) {
2229 return false;
2230 } else if constexpr (!(range_features::has_insert && range_features::has_erase)) {
2231 return false;
2232 } else if (!this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1,
2233 destParent, destRow)) {
2234 return false;
2235 }
2236
2237 range_type *source = this->childRange(sourceParent);
2238 range_type *destination = this->childRange(destParent);
2239
2240 // If we can insert data from another range into, then
2241 // use that to move the old data over.
2242 const auto destStart = QRangeModelDetails::pos(destination, destRow);
2243 if constexpr (range_features::has_insert_range) {
2244 const auto sourceStart = QRangeModelDetails::pos(*source, sourceRow);
2245 const auto sourceEnd = std::next(sourceStart, count);
2246
2247 destination->insert(destStart, std::move_iterator(sourceStart),
2248 std::move_iterator(sourceEnd));
2249 } else if constexpr (std::is_copy_constructible_v<row_type>) {
2250 // otherwise we have to make space first, and copy later.
2251 destination->insert(destStart, count, row_type{});
2252 }
2253
2254 row_ptr parentRow = destParent.isValid()
2255 ? QRangeModelDetails::pointerTo(this->rowData(destParent))
2256 : nullptr;
2257
2258 // if the source's parent was already inside the new parent row,
2259 // then the source row might have become invalid, so reset it.
2260 if (parentRow == static_cast<row_ptr>(sourceParent.internalPointer())) {
2261 if (sourceParent.row() < destRow) {
2262 source = this->childRange(sourceParent);
2263 } else {
2264 // the source parent moved down within destination
2265 source = this->childRange(this->createIndex(sourceParent.row() + count, 0,
2266 sourceParent.internalPointer()));
2267 }
2268 }
2269
2270 // move the data over and update the parent pointer
2271 {
2272 const auto writeStart = QRangeModelDetails::pos(destination, destRow);
2273 const auto writeEnd = std::next(writeStart, count);
2274 const auto sourceStart = QRangeModelDetails::pos(source, sourceRow);
2275 const auto sourceEnd = std::next(sourceStart, count);
2276
2277 for (auto write = writeStart, read = sourceStart; write != writeEnd; ++write, ++read) {
2278 // move data over if not already done, otherwise
2279 // only fix the parent pointer
2280 if constexpr (!range_features::has_insert_range)
2281 *write = std::move(*read);
2282 this->protocol().setParentRow(QRangeModelDetails::refTo(*write), parentRow);
2283 }
2284 // remove the old rows from the source parent
2285 source->erase(sourceStart, sourceEnd);
2286 }
2287
2288 // Fix the parent pointers in children of both source and destination
2289 // ranges, as the references to the entries might have become invalid.
2290 // We don't have to do that if the rows are pointers, as in that case
2291 // the references to the entries are stable.
2292 resetParentInChildren(children: destination);
2293 resetParentInChildren(children: source);
2294
2295 this->endMoveRows();
2296 return true;
2297 }
2298
2299 auto makeEmptyRow(const QModelIndex &parent)
2300 {
2301 // tree traversal protocol: if we are here, then it must be possible
2302 // to change the parent of a row.
2303 static_assert(tree_traits::has_setParentRow);
2304 row_type empty_row = this->protocol().newRow();
2305 if (QRangeModelDetails::isValid(empty_row) && parent.isValid()) {
2306 this->protocol().setParentRow(QRangeModelDetails::refTo(empty_row),
2307 QRangeModelDetails::pointerTo(this->rowData(parent)));
2308 }
2309 return empty_row;
2310 }
2311
2312 template <typename It, typename Sentinel>
2313 void deleteRemovedRows(It &&begin, Sentinel &&end)
2314 {
2315 if constexpr (tree_traits::has_deleteRow) {
2316 for (auto it = begin; it != end; ++it) {
2317 if constexpr (Base::isMutable()) {
2318 decltype(auto) children = this->protocol().childRows(QRangeModelDetails::refTo(*it));
2319 if (QRangeModelDetails::isValid(children)) {
2320 deleteRemovedRows(QRangeModelDetails::begin(children),
2321 QRangeModelDetails::end(children));
2322 QRangeModelDetails::refTo(children) = range_type{ };
2323 }
2324 }
2325
2326 this->protocol().deleteRow(std::move(*it));
2327 }
2328 }
2329 }
2330
2331 void resetParentInChildren(range_type *children)
2332 {
2333 if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) {
2334 const auto begin = QRangeModelDetails::begin(*children);
2335 const auto end = QRangeModelDetails::end(*children);
2336 for (auto it = begin; it != end; ++it) {
2337 decltype(auto) maybeChildren = this->protocol().childRows(*it);
2338 if (QRangeModelDetails::isValid(maybeChildren)) {
2339 auto &childrenRef = QRangeModelDetails::refTo(maybeChildren);
2340 QModelIndexList fromIndexes;
2341 QModelIndexList toIndexes;
2342 fromIndexes.reserve(size: Base::size(childrenRef));
2343 toIndexes.reserve(size: Base::size(childrenRef));
2344 auto *parentRow = QRangeModelDetails::pointerTo(*it);
2345
2346 int row = 0;
2347 for (auto &child : childrenRef) {
2348 const_row_ptr oldParent = this->protocol().parentRow(child);
2349 if (oldParent != parentRow) {
2350 fromIndexes.append(this->createIndex(row, 0, oldParent));
2351 toIndexes.append(this->createIndex(row, 0, parentRow));
2352 this->protocol().setParentRow(child, parentRow);
2353 }
2354 ++row;
2355 }
2356 this->changePersistentIndexList(fromIndexes, toIndexes);
2357 resetParentInChildren(children: &childrenRef);
2358 }
2359 }
2360 }
2361 }
2362
2363 decltype(auto) rowDataImpl(const QModelIndex &index) const
2364 {
2365 const_row_ptr parentRow = static_cast<const_row_ptr>(index.constInternalPointer());
2366 const range_type &siblings = childrenOf(parentRow);
2367 Q_ASSERT(index.row() < int(Base::size(siblings)));
2368 return *QRangeModelDetails::pos(siblings, index.row());
2369 }
2370
2371 decltype(auto) rowDataImpl(const QModelIndex &index)
2372 {
2373 row_ptr parentRow = static_cast<row_ptr>(index.internalPointer());
2374 range_type &siblings = childrenOf(parentRow);
2375 Q_ASSERT(index.row() < int(Base::size(siblings)));
2376 return *QRangeModelDetails::pos(siblings, index.row());
2377 }
2378
2379 const range_type *childRangeImpl(const QModelIndex &index) const
2380 {
2381 const auto &row = this->rowData(index);
2382 if (!QRangeModelDetails::isValid(row))
2383 return static_cast<const range_type *>(nullptr);
2384
2385 decltype(auto) children = this->protocol().childRows(QRangeModelDetails::refTo(row));
2386 return QRangeModelDetails::pointerTo(std::forward<decltype(children)>(children));
2387 }
2388
2389 range_type *childRangeImpl(const QModelIndex &index)
2390 {
2391 auto &row = this->rowData(index);
2392 if (!QRangeModelDetails::isValid(row))
2393 return static_cast<range_type *>(nullptr);
2394
2395 decltype(auto) children = this->protocol().childRows(QRangeModelDetails::refTo(row));
2396 using Children = std::remove_reference_t<decltype(children)>;
2397
2398 if constexpr (QRangeModelDetails::is_any_of<Children, std::optional>())
2399 if constexpr (std::is_default_constructible<typename Children::value_type>()) {
2400 if (!children)
2401 children.emplace(range_type{});
2402 }
2403
2404 return QRangeModelDetails::pointerTo(std::forward<decltype(children)>(children));
2405 }
2406
2407 const range_type &childrenOf(const_row_ptr row) const
2408 {
2409 return row ? QRangeModelDetails::refTo(this->protocol().childRows(*row))
2410 : *this->m_data.model();
2411 }
2412
2413private:
2414 range_type &childrenOf(row_ptr row)
2415 {
2416 return row ? QRangeModelDetails::refTo(this->protocol().childRows(*row))
2417 : *this->m_data.model();
2418 }
2419};
2420
2421// specialization for flat models without protocol
2422template <typename Range>
2423class QGenericTableItemModelImpl
2424 : public QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>
2425{
2426 using Base = QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>;
2427 friend class QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>;
2428
2429 using range_type = typename Base::range_type;
2430 using range_features = typename Base::range_features;
2431 using row_type = typename Base::row_type;
2432 using const_row_ptr = typename Base::const_row_ptr;
2433 using row_traits = typename Base::row_traits;
2434 using row_features = typename Base::row_features;
2435
2436 static constexpr bool is_mutable_impl = true;
2437
2438public:
2439 explicit QGenericTableItemModelImpl(Range &&model, QRangeModel *itemModel)
2440 : Base(std::forward<Range>(model), {}, itemModel)
2441 {}
2442
2443protected:
2444 QModelIndex indexImpl(int row, int column, const QModelIndex &) const
2445 {
2446 if constexpr (Base::dynamicColumns()) {
2447 if (column < int(Base::size(*QRangeModelDetails::pos(*this->m_data.model(), row))))
2448 return this->createIndex(row, column);
2449#ifndef QT_NO_DEBUG
2450 // if we got here, then column < columnCount(), but this row is too short
2451 qCritical(msg: "QRangeModel: Column-range at row %d is not large enough!", row);
2452#endif
2453 return {};
2454 } else {
2455 return this->createIndex(row, column);
2456 }
2457 }
2458
2459 QModelIndex parent(const QModelIndex &) const
2460 {
2461 return {};
2462 }
2463
2464 int rowCount(const QModelIndex &parent) const
2465 {
2466 if (parent.isValid())
2467 return 0;
2468 return int(Base::size(*this->m_data.model()));
2469 }
2470
2471 int columnCount(const QModelIndex &parent) const
2472 {
2473 if (parent.isValid())
2474 return 0;
2475
2476 // in a table, all rows have the same number of columns (as the first row)
2477 if constexpr (Base::dynamicColumns()) {
2478 return int(Base::size(*this->m_data.model()) == 0
2479 ? 0
2480 : Base::size(*QRangeModelDetails::begin(*this->m_data.model())));
2481 } else if constexpr (Base::one_dimensional_range) {
2482 return row_traits::fixed_size();
2483 } else {
2484 return Base::static_column_count;
2485 }
2486 }
2487
2488 static constexpr Qt::ItemFlags defaultFlags()
2489 {
2490 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren;
2491 }
2492
2493 static constexpr bool canInsertRowsImpl()
2494 {
2495 return Base::dynamicRows() && range_features::has_insert;
2496 }
2497
2498 static constexpr bool canRemoveRowsImpl()
2499 {
2500 return Base::dynamicRows() && range_features::has_erase;
2501 }
2502
2503 static constexpr bool canMoveColumns(const QModelIndex &source, const QModelIndex &destination)
2504 {
2505 return !source.isValid() && !destination.isValid();
2506 }
2507
2508 static constexpr bool canMoveRows(const QModelIndex &source, const QModelIndex &destination)
2509 {
2510 return !source.isValid() && !destination.isValid();
2511 }
2512
2513 constexpr bool moveRowsAcross(const QModelIndex &, int , int,
2514 const QModelIndex &, int) noexcept
2515 {
2516 // table/flat model: can't move rows between different parents
2517 return false;
2518 }
2519
2520 auto makeEmptyRow(const QModelIndex &)
2521 {
2522 row_type empty_row = this->protocol().newRow();
2523
2524 // dynamically sized rows all have to have the same column count
2525 if constexpr (Base::dynamicColumns() && row_features::has_resize) {
2526 if (QRangeModelDetails::isValid(empty_row))
2527 QRangeModelDetails::refTo(empty_row).resize(this->itemModel().columnCount());
2528 }
2529
2530 return empty_row;
2531 }
2532
2533 template <typename It, typename Sentinel>
2534 void deleteRemovedRows(It &&begin, Sentinel &&end)
2535 {
2536 if constexpr (Base::protocol_traits::has_deleteRow) {
2537 for (auto it = begin; it != end; ++it)
2538 this->protocol().deleteRow(std::move(*it));
2539 }
2540 }
2541
2542 decltype(auto) rowDataImpl(const QModelIndex &index) const
2543 {
2544 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*this->m_data.model())));
2545 return *QRangeModelDetails::pos(*this->m_data.model(), index.row());
2546 }
2547
2548 decltype(auto) rowDataImpl(const QModelIndex &index)
2549 {
2550 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*this->m_data.model())));
2551 return *QRangeModelDetails::pos(*this->m_data.model(), index.row());
2552 }
2553
2554 const range_type *childRangeImpl(const QModelIndex &) const
2555 {
2556 return nullptr;
2557 }
2558
2559 range_type *childRangeImpl(const QModelIndex &)
2560 {
2561 return nullptr;
2562 }
2563
2564 const range_type &childrenOf(const_row_ptr row) const
2565 {
2566 Q_ASSERT(!row);
2567 return *this->m_data.model();
2568 }
2569
2570 void resetParentInChildren(range_type *)
2571 {
2572 }
2573};
2574
2575QT_END_NAMESPACE
2576
2577#endif // Q_QDOC
2578
2579#endif // QRANGEMODEL_IMPL_H
2580

source code of qtbase/src/corelib/itemmodels/qrangemodel_impl.h