5#ifndef QRANGEMODEL_IMPL_H
6#define QRANGEMODEL_IMPL_H
11#error Do not include qrangemodel_impl.h directly
15#pragma qt_sync_skip_header_check
16#pragma qt_sync_stop_processing
19#include <QtCore/qabstractitemmodel.h>
20#include <QtCore/qmetaobject.h>
21#include <QtCore/qvariant.h>
22#include <QtCore/qmap.h>
28#include <QtCore/q20type_traits.h>
30#include <QtCore/q23utility.h>
36template <
typename Applier, size_t ...Is>
44 static_cast<
void>(((Is == index ? (applier(std::integral_constant<size_t, Is>{}),
true) :
false)
48template <size_t IndexCount,
typename Applier>
51 applyIndexSwitch(index, std::forward<Applier>(applier), std::make_index_sequence<IndexCount>());
55template <
typename Interface>
59 template <
typename Arg>
60 static constexpr bool passArgAsValue =
sizeof(
Arg) <=
sizeof(
size_t)
63 template <
typename ...>
66 template <
typename M,
typename R,
typename I,
typename... Args>
67 struct MethodImpl<M, R, I, Args...>
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&&>...>;
73 static constexpr size_t index()
75 return index(std::make_index_sequence<std::tuple_size_v<Methods<>>>());
80 static constexpr bool matchesAt()
82 return std::is_base_of_v<M, std::tuple_element_t<Ix, Methods<>>>;
85 template <size_t... Is>
86 static constexpr size_t index(std::index_sequence<Is...>)
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) + ...);
93 static R invoke(I &intf , Args... args)
95 Q_ASSERT(intf.m_callFN);
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);
102 alignas(R)
std::byte buf[
sizeof(R)];
103 intf.m_callFN(index(), baseIntf, buf, &callArgs);
105 R* result =
std::launder(
reinterpret_cast<R*>(buf));
106 QScopeGuard destroyBuffer([result]() {
std::destroy_at(result); });
107 return std::forward<R>(*result);
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...);
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;
126 template <
typename C = Interface>
using Methods =
typename C::
template MethodTemplates<C>;
129 template <
auto prototype>
132 template <
typename Method,
typename... Args>
133 auto call(Args &&... args)
const
135 return Method::invoke(
static_cast<
const Interface &>(*
this),
std::forward<Args>(args)...);
138 template <
typename Method,
typename... Args>
141 return Method::invoke(
static_cast<Interface &>(*
this),
std::forward<Args>(args)...);
165template <
typename Subclass,
typename Interface>
169 template <
typename C = Subclass>
using Methods =
typename C::
template MethodTemplates<C>;
171 template <size_t OverriddenIndex>
172 static constexpr size_t interfaceMethodIndex() {
173 return std::tuple_element_t<OverriddenIndex, Methods<>>::index();
176 template <size_t... Is>
177 static void callImpl(size_t index, Subclass &subclass,
void *ret,
void *args, std::index_sequence<Is...>)
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");
187 auto doInvoke = [&](
auto idxConstant) {
188 std::tuple_element_t<idxConstant.value, Methods<>>::doInvoke(subclass, ret, args);
190 applyIndexSwitch(index, doInvoke, std::index_sequence<interfaceMethodIndex<Is>()...>{});
193 static void callImpl(size_t index,
typename Interface::base_interface &intf,
void *ret,
void *args)
195 constexpr auto seq = std::make_index_sequence<std::tuple_size_v<Methods<>>>();
196 callImpl(index,
static_cast<Subclass&>(intf), ret, args, seq);
199 template <
typename BaseMethod>
200 using OverridenSignature =
typename BaseMethod::
template Overridden<Subclass>;
203 template <
typename... Args>
205 : Interface(
std::forward<Args>(args)...)
207 Interface::initCallFN(&QQuasiVirtualSubclass::callImpl);
211 template <
typename BaseMethod, OverridenSignature<BaseMethod> overridden>
215 static constexpr void doInvoke(Subclass &subclass,
void *ret,
void *args)
217 using Return =
typename BaseMethod::return_type;
218 using PackedArgs =
typename BaseMethod::call_args;
221 Q_ASSERT(
std::is_void_v<Return> == !ret);
223 auto invoke = [&subclass](
auto &&...params)
225 return std::invoke(overridden, &subclass,
std::forward<
decltype(params)>(params)...);
228 if constexpr (
std::is_void_v<Return>) {
229 std::apply(invoke,
std::move(*
static_cast<PackedArgs *>(args)));
233 using Alloc =
std::allocator<Return>;
235 std::allocator_traits<Alloc>::construct(alloc,
static_cast<Return *>(ret),
236 std::apply(invoke,
std::move(*
static_cast<PackedArgs *>(args))));
249 template <
typename T,
template <
typename...>
typename... Templates>
252 template <
template <
typename...>
typename Template,
254 template <
typename...>
typename...
Templates>
257 template <
typename T,
258 template <
typename...>
typename Template,
259 template <
typename...>
typename...
Templates>
262 template <
typename T,
template <
typename...>
typename...
Templates>
265 template <
typename T,
typename =
void>
268 template <
typename T>
272 template <
typename T,
typename =
void>
275 template <
typename T>
287 template <
typename T>
289#ifndef QT_NO_SCOPED_POINTER
295 template <
typename T>
299 template <
typename T>
303 template <
typename 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>())
310 else if constexpr (is_smart_ptr<Type>())
312 else if constexpr (is_any_of<Type, std::reference_wrapper>())
313 return std::addressof(t.get());
315 return std::addressof(
std::forward<T>(t));
318 template <
typename T>
321 template <
typename T>
324 template <
typename T,
typename =
void>
328 template <
typename T>
330 template <
typename T>
333 template <
typename T,
typename =
void>
339 template <
typename T>
342 template <
typename T,
typename =
void>
344 template <
typename T>
347 template <
typename T>
350 template <
typename T>
351 static constexpr bool isValid(
const T &t)
noexcept
353 if constexpr (
std::is_array_v<T>)
355 else if constexpr (is_validatable<T>())
361 template <
typename T>
362 static decltype(
auto)
refTo(T&& t) {
363 Q_ASSERT(isValid(t));
365 using Type = q20::remove_cvref_t<T>;
366 if constexpr (is_any_of<T, std::optional>())
367 return *
std::forward<T>(t);
368 if constexpr (!is_wrapped<Type>() || is_any_unique_ptr<Type>())
369 return q23::forward_like<T>(*pointerTo(t));
371 return *pointerTo(t);
374 template <
typename It>
375 auto key(It&& it) ->
decltype(it.key()) {
return std::forward<It>(it).key(); }
376 template <
typename It>
377 auto key(It&& it) ->
decltype((it->first)) {
return std::forward<It>(it)->first; }
379 template <
typename It>
380 auto value(It&& it) ->
decltype(it.value()) {
return std::forward<It>(it).value(); }
381 template <
typename It>
382 auto value(It&& it) ->
decltype((it->second)) {
return std::forward<It>(it)->second; }
385 template <
typename C>
386 static auto begin(C &&c) ->
decltype(
std::begin(refTo(
std::forward<C>(c))))
387 {
return std::begin(refTo(
std::forward<C>(c))); }
388 template <
typename C>
389 static auto end(C &&c) ->
decltype(
std::end(refTo(
std::forward<C>(c))))
390 {
return std::end(refTo(
std::forward<C>(c))); }
391 template <
typename C>
392 static auto pos(C &&c,
int i)
400 template <
typename C,
typename =
void>
403 template <
typename C>
414 template <
typename C,
typename =
void>
417 template <
typename C>
426 template <
typename C,
typename =
void>
429 template <
typename C>
437 template <
typename C,
typename =
void>
440 template <
typename C>
449 template <
typename It,
typename =
void>
452 template <
typename It>
458 template <
typename C,
typename =
void>
461 template <
typename C>
471 template <
typename C>
472 static void rotate(C& c,
int src,
int count,
int dst) {
474 using Container = std::remove_reference_t<
decltype(container)>;
477 const auto srcEnd =
std::next(srcBegin, count);
480 if constexpr (test_splice<Container>::value) {
481 if (dst > src && dst < src + count)
482 container.splice(srcBegin, container, dstBegin, srcEnd);
484 container.splice(dstBegin, container, srcBegin, srcEnd);
487 std::rotate(srcBegin, srcEnd, dstBegin);
489 std::rotate(dstBegin, srcBegin, srcEnd);
502 template <
typename C>
511 template <
typename C>
515 template <
typename C,
typename =
void>
517 template <
typename C>
520 template <
typename C,
typename =
void>
522 template <
typename C>
527 template <
typename C,
typename =
void>
538 template <
typename C>
579 template <
typename C>
581 template <
typename C>
588 template <
typename T,
typename =
void>
594 template <
typename T>
606 template <
typename T,
typename =
void>
609 template <
typename T>
622 "The return type of the ItemAccess::writeRole implementation "
623 "needs to be convertible to a bool!");
626 "The return type of the ItemAccess::readRole implementation "
627 "needs to be convertible to QVariant!");
633 template <
typename T,
typename =
void>
646 template <
typename T>
682 template <
typename T>
703 template <
typename T>
707 template <
typename Range>
713 auto newRow() ->
decltype(R{}) {
return R{}; }
716 template <
typename Range>
747 template <
typename Range>
750 template <
typename R >
751 auto parentRow(
const R& row)
const ->
decltype(row.parentRow())
753 return row.parentRow();
756 template <
typename R >
757 auto setParentRow(R &row, R* parent) ->
decltype(row.setParentRow(parent))
759 row.setParentRow(parent);
762 template <
typename R >
763 auto childRows(
const R &row)
const ->
decltype(row.childRows())
765 return row.childRows();
768 template <
typename R >
771 return row.childRows();
775 template <
typename P,
typename R,
typename =
void>
777 template <
typename P,
typename R>
782 template <
typename P,
typename R,
typename =
void>
784 template <
typename P,
typename R>
789 template <
typename P,
typename R,
typename =
void>
791 template <
typename P,
typename R>
797 template <
typename P,
typename R,
typename =
void>
799 template <
typename P,
typename R>
805 template <
typename P,
typename =
void>
807 template <
typename P>
811 template <
typename P,
typename R,
typename =
void>
813 template <
typename P,
typename R>
818 template <
typename Range,
830 template <
typename Range>
840 template <
typename Range,
typename Protocol>
859 template <
bool cacheProperties>
881 template <
typename ModelStorage,
typename =
void>
900 template <
typename ModelStorage,
typename ItemType>
908 auto model() {
return pointerTo(
this->m_model); }
909 auto model()
const {
return pointerTo(
this->m_model); }
911 template <
typename Model = ModelStorage>
928 template <
typename StaticContainer,
typename F>
931 using type = std::remove_cv_t<QRangeModelDetails::wrapped_t<StaticContainer>>;
932 static_assert(QRangeModelDetails::array_like_v<type> || QRangeModelDetails::tuple_like_v<type>,
933 "Internal error: expected an array-like or a tuple-like type");
937 if constexpr (QRangeModelDetails::array_like_v<type>) {
938 Q_ASSERT(idx <
std::size(ref));
941 constexpr size_t size = std::tuple_size_v<type>;
942 Q_ASSERT(idx < std::tuple_size_v<type>);
943 QtPrivate::applyIndexSwitch<size>(idx, [&](
auto idxConstant) {
944 function(get<idxConstant>(ref));
952 template <
typename T>
955 using type = QRangeModelDetails::wrapped_t<T>;
956 if constexpr (QRangeModelDetails::array_like_v<type>) {
958 return QMetaType::fromType<std::tuple_element_t<0, type>>();
960 constexpr auto size = std::tuple_size_v<type>;
961 Q_ASSERT(idx < size);
963 QtPrivate::applyIndexSwitch<size>(idx, [&metaType](
auto idxConstant) {
964 using ElementType = std::tuple_element_t<idxConstant.value, type>;
965 metaType = QMetaType::fromType<QRangeModelDetails::wrapped_t<ElementType>>();
975 bool setHeaderData(
int section, Qt::Orientation orientation,
const QVariant &data,
int role);
976 bool setData(
const QModelIndex &index,
const QVariant &data,
int role);
977 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data);
981 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
const QModelIndex &destParent,
int destColumn);
982 bool insertRows(
int row,
int count,
const QModelIndex &parent);
983 bool removeRows(
int row,
int count,
const QModelIndex &parent);
984 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
const QModelIndex &destParent,
int destRow);
997 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const;
1027 template <
typename C>
1059 QRangeModel *m_rangeModel;
1063 : m_rangeModel(itemModel)
1068 inline void dataChanged(
const QModelIndex &from,
const QModelIndex &to,
1069 const QList<
int> &roles);
1074 inline bool beginMoveColumns(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1075 const QModelIndex &destParent,
int destRow);
1077 inline void beginInsertRows(
const QModelIndex &parent,
int start,
int count);
1079 inline void beginRemoveRows(
const QModelIndex &parent,
int start,
int count);
1081 inline bool beginMoveRows(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1082 const QModelIndex &destParent,
int destRow);
1093template <
typename Structure,
typename Range,
1094 typename Protocol = QRangeModelDetails::table_protocol_t<Range>>
1123 "Currently, std::optional is not supported for ranges and rows, as "
1124 "it has range semantics in c++26. Once the required behavior is clarified, "
1125 "std::optional for ranges and rows will be supported.");
1132 Structure&
that() {
return static_cast<Structure &>(*
this); }
1133 const Structure&
that()
const {
return static_cast<
const Structure &>(*
this); }
1135 template <
typename C>
1136 static constexpr int size(
const C &c)
1142 if constexpr (test_size<C>()) {
1143 return int(
std::size(c));
1145#if defined(__cpp_lib_ranges)
1146 using std::ranges::distance;
1148 using std::distance;
1150 using container_type = std::conditional_t<range_traits<C>::has_cbegin,
1153 container_type& container =
const_cast<container_type &>(refTo(c));
1154 return int(distance(
std::begin(container),
std::end(container)));
1170 template <
typename T>
1190 {
return lhs.n == rhs.n; }
1192 {
return !(lhs == rhs); }
1203 "The range holding a move-only row-type must support insert(pos, start, end)");
1208 return range_features::is_mutable && row_features::is_mutable
1209 && std::is_reference_v<row_reference>
1210 && Structure::is_mutable_impl;
1233 if (row < 0 || column < 0 || column >= columnCount(parent)
1234 || row >= rowCount(parent)) {
1238 return that().indexImpl(row, column, parent);
1243 if (row == index.row() && column == index.column())
1246 if (column < 0 || column >=
this->columnCount({}))
1249 if (row == index.row())
1250 return this->createIndex(row, column, index.constInternalPointer());
1252 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
1253 const auto siblingCount = size(that().childrenOf(parentRow));
1254 if (row < 0 || row >=
int(siblingCount))
1256 return this->createIndex(row, column, parentRow);
1261 if (!index.isValid())
1262 return Qt::NoItemFlags;
1264 Qt::ItemFlags f = Structure::defaultFlags();
1266 if constexpr (isMutable()) {
1267 if constexpr (row_traits::hasMetaObject) {
1268 if (index.column() < row_traits::fixed_size()) {
1269 const QMetaObject mo = wrapped_row_type::staticMetaObject;
1270 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
1271 if (prop.isWritable())
1272 f |= Qt::ItemIsEditable;
1275 f |= Qt::ItemIsEditable;
1276 }
else if constexpr (std::is_reference_v<row_reference> && !std::is_const_v<row_reference>) {
1279 const_row_reference row = rowData(index);
1280 row_reference mutableRow =
const_cast<row_reference>(row);
1283 using target_type =
decltype(ref);
1284 if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
1285 f &= ~Qt::ItemIsEditable;
1286 else if constexpr (std::is_lvalue_reference_v<target_type>)
1287 f |= Qt::ItemIsEditable;
1292 f &= ~Qt::ItemIsEditable;
1302 if (role != Qt::DisplayRole || orientation != Qt::Horizontal
1303 || section < 0 || section >= columnCount({})) {
1304 return this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1307 if constexpr (row_traits::hasMetaObject) {
1308 if (row_traits::fixed_size() == 1) {
1309 const QMetaType metaType = QMetaType::fromType<wrapped_row_type>();
1310 result = QString::fromUtf8(metaType.name());
1311 }
else if (section <= row_traits::fixed_size()) {
1312 const QMetaProperty prop = wrapped_row_type::staticMetaObject.property(
1313 section + wrapped_row_type::staticMetaObject.propertyOffset());
1314 result = QString::fromUtf8(prop.name());
1317 if constexpr (QRangeModelDetails::array_like_v<wrapped_row_type>) {
1320 const QMetaType metaType = QRangeModelImplBase::meta_type_at<wrapped_row_type>(section);
1321 if (metaType.isValid())
1322 result = QString::fromUtf8(metaType.name());
1325 if (!result.isValid())
1326 result =
this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1332 if (!index.isValid())
1335 QModelRoleData result(role);
1336 multiData(index, result);
1337 return std::move(result.data());
1342 QMap<
int, QVariant> result;
1344 const auto readItemData = [
this, &result, &tried](
const auto &value){
1346 using value_type = q20::remove_cvref_t<
decltype(value)>;
1347 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1348 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1350 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1351 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1353 const auto roles =
this->itemModel().roleNames().keys();
1354 for (
auto &role : roles) {
1355 if (role == Qt::RangeModelDataRole)
1357 QVariant data = ItemAccess::readRole(value, role);
1359 result[role] =
std::move(data);
1361 }
else if constexpr (multi_role()) {
1363 if constexpr (std::is_convertible_v<value_type,
decltype(result)>) {
1366 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1368 if constexpr (!multi_role::int_key)
1369 return this->itemModel().roleNames();
1373 for (
auto it =
std::begin(value); it !=
std::end(value); ++it) {
1375 Q_UNUSED(roleNames);
1376 if constexpr (multi_role::int_key)
1379 return roleNames.key(key.toUtf8(), -1);
1382 if (role != -1 && role != Qt::RangeModelDataRole)
1386 }
else if constexpr (has_metaobject<value_type>) {
1387 if (row_traits::fixed_size() <= 1) {
1389 const auto roleNames =
this->itemModel().roleNames();
1390 const auto end = roleNames.keyEnd();
1391 for (
auto it = roleNames.keyBegin(); it != end; ++it) {
1392 const int role = *it;
1393 if (role == Qt::RangeModelDataRole)
1397 result[role] =
std::move(data);
1403 if (index.isValid()) {
1404 readAt(index, readItemData);
1407 result =
this->itemModel().QAbstractItemModel::itemData(index);
1412 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const
1415 readAt(index, [
this, &index, roleDataSpan, &tried](
const auto &value) {
1418 using value_type = q20::remove_cvref_t<
decltype(value)>;
1419 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1420 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1422 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1423 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1425 for (
auto &roleData : roleDataSpan) {
1426 if (roleData.role() == Qt::RangeModelDataRole) {
1430 if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
1431 roleData.setData(QVariant::fromValue(QRangeModelDetails::refTo(value)));
1433 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1435 roleData.setData(ItemAccess::readRole(value, roleData.role()));
1438 }
else if constexpr (multi_role()) {
1440 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1442 if constexpr (!multi_role::int_key)
1443 return this->itemModel().roleNames();
1447 using key_type =
typename value_type::key_type;
1448 for (
auto &roleData : roleDataSpan) {
1449 const auto &it = [&roleNames, &value, role = roleData.role()]{
1450 Q_UNUSED(roleNames);
1451 if constexpr (multi_role::int_key)
1452 return value.find(key_type(role));
1454 return value.find(roleNames.value(role));
1456 if (it != QRangeModelDetails::end(value))
1457 roleData.setData(QRangeModelDetails::value(it));
1459 roleData.clearData();
1461 }
else if constexpr (has_metaobject<value_type>) {
1462 if (row_traits::fixed_size() <= 1) {
1464 for (
auto &roleData : roleDataSpan) {
1465 if (roleData.role() == Qt::RangeModelDataRole) {
1469 if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
1470 roleData.setData(QVariant::fromValue(QRangeModelDetails::refTo(value)));
1472 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1474 roleData.setData(readRole(roleData.role(),
1475 QRangeModelDetails::pointerTo(value)));
1478 }
else if (index.column() <= row_traits::fixed_size()) {
1480 for (
auto &roleData : roleDataSpan) {
1481 const int role = roleData.role();
1482 if (role == Qt::DisplayRole || role == Qt::EditRole) {
1483 roleData.setData(readProperty(index.column(),
1484 QRangeModelDetails::pointerTo(value)));
1486 roleData.clearData();
1492 for (
auto &roleData : roleDataSpan) {
1493 const int role = roleData.role();
1494 if (role == Qt::DisplayRole || role == Qt::EditRole
1495 || role == Qt::RangeModelDataRole) {
1496 roleData.setData(read(value));
1498 roleData.clearData();
1507 bool setData(
const QModelIndex &index,
const QVariant &data,
int role)
1509 if (!index.isValid())
1512 bool success =
false;
1513 if constexpr (isMutable()) {
1514 auto emitDataChanged = qScopeGuard([&success,
this, &index, role]{
1516 Q_EMIT
this->dataChanged(index, index,
1517 role == Qt::EditRole || role == Qt::RangeModelDataRole
1518 ? QList<
int>{} : QList<
int>{role});
1522 const auto writeData = [
this, column = index.column(), &data, role](
auto &&target) ->
bool {
1523 using value_type = q20::remove_cvref_t<
decltype(target)>;
1524 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1525 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1527 auto setRangeModelDataRole = [&target, &data]{
1529 constexpr auto targetMetaType = QMetaType::fromType<value_type>();
1530 const auto dataMetaType = data.metaType();
1531 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>) {
1536 }
else if constexpr (QRangeModelDetails::is_wrapped<value_type>()) {
1540 if (
const auto mt = QMetaType::fromType<wrapped_value_type>();
1541 data.canConvert(mt)) {
1542 targetRef = data.value<wrapped_value_type>();
1544 }
else if (
const auto mtp = QMetaType::fromType<wrapped_value_type *>();
1545 data.canConvert(mtp)) {
1546 targetRef = *data.value<wrapped_value_type *>();
1550 }
else if (targetMetaType == dataMetaType) {
1551 targetRef = data.value<value_type>();
1553 }
else if (dataMetaType.flags() & QMetaType::PointerToGadget) {
1554 targetRef = *data.value<value_type *>();
1558 qCritical(
"Not able to assign %s to %s",
1559 qPrintable(QDebug::toString(data)), targetMetaType.name());
1564 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1565 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1566 if (role == Qt::RangeModelDataRole)
1567 return setRangeModelDataRole();
1568 return ItemAccess::writeRole(target, data, role);
1569 }
if constexpr (has_metaobject<value_type>) {
1570 if (row_traits::fixed_size() <= 1) {
1571 if (role == Qt::RangeModelDataRole)
1572 return setRangeModelDataRole();
1574 }
else if (column <= row_traits::fixed_size()
1575 && (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::RangeModelDataRole)) {
1576 return writeProperty(column, QRangeModelDetails::pointerTo(target), data);
1578 }
else if constexpr (multi_role::value) {
1579 Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role);
1582 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1584 if constexpr (!multi_role::int_key)
1585 return this->itemModel().roleNames();
1589 if (role == Qt::EditRole) {
1590 if constexpr (multi_role::int_key) {
1591 if (target.find(roleToSet) == target.end())
1592 roleToSet = Qt::DisplayRole;
1594 if (target.find(roleNames.value(roleToSet)) == target.end())
1595 roleToSet = Qt::DisplayRole;
1598 if constexpr (multi_role::int_key)
1599 return write(target[roleToSet], data);
1601 return write(target[roleNames.value(roleToSet)], data);
1602 }
else if (role == Qt::DisplayRole || role == Qt::EditRole
1603 || role == Qt::RangeModelDataRole) {
1604 return write(target, data);
1609 success = writeAt(index, writeData);
1614 template <
typename LHS,
typename RHS>
1617 if constexpr (
std::is_pointer_v<RHS>) {
1621 if constexpr (
std::is_assignable_v<LHS, RHS>)
1622 org =
std::forward<RHS>(copy);
1627 template <
typename LHS,
typename RHS>
1630 updateTarget(*org,
std::forward<RHS>(copy));
1633 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data)
1635 if (!index.isValid() || data.isEmpty())
1638 bool success =
false;
1639 if constexpr (isMutable()) {
1640 auto emitDataChanged = qScopeGuard([&success,
this, &index, &data]{
1642 Q_EMIT
this->dataChanged(index, index, data.keys());
1646 auto writeItemData = [
this, &tried, &data](
auto &target) ->
bool {
1648 using value_type = q20::remove_cvref_t<
decltype(target)>;
1649 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1650 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1654 auto makeCopy = [](
const value_type &original){
1655 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>)
1657 else if constexpr (std::is_pointer_v<
decltype(original)>)
1659 else if constexpr (std::is_copy_assignable_v<value_type>)
1665 const auto roleNames =
this->itemModel().roleNames();
1667 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1669 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1670 const auto roles = roleNames.keys();
1671 auto targetCopy = makeCopy(target);
1672 for (
int role : roles) {
1673 if (!ItemAccess::writeRole(QRangeModelDetails::refTo(targetCopy),
1674 data.value(role), role)) {
1678 updateTarget(target,
std::move(targetCopy));
1680 }
else if constexpr (multi_role()) {
1681 using key_type =
typename value_type::key_type;
1683 const auto roleName = [&roleNames](
int role) {
1684 return roleNames.value(role);
1689 if constexpr (!multi_role::int_key)
1691 auto invalid =
std::find_if(data.keyBegin(), data.keyEnd(),
1692 [&roleName](
int role) {
return roleName(role).isEmpty(); }
1695 if (invalid != data.keyEnd()) {
1697 qWarning(
"No role name set for %d", *invalid);
1703 for (
auto &&[role, value] : data.asKeyValueRange()) {
1704 if constexpr (multi_role::int_key)
1705 target[
static_cast<key_type>(role)] = value;
1707 target[QString::fromUtf8(roleName(role))] = value;
1710 }
else if constexpr (has_metaobject<value_type>) {
1711 if (row_traits::fixed_size() <= 1) {
1713 auto targetCopy = makeCopy(target);
1714 for (
auto &&[role, value] : data.asKeyValueRange()) {
1715 if (role == Qt::RangeModelDataRole)
1717 if (!writeRole(role, QRangeModelDetails::pointerTo(targetCopy), value)) {
1718 const QByteArray roleName = roleNames.value(role);
1720 qWarning(
"Failed to write value '%s' to role '%s'",
1721 qPrintable(QDebug::toString(value)), roleName.data());
1726 updateTarget(target,
std::move(targetCopy));
1733 success = writeAt(index, writeItemData);
1738 emitDataChanged.dismiss();
1739 success =
this->itemModel().QAbstractItemModel::setItemData(index, data);
1747 if (!index.isValid())
1750 bool success =
false;
1751 if constexpr (isMutable()) {
1752 auto emitDataChanged = qScopeGuard([&success,
this, &index]{
1754 Q_EMIT
this->dataChanged(index, index, {});
1757 auto clearData = [column = index.column()](
auto &&target) {
1758 if constexpr (row_traits::hasMetaObject) {
1759 if (row_traits::fixed_size() <= 1) {
1762 }
else if (column <= row_traits::fixed_size()) {
1763 return resetProperty(column, QRangeModelDetails::pointerTo(target));
1772 success = writeAt(index, clearData);
1780 using item_type =
typename row_traits::item_type;
1781 if constexpr (QRangeModelDetails::has_metaobject_v<item_type>) {
1782 return QRangeModelImplBase::roleNamesForMetaObject(
this->itemModel(),
1783 QRangeModelDetails::wrapped_t<item_type>::staticMetaObject);
1784 }
else if constexpr (std::negation_v<std::disjunction<std::is_void<item_type>,
1785 QRangeModelDetails::is_multi_role<item_type>>>) {
1786 return QRangeModelImplBase::roleNamesForSimpleType();
1789 return this->itemModel().QAbstractItemModel::roleNames();
1793 template <
typename InsertFn>
1798 range_type *
const children = childRange(parent);
1802 this->beginInsertColumns(parent, column, column + count - 1);
1804 for (
auto &child : *children) {
1805 auto it = QRangeModelDetails::pos(child, column);
1806 (
void)insertFn(QRangeModelDetails::refTo(child), it, count);
1809 this->endInsertColumns();
1816 if constexpr (dynamicColumns() && isMutable() && row_features::has_insert) {
1817 return doInsertColumns(column, count, parent, [](
auto &row,
auto it,
int n){
1818 row.insert(it, n, {});
1828 if constexpr (dynamicColumns() && isMutable() && row_features::has_erase) {
1829 if (column < 0 || column + count > columnCount(parent))
1832 range_type *
const children = childRange(parent);
1836 this->beginRemoveColumns(parent, column, column + count - 1);
1837 for (
auto &child : *children) {
1838 const auto start = QRangeModelDetails::pos(child, column);
1839 QRangeModelDetails::refTo(child).erase(start, std::next(start, count));
1841 this->endRemoveColumns();
1847 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
1848 const QModelIndex &destParent,
int destColumn)
1851 if (sourceParent != destParent)
1853 if constexpr (isMutable() && (row_features::has_rotate || row_features::has_splice)) {
1854 if (!Structure::canMoveColumns(sourceParent, destParent))
1860 range_type *
const children = childRange(sourceParent);
1864 if (!
this->beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1,
1865 destParent, destColumn)) {
1869 for (
auto &child : *children)
1870 QRangeModelDetails::rotate(child, sourceColumn, count, destColumn);
1872 this->endMoveColumns();
1879 template <
typename InsertFn>
1880 bool doInsertRows(
int row,
int count,
const QModelIndex &parent, InsertFn &&insertFn)
1882 range_type *children = childRange(parent);
1886 this->beginInsertRows(parent, row, row + count - 1);
1888 row_ptr parentRow = parent.isValid()
1891 (
void)
std::forward<InsertFn>(insertFn)(*children, parentRow, row, count);
1895 that().resetParentInChildren(children);
1897 this->endInsertRows();
1905 return doInsertRows(row, count, parent,
1906 [
this](range_type &children, row_ptr parentRow,
int r,
int n){
1910 if constexpr (range_features::has_insert_range) {
1913 auto start = children.insert(pos, n,
nullptr);
1916 children.insert(pos, n,
std::move(*generator));
1925 bool removeRows(
int row,
int count,
const QModelIndex &parent = {})
1928 const int prevRowCount = rowCount(parent);
1929 if (row < 0 || row + count > prevRowCount)
1932 range_type *children = childRange(parent);
1936 this->beginRemoveRows(parent, row, row + count - 1);
1937 [[maybe_unused]]
bool callEndRemoveColumns =
false;
1941 if (prevRowCount == count) {
1942 if (
const int columns = columnCount(parent)) {
1943 callEndRemoveColumns =
true;
1944 this->beginRemoveColumns(parent, 0, columns - 1);
1950 const auto end =
std::next(begin, count);
1951 that().deleteRemovedRows(begin, end);
1952 children->erase(begin, end);
1956 that().resetParentInChildren(children);
1959 if (callEndRemoveColumns) {
1960 Q_ASSERT(columnCount(parent) == 0);
1961 this->endRemoveColumns();
1964 this->endRemoveRows();
1971 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
1972 const QModelIndex &destParent,
int destRow)
1974 if constexpr (isMutable() && (range_features::has_rotate || range_features::has_splice)) {
1975 if (!Structure::canMoveRows(sourceParent, destParent))
1978 if (sourceParent != destParent) {
1979 return that().moveRowsAcross(sourceParent, sourceRow, count,
1980 destParent, destRow);
1983 if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0
1984 || sourceRow < 0 || sourceRow + count - 1 >=
this->rowCount(sourceParent)
1985 || destRow < 0 || destRow >
this->rowCount(destParent)) {
1989 range_type *source = childRange(sourceParent);
1991 if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow))
1996 that().resetParentInChildren(source);
1998 this->endMoveRows();
2010 int rowCount(
const QModelIndex &parent)
const {
return that().rowCountImpl(parent); }
2012 int columnCount(
const QModelIndex &parent)
const {
return that().columnCountImpl(parent); }
2016 template <
typename BaseMethod,
typename BaseMethod::
template Overridden<
Self> overridden>
2061 static constexpr bool modelCopied = !QRangeModelDetails::is_wrapped<Range>() &&
2062 (std::is_reference_v<Range> || std::is_const_v<std::remove_reference_t<Range>>);
2064 static constexpr bool modelShared = QRangeModelDetails::is_any_shared_ptr<Range>();
2066 static constexpr bool default_row_deleter = protocol_traits::is_default &&
2067 protocol_traits::has_deleteRow;
2069 static constexpr bool ambiguousRowOwnership = (modelCopied || modelShared) &&
2072 static_assert(!ambiguousRowOwnership,
2073 "Using of copied and shared tree and table models with rows as raw pointers, "
2074 "and the default protocol is not allowed due to ambiguity of rows ownership. "
2075 "Move the model in, use another row type, or implement a custom tree protocol.");
2077 if constexpr (protocol_traits::has_deleteRow && !std::is_pointer_v<Range>
2078 && !QRangeModelDetails::is_any_of<Range, std::reference_wrapper>()) {
2079 const auto begin = QRangeModelDetails::begin(*m_data.model());
2080 const auto end = QRangeModelDetails::end(*m_data.model());
2081 that().deleteRemovedRows(begin, end);
2087 if constexpr (dynamicColumns() && !row_features::has_resize) {
2091 }
else if constexpr (!protocol_traits::has_newRow) {
2094 }
else if constexpr (!range_features::has_insert_range
2095 && !std::is_copy_constructible_v<row_type>) {
2101 return Structure::canInsertRowsImpl();
2107 return Structure::canRemoveRowsImpl();
2110 template <
typename F>
2111 bool writeAt(
const QModelIndex &index, F&& writer)
2113 bool result =
false;
2114 row_reference row = rowData(index);
2117 result = writer(row);
2122 QRangeModelImplBase::for_element_at(row, index.column(), [&writer, &result](
auto &&target) {
2123 using target_type =
decltype(target);
2125 if constexpr (std::is_lvalue_reference_v<target_type>
2126 && !std::is_const_v<std::remove_reference_t<target_type>>) {
2127 result = writer(
std::forward<target_type>(target));
2136 template <
typename F>
2137 void readAt(
const QModelIndex &index, F&& reader)
const {
2138 const_row_reference row = rowData(index);
2149 template <
typename Value>
2152 if constexpr (std::is_constructible_v<QVariant, Value>)
2153 return QVariant(value);
2155 return QVariant::fromValue(value);
2157 template <
typename Value>
2161 if constexpr (std::is_constructible_v<QVariant, Value *>)
2162 return QVariant(value);
2164 return read(*value);
2169 template <
typename Target>
2170 static bool write(Target &target,
const QVariant &value)
2172 using Type = std::remove_reference_t<Target>;
2173 if constexpr (std::is_constructible_v<Target, QVariant>) {
2176 }
else if (value.canConvert<Type>()) {
2177 target = value.value<Type>();
2182 template <
typename Target>
2183 static bool write(Target *target,
const QVariant &value)
2186 return write(*target, value);
2190 template <
typename ItemType>
2194 operator QMetaProperty()
const {
2195 const QByteArray roleName = that.itemModel().roleNames().value(role);
2196 const QMetaObject &mo = ItemType::staticMetaObject;
2197 if (
const int index = mo.indexOfProperty(roleName.data());
2199 return mo.property(index);
2203 const QRangeModelImpl &that;
2205 } findProperty{*
this, role};
2207 if constexpr (ModelData::cachesProperties)
2208 return *m_data.properties.tryEmplace(role, findProperty).iterator;
2210 return findProperty;
2213 template <
typename ItemType>
2216 using item_type = std::remove_pointer_t<ItemType>;
2218 QMetaProperty prop = roleProperty<item_type>(role);
2219 if (!prop.isValid() && role == Qt::EditRole)
2220 prop = roleProperty<item_type>(Qt::DisplayRole);
2223 result = readProperty(prop, gadget);
2227 template <
typename ItemType>
2230 return readRole(role, &gadget);
2233 template <
typename ItemType>
2236 if constexpr (std::is_base_of_v<QObject, ItemType>)
2237 return prop.read(gadget);
2239 return prop.readOnGadget(gadget);
2241 template <
typename ItemType>
2244 using item_type = std::remove_pointer_t<ItemType>;
2245 const QMetaObject &mo = item_type::staticMetaObject;
2246 const QMetaProperty prop = mo.property(property + mo.propertyOffset());
2247 return readProperty(prop, gadget);
2250 template <
typename ItemType>
2253 return readProperty(property, &gadget);
2256 template <
typename ItemType>
2257 bool writeRole(
int role, ItemType *gadget,
const QVariant &data)
2259 using item_type = std::remove_pointer_t<ItemType>;
2260 auto prop = roleProperty<item_type>(role);
2261 if (!prop.isValid() && role == Qt::EditRole)
2262 prop = roleProperty<item_type>(Qt::DisplayRole);
2264 return prop.isValid() ? writeProperty(prop, gadget, data) :
false;
2267 template <
typename ItemType>
2268 bool writeRole(
int role, ItemType &&gadget,
const QVariant &data)
2270 return writeRole(role, &gadget, data);
2273 template <
typename ItemType>
2274 static bool writeProperty(
const QMetaProperty &prop, ItemType *gadget,
const QVariant &data)
2276 if constexpr (std::is_base_of_v<QObject, ItemType>)
2277 return prop.write(gadget, data);
2279 return prop.writeOnGadget(gadget, data);
2281 template <
typename ItemType>
2284 using item_type = std::remove_pointer_t<ItemType>;
2285 const QMetaObject &mo = item_type::staticMetaObject;
2286 return writeProperty(mo.property(property + mo.propertyOffset()), gadget, data);
2289 template <
typename ItemType>
2290 static bool writeProperty(
int property, ItemType &&gadget,
const QVariant &data)
2292 return writeProperty(property, &gadget, data);
2295 template <
typename ItemType>
2298 using item_type = std::remove_pointer_t<ItemType>;
2299 const QMetaObject &mo = item_type::staticMetaObject;
2300 bool success =
true;
2301 if (property == -1) {
2303 if constexpr (std::is_base_of_v<QObject, item_type>) {
2304 for (
int p = mo.propertyOffset(); p < mo.propertyCount(); ++p)
2305 success = writeProperty(mo.property(p), object, {}) && success;
2310 success = writeProperty(mo.property(property + mo.propertyOffset()), object, {});
2315 template <
typename ItemType>
2318 return resetProperty(property, &object);
2324 Q_ASSERT(index.isValid());
2325 return that().rowDataImpl(index);
2330 Q_ASSERT(index.isValid());
2331 return that().rowDataImpl(index);
2336 if (!index.isValid())
2337 return m_data.model();
2340 return that().childRangeImpl(index);
2345 if (!index.isValid())
2346 return m_data.model();
2349 return that().childRangeImpl(index);
2359template <
typename Range,
typename Protocol>
2366 using range_type =
typename Base::range_type;
2367 using range_features =
typename Base::range_features;
2368 using row_type =
typename Base::row_type;
2369 using row_ptr =
typename Base::row_ptr;
2370 using const_row_ptr =
typename Base::const_row_ptr;
2372 using tree_traits =
typename Base::protocol_traits;
2373 static constexpr bool is_mutable_impl = tree_traits::has_mutable_childRows;
2375 static constexpr bool rows_are_any_refs_or_pointers = Base::rows_are_raw_pointers ||
2376 QRangeModelDetails::is_smart_ptr<row_type>() ||
2377 QRangeModelDetails::is_any_of<row_type,
std::reference_wrapper>();
2378 static_assert(!Base::dynamicColumns(),
"A tree must have a static number of columns!");
2382 : Base(
std::forward<Range>(model),
std::forward<Protocol>(p), itemModel)
2388 if (!parent.isValid())
2389 return this->createIndex(row, column);
2391 if (parent.column())
2392 return QModelIndex();
2394 const_row_ptr grandParent =
static_cast<const_row_ptr>(parent.constInternalPointer());
2395 const auto &parentSiblings = childrenOf(grandParent);
2402 if (!child.isValid())
2406 const_row_ptr parentRow =
static_cast<const_row_ptr>(child.constInternalPointer());
2411 auto &&grandParent =
this->protocol().parentRow(
QRangeModelDetails::refTo(parentRow));
2412 const range_type &parentSiblings = childrenOf(
QRangeModelDetails::pointerTo(grandParent));
2416 const auto it =
std::find_if(begin, end, [parentRow](
auto &&s){
2420 return this->createIndex(
std::distance(begin, it), 0,
2427 return Base::size(
this->childRange(parent));
2433 if constexpr (Base::one_dimensional_range)
2436 return Base::static_column_count;
2441 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
2449 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2450 && Base::dynamicRows() && range_features::has_insert;
2458 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2459 && Base::dynamicRows() && range_features::has_erase;
2467 static constexpr bool canMoveRows(
const QModelIndex &,
const QModelIndex &)
2473 const QModelIndex &destParent,
int destRow)
2478 if constexpr (!rows_are_any_refs_or_pointers && !tree_traits::has_setParentRow) {
2480 }
else if constexpr (!(range_features::has_insert && range_features::has_erase)) {
2482 }
else if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1,
2483 destParent, destRow)) {
2487 range_type *source =
this->childRange(sourceParent);
2488 range_type *destination =
this->childRange(destParent);
2493 if constexpr (range_features::has_insert_range) {
2495 const auto sourceEnd =
std::next(sourceStart, count);
2497 destination->insert(destStart,
std::move_iterator(sourceStart),
2498 std::move_iterator(sourceEnd));
2499 }
else if constexpr (
std::is_copy_constructible_v<row_type>) {
2501 destination->insert(destStart, count, row_type{});
2504 row_ptr parentRow = destParent.isValid()
2510 if (parentRow ==
static_cast<row_ptr>(sourceParent.internalPointer())) {
2511 if (sourceParent.row() < destRow) {
2512 source =
this->childRange(sourceParent);
2515 source =
this->childRange(
this->createIndex(sourceParent.row() + count, 0,
2516 sourceParent.internalPointer()));
2523 const auto writeEnd =
std::next(writeStart, count);
2525 const auto sourceEnd =
std::next(sourceStart, count);
2527 for (
auto write = writeStart, read = sourceStart; write != writeEnd; ++write, ++read) {
2530 if constexpr (!range_features::has_insert_range)
2531 *write =
std::move(*read);
2535 source->erase(sourceStart, sourceEnd);
2545 this->endMoveRows();
2553 static_assert(tree_traits::has_setParentRow);
2554 row_type empty_row =
this->protocol().newRow();
2560 template <
typename It,
typename Sentinel>
2563 if constexpr (tree_traits::has_deleteRow) {
2564 for (
auto it = begin; it != end; ++it) {
2565 if constexpr (Base::isMutable()) {
2566 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(*it));
2574 this->protocol().deleteRow(
std::move(*it));
2581 if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) {
2584 for (
auto it = begin; it != end; ++it) {
2585 decltype(
auto) maybeChildren =
this->protocol().childRows(*it);
2588 QModelIndexList fromIndexes;
2589 QModelIndexList toIndexes;
2590 fromIndexes.reserve(Base::size(childrenRef));
2591 toIndexes.reserve(Base::size(childrenRef));
2595 for (
auto &child : childrenRef) {
2596 const_row_ptr oldParent =
this->protocol().parentRow(child);
2597 if (oldParent != parentRow) {
2598 fromIndexes.append(
this->createIndex(row, 0, oldParent));
2599 toIndexes.append(
this->createIndex(row, 0, parentRow));
2600 this->protocol().setParentRow(child, parentRow);
2604 this->changePersistentIndexList(fromIndexes, toIndexes);
2613 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
2614 const range_type &siblings = childrenOf(parentRow);
2615 Q_ASSERT(index.row() <
int(Base::size(siblings)));
2621 row_ptr parentRow =
static_cast<row_ptr>(index.internalPointer());
2622 range_type &siblings = childrenOf(parentRow);
2623 Q_ASSERT(index.row() <
int(Base::size(siblings)));
2629 const auto &row =
this->rowData(index);
2631 return static_cast<
const range_type *>(
nullptr);
2633 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
2634 return QRangeModelDetails::pointerTo(std::forward<
decltype(children)>(children));
2639 auto &row =
this->rowData(index);
2641 return static_cast<range_type *>(
nullptr);
2643 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
2644 using Children = std::remove_reference_t<
decltype(children)>;
2646 if constexpr (QRangeModelDetails::is_any_of<Children, std::optional>())
2647 if constexpr (std::is_default_constructible<
typename Children::value_type>()) {
2649 children.emplace(range_type{});
2652 return QRangeModelDetails::pointerTo(std::forward<
decltype(children)>(children));
2658 : *
this->m_data.model();
2662 range_type &childrenOf(row_ptr row)
2665 : *
this->m_data.model();
2670template <
typename Range>
2677 static constexpr bool is_mutable_impl =
true;
2694 if constexpr (Base::dynamicColumns()) {
2695 if (column <
int(Base::size(*QRangeModelDetails::pos(*
this->m_data.model(), row))))
2696 return this->createIndex(row, column);
2699 qCritical(
"QRangeModel: Column-range at row %d is not large enough!", row);
2703 return this->createIndex(row, column);
2714 if (parent.isValid())
2716 return int(Base::size(*
this->m_data.model()));
2721 if (parent.isValid())
2725 if constexpr (Base::dynamicColumns()) {
2726 return int(Base::size(*
this->m_data.model()) == 0
2728 : Base::size(*QRangeModelDetails::begin(*
this->m_data.model())));
2729 }
else if constexpr (Base::one_dimensional_range) {
2730 return row_traits::fixed_size();
2732 return Base::static_column_count;
2738 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren;
2743 return Base::dynamicRows() && range_features::has_insert;
2748 return Base::dynamicRows() && range_features::has_erase;
2751 static constexpr bool canMoveColumns(
const QModelIndex &source,
const QModelIndex &destination)
2753 return !source.isValid() && !destination.isValid();
2756 static constexpr bool canMoveRows(
const QModelIndex &source,
const QModelIndex &destination)
2758 return !source.isValid() && !destination.isValid();
2762 const QModelIndex &,
int)
noexcept
2770 row_type empty_row =
this->protocol().newRow();
2773 if constexpr (Base::dynamicColumns() && row_features::has_resize) {
2781 template <
typename It,
typename Sentinel>
2784 if constexpr (Base::protocol_traits::has_deleteRow) {
2785 for (
auto it = begin; it != end; ++it)
2786 this->protocol().deleteRow(
std::move(*it));
2792 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
2798 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
2815 return *
this->m_data.model();
QModelIndex parentImpl(const QModelIndex &) const
static constexpr bool canMoveRows(const QModelIndex &source, const QModelIndex &destination)
void deleteRemovedRows(It &&begin, Sentinel &&end)
const range_type & childrenOf(const_row_ptr row) const
static constexpr bool canRemoveRowsImpl()
QGenericTableItemModelImpl(Range &&model, QRangeModel *itemModel)
range_type * childRangeImpl(const QModelIndex &)
int columnCountImpl(const QModelIndex &parent) const
constexpr bool moveRowsAcross(const QModelIndex &, int, int, const QModelIndex &, int) noexcept
decltype(auto) rowDataImpl(const QModelIndex &index) const
static constexpr bool canInsertRowsImpl()
const range_type * childRangeImpl(const QModelIndex &) const
int rowCountImpl(const QModelIndex &parent) const
void resetParentInChildren(range_type *)
static constexpr bool canMoveColumns(const QModelIndex &source, const QModelIndex &destination)
decltype(auto) rowDataImpl(const QModelIndex &index)
QModelIndex indexImpl(int row, int column, const QModelIndex &) const
static constexpr Qt::ItemFlags defaultFlags()
auto makeEmptyRow(typename Base::row_ptr)
static constexpr bool canMoveColumns(const QModelIndex &, const QModelIndex &)
auto makeEmptyRow(row_ptr parentRow)
range_type * childRangeImpl(const QModelIndex &index)
bool moveRowsAcross(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destParent, int destRow)
void resetParentInChildren(range_type *children)
int rowCountImpl(const QModelIndex &parent) const
static constexpr bool canRemoveRowsImpl()
int columnCountImpl(const QModelIndex &) const
static constexpr bool canMoveRows(const QModelIndex &, const QModelIndex &)
const range_type & childrenOf(const_row_ptr row) const
decltype(auto) rowDataImpl(const QModelIndex &index)
QGenericTreeItemModelImpl(Range &&model, Protocol &&p, QRangeModel *itemModel)
QModelIndex indexImpl(int row, int column, const QModelIndex &parent) const
void deleteRemovedRows(It &&begin, Sentinel &&end)
const range_type * childRangeImpl(const QModelIndex &index) const
static constexpr bool canInsertRowsImpl()
decltype(auto) rowDataImpl(const QModelIndex &index) const
static constexpr Qt::ItemFlags defaultFlags()
QModelIndex parentImpl(const QModelIndex &child) const
const QAbstractItemModel & itemModel() const
void beginInsertRows(const QModelIndex &parent, int start, int count)
void multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const
bool beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destParent, int destRow)
bool setItemData(const QModelIndex &index, const QMap< int, QVariant > &data)
QMap< int, QVariant > itemData(const QModelIndex &index) const
bool insertRows(int row, int count, const QModelIndex &parent)
static constexpr QMetaType meta_type_at(size_t idx)
Qt::ItemFlags flags(const QModelIndex &index) const
bool beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destParent, int destRow)
void beginRemoveRows(const QModelIndex &parent, int start, int count)
bool clearItemData(const QModelIndex &index)
QVariant data(const QModelIndex &index, int role) const
QRangeModelImplBase(QRangeModel *itemModel)
static auto for_element_at(StaticContainer &&container, std::size_t idx, F &&function)
void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to)
int columnCount(const QModelIndex &parent) const
QModelIndex sibling(int row, int column, const QModelIndex &index) const
void beginInsertColumns(const QModelIndex &parent, int start, int count)
std::tuple< typename C::Destroy, typename C::InvalidateCaches, typename C::SetHeaderData, typename C::SetData, typename C::SetItemData, typename C::ClearItemData, typename C::InsertColumns, typename C::RemoveColumns, typename C::MoveColumns, typename C::InsertRows, typename C::RemoveRows, typename C::MoveRows, typename C::Index, typename C::Parent, typename C::Sibling, typename C::RowCount, typename C::ColumnCount, typename C::Flags, typename C::HeaderData, typename C::Data, typename C::ItemData, typename C::RoleNames, typename C::MultiData > MethodTemplates
bool insertColumns(int column, int count, const QModelIndex &parent)
bool removeRows(int row, int count, const QModelIndex &parent)
QModelIndex parent(const QModelIndex &child) const
QAbstractItemModel & itemModel()
QModelIndex createIndex(int row, int column, const void *ptr=nullptr) const
QHash< int, QByteArray > roleNames() const
bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destParent, int destColumn)
bool setData(const QModelIndex &index, const QVariant &data, int role)
void dataChanged(const QModelIndex &from, const QModelIndex &to, const QList< int > &roles)
QVariant headerData(int section, Qt::Orientation orientation, int role) const
bool removeColumns(int column, int count, const QModelIndex &parent)
QModelIndex index(int row, int column, const QModelIndex &parent) const
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &data, int role)
int rowCount(const QModelIndex &parent) const
void beginRemoveColumns(const QModelIndex &parent, int start, int count)
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destParent, int destRow)
bool removeRows(int row, int count, const QModelIndex &parent={})
static QVariant readProperty(const QMetaProperty &prop, ItemType *gadget)
QHash< int, QByteArray > roleNames() const
row_reference rowData(const QModelIndex &index)
static constexpr bool dynamicRows()
static QVariant read(const Value &value)
const range_type * childRange(const QModelIndex &index) const
bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destParent, int destColumn)
static constexpr bool has_metaobject
QMetaProperty roleProperty(int role) const
QVariant readRole(int role, const ItemType &gadget) const
int columnCount(const QModelIndex &parent) const
bool writeRole(int role, ItemType &&gadget, const QVariant &data)
static bool write(Target *target, const QVariant &value)
Qt::ItemFlags flags(const QModelIndex &index) const
void readAt(const QModelIndex &index, F &&reader) const
bool insertColumns(int column, int count, const QModelIndex &parent)
typename Ancestor::template Override< BaseMethod, overridden > Override
QVariant data(const QModelIndex &index, int role) const
QVariant headerData(int section, Qt::Orientation orientation, int role) const
bool clearItemData(const QModelIndex &index)
void multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const
const protocol_type & protocol() const
static bool resetProperty(int property, ItemType &&object)
QModelIndex sibling(int row, int column, const QModelIndex &index) const
static bool writeProperty(int property, ItemType &&gadget, const QVariant &data)
bool setItemData(const QModelIndex &index, const QMap< int, QVariant > &data)
bool insertRows(int row, int count, const QModelIndex &parent)
static constexpr bool canInsertRows()
static bool writeProperty(const QMetaProperty &prop, ItemType *gadget, const QVariant &data)
static constexpr int size(const C &c)
const_row_reference rowData(const QModelIndex &index) const
bool writeAt(const QModelIndex &index, F &&writer)
static constexpr bool one_dimensional_range
static constexpr bool rows_are_raw_pointers
bool setHeaderData(int, Qt::Orientation, const QVariant &, int)
bool removeColumns(int column, int count, const QModelIndex &parent)
static constexpr bool isMutable()
bool setData(const QModelIndex &index, const QVariant &data, int role)
QModelIndex parent(const QModelIndex &child) const
static QVariant read(Value *value)
static bool write(Target &target, const QVariant &value)
static QVariant readProperty(int property, const ItemType &gadget)
bool writeRole(int role, ItemType *gadget, const QVariant &data)
QRangeModelImpl< Structure, Range, Protocol > Self
static constexpr bool canRemoveRows()
static constexpr int static_column_count
static QVariant readProperty(int property, ItemType *gadget)
protocol_type & protocol()
QtPrivate::QQuasiVirtualSubclass< Self, QRangeModelImplBase > Ancestor
int rowCount(const QModelIndex &parent) const
static constexpr bool rows_are_owning_or_raw_pointers
QModelIndex index(int row, int column, const QModelIndex &parent) const
static constexpr int static_row_count
static bool writeProperty(int property, ItemType *gadget, const QVariant &data)
QRangeModelImpl(Range &&model, Protocol &&protocol, QRangeModel *itemModel)
const Structure & that() const
void updateTarget(LHS *org, RHS &©) noexcept
static constexpr bool dynamicColumns()
range_type * childRange(const QModelIndex &index)
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destParent, int destRow)
QVariant readRole(int role, ItemType *gadget) const
static bool resetProperty(int property, ItemType *object)
bool doInsertColumns(int column, int count, const QModelIndex &parent, InsertFn insertFn)
void updateTarget(LHS &org, RHS &©) noexcept
QMap< int, QVariant > itemData(const QModelIndex &index) const
bool doInsertRows(int row, int count, const QModelIndex &parent, InsertFn &&insertFn)
Method<&QQuasiVirtualInterface::destroy > Destroy
void initCallFN(CallFN func)
QQuasiVirtualInterface()=default
auto call(Args &&... args) const
~QQuasiVirtualInterface()=default
auto call(Args &&... args)
QQuasiVirtualInterface< Interface > base_interface
void(*)(size_t index, base_interface &intf, void *ret, void *args) CallFN
QQuasiVirtualSubclass(Args &&... args)
static auto end(C &&c) -> decltype(std::end(refTo(std::forward< C >(c))))
static constexpr bool has_metaobject_v
static constexpr bool is_range_v
static constexpr bool array_like_v
static void rotate(C &c, int src, int count, int dst)
static constexpr bool tuple_like_v
auto value(It &&it) -> decltype(it.value())
static auto begin(C &&c) -> decltype(std::begin(refTo(std::forward< C >(c))))
auto key(It &&it) -> decltype(it.key())
static constexpr int static_size_v
static constexpr bool isValid(const T &t) noexcept
static auto pos(C &&c, int i)
static decltype(auto) refTo(T &&t)
static auto pointerTo(T &&t)
static constexpr bool is_multi_role_v
void applyIndexSwitch(size_t index, Applier &&applier, std::index_sequence< Is... >)
void applyIndexSwitch(size_t index, Applier &&applier)
auto setParentRow(R &row, R *parent) -> decltype(row.setParentRow(parent))
auto childRows(R &row) -> decltype(row.childRows())
auto childRows(const R &row) const -> decltype(row.childRows())
auto parentRow(const R &row) const -> decltype(row.parentRow())
auto newRow() -> decltype(R{})
static constexpr bool cachesProperties
QHash< int, QMetaProperty > properties
static constexpr bool cachesProperties
std::remove_const_t< ModelStorage > m_model
static constexpr bool int_key
static constexpr bool has_erase
static constexpr bool has_splice
static constexpr bool has_resize
static constexpr bool is_mutable
static constexpr bool has_rotate
static constexpr bool has_cbegin
static constexpr bool has_insert
static constexpr bool is_default
static constexpr bool has_setParentRow
static constexpr bool is_list
static constexpr bool has_mutable_childRows
static constexpr bool has_deleteRow
static constexpr bool has_newRow
static constexpr bool is_tree
static constexpr bool is_table
static constexpr bool has_insert_range
static constexpr bool is_mutable
static constexpr bool has_rotate
static constexpr bool has_resize
static constexpr bool has_insert
static constexpr bool has_cbegin
static constexpr bool has_splice
static constexpr bool has_erase
static constexpr bool isMultiRole
static constexpr int fixed_size()
static constexpr int static_size
static constexpr bool is_range
static constexpr bool hasMetaObject
std::input_iterator_tag iterator_category
friend bool operator==(const EmptyRowGenerator &lhs, const EmptyRowGenerator &rhs) noexcept
friend bool operator!=(const EmptyRowGenerator &lhs, const EmptyRowGenerator &rhs) noexcept
EmptyRowGenerator & operator++()
void operator()(QQuasiVirtualInterface *self) const