4#ifndef QGENERICITEMMODEL_IMPL_H
5#define QGENERICITEMMODEL_IMPL_H
9#ifndef QGENERICITEMMODEL_H
10#error Do not include qgenericitemmodel_impl.h directly
14#pragma qt_sync_skip_header_check
15#pragma qt_sync_stop_processing
18#include <QtCore/qabstractitemmodel.h>
19#include <QtCore/qmetaobject.h>
20#include <QtCore/qvariant.h>
21#include <QtCore/qmap.h>
27#include <QtCore/q20type_traits.h>
29#include <QtCore/q23utility.h>
35 template <
typename T,
template <
typename...>
typename... Templates>
38 template <
template <
typename...>
typename Template,
40 template <
typename...>
typename...
Templates>
44 template <
typename...>
typename Template,
45 template <
typename...>
typename...
Templates>
48 template <
typename T,
template <
typename...>
typename...
Templates>
52 using is_validatable =
std::is_constructible<
bool, T>;
54 template <
typename T,
typename =
void>
82 using Type = q20::remove_cvref_t<T>;
83 if constexpr (is_any_of<Type, std::optional>())
84 return t ?
std::addressof(*
std::forward<T>(t)) :
nullptr;
85 else if constexpr (std::is_pointer<Type>())
87 else if constexpr (is_smart_ptr<Type>())
89 else if constexpr (is_any_of<Type, std::reference_wrapper>())
90 return std::addressof(t.get());
92 return std::addressof(
std::forward<T>(t));
101 template <
typename T>
102 static constexpr bool isValid(
const T &t)
noexcept
104 if constexpr (is_validatable<T>())
110 template <
typename T>
111 static decltype(
auto)
refTo(T&& t) {
112 Q_ASSERT(isValid(t));
114 using Type = q20::remove_cvref_t<T>;
115 if constexpr (is_any_of<T, std::optional>())
116 return *
std::forward<T>(t);
117 if constexpr (!is_wrapped<Type>() || is_any_unique_ptr<Type>())
118 return q23::forward_like<T>(*pointerTo(t));
120 return *pointerTo(t);
123 template <
typename It>
124 auto key(It&& it) ->
decltype(it.key()) {
return it.key(); }
125 template <
typename It>
126 auto key(It&& it) ->
decltype((it->first)) {
return it->first; }
128 template <
typename It>
129 auto value(It&& it) ->
decltype(it.value()) {
return it.value(); }
130 template <
typename It>
131 auto value(It&& it) ->
decltype((it->second)) {
return it->second; }
134 template <
typename C>
135 static auto begin(C &&c) ->
decltype(
std::begin(refTo(
std::forward<C>(c))))
136 {
return std::begin(refTo(
std::forward<C>(c))); }
137 template <
typename C>
138 static auto end(C &&c) ->
decltype(
std::end(refTo(
std::forward<C>(c))))
139 {
return std::end(refTo(
std::forward<C>(c))); }
140 template <
typename C>
141 static auto cbegin(C &&c) ->
decltype(
std::cbegin(refTo(
std::forward<C>(c))))
142 {
return std::cbegin(refTo(
std::forward<C>(c))); }
143 template <
typename C>
144 static auto cend(C &&c) ->
decltype(
std::cend(refTo(
std::forward<C>(c))))
145 {
return std::cend(refTo(
std::forward<C>(c))); }
146 template <
typename C>
147 static auto pos(C &&c,
int i)
149 template <
typename C>
158 template <
typename C,
typename =
void>
161 template <
typename C>
172 template <
typename C,
typename =
void>
175 template <
typename C>
184 template <
typename C,
typename =
void>
187 template <
typename C>
195 template <
typename C,
typename =
void>
198 template <
typename C>
215 template <
typename C>
224 template <
typename C>
228 template <
typename C,
typename =
void>
230 template <
typename C>
233 template <
typename C,
typename =
void>
241 template <
typename C>
276 template <
typename C>
282 template <
typename T,
typename =
void>
293 template <
typename T>
312 template <
class... Ts>
struct make_void {
using type =
void; };
314 template <
typename T>
321 static const int columnCount = []{
322 const QMetaObject &mo = T::staticMetaObject;
323 return mo.propertyCount() - mo.propertyOffset();
329 template <
typename T>
335 template <
typename T,
typename =
void>
337 template <
typename T>
341 template <
typename T>
344 template <
typename Range>
350 auto newRow() ->
decltype(R{}) {
return R{}; }
353 template <
typename Range>
384 template <
typename Range>
387 template <
typename R >
388 auto parentRow(
const R& row)
const ->
decltype(row.parentRow())
390 return row.parentRow();
393 template <
typename R >
394 auto setParentRow(R &row, R* parent) ->
decltype(row.setParentRow(parent))
396 row.setParentRow(parent);
399 template <
typename R >
400 auto childRows(
const R &row)
const ->
decltype(row.childRows())
402 return row.childRows();
405 template <
typename R >
408 return row.childRows();
412 template <
typename P,
typename R,
typename =
void>
414 template <
typename P,
typename R>
419 template <
typename P,
typename R,
typename =
void>
421 template <
typename P,
typename R>
426 template <
typename P,
typename R,
typename =
void>
428 template <
typename P,
typename R>
434 template <
typename P,
typename R,
typename =
void>
436 template <
typename P,
typename R>
442 template <
typename P,
typename =
void>
444 template <
typename P>
448 template <
typename P,
typename R,
typename =
void>
450 template <
typename P,
typename R>
455 template <
typename Range,
467 template <
typename Range>
477 template <
typename Range,
typename Protocol>
494 template <
typename ModelStorage>
504class QGenericItemModel;
517 :
static_cast<
void>(0)), ...);
520 template <
typename T,
typename F>
537 template <
typename T>
552 template <
typename Ret,
typename Class,
typename ...
Args>
560 template <
typename Ret,
typename Class,
typename ...
Args>
606 using CallTupleFN =
decltype(call);
608 CallConstFN *callConst_fn;
609 CallTupleFN *call_fn;
610 QGenericItemModel *m_itemModel;
613 template <
typename Impl>
622 inline void dataChanged(
const QModelIndex &from,
const QModelIndex &to,
623 const QList<
int> &roles);
628 inline bool beginMoveColumns(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
629 const QModelIndex &destParent,
int destRow);
631 inline void beginInsertRows(
const QModelIndex &parent,
int start,
int count);
633 inline void beginRemoveRows(
const QModelIndex &parent,
int start,
int count);
635 inline bool beginMoveRows(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
636 const QModelIndex &destParent,
int destRow);
642 template <
typename Ret,
typename ...Args>
646 const auto tuple =
std::tie(args...);
647 callConst_fn(op,
this, &ret, &tuple);
651 template <
typename Ret,
typename ...Args>
655 const auto tuple =
std::tie(args...);
656 call_fn(op,
this, &ret, &tuple);
661template <
typename Structure,
typename Range,
662 typename Protocol = QGenericItemModelDetails::table_protocol_t<Range>>
675 "Currently, std::optional is not supported for ranges and rows, as "
676 "it has range semantics in c++26. Once the required behavior is clarified, "
677 "std::optional for ranges and rows will be supported.");
681 Structure&
that() {
return static_cast<Structure &>(*
this); }
682 const Structure&
that()
const {
return static_cast<
const Structure &>(*
this); }
684 template <
typename C>
685 static constexpr int size(
const C &c)
690 if constexpr (QGenericItemModelDetails::test_size<C>()) {
691 return int(
std::size(c));
693#if defined(__cpp_lib_ranges)
694 return int(std::ranges::distance(QGenericItemModelDetails::begin(c),
695 QGenericItemModelDetails::end(c)));
711 return range_features::is_mutable && row_features::is_mutable
712 && std::is_reference_v<row_reference>
713 && Structure::is_mutable_impl;
731 template <
typename T>
750 using iterator_category =
std::input_iterator_tag;
751 using difference_type =
int;
756 {
return lhs.n == rhs.n; }
758 {
return !(lhs == rhs); }
760 difference_type
n = 0;
769 "The range holding a move-only row-type must support insert(pos, start, end)");
783 case Index: makeCall(that, &Self::index, r, args);
785 case Parent: makeCall(that, &Structure::parent, r, args);
787 case Sibling: makeCall(that, &Self::sibling, r, args);
789 case RowCount: makeCall(that, &Structure::rowCount, r, args);
791 case ColumnCount: makeCall(that, &Structure::columnCount, r, args);
793 case Flags: makeCall(that, &Self::flags, r, args);
795 case HeaderData: makeCall(that, &Self::headerData, r, args);
797 case Data: makeCall(that, &Self::data, r, args);
799 case ItemData: makeCall(that, &Self::itemData, r, args);
807 case Destroy:
delete static_cast<Structure *>(that);
809 case SetData: makeCall(that, &Self::setData, r, args);
811 case SetItemData: makeCall(that, &Self::setItemData, r, args);
813 case ClearItemData: makeCall(that, &Self::clearItemData, r, args);
815 case InsertColumns: makeCall(that, &Self::insertColumns, r, args);
817 case RemoveColumns: makeCall(that, &Self::removeColumns, r, args);
819 case MoveColumns: makeCall(that, &Self::moveColumns, r, args);
821 case InsertRows: makeCall(that, &Self::insertRows, r, args);
823 case RemoveRows: makeCall(that, &Self::removeRows, r, args);
825 case MoveRows: makeCall(that, &Self::moveRows, r, args);
833 if (row < 0 || column < 0 || column >= that().columnCount(parent)
834 || row >= that().rowCount(parent)) {
838 return that().indexImpl(row, column, parent);
843 if (row == index.row() && column == index.column())
846 if (column < 0 || column >= itemModel().columnCount())
849 if (row == index.row())
850 return createIndex(row, column, index.constInternalPointer());
852 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
853 const auto siblingCount = size(that().childrenOf(parentRow));
854 if (row < 0 || row >=
int(siblingCount))
856 return createIndex(row, column, parentRow);
861 if (!index.isValid())
862 return Qt::NoItemFlags;
864 Qt::ItemFlags f = Structure::defaultFlags();
866 if constexpr (has_metaobject<wrapped_row_type>) {
867 if (index.column() < row_traits::fixed_size()) {
868 const QMetaObject mo = wrapped_row_type::staticMetaObject;
869 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
870 if (prop.isWritable())
871 f |= Qt::ItemIsEditable;
874 if constexpr (isMutable())
875 f |= Qt::ItemIsEditable;
876 }
else if constexpr (std::is_reference_v<row_reference> && !std::is_const_v<row_reference>) {
879 const_row_reference row = rowData(index);
880 row_reference mutableRow =
const_cast<row_reference>(row);
882 for_element_at(mutableRow, index.column(), [&f](
auto &&ref){
883 using target_type =
decltype(ref);
884 if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
885 f &= ~Qt::ItemIsEditable;
886 else if constexpr (std::is_lvalue_reference_v<target_type>)
887 f |= Qt::ItemIsEditable;
892 f &= ~Qt::ItemIsEditable;
901 if (role != Qt::DisplayRole || orientation != Qt::Horizontal
902 || section < 0 || section >= that().columnCount({})) {
903 return itemModel().QAbstractItemModel::headerData(section, orientation, role);
906 if constexpr (has_metaobject<wrapped_row_type>) {
907 if (row_traits::fixed_size() == 1) {
908 const QMetaType metaType = QMetaType::fromType<wrapped_row_type>();
909 result = QString::fromUtf8(metaType.name());
910 }
else if (section <= row_traits::fixed_size()) {
911 const QMetaProperty prop = wrapped_row_type::staticMetaObject.property(
912 section + wrapped_row_type::staticMetaObject.propertyOffset());
913 result = QString::fromUtf8(prop.name());
916 const QMetaType metaType = meta_type_at<row_type>(section);
917 if (metaType.isValid())
918 result = QString::fromUtf8(metaType.name());
920 if (!result.isValid())
921 result = itemModel().QAbstractItemModel::headerData(section, orientation, role);
928 const auto readData = [
this, column = index.column(), &result, role](
const auto &value) {
930 using value_type = q20::remove_cvref_t<
decltype(value)>;
931 using multi_role = QGenericItemModelDetails::is_multi_role<value_type>;
932 if constexpr (has_metaobject<value_type>) {
933 if (row_traits::fixed_size() <= 1) {
935 }
else if (column <= row_traits::fixed_size()
936 && (role == Qt::DisplayRole || role == Qt::EditRole)) {
937 result = readProperty(column, QGenericItemModelDetails::pointerTo(value));
939 }
else if constexpr (multi_role::value) {
940 const auto it = [
this, &value, role]{
942 if constexpr (multi_role::int_key)
943 return std::as_const(value).find(Qt::ItemDataRole(role));
945 return std::as_const(value).find(roleNames().value(role));
947 if (it != value.cend()) {
950 }
else if (role == Qt::DisplayRole || role == Qt::EditRole) {
951 result = read(value);
956 readAt(index, readData);
963 QMap<
int, QVariant> result;
965 const auto readItemData = [
this, &result, &tried](
auto &&value){
967 using value_type = q20::remove_cvref_t<
decltype(value)>;
968 using multi_role = QGenericItemModelDetails::is_multi_role<value_type>;
969 if constexpr (multi_role()) {
971 if constexpr (std::is_convertible_v<value_type,
decltype(result)>) {
974 for (
auto it =
std::cbegin(value); it !=
std::cend(value); ++it) {
977 if constexpr (multi_role::int_key)
980 return roleNames().key(key.toUtf8(), -1);
987 }
else if constexpr (has_metaobject<value_type>) {
988 if (row_traits::fixed_size() <= 1) {
990 using meta_type = QGenericItemModelDetails::wrapped_t<value_type>;
991 const QMetaObject &mo = meta_type::staticMetaObject;
992 for (
auto &&[role, roleName] : roleNames().asKeyValueRange()) {
994 if constexpr (std::is_base_of_v<QObject, meta_type>) {
996 data = value->property(roleName);
998 const int pi = mo.indexOfProperty(roleName.constData());
1000 const QMetaProperty prop = mo.property(pi);
1002 data = prop.readOnGadget(QGenericItemModelDetails::pointerTo(value));
1006 result[role] = std::move(data);
1012 if (index.isValid()) {
1013 readAt(index, readItemData);
1016 result = itemModel().QAbstractItemModel::itemData(index);
1021 bool setData(
const QModelIndex &index,
const QVariant &data,
int role)
1023 if (!index.isValid())
1026 bool success =
false;
1027 if constexpr (isMutable()) {
1028 auto emitDataChanged = qScopeGuard([&success,
this, &index, &role]{
1030 Q_EMIT dataChanged(index, index, role == Qt::EditRole
1031 ? QList<
int>{} : QList{role});
1035 const auto writeData = [
this, column = index.column(), &data, role](
auto &&target) ->
bool {
1036 using value_type = q20::remove_cvref_t<
decltype(target)>;
1037 using multi_role = QGenericItemModelDetails::is_multi_role<value_type>;
1038 if constexpr (has_metaobject<value_type>) {
1039 if (QMetaType::fromType<value_type>() == data.metaType()) {
1040 if constexpr (std::is_copy_assignable_v<value_type>) {
1041 target = data.value<value_type>();
1044 qCritical(
"Cannot assign %s", QMetaType::fromType<value_type>().name());
1047 }
else if (row_traits::fixed_size() <= 1) {
1049 }
else if (column <= row_traits::fixed_size()
1050 && (role == Qt::DisplayRole || role == Qt::EditRole)) {
1051 return writeProperty(column, QGenericItemModelDetails::pointerTo(target), data);
1053 }
else if constexpr (multi_role::value) {
1054 Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role);
1057 if (role == Qt::EditRole) {
1058 if constexpr (multi_role::int_key) {
1059 if (target.find(roleToSet) == target.end())
1060 roleToSet = Qt::DisplayRole;
1062 if (target.find(roleNames().value(roleToSet)) == target.end())
1063 roleToSet = Qt::DisplayRole;
1066 if constexpr (multi_role::int_key)
1067 return write(target[roleToSet], data);
1069 return write(target[roleNames().value(roleToSet)], data);
1070 }
else if (role == Qt::DisplayRole || role == Qt::EditRole) {
1071 return write(target, data);
1076 success = writeAt(index, writeData);
1081 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data)
1083 if (!index.isValid() || data.isEmpty())
1086 bool success =
false;
1087 if constexpr (isMutable()) {
1088 auto emitDataChanged = qScopeGuard([&success,
this, &index, &data]{
1090 Q_EMIT dataChanged(index, index, data.keys());
1094 auto writeItemData = [
this, &tried, &data](
auto &target) ->
bool {
1096 using value_type = q20::remove_cvref_t<
decltype(target)>;
1097 using multi_role = QGenericItemModelDetails::is_multi_role<value_type>;
1098 if constexpr (multi_role()) {
1099 using key_type =
typename value_type::key_type;
1101 const auto roleName = [map = roleNames()](
int role) {
return map.value(role); };
1105 if constexpr (!multi_role::int_key)
1107 auto invalid =
std::find_if(data.keyBegin(), data.keyEnd(),
1108 [&roleName](
int role) {
return roleName(role).isEmpty(); }
1111 if (invalid != data.keyEnd()) {
1112 qWarning(
"No role name set for %d", *invalid);
1117 for (
auto &&[role, value] : data.asKeyValueRange()) {
1118 if constexpr (multi_role::int_key)
1119 target[
static_cast<key_type>(role)] = value;
1121 target[QString::fromUtf8(roleName(role))] = value;
1124 }
else if constexpr (has_metaobject<value_type>) {
1125 if (row_traits::fixed_size() <= 1) {
1127 using meta_type = QGenericItemModelDetails::wrapped_t<value_type>;
1128 const QMetaObject &mo = meta_type::staticMetaObject;
1131 auto targetCopy = [](
auto &&origin) {
1132 if constexpr (std::is_base_of_v<QObject, meta_type>)
1134 else if constexpr (
std::is_pointer_v<
decltype(target)>)
1136 else if constexpr (std::is_copy_assignable_v<value_type>)
1141 for (
auto &&[role, value] : data.asKeyValueRange()) {
1142 const QByteArray roleName = roleNames().value(role);
1143 bool written =
false;
1144 if constexpr (std::is_base_of_v<QObject, meta_type>) {
1146 written = targetCopy->setProperty(roleName, value);
1148 const int pi = mo.indexOfProperty(roleName.constData());
1150 const QMetaProperty prop = mo.property(pi);
1152 written = prop.writeOnGadget(QGenericItemModelDetails::pointerTo(targetCopy), value);
1156 qWarning(
"Failed to write value for %s", roleName.data());
1160 if constexpr (std::is_base_of_v<QObject, meta_type>)
1161 target = targetCopy;
1162 else if constexpr (
std::is_pointer_v<
decltype(target)>)
1163 qSwap(*target, targetCopy);
1164 else if constexpr (
std::is_pointer_v<
decltype(targetCopy)>)
1167 qSwap(target, targetCopy);
1174 success = writeAt(index, writeItemData);
1179 emitDataChanged.dismiss();
1180 success = itemModel().QAbstractItemModel::setItemData(index, data);
1188 if (!index.isValid())
1191 bool success =
false;
1192 if constexpr (isMutable()) {
1193 auto emitDataChanged = qScopeGuard([&success,
this, &index]{
1195 Q_EMIT dataChanged(index, index, {});
1198 auto clearData = [column = index.column()](
auto &&target) {
1199 if constexpr (has_metaobject<row_type>) {
1200 if (row_traits::fixed_size() <= 1) {
1203 }
else if (column <= row_traits::fixed_size()) {
1204 return resetProperty(column, QGenericItemModelDetails::pointerTo(target));
1213 success = writeAt(index, clearData);
1220 if constexpr (dynamicColumns() && isMutable() && row_features::has_insert) {
1223 range_type *
const children = childRange(parent);
1227 beginInsertColumns(parent, column, column + count - 1);
1228 for (
auto &child : *children) {
1229 auto it = QGenericItemModelDetails::pos(child, column);
1230 QGenericItemModelDetails::refTo(child).insert(it, count, {});
1240 if constexpr (dynamicColumns() && isMutable() && row_features::has_erase) {
1241 if (column < 0 || column + count > that().columnCount(parent))
1244 range_type *
const children = childRange(parent);
1248 beginRemoveColumns(parent, column, column + count - 1);
1249 for (
auto &child : *children) {
1250 const auto start = QGenericItemModelDetails::pos(child, column);
1251 QGenericItemModelDetails::refTo(child).erase(start, std::next(start, count));
1259 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
1260 const QModelIndex &destParent,
int destColumn)
1263 if (sourceParent != destParent)
1265 if constexpr (isMutable()) {
1266 if (!Structure::canMoveColumns(sourceParent, destParent))
1272 range_type *
const children = childRange(sourceParent);
1276 if (!beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1,
1277 destParent, destColumn)) {
1281 for (
auto &child : *children) {
1282 const auto first = QGenericItemModelDetails::pos(child, sourceColumn);
1283 const auto middle = std::next(first, count);
1284 const auto last = QGenericItemModelDetails::pos(child, destColumn);
1286 if (sourceColumn < destColumn)
1287 std::rotate(first, middle, last);
1289 std::rotate(last, first, middle);
1302 range_type *children = childRange(parent);
1308 beginInsertRows(parent, row, row + count - 1);
1311 if constexpr (range_features::has_insert_range) {
1314 auto start = children->insert(pos, count, row_type{});
1317 children->insert(pos, count, *generator);
1322 that().resetParentInChildren(children);
1331 bool removeRows(
int row,
int count,
const QModelIndex &parent = {})
1333 if constexpr (Structure::canRemoveRows()) {
1334 const int prevRowCount = that().rowCount(parent);
1335 if (row < 0 || row + count > prevRowCount)
1338 range_type *children = childRange(parent);
1342 beginRemoveRows(parent, row, row + count - 1);
1343 [[maybe_unused]]
bool callEndRemoveColumns =
false;
1347 if (prevRowCount == count) {
1348 if (
const int columns = that().columnCount(parent)) {
1349 callEndRemoveColumns =
true;
1350 beginRemoveColumns(parent, 0, columns - 1);
1356 const auto end =
std::next(begin, count);
1357 that().deleteRemovedRows(begin, end);
1358 children->erase(begin, end);
1362 that().resetParentInChildren(children);
1365 if (callEndRemoveColumns) {
1366 Q_ASSERT(that().columnCount(parent) == 0);
1377 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
1378 const QModelIndex &destParent,
int destRow)
1380 if constexpr (isMutable()) {
1381 if (!Structure::canMoveRows(sourceParent, destParent))
1384 if (sourceParent != destParent) {
1385 return that().moveRowsAcross(sourceParent, sourceRow, count,
1386 destParent, destRow);
1389 if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0
1390 || sourceRow < 0 || sourceRow + count - 1 >= itemModel().rowCount(sourceParent)
1391 || destRow < 0 || destRow > itemModel().rowCount(destParent)) {
1395 range_type *source = childRange(sourceParent);
1397 if (!beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow))
1401 const auto middle =
std::next(first, count);
1404 if (sourceRow < destRow)
1405 std::rotate(first, middle, last);
1407 std::rotate(last, first, middle);
1409 that().resetParentInChildren(source);
1428 if constexpr (protocol_traits::has_deleteRow && !std::is_pointer_v<Range>
1429 && !QGenericItemModelDetails::is_any_of<Range, std::reference_wrapper>()) {
1430 const auto begin = QGenericItemModelDetails::begin(*m_data.model());
1431 const auto end = QGenericItemModelDetails::end(*m_data.model());
1432 that().deleteRemovedRows(begin, end);
1438 if constexpr (dynamicColumns() && !row_features::has_resize) {
1442 }
else if constexpr (!protocol_traits::has_newRow) {
1445 }
else if constexpr (!range_features::has_insert_range
1446 && !std::is_copy_constructible_v<row_type>) {
1452 return Structure::canInsertRows();
1456 template <
typename F>
1457 bool writeAt(
const QModelIndex &index, F&& writer)
1459 bool result =
false;
1460 row_reference row = rowData(index);
1463 result = writer(row);
1468 for_element_at(row, index.column(), [&writer, &result](
auto &&target) {
1469 using target_type =
decltype(target);
1471 if constexpr (std::is_lvalue_reference_v<target_type>
1472 && !std::is_const_v<std::remove_reference_t<target_type>>) {
1473 result = writer(
std::forward<target_type>(target));
1482 template <
typename F>
1483 void readAt(
const QModelIndex &index, F&& reader)
const {
1484 const_row_reference row = rowData(index);
1491 for_element_at(row, index.column(),
std::forward<F>(reader));
1495 template <
typename Value>
1498 if constexpr (std::is_constructible_v<QVariant, Value>)
1499 return QVariant(value);
1501 return QVariant::fromValue(value);
1503 template <
typename Value>
1507 if constexpr (std::is_constructible_v<QVariant, Value *>)
1508 return QVariant(value);
1510 return read(*value);
1515 template <
typename Target>
1516 static bool write(Target &target,
const QVariant &value)
1518 using Type = std::remove_reference_t<Target>;
1519 if constexpr (std::is_constructible_v<Target, QVariant>) {
1522 }
else if (value.canConvert<Type>()) {
1523 target = value.value<Type>();
1528 template <
typename Target>
1529 static bool write(Target *target,
const QVariant &value)
1532 return write(*target, value);
1536 template <
typename ItemType>
1539 const QMetaObject *mo = &ItemType::staticMetaObject;
1540 const QByteArray roleName = roleNames().value(role);
1541 if (
const int index = mo->indexOfProperty(roleName.data()); index >= 0)
1542 return mo->property(index);
1546 template <
typename ItemType>
1549 using item_type = std::remove_pointer_t<ItemType>;
1551 QMetaProperty prop = roleProperty<item_type>(role);
1552 if (!prop.isValid() && role == Qt::EditRole)
1553 prop = roleProperty<item_type>(Qt::DisplayRole);
1556 result = readProperty(prop, gadget);
1560 template <
typename ItemType>
1563 return readRole(role, &gadget);
1566 template <
typename ItemType>
1569 if constexpr (std::is_base_of_v<QObject, ItemType>)
1570 return prop.read(gadget);
1572 return prop.readOnGadget(gadget);
1574 template <
typename ItemType>
1577 using item_type = std::remove_pointer_t<ItemType>;
1578 const QMetaObject &mo = item_type::staticMetaObject;
1579 const QMetaProperty prop = mo.property(property + mo.propertyOffset());
1580 return readProperty(prop, gadget);
1583 template <
typename ItemType>
1586 return readProperty(property, &gadget);
1589 template <
typename ItemType>
1590 bool writeRole(
int role, ItemType *gadget,
const QVariant &data)
1592 using item_type = std::remove_pointer_t<ItemType>;
1593 auto prop = roleProperty<item_type>(role);
1594 if (!prop.isValid() && role == Qt::EditRole)
1595 prop = roleProperty<item_type>(Qt::DisplayRole);
1597 return writeProperty(prop, gadget, data);
1600 template <
typename ItemType>
1601 bool writeRole(
int role, ItemType &&gadget,
const QVariant &data)
1603 return writeRole(role, &gadget, data);
1606 template <
typename ItemType>
1607 static bool writeProperty(
const QMetaProperty &prop, ItemType *gadget,
const QVariant &data)
1609 if constexpr (std::is_base_of_v<QObject, ItemType>)
1610 return prop.write(gadget, data);
1612 return prop.writeOnGadget(gadget, data);
1614 template <
typename ItemType>
1617 using item_type = std::remove_pointer_t<ItemType>;
1618 const QMetaObject &mo = item_type::staticMetaObject;
1619 return writeProperty(mo.property(property + mo.propertyOffset()), gadget, data);
1622 template <
typename ItemType>
1623 static bool writeProperty(
int property, ItemType &&gadget,
const QVariant &data)
1625 return writeProperty(property, &gadget, data);
1628 template <
typename ItemType>
1631 using item_type = std::remove_pointer_t<ItemType>;
1632 const QMetaObject &mo = item_type::staticMetaObject;
1633 bool success =
true;
1634 if (property == -1) {
1636 if constexpr (std::is_base_of_v<QObject, item_type>) {
1637 for (
int p = mo.propertyOffset(); p < mo.propertyCount(); ++p)
1638 success = writeProperty(mo.property(p), object, {}) && success;
1643 success = writeProperty(mo.property(property + mo.propertyOffset()), object, {});
1648 template <
typename ItemType>
1651 return resetProperty(property, &object);
1657 Q_ASSERT(index.isValid());
1658 return that().rowDataImpl(index);
1663 Q_ASSERT(index.isValid());
1664 return that().rowDataImpl(index);
1669 if (!index.isValid())
1670 return m_data.model();
1673 return that().childRangeImpl(index);
1678 if (!index.isValid())
1679 return m_data.model();
1682 return that().childRangeImpl(index);
1696template <
typename Range,
typename Protocol>
1703 using range_type =
typename Base::range_type;
1704 using range_features =
typename Base::range_features;
1705 using row_type =
typename Base::row_type;
1706 using row_ptr =
typename Base::row_ptr;
1707 using const_row_ptr =
typename Base::const_row_ptr;
1709 using tree_traits =
typename Base::protocol_traits;
1710 static constexpr bool is_mutable_impl = tree_traits::has_mutable_childRows;
1712 static constexpr bool rows_are_any_refs_or_pointers = Base::rows_are_raw_pointers ||
1713 QGenericItemModelDetails::is_smart_ptr<row_type>() ||
1714 QGenericItemModelDetails::is_any_of<row_type,
std::reference_wrapper>();
1715 static_assert(!Base::dynamicColumns(),
"A tree must have a static number of columns!");
1719 : Base(
std::forward<Range>(model),
std::forward<Protocol>(p), itemModel)
1725 if (!parent.isValid())
1726 return this->createIndex(row, column);
1728 if (parent.column())
1729 return QModelIndex();
1731 const_row_ptr grandParent =
static_cast<const_row_ptr>(parent.constInternalPointer());
1732 const auto &parentSiblings = childrenOf(grandParent);
1739 if (!child.isValid())
1743 const_row_ptr parentRow =
static_cast<const_row_ptr>(child.constInternalPointer());
1753 const auto it =
std::find_if(begin, end, [parentRow](
auto &&s){
1757 return this->createIndex(
std::distance(begin, it), 0,
1764 return Base::size(
this->childRange(parent));
1770 if constexpr (Base::one_dimensional_range)
1773 return Base::static_column_count;
1778 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
1786 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
1787 && Base::dynamicRows() && range_features::has_insert;
1795 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
1796 && Base::dynamicRows() && range_features::has_erase;
1804 static constexpr bool canMoveRows(
const QModelIndex &,
const QModelIndex &)
1810 const QModelIndex &destParent,
int destRow)
1815 if constexpr (!rows_are_any_refs_or_pointers && !tree_traits::has_setParentRow) {
1817 }
else if constexpr (!(range_features::has_insert && range_features::has_erase)) {
1819 }
else if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1,
1820 destParent, destRow)) {
1824 range_type *source =
this->childRange(sourceParent);
1825 range_type *destination =
this->childRange(destParent);
1830 if constexpr (range_features::has_insert_range) {
1832 const auto sourceEnd =
std::next(sourceStart, count);
1834 destination->insert(destStart,
std::move_iterator(sourceStart),
1835 std::move_iterator(sourceEnd));
1836 }
else if constexpr (
std::is_copy_constructible_v<row_type>) {
1838 destination->insert(destStart, count, row_type{});
1841 row_ptr parentRow = destParent.isValid()
1847 if (parentRow ==
static_cast<row_ptr>(sourceParent.internalPointer())) {
1848 if (sourceParent.row() < destRow) {
1849 source =
this->childRange(sourceParent);
1852 source =
this->childRange(
this->createIndex(sourceParent.row() + count, 0,
1853 sourceParent.internalPointer()));
1860 const auto writeEnd =
std::next(writeStart, count);
1862 const auto sourceEnd =
std::next(sourceStart, count);
1864 for (
auto write = writeStart, read = sourceStart; write != writeEnd; ++write, ++read) {
1867 if constexpr (!range_features::has_insert_range)
1868 *write =
std::move(*read);
1872 source->erase(sourceStart, sourceEnd);
1882 this->endMoveRows();
1890 static_assert(tree_traits::has_setParentRow);
1891 row_type empty_row =
this->protocol().newRow();
1899 template <
typename It,
typename Sentinel>
1902 if constexpr (tree_traits::has_deleteRow) {
1903 for (
auto it = begin; it != end; ++it)
1904 this->protocol().deleteRow(*it);
1910 if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) {
1913 for (
auto it = begin; it != end; ++it) {
1914 if (
auto &maybeChildren =
this->protocol().childRows(*it)) {
1915 QModelIndexList fromIndexes;
1916 QModelIndexList toIndexes;
1917 fromIndexes.reserve(Base::size(*maybeChildren));
1918 toIndexes.reserve(Base::size(*maybeChildren));
1922 for (
auto &child : *maybeChildren) {
1923 const_row_ptr oldParent =
this->protocol().parentRow(child);
1924 if (oldParent != parentRow) {
1925 fromIndexes.append(
this->createIndex(row, 0, oldParent));
1926 toIndexes.append(
this->createIndex(row, 0, parentRow));
1927 this->protocol().setParentRow(child, parentRow);
1931 this->changePersistentIndexList(fromIndexes, toIndexes);
1940 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
1941 const range_type &siblings = childrenOf(parentRow);
1942 Q_ASSERT(index.row() <
int(Base::size(siblings)));
1948 row_ptr parentRow =
static_cast<row_ptr>(index.internalPointer());
1949 range_type &siblings = childrenOf(parentRow);
1950 Q_ASSERT(index.row() <
int(Base::size(siblings)));
1956 const auto &row =
this->rowData(index);
1958 return static_cast<
const range_type *>(
nullptr);
1961 return QGenericItemModelDetails::pointerTo(std::forward<
decltype(children)>(children));
1966 auto &row =
this->rowData(index);
1968 return static_cast<range_type *>(
nullptr);
1971 using Children = std::remove_reference_t<
decltype(children)>;
1973 if constexpr (QGenericItemModelDetails::is_any_of<Children, std::optional>()
1974 && std::is_default_constructible<
typename Children::value_type>()) {
1976 children.emplace(range_type{});
1979 return QGenericItemModelDetails::pointerTo(std::forward<
decltype(children)>(children));
1985 : *
this->m_data.model();
1989 range_type &childrenOf(row_ptr row)
1992 : *
this->m_data.model();
1997template <
typename Range>
2011 static constexpr bool is_mutable_impl =
true;
2021 if constexpr (Base::dynamicColumns()) {
2022 if (column <
int(Base::size(*QGenericItemModelDetails::cpos(*
this->m_data.model(), row))))
2023 return this->createIndex(row, column);
2025 qCritical(
"QGenericItemModel: Column-range at row %d is not large enough!", row);
2028 return this->createIndex(row, column);
2039 if (parent.isValid())
2041 return int(Base::size(*
this->m_data.model()));
2046 if (parent.isValid())
2050 if constexpr (Base::dynamicColumns()) {
2051 return int(Base::size(*
this->m_data.model()) == 0
2053 : Base::size(*QGenericItemModelDetails::cbegin(*
this->m_data.model())));
2054 }
else if constexpr (Base::one_dimensional_range) {
2055 return row_traits::fixed_size();
2057 return Base::static_column_count;
2063 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren;
2068 return Base::dynamicRows() && range_features::has_insert;
2073 return Base::dynamicRows() && range_features::has_erase;
2076 static constexpr bool canMoveColumns(
const QModelIndex &source,
const QModelIndex &destination)
2078 return !source.isValid() && !destination.isValid();
2081 static constexpr bool canMoveRows(
const QModelIndex &source,
const QModelIndex &destination)
2083 return !source.isValid() && !destination.isValid();
2087 const QModelIndex &,
int)
noexcept
2095 row_type empty_row =
this->protocol().newRow();
2098 if constexpr (Base::dynamicColumns() && row_features::has_resize) {
2106 template <
typename It,
typename Sentinel>
2109 if constexpr (Base::protocol_traits::has_deleteRow) {
2110 for (
auto it = begin; it != end; ++it)
2111 this->protocol().deleteRow(*it);
2117 Q_ASSERT(index.row() <
int(Base::size(*
this->m_data.model())));
2123 Q_ASSERT(index.row() <
int(Base::size(*
this->m_data.model())));
2140 return *
this->m_data.model();
void beginRemoveRows(const QModelIndex &parent, int start, int count)
~QGenericItemModelImplBase()=default
Ret call(Op op, const Args &...args)
QGenericItemModelImplBase(QGenericItemModel *itemModel, const Impl *)
bool beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destParent, int destRow)
void dataChanged(const QModelIndex &from, const QModelIndex &to, const QList< int > &roles)
const QAbstractItemModel & itemModel() const
QModelIndex createIndex(int row, int column, const void *ptr=nullptr) const
Ret callConst(ConstOp op, const Args &...args) const
bool beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destParent, int destRow)
QHash< int, QByteArray > roleNames() const
void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to)
QAbstractItemModel & itemModel()
void beginRemoveColumns(const QModelIndex &parent, int start, int count)
void beginInsertColumns(const QModelIndex &parent, int start, int count)
void beginInsertRows(const QModelIndex &parent, int start, int count)
QModelIndex index(int row, int column, const QModelIndex &parent) const
bool removeColumns(int column, int count, const QModelIndex &parent)
static bool writeProperty(int property, ItemType *gadget, const QVariant &data)
QModelIndex sibling(int row, int column, const QModelIndex &index) const
QVariant data(const QModelIndex &index, int role) const
QMetaProperty roleProperty(int role) const
static bool write(Target &target, const QVariant &value)
bool insertColumns(int column, int count, const QModelIndex &parent)
bool setItemData(const QModelIndex &index, const QMap< int, QVariant > &data)
static constexpr int size(const C &c)
static constexpr bool rows_are_owning_or_raw_pointers
static constexpr bool rows_are_raw_pointers
QMap< int, QVariant > itemData(const QModelIndex &index) const
static constexpr bool one_dimensional_range
static constexpr bool dynamicRows()
static constexpr bool canInsertRows()
bool clearItemData(const QModelIndex &index)
range_type * childRange(const QModelIndex &index)
static bool writeProperty(const QMetaProperty &prop, ItemType *gadget, const QVariant &data)
bool writeAt(const QModelIndex &index, F &&writer)
const Structure & that() const
QVariant readRole(int role, ItemType *gadget) const
static bool resetProperty(int property, ItemType &&object)
static constexpr int static_column_count
static QVariant readProperty(int property, const ItemType &gadget)
bool setData(const QModelIndex &index, const QVariant &data, int role)
protocol_type & protocol()
static void call(Op op, QGenericItemModelImplBase *that, void *r, const void *args)
bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destParent, int destColumn)
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destParent, int destRow)
QVariant headerData(int section, Qt::Orientation orientation, int role) const
QVariant readRole(int role, const ItemType &gadget) const
static constexpr bool dynamicColumns()
static QVariant readProperty(const QMetaProperty &prop, ItemType *gadget)
static constexpr bool has_metaobject
static constexpr int static_row_count
static bool resetProperty(int property, ItemType *object)
Qt::ItemFlags flags(const QModelIndex &index) const
QGenericItemModelImpl(Range &&model, Protocol &&protocol, QGenericItemModel *itemModel)
static QVariant read(const Value &value)
bool insertRows(int row, int count, const QModelIndex &parent)
static constexpr bool isMutable()
const_row_reference rowData(const QModelIndex &index) const
static QVariant readProperty(int property, ItemType *gadget)
static bool write(Target *target, const QVariant &value)
bool writeRole(int role, ItemType &&gadget, const QVariant &data)
const protocol_type & protocol() const
static bool writeProperty(int property, ItemType &&gadget, const QVariant &data)
const range_type * childRange(const QModelIndex &index) const
bool removeRows(int row, int count, const QModelIndex &parent={})
void readAt(const QModelIndex &index, F &&reader) const
bool writeRole(int role, ItemType *gadget, const QVariant &data)
static QVariant read(Value *value)
row_reference rowData(const QModelIndex &index)
static void callConst(ConstOp op, const QGenericItemModelImplBase *that, void *r, const void *args)
static constexpr bool canMoveRows(const QModelIndex &source, const QModelIndex &destination)
void deleteRemovedRows(It &&begin, Sentinel &&end)
QGenericTableItemModelImpl(Range &&model, QGenericItemModel *itemModel)
const range_type & childrenOf(const_row_ptr row) const
auto makeEmptyRow(const QModelIndex &)
auto childRangeImpl(const QModelIndex &)
QModelIndex parent(const QModelIndex &) const
auto childRangeImpl(const QModelIndex &) const
int rowCount(const QModelIndex &parent) const
static constexpr bool canRemoveRows()
constexpr bool moveRowsAcross(const QModelIndex &, int, int, const QModelIndex &, int) noexcept
decltype(auto) rowDataImpl(const QModelIndex &index) const
static constexpr bool canInsertRows()
int columnCount(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()
static constexpr bool canMoveColumns(const QModelIndex &, const QModelIndex &)
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 canInsertRows()
static constexpr bool canRemoveRows()
static constexpr bool canMoveRows(const QModelIndex &, const QModelIndex &)
const range_type & childrenOf(const_row_ptr row) const
decltype(auto) rowDataImpl(const QModelIndex &index)
QModelIndex indexImpl(int row, int column, const QModelIndex &parent) const
void deleteRemovedRows(It &&begin, Sentinel &&end)
QGenericTreeItemModelImpl(Range &&model, Protocol &&p, QGenericItemModel *itemModel)
const range_type * childRangeImpl(const QModelIndex &index) const
int rowCount(const QModelIndex &parent) const
decltype(auto) rowDataImpl(const QModelIndex &index) const
static constexpr Qt::ItemFlags defaultFlags()
auto makeEmptyRow(const QModelIndex &parent)
QModelIndex parent(const QModelIndex &child) const
static constexpr bool is_multi_role_v
static auto pointerTo(T &&t)
static decltype(auto) refTo(T &&t)
static auto end(C &&c) -> decltype(std::end(refTo(std::forward< C >(c))))
static auto cend(C &&c) -> decltype(std::cend(refTo(std::forward< C >(c))))
auto value(It &&it) -> decltype(it.value())
static auto cpos(C &&c, int i)
static auto begin(C &&c) -> decltype(std::begin(refTo(std::forward< C >(c))))
static constexpr bool is_range_v
static auto pos(C &&c, int i)
static auto cbegin(C &&c) -> decltype(std::cbegin(refTo(std::forward< C >(c))))
auto key(It &&it) -> decltype(it.key())
static constexpr bool has_metaobject_v
static constexpr bool isValid(const T &t) noexcept
static constexpr int static_size_v
auto childRows(const R &row) const -> decltype(row.childRows())
auto childRows(R &row) -> decltype(row.childRows())
auto setParentRow(R &row, R *parent) -> decltype(row.setParentRow(parent))
auto parentRow(const R &row) const -> decltype(row.parentRow())
auto newRow() -> decltype(R{})
static constexpr bool int_key
static constexpr bool is_mutable
static constexpr bool has_resize
static constexpr bool has_erase
static constexpr bool has_insert
static constexpr bool has_newRow
static constexpr bool has_mutable_childRows
static constexpr bool has_deleteRow
static constexpr bool has_setParentRow
static constexpr bool is_default
static constexpr bool has_erase
static constexpr bool has_resize
static constexpr bool has_insert
static constexpr bool has_insert_range
static constexpr bool is_mutable
static constexpr int static_size
static constexpr int fixed_size()
static constexpr bool is_range
static constexpr int static_size
friend bool operator==(const EmptyRowGenerator &lhs, const EmptyRowGenerator &rhs) noexcept
friend bool operator!=(const EmptyRowGenerator &lhs, const EmptyRowGenerator &rhs) noexcept
const QModelIndex * parent
EmptyRowGenerator & operator++()