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>
854 template <
bool cacheProperties>
876 template <
typename ModelStorage,
typename =
void>
895 template <
typename ModelStorage,
typename ItemType>
903 auto model() {
return pointerTo(
this->m_model); }
904 auto model()
const {
return pointerTo(
this->m_model); }
906 template <
typename Model = ModelStorage>
923 template <
typename StaticContainer,
typename F>
926 using type = std::remove_cv_t<QRangeModelDetails::wrapped_t<StaticContainer>>;
927 static_assert(QRangeModelDetails::array_like_v<type> || QRangeModelDetails::tuple_like_v<type>,
928 "Internal error: expected an array-like or a tuple-like type");
932 if constexpr (QRangeModelDetails::array_like_v<type>) {
933 Q_ASSERT(idx <
std::size(ref));
936 constexpr size_t size = std::tuple_size_v<type>;
937 Q_ASSERT(idx < std::tuple_size_v<type>);
938 QtPrivate::applyIndexSwitch<size>(idx, [&](
auto idxConstant) {
939 function(get<idxConstant>(ref));
947 template <
typename T>
950 using type = QRangeModelDetails::wrapped_t<T>;
951 if constexpr (QRangeModelDetails::array_like_v<type>) {
953 return QMetaType::fromType<std::tuple_element_t<0, type>>();
955 constexpr auto size = std::tuple_size_v<type>;
956 Q_ASSERT(idx < size);
958 QtPrivate::applyIndexSwitch<size>(idx, [&metaType](
auto idxConstant) {
959 using ElementType = std::tuple_element_t<idxConstant.value, type>;
960 metaType = QMetaType::fromType<QRangeModelDetails::wrapped_t<ElementType>>();
970 bool setHeaderData(
int section, Qt::Orientation orientation,
const QVariant &data,
int role);
971 bool setData(
const QModelIndex &index,
const QVariant &data,
int role);
972 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data);
976 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
const QModelIndex &destParent,
int destColumn);
977 bool insertRows(
int row,
int count,
const QModelIndex &parent);
978 bool removeRows(
int row,
int count,
const QModelIndex &parent);
979 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
const QModelIndex &destParent,
int destRow);
992 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const;
1022 template <
typename C>
1051 QRangeModel *m_rangeModel;
1055 : m_rangeModel(itemModel)
1060 inline void dataChanged(
const QModelIndex &from,
const QModelIndex &to,
1061 const QList<
int> &roles);
1066 inline bool beginMoveColumns(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1067 const QModelIndex &destParent,
int destRow);
1069 inline void beginInsertRows(
const QModelIndex &parent,
int start,
int count);
1071 inline void beginRemoveRows(
const QModelIndex &parent,
int start,
int count);
1073 inline bool beginMoveRows(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1074 const QModelIndex &destParent,
int destRow);
1085template <
typename Structure,
typename Range,
1086 typename Protocol = QRangeModelDetails::table_protocol_t<Range>>
1115 "Currently, std::optional is not supported for ranges and rows, as "
1116 "it has range semantics in c++26. Once the required behavior is clarified, "
1117 "std::optional for ranges and rows will be supported.");
1124 Structure&
that() {
return static_cast<Structure &>(*
this); }
1125 const Structure&
that()
const {
return static_cast<
const Structure &>(*
this); }
1127 template <
typename C>
1128 static constexpr int size(
const C &c)
1134 if constexpr (test_size<C>()) {
1135 return int(
std::size(c));
1137#if defined(__cpp_lib_ranges)
1138 using std::ranges::distance;
1140 using std::distance;
1142 using container_type = std::conditional_t<range_traits<C>::has_cbegin,
1145 container_type& container =
const_cast<container_type &>(refTo(c));
1146 return int(distance(
std::begin(container),
std::end(container)));
1152 return range_features::is_mutable && row_features::is_mutable
1153 && std::is_reference_v<row_reference>
1154 && Structure::is_mutable_impl;
1172 template <
typename T>
1192 {
return lhs.n == rhs.n; }
1194 {
return !(lhs == rhs); }
1205 "The range holding a move-only row-type must support insert(pos, start, end)");
1226 if (row < 0 || column < 0 || column >= columnCount(parent)
1227 || row >= rowCount(parent)) {
1231 return that().indexImpl(row, column, parent);
1236 if (row == index.row() && column == index.column())
1239 if (column < 0 || column >=
this->itemModel().columnCount())
1242 if (row == index.row())
1243 return this->createIndex(row, column, index.constInternalPointer());
1245 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
1246 const auto siblingCount = size(that().childrenOf(parentRow));
1247 if (row < 0 || row >=
int(siblingCount))
1249 return this->createIndex(row, column, parentRow);
1254 if (!index.isValid())
1255 return Qt::NoItemFlags;
1257 Qt::ItemFlags f = Structure::defaultFlags();
1259 if constexpr (isMutable()) {
1260 if constexpr (row_traits::hasMetaObject) {
1261 if (index.column() < row_traits::fixed_size()) {
1262 const QMetaObject mo = wrapped_row_type::staticMetaObject;
1263 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
1264 if (prop.isWritable())
1265 f |= Qt::ItemIsEditable;
1268 f |= Qt::ItemIsEditable;
1269 }
else if constexpr (std::is_reference_v<row_reference> && !std::is_const_v<row_reference>) {
1272 const_row_reference row = rowData(index);
1273 row_reference mutableRow =
const_cast<row_reference>(row);
1276 using target_type =
decltype(ref);
1277 if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
1278 f &= ~Qt::ItemIsEditable;
1279 else if constexpr (std::is_lvalue_reference_v<target_type>)
1280 f |= Qt::ItemIsEditable;
1285 f &= ~Qt::ItemIsEditable;
1295 if (role != Qt::DisplayRole || orientation != Qt::Horizontal
1296 || section < 0 || section >= columnCount({})) {
1297 return this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1300 if constexpr (row_traits::hasMetaObject) {
1301 if (row_traits::fixed_size() == 1) {
1302 const QMetaType metaType = QMetaType::fromType<wrapped_row_type>();
1303 result = QString::fromUtf8(metaType.name());
1304 }
else if (section <= row_traits::fixed_size()) {
1305 const QMetaProperty prop = wrapped_row_type::staticMetaObject.property(
1306 section + wrapped_row_type::staticMetaObject.propertyOffset());
1307 result = QString::fromUtf8(prop.name());
1310 if constexpr (QRangeModelDetails::array_like_v<wrapped_row_type>) {
1313 const QMetaType metaType = QRangeModelImplBase::meta_type_at<wrapped_row_type>(section);
1314 if (metaType.isValid())
1315 result = QString::fromUtf8(metaType.name());
1318 if (!result.isValid())
1319 result =
this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1325 if (!index.isValid())
1328 QModelRoleData result(role);
1329 multiData(index, result);
1330 return std::move(result.data());
1335 QMap<
int, QVariant> result;
1337 const auto readItemData = [
this, &result, &tried](
const auto &value){
1339 using value_type = q20::remove_cvref_t<
decltype(value)>;
1340 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1341 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1343 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1344 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1346 const auto roles =
this->itemModel().roleNames().keys();
1347 for (
auto &role : roles) {
1348 if (role == Qt::RangeModelDataRole)
1350 QVariant data = ItemAccess::readRole(value, role);
1352 result[role] =
std::move(data);
1354 }
else if constexpr (multi_role()) {
1356 if constexpr (std::is_convertible_v<value_type,
decltype(result)>) {
1359 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1361 if constexpr (!multi_role::int_key)
1362 return this->itemModel().roleNames();
1366 for (
auto it =
std::begin(value); it !=
std::end(value); ++it) {
1368 Q_UNUSED(roleNames);
1369 if constexpr (multi_role::int_key)
1372 return roleNames.key(key.toUtf8(), -1);
1375 if (role != -1 && role != Qt::RangeModelDataRole)
1379 }
else if constexpr (has_metaobject<value_type>) {
1380 if (row_traits::fixed_size() <= 1) {
1382 const auto roleNames =
this->itemModel().roleNames();
1383 const auto end = roleNames.keyEnd();
1384 for (
auto it = roleNames.keyBegin(); it != end; ++it) {
1385 const int role = *it;
1386 if (role == Qt::RangeModelDataRole)
1390 result[role] =
std::move(data);
1396 if (index.isValid()) {
1397 readAt(index, readItemData);
1400 result =
this->itemModel().QAbstractItemModel::itemData(index);
1405 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const
1408 readAt(index, [
this, &index, roleDataSpan, &tried](
const auto &value) {
1411 using value_type = q20::remove_cvref_t<
decltype(value)>;
1412 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1413 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1415 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1416 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1418 for (
auto &roleData : roleDataSpan) {
1419 if (roleData.role() == Qt::RangeModelDataRole) {
1423 if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
1424 roleData.setData(QVariant::fromValue(QRangeModelDetails::refTo(value)));
1426 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1428 roleData.setData(ItemAccess::readRole(value, roleData.role()));
1431 }
else if constexpr (multi_role()) {
1433 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1435 if constexpr (!multi_role::int_key)
1436 return this->itemModel().roleNames();
1440 using key_type =
typename value_type::key_type;
1441 for (
auto &roleData : roleDataSpan) {
1442 const auto &it = [&roleNames, &value, role = roleData.role()]{
1443 Q_UNUSED(roleNames);
1444 if constexpr (multi_role::int_key)
1445 return value.find(key_type(role));
1447 return value.find(roleNames.value(role));
1449 if (it != QRangeModelDetails::end(value))
1450 roleData.setData(QRangeModelDetails::value(it));
1452 roleData.clearData();
1454 }
else if constexpr (has_metaobject<value_type>) {
1455 if (row_traits::fixed_size() <= 1) {
1457 for (
auto &roleData : roleDataSpan) {
1458 if (roleData.role() == Qt::RangeModelDataRole) {
1462 if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
1463 roleData.setData(QVariant::fromValue(QRangeModelDetails::refTo(value)));
1465 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1467 roleData.setData(readRole(roleData.role(),
1468 QRangeModelDetails::pointerTo(value)));
1471 }
else if (index.column() <= row_traits::fixed_size()) {
1473 for (
auto &roleData : roleDataSpan) {
1474 const int role = roleData.role();
1475 if (role == Qt::DisplayRole || role == Qt::EditRole) {
1476 roleData.setData(readProperty(index.column(),
1477 QRangeModelDetails::pointerTo(value)));
1479 roleData.clearData();
1485 for (
auto &roleData : roleDataSpan) {
1486 const int role = roleData.role();
1487 if (role == Qt::DisplayRole || role == Qt::EditRole
1488 || role == Qt::RangeModelDataRole) {
1489 roleData.setData(read(value));
1491 roleData.clearData();
1500 bool setData(
const QModelIndex &index,
const QVariant &data,
int role)
1502 if (!index.isValid())
1505 bool success =
false;
1506 if constexpr (isMutable()) {
1507 auto emitDataChanged = qScopeGuard([&success,
this, &index, role]{
1509 Q_EMIT
this->dataChanged(index, index,
1510 role == Qt::EditRole || role == Qt::RangeModelDataRole
1511 ? QList<
int>{} : QList<
int>{role});
1515 const auto writeData = [
this, column = index.column(), &data, role](
auto &&target) ->
bool {
1516 using value_type = q20::remove_cvref_t<
decltype(target)>;
1517 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1518 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1520 auto setRangeModelDataRole = [&target, &data]{
1522 constexpr auto targetMetaType = QMetaType::fromType<value_type>();
1523 const auto dataMetaType = data.metaType();
1524 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>) {
1529 }
else if constexpr (QRangeModelDetails::is_wrapped<value_type>()) {
1533 if (
const auto mt = QMetaType::fromType<wrapped_value_type>();
1534 data.canConvert(mt)) {
1535 targetRef = data.value<wrapped_value_type>();
1537 }
else if (
const auto mtp = QMetaType::fromType<wrapped_value_type *>();
1538 data.canConvert(mtp)) {
1539 targetRef = *data.value<wrapped_value_type *>();
1543 }
else if (targetMetaType == dataMetaType) {
1544 targetRef = data.value<value_type>();
1546 }
else if (dataMetaType.flags() & QMetaType::PointerToGadget) {
1547 targetRef = *data.value<value_type *>();
1551 qCritical(
"Not able to assign %s to %s",
1552 qPrintable(QDebug::toString(data)), targetMetaType.name());
1557 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1558 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1559 if (role == Qt::RangeModelDataRole)
1560 return setRangeModelDataRole();
1561 return ItemAccess::writeRole(target, data, role);
1562 }
if constexpr (has_metaobject<value_type>) {
1563 if (row_traits::fixed_size() <= 1) {
1564 if (role == Qt::RangeModelDataRole)
1565 return setRangeModelDataRole();
1567 }
else if (column <= row_traits::fixed_size()
1568 && (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::RangeModelDataRole)) {
1569 return writeProperty(column, QRangeModelDetails::pointerTo(target), data);
1571 }
else if constexpr (multi_role::value) {
1572 Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role);
1575 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1577 if constexpr (!multi_role::int_key)
1578 return this->itemModel().roleNames();
1582 if (role == Qt::EditRole) {
1583 if constexpr (multi_role::int_key) {
1584 if (target.find(roleToSet) == target.end())
1585 roleToSet = Qt::DisplayRole;
1587 if (target.find(roleNames.value(roleToSet)) == target.end())
1588 roleToSet = Qt::DisplayRole;
1591 if constexpr (multi_role::int_key)
1592 return write(target[roleToSet], data);
1594 return write(target[roleNames.value(roleToSet)], data);
1595 }
else if (role == Qt::DisplayRole || role == Qt::EditRole
1596 || role == Qt::RangeModelDataRole) {
1597 return write(target, data);
1602 success = writeAt(index, writeData);
1607 template <
typename LHS,
typename RHS>
1610 if constexpr (
std::is_pointer_v<RHS>) {
1614 if constexpr (
std::is_assignable_v<LHS, RHS>)
1615 org =
std::forward<RHS>(copy);
1620 template <
typename LHS,
typename RHS>
1623 updateTarget(*org,
std::forward<RHS>(copy));
1626 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data)
1628 if (!index.isValid() || data.isEmpty())
1631 bool success =
false;
1632 if constexpr (isMutable()) {
1633 auto emitDataChanged = qScopeGuard([&success,
this, &index, &data]{
1635 Q_EMIT
this->dataChanged(index, index, data.keys());
1639 auto writeItemData = [
this, &tried, &data](
auto &target) ->
bool {
1641 using value_type = q20::remove_cvref_t<
decltype(target)>;
1642 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1643 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1647 auto makeCopy = [](
const value_type &original){
1648 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>)
1650 else if constexpr (std::is_pointer_v<
decltype(original)>)
1652 else if constexpr (std::is_copy_assignable_v<value_type>)
1658 const auto roleNames =
this->itemModel().roleNames();
1660 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1662 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1663 const auto roles = roleNames.keys();
1664 auto targetCopy = makeCopy(target);
1665 for (
int role : roles) {
1666 if (!ItemAccess::writeRole(QRangeModelDetails::refTo(targetCopy),
1667 data.value(role), role)) {
1671 updateTarget(target,
std::move(targetCopy));
1673 }
else if constexpr (multi_role()) {
1674 using key_type =
typename value_type::key_type;
1676 const auto roleName = [&roleNames](
int role) {
1677 return roleNames.value(role);
1682 if constexpr (!multi_role::int_key)
1684 auto invalid =
std::find_if(data.keyBegin(), data.keyEnd(),
1685 [&roleName](
int role) {
return roleName(role).isEmpty(); }
1688 if (invalid != data.keyEnd()) {
1690 qWarning(
"No role name set for %d", *invalid);
1696 for (
auto &&[role, value] : data.asKeyValueRange()) {
1697 if constexpr (multi_role::int_key)
1698 target[
static_cast<key_type>(role)] = value;
1700 target[QString::fromUtf8(roleName(role))] = value;
1703 }
else if constexpr (has_metaobject<value_type>) {
1704 if (row_traits::fixed_size() <= 1) {
1706 auto targetCopy = makeCopy(target);
1707 for (
auto &&[role, value] : data.asKeyValueRange()) {
1708 if (role == Qt::RangeModelDataRole)
1710 if (!writeRole(role, QRangeModelDetails::pointerTo(targetCopy), value)) {
1711 const QByteArray roleName = roleNames.value(role);
1713 qWarning(
"Failed to write value '%s' to role '%s'",
1714 qPrintable(QDebug::toString(value)), roleName.data());
1719 updateTarget(target,
std::move(targetCopy));
1726 success = writeAt(index, writeItemData);
1731 emitDataChanged.dismiss();
1732 success =
this->itemModel().QAbstractItemModel::setItemData(index, data);
1740 if (!index.isValid())
1743 bool success =
false;
1744 if constexpr (isMutable()) {
1745 auto emitDataChanged = qScopeGuard([&success,
this, &index]{
1747 Q_EMIT
this->dataChanged(index, index, {});
1750 auto clearData = [column = index.column()](
auto &&target) {
1751 if constexpr (row_traits::hasMetaObject) {
1752 if (row_traits::fixed_size() <= 1) {
1755 }
else if (column <= row_traits::fixed_size()) {
1756 return resetProperty(column, QRangeModelDetails::pointerTo(target));
1765 success = writeAt(index, clearData);
1773 using item_type =
typename row_traits::item_type;
1774 if constexpr (QRangeModelDetails::has_metaobject_v<item_type>) {
1775 return QRangeModelImplBase::roleNamesForMetaObject(
this->itemModel(),
1776 QRangeModelDetails::wrapped_t<item_type>::staticMetaObject);
1777 }
else if constexpr (std::negation_v<std::disjunction<std::is_void<item_type>,
1778 QRangeModelDetails::is_multi_role<item_type>>>) {
1779 return QRangeModelImplBase::roleNamesForSimpleType();
1782 return this->itemModel().QAbstractItemModel::roleNames();
1786 template <
typename InsertFn>
1791 range_type *
const children = childRange(parent);
1795 this->beginInsertColumns(parent, column, column + count - 1);
1797 for (
auto &child : *children) {
1798 auto it = QRangeModelDetails::pos(child, column);
1799 (
void)insertFn(QRangeModelDetails::refTo(child), it, count);
1802 this->endInsertColumns();
1809 if constexpr (dynamicColumns() && isMutable() && row_features::has_insert) {
1810 return doInsertColumns(column, count, parent, [](
auto &row,
auto it,
int n){
1811 row.insert(it, n, {});
1821 if constexpr (dynamicColumns() && isMutable() && row_features::has_erase) {
1822 if (column < 0 || column + count > columnCount(parent))
1825 range_type *
const children = childRange(parent);
1829 this->beginRemoveColumns(parent, column, column + count - 1);
1830 for (
auto &child : *children) {
1831 const auto start = QRangeModelDetails::pos(child, column);
1832 QRangeModelDetails::refTo(child).erase(start, std::next(start, count));
1834 this->endRemoveColumns();
1840 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
1841 const QModelIndex &destParent,
int destColumn)
1844 if (sourceParent != destParent)
1846 if constexpr (isMutable() && (row_features::has_rotate || row_features::has_splice)) {
1847 if (!Structure::canMoveColumns(sourceParent, destParent))
1853 range_type *
const children = childRange(sourceParent);
1857 if (!
this->beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1,
1858 destParent, destColumn)) {
1862 for (
auto &child : *children)
1863 QRangeModelDetails::rotate(child, sourceColumn, count, destColumn);
1865 this->endMoveColumns();
1872 template <
typename InsertFn>
1873 bool doInsertRows(
int row,
int count,
const QModelIndex &parent, InsertFn &&insertFn)
1875 range_type *children = childRange(parent);
1879 this->beginInsertRows(parent, row, row + count - 1);
1881 row_ptr parentRow = parent.isValid()
1884 (
void)
std::forward<InsertFn>(insertFn)(*children, parentRow, row, count);
1888 that().resetParentInChildren(children);
1890 this->endInsertRows();
1898 return doInsertRows(row, count, parent,
1899 [
this](range_type &children, row_ptr parentRow,
int r,
int n){
1903 if constexpr (range_features::has_insert_range) {
1906 auto start = children.insert(pos, n,
nullptr);
1909 children.insert(pos, n,
std::move(*generator));
1918 bool removeRows(
int row,
int count,
const QModelIndex &parent = {})
1921 const int prevRowCount = rowCount(parent);
1922 if (row < 0 || row + count > prevRowCount)
1925 range_type *children = childRange(parent);
1929 this->beginRemoveRows(parent, row, row + count - 1);
1930 [[maybe_unused]]
bool callEndRemoveColumns =
false;
1934 if (prevRowCount == count) {
1935 if (
const int columns = columnCount(parent)) {
1936 callEndRemoveColumns =
true;
1937 this->beginRemoveColumns(parent, 0, columns - 1);
1943 const auto end =
std::next(begin, count);
1944 that().deleteRemovedRows(begin, end);
1945 children->erase(begin, end);
1949 that().resetParentInChildren(children);
1952 if (callEndRemoveColumns) {
1953 Q_ASSERT(columnCount(parent) == 0);
1954 this->endRemoveColumns();
1957 this->endRemoveRows();
1964 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
1965 const QModelIndex &destParent,
int destRow)
1967 if constexpr (isMutable() && (range_features::has_rotate || range_features::has_splice)) {
1968 if (!Structure::canMoveRows(sourceParent, destParent))
1971 if (sourceParent != destParent) {
1972 return that().moveRowsAcross(sourceParent, sourceRow, count,
1973 destParent, destRow);
1976 if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0
1977 || sourceRow < 0 || sourceRow + count - 1 >=
this->itemModel().rowCount(sourceParent)
1978 || destRow < 0 || destRow >
this->itemModel().rowCount(destParent)) {
1982 range_type *source = childRange(sourceParent);
1984 if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow))
1989 that().resetParentInChildren(source);
1991 this->endMoveRows();
2000 int rowCount(
const QModelIndex &parent)
const {
return that().rowCount(parent); }
2002 int columnCount(
const QModelIndex &parent)
const {
return that().columnCount(parent); }
2006 template <
typename BaseMethod,
typename BaseMethod::
template Overridden<
Self> overridden>
2046 static constexpr bool modelCopied = !QRangeModelDetails::is_wrapped<Range>() &&
2047 (std::is_reference_v<Range> || std::is_const_v<std::remove_reference_t<Range>>);
2049 static constexpr bool modelShared = QRangeModelDetails::is_any_shared_ptr<Range>();
2051 static constexpr bool default_row_deleter = protocol_traits::is_default &&
2052 protocol_traits::has_deleteRow;
2054 static constexpr bool ambiguousRowOwnership = (modelCopied || modelShared) &&
2057 static_assert(!ambiguousRowOwnership,
2058 "Using of copied and shared tree and table models with rows as raw pointers, "
2059 "and the default protocol is not allowed due to ambiguity of rows ownership. "
2060 "Move the model in, use another row type, or implement a custom tree protocol.");
2062 if constexpr (protocol_traits::has_deleteRow && !std::is_pointer_v<Range>
2063 && !QRangeModelDetails::is_any_of<Range, std::reference_wrapper>()) {
2064 const auto begin = QRangeModelDetails::begin(*m_data.model());
2065 const auto end = QRangeModelDetails::end(*m_data.model());
2066 that().deleteRemovedRows(begin, end);
2072 if constexpr (dynamicColumns() && !row_features::has_resize) {
2076 }
else if constexpr (!protocol_traits::has_newRow) {
2079 }
else if constexpr (!range_features::has_insert_range
2080 && !std::is_copy_constructible_v<row_type>) {
2086 return Structure::canInsertRowsImpl();
2092 return Structure::canRemoveRowsImpl();
2095 template <
typename F>
2096 bool writeAt(
const QModelIndex &index, F&& writer)
2098 bool result =
false;
2099 row_reference row = rowData(index);
2102 result = writer(row);
2107 QRangeModelImplBase::for_element_at(row, index.column(), [&writer, &result](
auto &&target) {
2108 using target_type =
decltype(target);
2110 if constexpr (std::is_lvalue_reference_v<target_type>
2111 && !std::is_const_v<std::remove_reference_t<target_type>>) {
2112 result = writer(
std::forward<target_type>(target));
2121 template <
typename F>
2122 void readAt(
const QModelIndex &index, F&& reader)
const {
2123 const_row_reference row = rowData(index);
2134 template <
typename Value>
2137 if constexpr (std::is_constructible_v<QVariant, Value>)
2138 return QVariant(value);
2140 return QVariant::fromValue(value);
2142 template <
typename Value>
2146 if constexpr (std::is_constructible_v<QVariant, Value *>)
2147 return QVariant(value);
2149 return read(*value);
2154 template <
typename Target>
2155 static bool write(Target &target,
const QVariant &value)
2157 using Type = std::remove_reference_t<Target>;
2158 if constexpr (std::is_constructible_v<Target, QVariant>) {
2161 }
else if (value.canConvert<Type>()) {
2162 target = value.value<Type>();
2167 template <
typename Target>
2168 static bool write(Target *target,
const QVariant &value)
2171 return write(*target, value);
2175 template <
typename ItemType>
2179 operator QMetaProperty()
const {
2180 const QByteArray roleName = that.itemModel().roleNames().value(role);
2181 const QMetaObject &mo = ItemType::staticMetaObject;
2182 if (
const int index = mo.indexOfProperty(roleName.data());
2184 return mo.property(index);
2188 const QRangeModelImpl &that;
2190 } findProperty{*
this, role};
2192 if constexpr (ModelData::cachesProperties)
2193 return *m_data.properties.tryEmplace(role, findProperty).iterator;
2195 return findProperty;
2198 template <
typename ItemType>
2201 using item_type = std::remove_pointer_t<ItemType>;
2203 QMetaProperty prop = roleProperty<item_type>(role);
2204 if (!prop.isValid() && role == Qt::EditRole)
2205 prop = roleProperty<item_type>(Qt::DisplayRole);
2208 result = readProperty(prop, gadget);
2212 template <
typename ItemType>
2215 return readRole(role, &gadget);
2218 template <
typename ItemType>
2221 if constexpr (std::is_base_of_v<QObject, ItemType>)
2222 return prop.read(gadget);
2224 return prop.readOnGadget(gadget);
2226 template <
typename ItemType>
2229 using item_type = std::remove_pointer_t<ItemType>;
2230 const QMetaObject &mo = item_type::staticMetaObject;
2231 const QMetaProperty prop = mo.property(property + mo.propertyOffset());
2232 return readProperty(prop, gadget);
2235 template <
typename ItemType>
2238 return readProperty(property, &gadget);
2241 template <
typename ItemType>
2242 bool writeRole(
int role, ItemType *gadget,
const QVariant &data)
2244 using item_type = std::remove_pointer_t<ItemType>;
2245 auto prop = roleProperty<item_type>(role);
2246 if (!prop.isValid() && role == Qt::EditRole)
2247 prop = roleProperty<item_type>(Qt::DisplayRole);
2249 return prop.isValid() ? writeProperty(prop, gadget, data) :
false;
2252 template <
typename ItemType>
2253 bool writeRole(
int role, ItemType &&gadget,
const QVariant &data)
2255 return writeRole(role, &gadget, data);
2258 template <
typename ItemType>
2259 static bool writeProperty(
const QMetaProperty &prop, ItemType *gadget,
const QVariant &data)
2261 if constexpr (std::is_base_of_v<QObject, ItemType>)
2262 return prop.write(gadget, data);
2264 return prop.writeOnGadget(gadget, data);
2266 template <
typename ItemType>
2269 using item_type = std::remove_pointer_t<ItemType>;
2270 const QMetaObject &mo = item_type::staticMetaObject;
2271 return writeProperty(mo.property(property + mo.propertyOffset()), gadget, data);
2274 template <
typename ItemType>
2275 static bool writeProperty(
int property, ItemType &&gadget,
const QVariant &data)
2277 return writeProperty(property, &gadget, data);
2280 template <
typename ItemType>
2283 using item_type = std::remove_pointer_t<ItemType>;
2284 const QMetaObject &mo = item_type::staticMetaObject;
2285 bool success =
true;
2286 if (property == -1) {
2288 if constexpr (std::is_base_of_v<QObject, item_type>) {
2289 for (
int p = mo.propertyOffset(); p < mo.propertyCount(); ++p)
2290 success = writeProperty(mo.property(p), object, {}) && success;
2295 success = writeProperty(mo.property(property + mo.propertyOffset()), object, {});
2300 template <
typename ItemType>
2303 return resetProperty(property, &object);
2309 Q_ASSERT(index.isValid());
2310 return that().rowDataImpl(index);
2315 Q_ASSERT(index.isValid());
2316 return that().rowDataImpl(index);
2321 if (!index.isValid())
2322 return m_data.model();
2325 return that().childRangeImpl(index);
2330 if (!index.isValid())
2331 return m_data.model();
2334 return that().childRangeImpl(index);
2347template <
typename Range,
typename Protocol>
2354 using range_type =
typename Base::range_type;
2355 using range_features =
typename Base::range_features;
2356 using row_type =
typename Base::row_type;
2357 using row_ptr =
typename Base::row_ptr;
2358 using const_row_ptr =
typename Base::const_row_ptr;
2360 using tree_traits =
typename Base::protocol_traits;
2361 static constexpr bool is_mutable_impl = tree_traits::has_mutable_childRows;
2363 static constexpr bool rows_are_any_refs_or_pointers = Base::rows_are_raw_pointers ||
2364 QRangeModelDetails::is_smart_ptr<row_type>() ||
2365 QRangeModelDetails::is_any_of<row_type,
std::reference_wrapper>();
2366 static_assert(!Base::dynamicColumns(),
"A tree must have a static number of columns!");
2370 : Base(
std::forward<Range>(model),
std::forward<Protocol>(p), itemModel)
2376 if (!parent.isValid())
2377 return this->createIndex(row, column);
2379 if (parent.column())
2380 return QModelIndex();
2382 const_row_ptr grandParent =
static_cast<const_row_ptr>(parent.constInternalPointer());
2383 const auto &parentSiblings = childrenOf(grandParent);
2390 if (!child.isValid())
2394 const_row_ptr parentRow =
static_cast<const_row_ptr>(child.constInternalPointer());
2399 auto &&grandParent =
this->protocol().parentRow(
QRangeModelDetails::refTo(parentRow));
2400 const range_type &parentSiblings = childrenOf(
QRangeModelDetails::pointerTo(grandParent));
2404 const auto it =
std::find_if(begin, end, [parentRow](
auto &&s){
2408 return this->createIndex(
std::distance(begin, it), 0,
2415 return Base::size(
this->childRange(parent));
2421 if constexpr (Base::one_dimensional_range)
2424 return Base::static_column_count;
2429 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
2437 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2438 && Base::dynamicRows() && range_features::has_insert;
2446 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2447 && Base::dynamicRows() && range_features::has_erase;
2455 static constexpr bool canMoveRows(
const QModelIndex &,
const QModelIndex &)
2461 const QModelIndex &destParent,
int destRow)
2466 if constexpr (!rows_are_any_refs_or_pointers && !tree_traits::has_setParentRow) {
2468 }
else if constexpr (!(range_features::has_insert && range_features::has_erase)) {
2470 }
else if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1,
2471 destParent, destRow)) {
2475 range_type *source =
this->childRange(sourceParent);
2476 range_type *destination =
this->childRange(destParent);
2481 if constexpr (range_features::has_insert_range) {
2483 const auto sourceEnd =
std::next(sourceStart, count);
2485 destination->insert(destStart,
std::move_iterator(sourceStart),
2486 std::move_iterator(sourceEnd));
2487 }
else if constexpr (
std::is_copy_constructible_v<row_type>) {
2489 destination->insert(destStart, count, row_type{});
2492 row_ptr parentRow = destParent.isValid()
2498 if (parentRow ==
static_cast<row_ptr>(sourceParent.internalPointer())) {
2499 if (sourceParent.row() < destRow) {
2500 source =
this->childRange(sourceParent);
2503 source =
this->childRange(
this->createIndex(sourceParent.row() + count, 0,
2504 sourceParent.internalPointer()));
2511 const auto writeEnd =
std::next(writeStart, count);
2513 const auto sourceEnd =
std::next(sourceStart, count);
2515 for (
auto write = writeStart, read = sourceStart; write != writeEnd; ++write, ++read) {
2518 if constexpr (!range_features::has_insert_range)
2519 *write =
std::move(*read);
2523 source->erase(sourceStart, sourceEnd);
2533 this->endMoveRows();
2541 static_assert(tree_traits::has_setParentRow);
2542 row_type empty_row =
this->protocol().newRow();
2548 template <
typename It,
typename Sentinel>
2551 if constexpr (tree_traits::has_deleteRow) {
2552 for (
auto it = begin; it != end; ++it) {
2553 if constexpr (Base::isMutable()) {
2554 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(*it));
2562 this->protocol().deleteRow(
std::move(*it));
2569 if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) {
2572 for (
auto it = begin; it != end; ++it) {
2573 decltype(
auto) maybeChildren =
this->protocol().childRows(*it);
2576 QModelIndexList fromIndexes;
2577 QModelIndexList toIndexes;
2578 fromIndexes.reserve(Base::size(childrenRef));
2579 toIndexes.reserve(Base::size(childrenRef));
2583 for (
auto &child : childrenRef) {
2584 const_row_ptr oldParent =
this->protocol().parentRow(child);
2585 if (oldParent != parentRow) {
2586 fromIndexes.append(
this->createIndex(row, 0, oldParent));
2587 toIndexes.append(
this->createIndex(row, 0, parentRow));
2588 this->protocol().setParentRow(child, parentRow);
2592 this->changePersistentIndexList(fromIndexes, toIndexes);
2601 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
2602 const range_type &siblings = childrenOf(parentRow);
2603 Q_ASSERT(index.row() <
int(Base::size(siblings)));
2609 row_ptr parentRow =
static_cast<row_ptr>(index.internalPointer());
2610 range_type &siblings = childrenOf(parentRow);
2611 Q_ASSERT(index.row() <
int(Base::size(siblings)));
2617 const auto &row =
this->rowData(index);
2619 return static_cast<
const range_type *>(
nullptr);
2621 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
2622 return QRangeModelDetails::pointerTo(std::forward<
decltype(children)>(children));
2627 auto &row =
this->rowData(index);
2629 return static_cast<range_type *>(
nullptr);
2631 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
2632 using Children = std::remove_reference_t<
decltype(children)>;
2634 if constexpr (QRangeModelDetails::is_any_of<Children, std::optional>())
2635 if constexpr (std::is_default_constructible<
typename Children::value_type>()) {
2637 children.emplace(range_type{});
2640 return QRangeModelDetails::pointerTo(std::forward<
decltype(children)>(children));
2646 : *
this->m_data.model();
2650 range_type &childrenOf(row_ptr row)
2653 : *
this->m_data.model();
2658template <
typename Range>
2672 static constexpr bool is_mutable_impl =
true;
2682 if constexpr (Base::dynamicColumns()) {
2683 if (column <
int(Base::size(*QRangeModelDetails::pos(*
this->m_data.model(), row))))
2684 return this->createIndex(row, column);
2687 qCritical(
"QRangeModel: Column-range at row %d is not large enough!", row);
2691 return this->createIndex(row, column);
2702 if (parent.isValid())
2704 return int(Base::size(*
this->m_data.model()));
2709 if (parent.isValid())
2713 if constexpr (Base::dynamicColumns()) {
2714 return int(Base::size(*
this->m_data.model()) == 0
2716 : Base::size(*QRangeModelDetails::begin(*
this->m_data.model())));
2717 }
else if constexpr (Base::one_dimensional_range) {
2718 return row_traits::fixed_size();
2720 return Base::static_column_count;
2726 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren;
2731 return Base::dynamicRows() && range_features::has_insert;
2736 return Base::dynamicRows() && range_features::has_erase;
2739 static constexpr bool canMoveColumns(
const QModelIndex &source,
const QModelIndex &destination)
2741 return !source.isValid() && !destination.isValid();
2744 static constexpr bool canMoveRows(
const QModelIndex &source,
const QModelIndex &destination)
2746 return !source.isValid() && !destination.isValid();
2750 const QModelIndex &,
int)
noexcept
2758 row_type empty_row =
this->protocol().newRow();
2761 if constexpr (Base::dynamicColumns() && row_features::has_resize) {
2769 template <
typename It,
typename Sentinel>
2772 if constexpr (Base::protocol_traits::has_deleteRow) {
2773 for (
auto it = begin; it != end; ++it)
2774 this->protocol().deleteRow(
std::move(*it));
2780 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
2786 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
2803 return *
this->m_data.model();
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)
QModelIndex parent(const QModelIndex &) const
int rowCount(const QModelIndex &parent) const
range_type * childRangeImpl(const QModelIndex &)
constexpr bool moveRowsAcross(const QModelIndex &, int, int, const QModelIndex &, int) noexcept
decltype(auto) rowDataImpl(const QModelIndex &index) const
static constexpr bool canInsertRowsImpl()
int columnCount(const QModelIndex &parent) const
const range_type * childRangeImpl(const QModelIndex &) 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)
int columnCount(const QModelIndex &) const
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)
static constexpr bool canRemoveRowsImpl()
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()
int rowCount(const QModelIndex &parent) const
decltype(auto) rowDataImpl(const QModelIndex &index) const
static constexpr Qt::ItemFlags defaultFlags()
QModelIndex parent(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 has_mutable_childRows
static constexpr bool has_deleteRow
static constexpr bool has_newRow
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