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/qquasivirtual_impl.h>
21#include <QtCore/qmetaobject.h>
22#include <QtCore/qvariant.h>
23#include <QtCore/qmap.h>
24#include <QtCore/qscopedvaluerollback.h>
25#include <QtCore/qset.h>
26#include <QtCore/qvarlengtharray.h>
32#include <QtCore/qxptype_traits.h>
34#include <QtCore/q23utility.h>
40 template <
typename T,
template <
typename...>
typename... Templates>
43 template <
template <
typename...>
typename Template,
45 template <
typename...>
typename...
Templates>
49 template <
typename...>
typename Template,
50 template <
typename...>
typename...
Templates>
53 template <
typename T,
template <
typename...>
typename...
Templates>
56 template <
typename T,
typename =
void>
63 template <
typename T,
typename =
void>
80#ifndef QT_NO_SCOPED_POINTER
96 using Type = q20::remove_cvref_t<T>;
97 if constexpr (is_any_of<Type, std::optional>())
98 return t ?
std::addressof(*
std::forward<T>(t)) :
nullptr;
99 else if constexpr (std::is_pointer<Type>())
101 else if constexpr (is_smart_ptr<Type>())
103 else if constexpr (is_any_of<Type, std::reference_wrapper>())
104 return std::addressof(t.get());
106 return std::addressof(
std::forward<T>(t));
109 template <
typename T>
119 template <
typename T>
122 template <
typename T>
127 template <
typename T,
typename =
void>
131 template <
typename T>
134 template <
typename T>
137 template <
typename T,
typename =
void>
143 template <
typename T>
146 template <
typename T,
typename =
void>
148 template <
typename T>
151 template <
typename T>
154 template <
typename T>
155 static constexpr bool isValid(
const T &t)
noexcept
157 if constexpr (
std::is_array_v<T>)
159 else if constexpr (is_validatable<T>())
165 template <
typename T>
166 static decltype(
auto)
refTo(T&& t) {
169 using Type = q20::remove_cvref_t<T>;
170 if constexpr (is_any_of<T, std::optional>())
171 return *
std::forward<T>(t);
172 if constexpr (!is_wrapped<Type>() || is_any_unique_ptr<Type>())
173 return q23::forward_like<T>(*QRangeModelDetails::pointerTo(t));
178 template <
typename It>
179 auto key(It&& it) ->
decltype(it.key()) {
return std::forward<It>(it).key(); }
180 template <
typename It>
181 auto key(It&& it) ->
decltype((it->first)) {
return std::forward<It>(it)->first; }
183 template <
typename It>
184 auto value(It&& it) ->
decltype(it.value()) {
return std::forward<It>(it).value(); }
185 template <
typename It>
186 auto value(It&& it) ->
decltype((it->second)) {
return std::forward<It>(it)->second; }
192 template <
typename C>
195 template <
typename C>
198 template <
typename C>
199 static auto pos(C &&c,
int i)
207 template <
typename C,
typename =
void>
210 template <
typename C>
221 template <
typename C,
typename =
void>
224 template <
typename C>
233 template <
typename C,
typename =
void>
236 template <
typename C>
244 template <
typename C,
typename =
void>
247 template <
typename C>
258 template <
typename It>
260 std::is_swappable<
decltype(*
std::declval<It>())>,
261 std::is_base_of<
std::forward_iterator_tag,
265 template <
typename C,
typename =
void>
268 template <
typename C>
278 template <
typename C>
279 static void rotate(C& c,
int src,
int count,
int dst) {
281 using Container = std::remove_reference_t<
decltype(container)>;
284 const auto srcEnd =
std::next(srcBegin, count);
287 if constexpr (test_splice<Container>::value) {
288 if (dst > src && dst < src + count)
289 container.splice(srcBegin, container, dstBegin, srcEnd);
291 container.splice(dstBegin, container, srcBegin, srcEnd);
294 std::rotate(srcBegin, srcEnd, dstBegin);
296 std::rotate(dstBegin, srcBegin, srcEnd);
309 template <
typename C>
318 template <
typename C>
323 template <
typename C,
typename =
void>
325 template <
typename C>
328 template <
typename C,
typename =
void>
330 template <
typename C>
335 template <
typename C,
typename =
void>
346 template <
typename C>
387 template <
typename C>
389 template <
typename C>
395 template <
typename T,
typename =
void>
401 template <
typename T>
415 "The return type of the ItemAccess::writeRole implementation "
416 "needs to be convertible to a bool!");
419 "The return type of the ItemAccess::readRole implementation "
420 "needs to be convertible to QVariant!");
432 template <
typename T,
typename =
void>
438 template <
typename T>
455 template <
typename T,
typename =
void>
472 template <
typename C,
typename Fn>
478 std::forward<Fn>(fn)(
std::forward<C>(container));
481 template <
typename Fn>
487 int columnIndex = -1;
490 return std::forward<Fn>(fn)(firstIndex.siblingAtColumn(++columnIndex),
498 template <
typename T>
518 template <
typename C,
typename F>
553 template <
typename Fn>
573 template <
typename C,
typename F>
585 template <
typename Fn>
601 template <
typename T>
622 template <
typename C,
typename F>
642 template <
typename Fn>
649 template <
typename T,
typename =
void>
652 template <
typename That>
655 return That::roleNamesForSimpleType();
662 template <
typename That>
669 template <
typename T>
675 template <
typename T>
678 template <
typename That>
685 template <
typename T>
689 template <
typename Range>
695 auto newRow() ->
decltype(R{}) {
return R{}; }
698 template <
typename Range>
726 template <
typename Range,
734 template <
typename Range>
737 template <
typename R >
738 auto parentRow(
const R& row)
const ->
decltype(row.parentRow())
740 return row.parentRow();
743 template <
typename R >
744 auto setParentRow(R &row, R* parent) ->
decltype(row.setParentRow(parent))
746 row.setParentRow(parent);
749 template <
typename R >
750 auto childRows(
const R &row)
const ->
decltype(row.childRows())
752 return row.childRows();
755 template <
typename R >
758 return row.childRows();
762 template <
typename P,
typename R>
765 template <
typename P,
typename R>
768 template <
typename P,
typename R>
771 template <
typename P,
typename R>
774 template <
typename P,
typename R>
778 template <
typename P,
typename R>
781 template <
typename P,
typename R>
784 template <
typename P,
typename R>
787 template <
typename P,
typename =
void>
789 template <
typename P>
793 template <
typename P,
typename R,
typename =
void>
795 template <
typename P,
typename R>
800 template <
typename Range,
812 template <
typename Range>
825 template <
typename Range,
typename Protocol>
861 template <
bool cacheProperties,
bool itemsAreQObjects>
893 return lhs.sender == rhs.sender && lhs
.role == rhs
.role;
897 return qHashMulti(seed, c.sender, c
.role);
921 template <
typename ModelStorage,
typename =
void>
940 template <
typename ModelStorage,
typename PropertyStorage>
951 template <
typename Model = ModelStorage>
977 bool setHeaderData(
int section, Qt::Orientation orientation,
const QVariant &data,
int role);
978 bool setData(
const QModelIndex &index,
const QVariant &data,
int role);
979 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data);
983 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
const QModelIndex &destParent,
int destColumn);
984 bool insertRows(
int row,
int count,
const QModelIndex &parent);
985 bool removeRows(
int row,
int count,
const QModelIndex &parent);
986 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
const QModelIndex &destParent,
int destRow);
999 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const;
1031 template <
typename C>
1063 friend class QRangeModelPrivate;
1066 QRangeModel *m_rangeModel;
1070 : m_rangeModel(itemModel)
1076 inline void dataChanged(
const QModelIndex &from,
const QModelIndex &to,
1077 const QList<
int> &roles);
1084 inline bool beginMoveColumns(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1085 const QModelIndex &destParent,
int destRow);
1087 inline void beginInsertRows(
const QModelIndex &parent,
int start,
int count);
1089 inline void beginRemoveRows(
const QModelIndex &parent,
int start,
int count);
1091 inline bool beginMoveRows(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1092 const QModelIndex &destParent,
int destRow);
1112 QRangeModelDetails::AutoConnectContext *context,
1113 int role,
const QMetaProperty &property);
1115 QRangeModelDetails::AutoConnectContext *context,
1116 int role,
const QMetaProperty &property);
1118 QRangeModelDetails::AutoConnectContext *context,
1119 const QHash<
int, QMetaProperty> &properties);
1121 QRangeModelDetails::AutoConnectContext *context,
1122 const QHash<
int, QMetaProperty> &properties);
1125template <
typename Structure,
typename Range,
1126 typename Protocol = QRangeModelDetails::table_protocol_t<Range>>
1162 "Currently, std::optional is not supported for ranges and rows, as "
1163 "it has range semantics in c++26. Once the required behavior is clarified, "
1164 "std::optional for ranges and rows will be supported.");
1171 Structure&
that() {
return static_cast<Structure &>(*
this); }
1172 const Structure&
that()
const {
return static_cast<
const Structure &>(*
this); }
1174 template <
typename C>
1175 static constexpr int size(
const C &c)
1180 if constexpr (QRangeModelDetails::test_size<C>()) {
1182 return int(size(c));
1184#if defined(__cpp_lib_ranges)
1185 using std::ranges::distance;
1187 using std::distance;
1189 using container_type = std::conditional_t<QRangeModelDetails::range_traits<C>::has_cbegin,
1190 const QRangeModelDetails::wrapped_t<C>,
1191 QRangeModelDetails::wrapped_t<C>>;
1192 container_type& container =
const_cast<container_type &>(
QRangeModelDetails::refTo(c));
1208 return this->blockDataChangedDispatch();
1218 template <
typename T>
1238 {
return lhs.n == rhs.n; }
1240 {
return !(lhs == rhs); }
1251 "The range holding a move-only row-type must support insert(pos, start, end)");
1258 return range_features::is_mutable && row_features::is_mutable
1259 && std::is_reference_v<row_reference>
1260 && Structure::is_mutable_impl;
1283 if (row < 0 || column < 0 || column >= columnCount(parent)
1284 || row >= rowCount(parent)) {
1288 return that().indexImpl(row, column, parent);
1293 if (row == index.row() && column == index.column())
1296 if (column < 0 || column >=
this->columnCount({}))
1299 if (row == index.row())
1300 return this->createIndex(row, column, index.constInternalPointer());
1302 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
1303 const auto siblingCount = size(that().childrenOf(parentRow));
1304 if (row < 0 || row >=
int(siblingCount))
1306 return this->createIndex(row, column, parentRow);
1311 if (!index.isValid())
1312 return Qt::NoItemFlags;
1315 std::optional<Qt::ItemFlags> customFlags;
1316 readAt(index, [&customFlags](
auto &&ref){
1318 using wrapped_value_type = q20::remove_cvref_t<QRangeModelDetails::wrapped_t<
decltype(ref)>>;
1319 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>::hasFlags) {
1320 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1321 customFlags = ItemAccess::flags(ref);
1322 if constexpr (!isMutable())
1323 *customFlags &= ~Qt::ItemIsEditable;
1327 return *customFlags;
1330 Qt::ItemFlags f = Structure::defaultFlags();
1332 if constexpr (isMutable()) {
1333 if constexpr (row_traits::hasMetaObject) {
1334 if (index.column() < row_traits::fixed_size()) {
1335 const QMetaObject mo = wrapped_row_type::staticMetaObject;
1336 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
1337 if (prop.isWritable())
1338 f |= Qt::ItemIsEditable;
1341 f |= Qt::ItemIsEditable;
1342 }
else if constexpr (std::is_reference_v<row_reference> && !std::is_const_v<row_reference>) {
1345 const_row_reference row = rowData(index);
1346 row_reference mutableRow =
const_cast<row_reference>(row);
1348 row_traits::for_element_at(mutableRow, index.column(), [&f](
auto &&ref){
1349 using target_type =
decltype(ref);
1350 if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
1351 f &= ~Qt::ItemIsEditable;
1352 else if constexpr (std::is_lvalue_reference_v<target_type>)
1353 f |= Qt::ItemIsEditable;
1358 f &= ~Qt::ItemIsEditable;
1368 if constexpr (QRangeModelDetails::hasHeaderData<wrapped_row_type>) {
1369 if (orientation == Qt::Horizontal) {
1370 result = QRangeModelDetails::QRangeModelRowOptions<wrapped_row_type>::headerData(
1373 if (result.isValid())
1378 if (role != Qt::DisplayRole || orientation != Qt::Horizontal
1379 || section < 0 || section >= columnCount({})) {
1380 return this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1383 result = row_traits::column_name(section);
1384 if (!result.isValid())
1385 result =
this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1391 if (!index.isValid())
1394 QModelRoleData result(role);
1395 multiData(index, result);
1396 return std::move(result.data());
1401 return role == Qt::RangeModelDataRole
1402 || role == Qt::RangeModelAdapterRole;
1407 return role == Qt::DisplayRole || role == Qt::EditRole;
1412 QMap<
int, QVariant> result;
1414 if (index.isValid()) {
1418 readAt(index, [&result, &tried](
const auto &value) {
1419 if constexpr (std::is_convertible_v<
decltype(value),
decltype(result)>) {
1425 const auto roles =
this->itemModel().roleNames().keys();
1426 QVarLengthArray<QModelRoleData, 16> roleDataArray;
1427 roleDataArray.reserve(roles.size());
1428 for (
auto role : roles) {
1429 if (isRangeModelRole(role))
1431 roleDataArray.emplace_back(role);
1433 QModelRoleDataSpan roleDataSpan(roleDataArray);
1434 multiData(index, roleDataSpan);
1436 for (QModelRoleData &roleData : roleDataSpan) {
1437 if (roleData.data().isValid())
1438 result[roleData.role()] = std::move(roleData.data());
1447 template <
typename value_type>
1450 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1451 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1453 const auto readModelData = [&value](QModelRoleData &roleData){
1454 const int role = roleData.role();
1455 if (role == Qt::RangeModelDataRole) {
1459 if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
1460 roleData.setData(QVariant::fromValue(QRangeModelDetails::refTo(value)));
1462 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1463 }
else if (role == Qt::RangeModelAdapterRole) {
1465 if constexpr (
std::is_copy_assignable_v<value_type>)
1466 roleData.setData(QVariant::fromValue(value));
1468 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1475 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1476 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1478 for (
auto &roleData : roleDataSpan) {
1479 if (!readModelData(roleData)) {
1480 roleData.setData(ItemAccess::readRole(QRangeModelDetails::refTo(value),
1484 }
else if constexpr (multi_role()) {
1486 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1488 if constexpr (!multi_role::int_key)
1489 return that->itemModel().roleNames();
1493 using key_type =
typename value_type::key_type;
1494 for (
auto &roleData : roleDataSpan) {
1495 const auto &it = [&roleNames, &value, role = roleData.role()]{
1496 Q_UNUSED(roleNames);
1497 if constexpr (multi_role::int_key)
1498 return value.find(key_type(role));
1500 return value.find(roleNames.value(role));
1502 if (it != QRangeModelDetails::adl_end(value))
1503 roleData.setData(QRangeModelDetails::value(it));
1505 roleData.clearData();
1507 }
else if constexpr (has_metaobject<value_type>) {
1508 if (row_traits::fixed_size() <= 1) {
1510 for (
auto &roleData : roleDataSpan) {
1511 if (!readModelData(roleData)) {
1512 roleData.setData(that->readRole(index, roleData.role(),
1513 QRangeModelDetails::pointerTo(value)));
1516 }
else if (index.column() <= row_traits::fixed_size()) {
1518 for (
auto &roleData : roleDataSpan) {
1519 const int role = roleData.role();
1520 if (isPrimaryRole(role)) {
1521 roleData.setData(that->readProperty(index,
1522 QRangeModelDetails::pointerTo(value)));
1524 roleData.clearData();
1530 for (
auto &roleData : roleDataSpan) {
1531 const int role = roleData.role();
1532 if (isPrimaryRole(role) || isRangeModelRole(role))
1533 roleData.setData(read(value));
1535 roleData.clearData();
1546 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const
1549 readAt(index,
ItemReader{index, roleDataSpan,
this, tried});
1554 bool setData(
const QModelIndex &index,
const QVariant &data,
int role)
1556 if (!index.isValid())
1559 bool success =
false;
1560 if constexpr (isMutable()) {
1561 auto emitDataChanged = qScopeGuard([&success,
this, &index, role]{
1563 Q_EMIT
this->dataChanged(index, index,
1564 role == Qt::EditRole || role == Qt::RangeModelDataRole
1565 || role == Qt::RangeModelAdapterRole
1566 ? QList<
int>{} : QList<
int>{role});
1572 const auto writeData = [
this, column = index.column(), &data, role](
auto &&target) ->
bool {
1573 using value_type = q20::remove_cvref_t<
decltype(target)>;
1574 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1575 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1577 auto setRangeModelDataRole = [&target, &data]{
1578 constexpr auto targetMetaType = QMetaType::fromType<value_type>();
1579 const auto dataMetaType = data.metaType();
1580 constexpr bool isWrapped = QRangeModelDetails::is_wrapped<value_type>();
1581 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>) {
1585 if constexpr (isWrapped) {
1586 constexpr bool is_raw_pointer = std::is_pointer_v<value_type>;
1587 if constexpr (!is_raw_pointer && std::is_copy_assignable_v<value_type>) {
1588 if (data.canConvert(targetMetaType)) {
1589 target = data.value<value_type>();
1592 }
else if constexpr (is_raw_pointer) {
1594 target = data.value<value_type>();
1603 }
else if constexpr (isWrapped) {
1608 if (
const auto mt = QMetaType::fromType<wrapped_value_type>();
1609 data.canConvert(mt)) {
1610 targetRef = data.value<wrapped_value_type>();
1612 }
else if (
const auto mtp = QMetaType::fromType<wrapped_value_type *>();
1613 data.canConvert(mtp)) {
1614 targetRef = *data.value<wrapped_value_type *>();
1618 }
else if (targetMetaType == dataMetaType) {
1619 QRangeModelDetails::refTo(target) = data.value<value_type>();
1621 }
else if (dataMetaType.flags() & QMetaType::PointerToGadget) {
1622 QRangeModelDetails::refTo(target) = *data.value<value_type *>();
1626 qCritical(
"Not able to assign %s to %s",
1627 qPrintable(QDebug::toString(data)), targetMetaType.name());
1632 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1633 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1634 if (isRangeModelRole(role))
1635 return setRangeModelDataRole();
1636 return ItemAccess::writeRole(QRangeModelDetails::refTo(target), data, role);
1637 }
else if constexpr (has_metaobject<value_type>) {
1638 if (row_traits::fixed_size() <= 1) {
1639 if (isRangeModelRole(role))
1640 return setRangeModelDataRole();
1642 }
else if (column <= row_traits::fixed_size()
1643 && (isPrimaryRole(role) || isRangeModelRole(role))) {
1646 }
else if constexpr (multi_role::value) {
1647 Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role);
1650 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1652 if constexpr (!multi_role::int_key)
1653 return this->itemModel().roleNames();
1657 if (role == Qt::EditRole) {
1658 if constexpr (multi_role::int_key) {
1659 if (target.find(roleToSet) == target.end())
1660 roleToSet = Qt::DisplayRole;
1662 if (target.find(roleNames.value(roleToSet)) == target.end())
1663 roleToSet = Qt::DisplayRole;
1666 if constexpr (multi_role::int_key)
1667 return write(target[roleToSet], data);
1669 return write(target[roleNames.value(roleToSet)], data);
1670 }
else if (isPrimaryRole(role) || isRangeModelRole(role)) {
1671 return write(target, data);
1676 success = writeAt(index, writeData);
1679 if (success && isRangeModelRole(role) &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
1680 if (QObject *item = data.value<QObject *>())
1681 Self::connectProperties(index, item, m_data.context, m_data.properties);
1688 template <
typename LHS,
typename RHS>
1691 if constexpr (
std::is_pointer_v<RHS>)
1693 else if constexpr (
std::is_assignable_v<LHS, RHS>)
1694 org =
std::forward<RHS>(copy);
1698 template <
typename LHS,
typename RHS>
1701 updateTarget(*org,
std::forward<RHS>(copy));
1704 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data)
1706 if (!index.isValid() || data.isEmpty())
1709 bool success =
false;
1710 if constexpr (isMutable()) {
1711 auto emitDataChanged = qScopeGuard([&success,
this, &index, &data]{
1713 Q_EMIT
this->dataChanged(index, index, data.keys());
1719 auto writeItemData = [
this, &tried, &data](
auto &target) ->
bool {
1721 using value_type = q20::remove_cvref_t<
decltype(target)>;
1722 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1723 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1727 auto makeCopy = [](
const value_type &original){
1728 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>)
1730 else if constexpr (std::is_pointer_v<
decltype(original)>)
1732 else if constexpr (std::is_copy_assignable_v<value_type>)
1738 const auto roleNames =
this->itemModel().roleNames();
1740 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1742 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1743 const auto roles = roleNames.keys();
1744 auto targetCopy = makeCopy(target);
1745 for (
int role : roles) {
1746 if (!ItemAccess::writeRole(QRangeModelDetails::refTo(targetCopy),
1747 data.value(role), role)) {
1751 updateTarget(target,
std::move(targetCopy));
1753 }
else if constexpr (multi_role()) {
1754 using key_type =
typename value_type::key_type;
1756 const auto roleName = [&roleNames](
int role) {
1757 return roleNames.value(role);
1762 if constexpr (!multi_role::int_key)
1764 auto invalid =
std::find_if(data.keyBegin(), data.keyEnd(),
1765 [&roleName](
int role) {
return roleName(role).isEmpty(); }
1768 if (invalid != data.keyEnd()) {
1770 qWarning(
"No role name set for %d", *invalid);
1776 for (
auto &&[role, value] : data.asKeyValueRange()) {
1777 if constexpr (multi_role::int_key)
1778 target[
static_cast<key_type>(role)] = value;
1780 target[QString::fromUtf8(roleName(role))] = value;
1783 }
else if constexpr (has_metaobject<value_type>) {
1784 if (row_traits::fixed_size() <= 1) {
1786 auto targetCopy = makeCopy(target);
1787 for (
auto &&[role, value] : data.asKeyValueRange()) {
1788 if (isRangeModelRole(role))
1790 if (!writeRole(role, QRangeModelDetails::pointerTo(targetCopy), value)) {
1791 const QByteArray roleName = roleNames.value(role);
1793 qWarning(
"Failed to write value '%s' to role '%s'",
1794 qPrintable(QDebug::toString(value)), roleName.data());
1799 updateTarget(target,
std::move(targetCopy));
1806 success = writeAt(index, writeItemData);
1811 emitDataChanged.dismiss();
1812 success =
this->itemModel().QAbstractItemModel::setItemData(index, data);
1820 if (!index.isValid())
1823 bool success =
false;
1824 if constexpr (isMutable()) {
1825 auto emitDataChanged = qScopeGuard([&success,
this, &index]{
1827 Q_EMIT
this->dataChanged(index, index, {});
1830 auto clearData = [column = index.column()](
auto &&target) {
1831 if constexpr (row_traits::hasMetaObject) {
1832 if (row_traits::fixed_size() <= 1) {
1835 }
else if (column <= row_traits::fixed_size()) {
1845 success = writeAt(index, clearData);
1853 using item_type = QRangeModelDetails::wrapped_t<
typename row_traits::item_type>;
1854 using item_traits =
typename QRangeModelDetails::item_traits<item_type>;
1855 return item_traits::roleNames(
this);
1862 return row_traits::for_each_element(QRangeModelDetails::refTo(row),
1863 this->itemModel().index(rowIndex, 0, parent),
1864 [
this](
const QModelIndex &index,
const QObject *item) {
1865 if constexpr (isMutable())
1866 return Self::connectProperties(index, item, m_data.context, m_data.properties);
1868 return Self::connectPropertiesConst(index, item, m_data.context, m_data.properties);
1876 row_traits::for_each_element(QRangeModelDetails::refTo(row),
1877 this->itemModel().index(rowIndex, 0, parent),
1878 [
this](
const QModelIndex &,
const QObject *item) {
1879 m_data.connections.removeIf([item](
const auto &connection) {
1880 return connection.sender == item;
1889 using item_type = std::remove_pointer_t<
typename row_traits::item_type>;
1890 using Mapping = QRangeModelDetails::AutoConnectContext::AutoConnectMapping;
1892 delete m_data.context;
1893 m_data.connections = {};
1894 switch (
this->autoConnectPolicy()) {
1895 case AutoConnectPolicy::None:
1896 m_data.context =
nullptr;
1898 case AutoConnectPolicy::Full:
1899 m_data.context =
new QRangeModelDetails::AutoConnectContext(&
this->itemModel());
1901 m_data.properties = QRangeModelImplBase::roleProperties(
this->itemModel(),
1902 item_type::staticMetaObject);
1903 m_data.context->mapping = Mapping::Roles;
1905 m_data.properties = QRangeModelImplBase::columnProperties(wrapped_row_type::staticMetaObject);
1906 m_data.context->mapping = Mapping::Columns;
1908 if (!m_data.properties.isEmpty())
1909 that().autoConnectPropertiesImpl();
1911 case AutoConnectPolicy::OnRead:
1912 m_data.context =
new QRangeModelDetails::AutoConnectContext(&
this->itemModel());
1914 m_data.context->mapping = Mapping::Roles;
1916 m_data.properties = QRangeModelImplBase::columnProperties(wrapped_row_type::staticMetaObject);
1917 m_data.context->mapping = Mapping::Columns;
1923 qWarning(
"All items in the range must be QObject subclasses");
1928 template <
typename InsertFn>
1933 range_type *
const children = childRange(parent);
1937 this->beginInsertColumns(parent, column, column + count - 1);
1939 for (
auto &child : *children) {
1940 auto it = QRangeModelDetails::pos(child, column);
1941 (
void)insertFn(QRangeModelDetails::refTo(child), it, count);
1944 this->endInsertColumns();
1950 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
1951 for (
int r = 0; r < that().rowCount(parent); ++r) {
1952 for (
int c = column; c < column + count; ++c) {
1953 const QModelIndex index = that().index(r, c, parent);
1954 writeAt(index, [
this, &index](QObject *item){
1955 return Self::connectProperties(index, item,
1956 m_data.context, m_data.properties);
1968 if constexpr (dynamicColumns() && isMutable() && row_features::has_insert) {
1969 return doInsertColumns(column, count, parent, [](
auto &row,
auto it,
int n){
1970 row.insert(it, n, {});
1980 if constexpr (dynamicColumns() && isMutable() && row_features::has_erase) {
1981 if (column < 0 || column + count > columnCount(parent))
1984 range_type *
const children = childRange(parent);
1989 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead) {
1990 for (
int r = 0; r < that().rowCount(parent); ++r) {
1991 for (
int c = column; c < column + count; ++c) {
1992 const QModelIndex index = that().index(r, c, parent);
1993 writeAt(index, [
this](QObject *item){
1994 m_data.connections.removeIf([item](
const auto &connection) {
1995 return connection.sender == item;
2004 this->beginRemoveColumns(parent, column, column + count - 1);
2005 for (
auto &child : *children) {
2006 const auto start = QRangeModelDetails::pos(child, column);
2007 QRangeModelDetails::refTo(child).erase(start, std::next(start, count));
2009 this->endRemoveColumns();
2015 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
2016 const QModelIndex &destParent,
int destColumn)
2019 if (sourceParent != destParent)
2021 if constexpr (isMutable() && (row_features::has_rotate || row_features::has_splice)) {
2022 if (!Structure::canMoveColumns(sourceParent, destParent))
2028 range_type *
const children = childRange(sourceParent);
2032 if (!
this->beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1,
2033 destParent, destColumn)) {
2037 for (
auto &child : *children)
2038 QRangeModelDetails::rotate(child, sourceColumn, count, destColumn);
2040 this->endMoveColumns();
2047 template <
typename InsertFn>
2048 bool doInsertRows(
int row,
int count,
const QModelIndex &parent, InsertFn &&insertFn)
2050 range_type *children = childRange(parent);
2054 this->beginInsertRows(parent, row, row + count - 1);
2056 row_ptr parentRow = parent.isValid()
2059 (
void)
std::forward<InsertFn>(insertFn)(*children, parentRow, row, count);
2063 that().resetParentInChildren(children);
2065 this->endInsertRows();
2071 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
2073 const auto end =
std::next(begin, count);
2075 for (
auto it = begin; it != end; ++it, ++rowIndex)
2076 autoConnectPropertiesInRow(*it, rowIndex, parent);
2086 return doInsertRows(row, count, parent,
2087 [
this](range_type &children, row_ptr parentRow,
int r,
int n){
2091 if constexpr (range_features::has_insert_range) {
2094 auto start = children.insert(pos, n,
nullptr);
2097 children.insert(pos, n,
std::move(*generator));
2106 bool removeRows(
int row,
int count,
const QModelIndex &parent = {})
2109 const int prevRowCount = rowCount(parent);
2110 if (row < 0 || row + count > prevRowCount)
2113 range_type *children = childRange(parent);
2118 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead) {
2120 const auto end =
std::next(begin, count);
2122 for (
auto it = begin; it != end; ++it, ++rowIndex)
2123 clearConnectionInRow(*it, rowIndex, parent);
2127 this->beginRemoveRows(parent, row, row + count - 1);
2128 [[maybe_unused]]
bool callEndRemoveColumns =
false;
2132 if (prevRowCount == count) {
2133 if (
const int columns = columnCount(parent)) {
2134 callEndRemoveColumns =
true;
2135 this->beginRemoveColumns(parent, 0, columns - 1);
2141 const auto end =
std::next(begin, count);
2142 that().deleteRemovedRows(begin, end);
2143 children->erase(begin, end);
2147 that().resetParentInChildren(children);
2150 if (callEndRemoveColumns) {
2151 Q_ASSERT(columnCount(parent) == 0);
2152 this->endRemoveColumns();
2155 this->endRemoveRows();
2162 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
2163 const QModelIndex &destParent,
int destRow)
2165 if constexpr (isMutable() && (range_features::has_rotate || range_features::has_splice)) {
2166 if (!Structure::canMoveRows(sourceParent, destParent))
2169 if (sourceParent != destParent) {
2170 return that().moveRowsAcross(sourceParent, sourceRow, count,
2171 destParent, destRow);
2174 if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0
2175 || sourceRow < 0 || sourceRow + count - 1 >=
this->rowCount(sourceParent)
2176 || destRow < 0 || destRow >
this->rowCount(destParent)) {
2180 range_type *source = childRange(sourceParent);
2182 if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow))
2187 that().resetParentInChildren(source);
2189 this->endMoveRows();
2201 int rowCount(
const QModelIndex &parent)
const {
return that().rowCountImpl(parent); }
2206 return row_traits::fixed_size();
2210 int columnCount(
const QModelIndex &parent)
const {
return that().columnCountImpl(parent); }
2261 static constexpr bool modelCopied = !QRangeModelDetails::is_wrapped<Range>() &&
2262 (std::is_reference_v<Range> || std::is_const_v<std::remove_reference_t<Range>>);
2264 static constexpr bool modelShared = QRangeModelDetails::is_any_shared_ptr<Range>();
2266 static constexpr bool default_row_deleter = protocol_traits::is_default &&
2267 protocol_traits::has_deleteRow;
2269 static constexpr bool ambiguousRowOwnership = (modelCopied || modelShared) &&
2272 static_assert(!ambiguousRowOwnership,
2273 "Using of copied and shared tree and table models with rows as raw pointers, "
2274 "and the default protocol is not allowed due to ambiguity of rows ownership. "
2275 "Move the model in, use another row type, or implement a custom tree protocol.");
2277 if constexpr (protocol_traits::has_deleteRow && !std::is_pointer_v<Range>
2278 && !QRangeModelDetails::is_any_of<Range, std::reference_wrapper>()) {
2281 that().deleteRemovedRows(begin, end);
2287 if constexpr (dynamicColumns() && !row_features::has_resize) {
2291 }
else if constexpr (!protocol_traits::has_newRow) {
2294 }
else if constexpr (!range_features::has_insert_range
2295 && !std::is_copy_constructible_v<row_type>) {
2301 return Structure::canInsertRowsImpl();
2307 return Structure::canRemoveRowsImpl();
2310 template <
typename F>
2311 bool writeAt(
const QModelIndex &index, F&& writer)
2313 bool result =
false;
2314 row_reference row = rowData(index);
2317 row_traits::for_element_at(row, index.column(), [&writer, &result](
auto &&target) {
2318 using target_type =
decltype(target);
2320 if constexpr (std::is_lvalue_reference_v<target_type>
2321 && !std::is_const_v<std::remove_reference_t<target_type>>) {
2322 result = writer(std::forward<target_type>(target));
2330 template <
typename F>
2331 void readAt(
const QModelIndex &index, F&& reader)
const {
2332 const_row_reference row = rowData(index);
2333 if (QRangeModelDetails::isValid(row))
2334 row_traits::for_element_at(row, index.column(), std::forward<F>(reader));
2337 template <
typename Value>
2340 if constexpr (std::is_constructible_v<QVariant, Value>)
2341 return QVariant(value);
2343 return QVariant::fromValue(value);
2345 template <
typename Value>
2349 if constexpr (std::is_constructible_v<QVariant, Value *>)
2350 return QVariant(value);
2352 return read(*value);
2357 template <
typename Target>
2358 static bool write(Target &target,
const QVariant &value)
2360 using Type = std::remove_reference_t<Target>;
2361 if constexpr (std::is_constructible_v<Target, QVariant>) {
2364 }
else if (value.canConvert<Type>()) {
2365 target = value.value<Type>();
2370 template <
typename Target>
2371 static bool write(Target *target,
const QVariant &value)
2374 return write(*target, value);
2378 template <
typename ItemType>
2382 operator QMetaProperty()
const {
2383 const QByteArray roleName = that.itemModel().roleNames().value(role);
2384 const QMetaObject &mo = ItemType::staticMetaObject;
2385 if (
const int index = mo.indexOfProperty(roleName.data());
2387 return mo.property(index);
2391 const QRangeModelImpl &that;
2393 } findProperty{*
this, role};
2395 if constexpr (ModelData::cachesProperties)
2396 return *m_data.properties.tryEmplace(role, findProperty).iterator;
2398 return findProperty;
2402 const QObject *gadget,
const QMetaProperty &prop)
const
2404 const typename ModelData::Connection connection = {gadget, role};
2405 if (prop.hasNotifySignal() &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead
2406 && !m_data.connections.contains(connection)) {
2407 if constexpr (isMutable())
2408 Self::connectProperty(index, gadget, m_data.context, role, prop);
2410 Self::connectPropertyConst(index, gadget, m_data.context, role, prop);
2411 m_data.connections.insert(connection);
2415 template <
typename ItemType>
2418 using item_type = std::remove_pointer_t<ItemType>;
2420 QMetaProperty prop = roleProperty<item_type>(role);
2421 if (!prop.isValid() && role == Qt::EditRole) {
2422 role = Qt::DisplayRole;
2423 prop = roleProperty<item_type>(Qt::DisplayRole);
2426 if (prop.isValid()) {
2427 if constexpr (itemsAreQObjects)
2428 connectPropertyOnRead(index, role, gadget, prop);
2429 result = readProperty(prop, gadget);
2434 template <
typename ItemType>
2437 return readRole(index, role, &gadget);
2440 template <
typename ItemType>
2443 if constexpr (std::is_base_of_v<QObject, ItemType>)
2444 return prop.read(gadget);
2446 return prop.readOnGadget(gadget);
2449 template <
typename ItemType>
2452 using item_type = std::remove_pointer_t<ItemType>;
2453 const QMetaObject &mo = item_type::staticMetaObject;
2454 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
2456 if constexpr (rowsAreQObjects)
2457 connectPropertyOnRead(index, Qt::DisplayRole, gadget, prop);
2459 return readProperty(prop, gadget);
2462 template <
typename ItemType>
2465 return readProperty(index, &gadget);
2468 template <
typename ItemType>
2469 bool writeRole(
int role, ItemType *gadget,
const QVariant &data)
2471 using item_type = std::remove_pointer_t<ItemType>;
2472 auto prop = roleProperty<item_type>(role);
2473 if (!prop.isValid() && role == Qt::EditRole)
2474 prop = roleProperty<item_type>(Qt::DisplayRole);
2476 return prop.isValid() ? writeProperty(prop, gadget, data) :
false;
2479 template <
typename ItemType>
2480 bool writeRole(
int role, ItemType &&gadget,
const QVariant &data)
2482 return writeRole(role, &gadget, data);
2485 template <
typename ItemType>
2486 static bool writeProperty(
const QMetaProperty &prop, ItemType *gadget,
const QVariant &data)
2488 if constexpr (std::is_base_of_v<QObject, ItemType>)
2489 return prop.write(gadget, data);
2491 return prop.writeOnGadget(gadget, data);
2493 template <
typename ItemType>
2496 using item_type = std::remove_pointer_t<ItemType>;
2497 const QMetaObject &mo = item_type::staticMetaObject;
2498 return writeProperty(mo.property(property + mo.propertyOffset()), gadget, data);
2501 template <
typename ItemType>
2502 static bool writeProperty(
int property, ItemType &&gadget,
const QVariant &data)
2504 return writeProperty(property, &gadget, data);
2507 template <
typename ItemType>
2510 using item_type = std::remove_pointer_t<ItemType>;
2511 const QMetaObject &mo = item_type::staticMetaObject;
2512 bool success =
true;
2513 if (property == -1) {
2515 if constexpr (std::is_base_of_v<QObject, item_type>) {
2516 for (
int p = mo.propertyOffset(); p < mo.propertyCount(); ++p)
2517 success = writeProperty(mo.property(p), object, {}) && success;
2522 success = writeProperty(mo.property(property + mo.propertyOffset()), object, {});
2527 template <
typename ItemType>
2530 return resetProperty(property, &object);
2536 Q_ASSERT(index.isValid());
2537 return that().rowDataImpl(index);
2542 Q_ASSERT(index.isValid());
2543 return that().rowDataImpl(index);
2548 if (!index.isValid())
2549 return m_data.model();
2552 return that().childRangeImpl(index);
2557 if (!index.isValid())
2558 return m_data.model();
2561 return that().childRangeImpl(index);
2572template <
typename Range,
typename Protocol>
2579 using range_type =
typename Base::range_type;
2580 using range_features =
typename Base::range_features;
2581 using row_type =
typename Base::row_type;
2582 using row_ptr =
typename Base::row_ptr;
2583 using const_row_ptr =
typename Base::const_row_ptr;
2585 using tree_traits =
typename Base::protocol_traits;
2586 static constexpr bool is_mutable_impl = tree_traits::has_mutable_childRows;
2588 static constexpr bool rows_are_any_refs_or_pointers = Base::rows_are_raw_pointers ||
2589 QRangeModelDetails::is_smart_ptr<row_type>() ||
2590 QRangeModelDetails::is_any_of<row_type,
std::reference_wrapper>();
2591 static_assert(!Base::dynamicColumns(),
"A tree must have a static number of columns!");
2595 : Base(
std::forward<Range>(model),
std::forward<Protocol>(p), itemModel)
2600 for (
auto &&child : children)
2612 auto *children =
this->childRange(parent);
2615 return autoConnectPropertiesRange(QRangeModelDetails::refTo(children), parent);
2621 if (!parent.isValid())
2622 return this->createIndex(row, column);
2624 if (parent.column())
2625 return QModelIndex();
2627 const_row_ptr grandParent =
static_cast<const_row_ptr>(parent.constInternalPointer());
2628 const auto &parentSiblings = childrenOf(grandParent);
2635 if (!child.isValid())
2639 const_row_ptr parentRow =
static_cast<const_row_ptr>(child.constInternalPointer());
2644 auto &&grandParent =
this->protocol().parentRow(
QRangeModelDetails::refTo(parentRow));
2645 const range_type &parentSiblings = childrenOf(
QRangeModelDetails::pointerTo(grandParent));
2649 const auto it =
std::find_if(begin, end, [parentRow](
auto &&s){
2653 return this->createIndex(
std::distance(begin, it), 0,
2660 return Base::size(
this->childRange(parent));
2667 return Base::fixedColumnCount();
2672 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
2680 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2681 && Base::dynamicRows() && range_features::has_insert;
2689 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2690 && Base::dynamicRows() && range_features::has_erase;
2698 static constexpr bool canMoveRows(
const QModelIndex &,
const QModelIndex &)
2704 const QModelIndex &destParent,
int destRow)
2709 if constexpr (!rows_are_any_refs_or_pointers && !tree_traits::has_setParentRow) {
2711 }
else if constexpr (!(range_features::has_insert && range_features::has_erase)) {
2713 }
else if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1,
2714 destParent, destRow)) {
2718 range_type *source =
this->childRange(sourceParent);
2719 range_type *destination =
this->childRange(destParent);
2724 if constexpr (range_features::has_insert_range) {
2726 const auto sourceEnd =
std::next(sourceStart, count);
2728 destination->insert(destStart,
std::move_iterator(sourceStart),
2729 std::move_iterator(sourceEnd));
2730 }
else if constexpr (
std::is_copy_constructible_v<row_type>) {
2732 destination->insert(destStart, count, row_type{});
2735 row_ptr parentRow = destParent.isValid()
2741 if (parentRow ==
static_cast<row_ptr>(sourceParent.internalPointer())) {
2742 if (sourceParent.row() < destRow) {
2743 source =
this->childRange(sourceParent);
2746 source =
this->childRange(
this->createIndex(sourceParent.row() + count, 0,
2747 sourceParent.internalPointer()));
2754 const auto writeEnd =
std::next(writeStart, count);
2756 const auto sourceEnd =
std::next(sourceStart, count);
2758 for (
auto write = writeStart, read = sourceStart; write != writeEnd; ++write, ++read) {
2761 if constexpr (!range_features::has_insert_range)
2762 *write =
std::move(*read);
2766 source->erase(sourceStart, sourceEnd);
2776 this->endMoveRows();
2784 static_assert(tree_traits::has_setParentRow);
2785 row_type empty_row =
this->protocol().newRow();
2791 template <
typename It,
typename Sentinel>
2794 if constexpr (tree_traits::has_deleteRow) {
2795 for (
auto it = begin; it != end; ++it) {
2796 if constexpr (Base::isMutable()) {
2797 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(*it));
2805 this->protocol().deleteRow(
std::move(*it));
2812 const auto persistentIndexList =
this->persistentIndexList();
2813 const auto [firstColumn, lastColumn] = [&persistentIndexList]{
2814 int first = std::numeric_limits<
int>::max();
2816 for (
const auto &pmi : persistentIndexList) {
2817 first = (
std::min)(pmi.column(), first);
2818 last = (
std::max)(pmi.column(), last);
2820 return std::pair(first, last);
2828 if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) {
2829 const bool changePersistentIndexes = pmiToColumn >= pmiFromColumn;
2832 for (
auto it = begin; it != end; ++it) {
2833 decltype(
auto) maybeChildren =
this->protocol().childRows(*it);
2836 QModelIndexList fromIndexes;
2837 QModelIndexList toIndexes;
2838 if (changePersistentIndexes) {
2839 fromIndexes.reserve(Base::size(childrenRef) * (pmiToColumn - pmiFromColumn + 1));
2840 toIndexes.reserve(Base::size(childrenRef) * (pmiToColumn - pmiFromColumn + 1));
2845 for (
auto &child : childrenRef) {
2846 const_row_ptr oldParent =
this->protocol().parentRow(child);
2847 if (oldParent != parentRow) {
2848 if (changePersistentIndexes) {
2849 for (
int column = pmiFromColumn; column <= pmiToColumn; ++column) {
2850 fromIndexes.append(
this->createIndex(row, column, oldParent));
2851 toIndexes.append(
this->createIndex(row, column, parentRow));
2854 this->protocol().setParentRow(child, parentRow);
2858 if (changePersistentIndexes)
2859 this->changePersistentIndexList(fromIndexes, toIndexes);
2869 for (
const auto &row : range) {
2870 if (!
this->autoConnectPropertiesInRow(row, rowIndex, parent))
2875 if (!autoConnectPropertiesRange(QRangeModelDetails::refTo(children),
2876 this->itemModel().index(rowIndex, 0, parent))) {
2887 return autoConnectPropertiesRange(*
this->m_data.model(), {});
2892 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
2893 const range_type &siblings = childrenOf(parentRow);
2894 Q_ASSERT(index.row() <
int(Base::size(siblings)));
2900 row_ptr parentRow =
static_cast<row_ptr>(index.internalPointer());
2901 range_type &siblings = childrenOf(parentRow);
2902 Q_ASSERT(index.row() <
int(Base::size(siblings)));
2908 const auto &row =
this->rowData(index);
2910 return static_cast<
const range_type *>(
nullptr);
2912 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
2918 auto &row =
this->rowData(index);
2920 return static_cast<range_type *>(
nullptr);
2922 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
2923 using Children = std::remove_reference_t<
decltype(children)>;
2925 if constexpr (QRangeModelDetails::is_any_of<Children, std::optional>())
2926 if constexpr (std::is_default_constructible<
typename Children::value_type>()) {
2928 children.emplace(range_type{});
2937 : *
this->m_data.model();
2941 range_type &childrenOf(row_ptr row)
2944 : *
this->m_data.model();
2949template <
typename Range>
2956 static constexpr bool is_mutable_impl =
true;
2973 if constexpr (Base::dynamicColumns()) {
2974 if (column <
int(Base::size(*QRangeModelDetails::pos(*
this->m_data.model(), row))))
2975 return this->createIndex(row, column);
2978 qCritical(
"QRangeModel: Column-range at row %d is not large enough!", row);
2982 return this->createIndex(row, column);
2993 if (parent.isValid())
2995 return int(Base::size(*
this->m_data.model()));
3000 if (parent.isValid())
3004 if constexpr (Base::dynamicColumns()) {
3005 return int(Base::size(*
this->m_data.model()) == 0
3007 : Base::size(*QRangeModelDetails::adl_begin(*
this->m_data.model())));
3009 return Base::fixedColumnCount();
3015 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren;
3020 return Base::dynamicRows() && range_features::has_insert;
3025 return Base::dynamicRows() && range_features::has_erase;
3028 static constexpr bool canMoveColumns(
const QModelIndex &source,
const QModelIndex &destination)
3030 return !source.isValid() && !destination.isValid();
3033 static constexpr bool canMoveRows(
const QModelIndex &source,
const QModelIndex &destination)
3035 return !source.isValid() && !destination.isValid();
3039 const QModelIndex &,
int)
noexcept
3047 row_type empty_row =
this->protocol().newRow();
3050 if constexpr (Base::dynamicColumns() && row_features::has_resize) {
3058 template <
typename It,
typename Sentinel>
3061 if constexpr (Base::protocol_traits::has_deleteRow) {
3062 for (
auto it = begin; it != end; ++it)
3063 this->protocol().deleteRow(
std::move(*it));
3069 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
3075 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
3092 return *
this->m_data.model();
3103 for (
const auto &row : *
this->m_data.model()) {
3104 result &=
this->autoConnectPropertiesInRow(row, rowIndex, {});
QModelIndex parentImpl(const QModelIndex &) const
static constexpr bool canMoveRows(const QModelIndex &source, const QModelIndex &destination)
void deleteRemovedRows(It &&begin, Sentinel &&end)
const range_type & childrenOf(const_row_ptr row) const
static constexpr bool canRemoveRowsImpl()
QGenericTableItemModelImpl(Range &&model, QRangeModel *itemModel)
range_type * childRangeImpl(const QModelIndex &)
int columnCountImpl(const QModelIndex &parent) const
constexpr bool moveRowsAcross(const QModelIndex &, int, int, const QModelIndex &, int) noexcept
decltype(auto) rowDataImpl(const QModelIndex &index) const
static constexpr bool canInsertRowsImpl()
const range_type * childRangeImpl(const QModelIndex &) const
int rowCountImpl(const QModelIndex &parent) const
void resetParentInChildren(range_type *)
bool autoConnectPropertiesImpl() const
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)
void setParentRow(range_type &children, row_ptr parent)
bool autoConnectPropertiesImpl() 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)
int rowCountImpl(const QModelIndex &parent) const
static constexpr bool canRemoveRowsImpl()
void resetParentInChildrenRecursive(range_type *children, int pmiFromColumn, int pmiToColumn)
int columnCountImpl(const QModelIndex &) const
static constexpr bool canMoveRows(const QModelIndex &, const QModelIndex &)
const range_type & childrenOf(const_row_ptr row) const
decltype(auto) rowDataImpl(const QModelIndex &index)
QGenericTreeItemModelImpl(Range &&model, Protocol &&p, QRangeModel *itemModel)
bool autoConnectPropertiesRange(const range_type &range, const QModelIndex &parent) const
QModelIndex indexImpl(int row, int column, const QModelIndex &parent) const
void deleteRemovedRows(It &&begin, Sentinel &&end)
bool autoConnectProperties(const QModelIndex &parent) const
const range_type * childRangeImpl(const QModelIndex &index) const
static constexpr bool canInsertRowsImpl()
decltype(auto) rowDataImpl(const QModelIndex &index) const
void deleteRemovedRows(range_type &range)
static constexpr Qt::ItemFlags defaultFlags()
QModelIndex parentImpl(const QModelIndex &child) const
const QAbstractItemModel & itemModel() const
void beginInsertRows(const QModelIndex &parent, int start, int count)
void multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const
bool beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destParent, int destRow)
bool setItemData(const QModelIndex &index, const QMap< int, QVariant > &data)
QMap< int, QVariant > itemData(const QModelIndex &index) const
bool insertRows(int row, int count, const QModelIndex &parent)
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
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, typename C::SetAutoConnectPolicy > MethodTemplates
QRangeModelImplBase(QRangeModel *itemModel)
QModelIndexList persistentIndexList() const
void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to)
int columnCount(const QModelIndex &parent) const
static Q_CORE_EXPORT bool connectProperties(const QModelIndex &index, const QObject *item, QRangeModelDetails::AutoConnectContext *context, const QHash< int, QMetaProperty > &properties)
QModelIndex sibling(int row, int column, const QModelIndex &index) const
void beginInsertColumns(const QModelIndex &parent, int start, int count)
bool insertColumns(int column, int count, const QModelIndex &parent)
void setAutoConnectPolicy()
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
static Q_CORE_EXPORT bool connectPropertiesConst(const QModelIndex &index, const QObject *item, QRangeModelDetails::AutoConnectContext *context, const QHash< int, QMetaProperty > &properties)
AutoConnectPolicy autoConnectPolicy() const
bool removeColumns(int column, int count, const QModelIndex &parent)
static Q_CORE_EXPORT bool connectPropertyConst(const QModelIndex &index, const QObject *item, QRangeModelDetails::AutoConnectContext *context, int role, const QMetaProperty &property)
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
static Q_CORE_EXPORT bool connectProperty(const QModelIndex &index, const QObject *item, QRangeModelDetails::AutoConnectContext *context, int role, const QMetaProperty &property)
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)
auto maybeBlockDataChangedDispatch()
static constexpr bool has_metaobject
QMetaProperty roleProperty(int role) const
int columnCount(const QModelIndex &parent) const
bool writeRole(int role, ItemType &&gadget, const QVariant &data)
static bool write(Target *target, const QVariant &value)
void connectPropertyOnRead(const QModelIndex &index, int role, const QObject *gadget, const QMetaProperty &prop) const
Qt::ItemFlags flags(const QModelIndex &index) const
void readAt(const QModelIndex &index, F &&reader) const
bool insertColumns(int column, int count, const QModelIndex &parent)
QVariant data(const QModelIndex &index, int role) const
QVariant headerData(int section, Qt::Orientation orientation, int role) const
static constexpr bool isRangeModelRole(int role)
bool clearItemData(const QModelIndex &index)
void multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const
static constexpr int fixedColumnCount()
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)
QVariant readProperty(const QModelIndex &index, ItemType *gadget) const
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)
bool writeRole(int role, ItemType *gadget, const QVariant &data)
QVariant readRole(const QModelIndex &index, int role, const ItemType &gadget) const
QRangeModelImpl< Structure, Range, Protocol > Self
static constexpr bool canRemoveRows()
static constexpr int static_column_count
QVariant readProperty(const QModelIndex &index, const ItemType &gadget) const
protocol_type & protocol()
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
void setAutoConnectPolicy()
static bool writeProperty(int property, ItemType *gadget, const QVariant &data)
QRangeModelImpl(Range &&model, Protocol &&protocol, QRangeModel *itemModel)
const Structure & that() const
static constexpr bool isPrimaryRole(int role)
void updateTarget(LHS *org, RHS &©) noexcept
static constexpr bool itemsAreQObjects
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(const QModelIndex &index, int role, ItemType *gadget) const
static bool resetProperty(int property, ItemType *object)
bool autoConnectPropertiesInRow(const row_type &row, int rowIndex, const QModelIndex &parent) const
static constexpr bool rowsAreQObjects
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
void clearConnectionInRow(const row_type &row, int rowIndex, const QModelIndex &parent) const
bool doInsertRows(int row, int count, const QModelIndex &parent, InsertFn &&insertFn)
static auto adl_end(C &&c) -> decltype(end(QRangeModelDetails::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
typename QRangeModelDetails::wrapped_helper< T >::type wrapped_t
auto value(It &&it) -> decltype(it.value())
std::conjunction< std::is_swappable< decltype(*std::declval< It >())>, std::is_base_of< std::forward_iterator_tag, typename std::iterator_traits< It >::iterator_category > > test_rotate
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 constexpr bool hasHeaderData
static decltype(auto) refTo(T &&t)
static auto pointerTo(T &&t)
static auto adl_begin(C &&c) -> decltype(begin(QRangeModelDetails::refTo(std::forward< C >(c))))
static constexpr bool is_multi_role_v
friend bool operator==(const Connection &lhs, const Connection &rhs) noexcept
friend size_t qHash(const Connection &c, size_t seed) noexcept
QSet< Connection > connections
~ConnectionStorage()=default
AutoConnectContext * context
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{})
QHash< int, QMetaProperty > properties
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 hasFlags
static QHash< int, QByteArray > roleNames(That *)
static constexpr bool has_erase
static constexpr bool has_splice
static constexpr bool has_resize
static constexpr bool is_mutable
static constexpr bool has_rotate
static constexpr bool has_cbegin
static constexpr bool has_insert
static constexpr bool is_default
static constexpr bool has_setParentRow
static constexpr bool is_list
static constexpr bool has_mutable_childRows
static constexpr bool has_deleteRow
static constexpr bool has_newRow
static constexpr bool is_tree
static constexpr bool is_table
static constexpr bool has_insert_range
static constexpr bool is_mutable
static constexpr bool has_rotate
static constexpr bool has_resize
static constexpr bool has_insert
static constexpr bool has_cbegin
static constexpr bool has_splice
static constexpr bool has_erase
static constexpr bool isMultiRole
static constexpr int fixed_size()
static bool for_each_element(const T &row, const QModelIndex &firstIndex, Fn &&fn)
static QVariant column_name(int)
static constexpr int static_size
static constexpr bool is_range
static void for_element_at(C &&container, std::size_t idx, Fn &&fn)
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++()
const QRangeModelImpl * that
QModelRoleDataSpan roleDataSpan
void operator()(const value_type &value) const
const QModelIndex & index