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>
398 template <
typename T>
411 "The return type of the ItemAccess::writeRole implementation "
412 "needs to be convertible to a bool!");
415 "The return type of the ItemAccess::readRole implementation "
416 "needs to be convertible to QVariant!");
423 template <
typename T,
typename =
void>
429 template <
typename T>
446 template <
typename T,
typename =
void>
463 template <
typename C,
typename Fn>
469 std::forward<Fn>(fn)(
std::forward<C>(container));
472 template <
typename Fn>
478 int columnIndex = -1;
481 return std::forward<Fn>(fn)(firstIndex.siblingAtColumn(++columnIndex),
489 template <
typename T>
509 template <
typename C,
typename F>
544 template <
typename Fn>
564 template <
typename C,
typename F>
576 template <
typename Fn>
592 template <
typename T>
613 template <
typename C,
typename F>
633 template <
typename Fn>
640 template <
typename T,
typename =
void>
643 template <
typename That>
646 return That::roleNamesForSimpleType();
653 template <
typename That>
660 template <
typename T>
666 template <
typename T>
669 template <
typename That>
676 template <
typename T>
680 template <
typename Range>
686 auto newRow() ->
decltype(R{}) {
return R{}; }
689 template <
typename Range>
717 template <
typename Range,
725 template <
typename Range>
728 template <
typename R >
729 auto parentRow(
const R& row)
const ->
decltype(row.parentRow())
731 return row.parentRow();
734 template <
typename R >
735 auto setParentRow(R &row, R* parent) ->
decltype(row.setParentRow(parent))
737 row.setParentRow(parent);
740 template <
typename R >
741 auto childRows(
const R &row)
const ->
decltype(row.childRows())
743 return row.childRows();
746 template <
typename R >
749 return row.childRows();
753 template <
typename P,
typename R>
756 template <
typename P,
typename R>
759 template <
typename P,
typename R>
762 template <
typename P,
typename R>
765 template <
typename P,
typename R>
769 template <
typename P,
typename R>
772 template <
typename P,
typename R>
775 template <
typename P,
typename R>
778 template <
typename P,
typename =
void>
780 template <
typename P>
784 template <
typename P,
typename R,
typename =
void>
786 template <
typename P,
typename R>
791 template <
typename Range,
803 template <
typename Range>
816 template <
typename Range,
typename Protocol>
852 template <
bool cacheProperties,
bool itemsAreQObjects>
884 return lhs.sender == rhs.sender && lhs
.role == rhs
.role;
888 return qHashMulti(seed, c.sender, c
.role);
912 template <
typename ModelStorage,
typename =
void>
931 template <
typename ModelStorage,
typename PropertyStorage>
942 template <
typename Model = ModelStorage>
968 bool setHeaderData(
int section, Qt::Orientation orientation,
const QVariant &data,
int role);
969 bool setData(
const QModelIndex &index,
const QVariant &data,
int role);
970 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data);
974 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
const QModelIndex &destParent,
int destColumn);
975 bool insertRows(
int row,
int count,
const QModelIndex &parent);
976 bool removeRows(
int row,
int count,
const QModelIndex &parent);
977 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
const QModelIndex &destParent,
int destRow);
990 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const;
1022 template <
typename C>
1054 friend class QRangeModelPrivate;
1057 QRangeModel *m_rangeModel;
1061 : m_rangeModel(itemModel)
1066 inline void dataChanged(
const QModelIndex &from,
const QModelIndex &to,
1067 const QList<
int> &roles);
1074 inline bool beginMoveColumns(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1075 const QModelIndex &destParent,
int destRow);
1077 inline void beginInsertRows(
const QModelIndex &parent,
int start,
int count);
1079 inline void beginRemoveRows(
const QModelIndex &parent,
int start,
int count);
1081 inline bool beginMoveRows(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1082 const QModelIndex &destParent,
int destRow);
1102 QRangeModelDetails::AutoConnectContext *context,
1103 int role,
const QMetaProperty &property);
1105 QRangeModelDetails::AutoConnectContext *context,
1106 int role,
const QMetaProperty &property);
1108 QRangeModelDetails::AutoConnectContext *context,
1109 const QHash<
int, QMetaProperty> &properties);
1111 QRangeModelDetails::AutoConnectContext *context,
1112 const QHash<
int, QMetaProperty> &properties);
1115template <
typename Structure,
typename Range,
1116 typename Protocol = QRangeModelDetails::table_protocol_t<Range>>
1152 "Currently, std::optional is not supported for ranges and rows, as "
1153 "it has range semantics in c++26. Once the required behavior is clarified, "
1154 "std::optional for ranges and rows will be supported.");
1161 Structure&
that() {
return static_cast<Structure &>(*
this); }
1162 const Structure&
that()
const {
return static_cast<
const Structure &>(*
this); }
1164 template <
typename C>
1165 static constexpr int size(
const C &c)
1170 if constexpr (QRangeModelDetails::test_size<C>()) {
1172 return int(size(c));
1174#if defined(__cpp_lib_ranges)
1175 using std::ranges::distance;
1177 using std::distance;
1179 using container_type = std::conditional_t<QRangeModelDetails::range_traits<C>::has_cbegin,
1180 const QRangeModelDetails::wrapped_t<C>,
1181 QRangeModelDetails::wrapped_t<C>>;
1182 container_type& container =
const_cast<container_type &>(
QRangeModelDetails::refTo(c));
1198 return this->blockDataChangedDispatch();
1208 template <
typename T>
1228 {
return lhs.n == rhs.n; }
1230 {
return !(lhs == rhs); }
1241 "The range holding a move-only row-type must support insert(pos, start, end)");
1248 return range_features::is_mutable && row_features::is_mutable
1249 && std::is_reference_v<row_reference>
1250 && Structure::is_mutable_impl;
1273 if (row < 0 || column < 0 || column >= columnCount(parent)
1274 || row >= rowCount(parent)) {
1278 return that().indexImpl(row, column, parent);
1283 if (row == index.row() && column == index.column())
1286 if (column < 0 || column >=
this->columnCount({}))
1289 if (row == index.row())
1290 return this->createIndex(row, column, index.constInternalPointer());
1292 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
1293 const auto siblingCount = size(that().childrenOf(parentRow));
1294 if (row < 0 || row >=
int(siblingCount))
1296 return this->createIndex(row, column, parentRow);
1301 if (!index.isValid())
1302 return Qt::NoItemFlags;
1304 Qt::ItemFlags f = Structure::defaultFlags();
1306 if constexpr (isMutable()) {
1307 if constexpr (row_traits::hasMetaObject) {
1308 if (index.column() < row_traits::fixed_size()) {
1309 const QMetaObject mo = wrapped_row_type::staticMetaObject;
1310 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
1311 if (prop.isWritable())
1312 f |= Qt::ItemIsEditable;
1315 f |= Qt::ItemIsEditable;
1316 }
else if constexpr (std::is_reference_v<row_reference> && !std::is_const_v<row_reference>) {
1319 const_row_reference row = rowData(index);
1320 row_reference mutableRow =
const_cast<row_reference>(row);
1322 row_traits::for_element_at(mutableRow, index.column(), [&f](
auto &&ref){
1323 using target_type =
decltype(ref);
1324 if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
1325 f &= ~Qt::ItemIsEditable;
1326 else if constexpr (std::is_lvalue_reference_v<target_type>)
1327 f |= Qt::ItemIsEditable;
1332 f &= ~Qt::ItemIsEditable;
1342 if constexpr (QRangeModelDetails::hasHeaderData<wrapped_row_type>) {
1343 if (orientation == Qt::Horizontal) {
1344 result = QRangeModelDetails::QRangeModelRowOptions<wrapped_row_type>::headerData(
1347 if (result.isValid())
1352 if (role != Qt::DisplayRole || orientation != Qt::Horizontal
1353 || section < 0 || section >= columnCount({})) {
1354 return this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1357 result = row_traits::column_name(section);
1358 if (!result.isValid())
1359 result =
this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1365 if (!index.isValid())
1368 QModelRoleData result(role);
1369 multiData(index, result);
1370 return std::move(result.data());
1375 return role == Qt::RangeModelDataRole
1376 || role == Qt::RangeModelAdapterRole;
1381 return role == Qt::DisplayRole || role == Qt::EditRole;
1386 QMap<
int, QVariant> result;
1388 if (index.isValid()) {
1392 readAt(index, [&result, &tried](
const auto &value) {
1393 if constexpr (std::is_convertible_v<
decltype(value),
decltype(result)>) {
1399 const auto roles =
this->itemModel().roleNames().keys();
1400 QVarLengthArray<QModelRoleData, 16> roleDataArray;
1401 roleDataArray.reserve(roles.size());
1402 for (
auto role : roles) {
1403 if (isRangeModelRole(role))
1405 roleDataArray.emplace_back(role);
1407 QModelRoleDataSpan roleDataSpan(roleDataArray);
1408 multiData(index, roleDataSpan);
1410 for (QModelRoleData &roleData : roleDataSpan) {
1411 if (roleData.data().isValid())
1412 result[roleData.role()] = std::move(roleData.data());
1419 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const
1422 readAt(index, [
this, &index, roleDataSpan, &tried](
const auto &value) {
1425 using value_type = q20::remove_cvref_t<
decltype(value)>;
1426 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1427 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1429 const auto readModelData = [&value](QModelRoleData &roleData){
1430 const int role = roleData.role();
1431 if (role == Qt::RangeModelDataRole) {
1435 if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
1436 roleData.setData(QVariant::fromValue(QRangeModelDetails::refTo(value)));
1438 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1439 }
else if (role == Qt::RangeModelAdapterRole) {
1441 if constexpr (std::is_copy_assignable_v<value_type>)
1442 roleData.setData(QVariant::fromValue(value));
1444 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1451 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1452 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1454 for (
auto &roleData : roleDataSpan) {
1455 if (!readModelData(roleData)) {
1456 roleData.setData(ItemAccess::readRole(QRangeModelDetails::refTo(value),
1460 }
else if constexpr (multi_role()) {
1462 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1464 if constexpr (!multi_role::int_key)
1465 return this->itemModel().roleNames();
1469 using key_type =
typename value_type::key_type;
1470 for (
auto &roleData : roleDataSpan) {
1471 const auto &it = [&roleNames, &value, role = roleData.role()]{
1472 Q_UNUSED(roleNames);
1473 if constexpr (multi_role::int_key)
1474 return value.find(key_type(role));
1476 return value.find(roleNames.value(role));
1478 if (it != QRangeModelDetails::adl_end(value))
1479 roleData.setData(QRangeModelDetails::value(it));
1481 roleData.clearData();
1483 }
else if constexpr (has_metaobject<value_type>) {
1484 if (row_traits::fixed_size() <= 1) {
1486 for (
auto &roleData : roleDataSpan) {
1487 if (!readModelData(roleData)) {
1488 roleData.setData(readRole(index, roleData.role(),
1489 QRangeModelDetails::pointerTo(value)));
1492 }
else if (index.column() <= row_traits::fixed_size()) {
1494 for (
auto &roleData : roleDataSpan) {
1495 const int role = roleData.role();
1496 if (isPrimaryRole(role)) {
1497 roleData.setData(readProperty(index,
1498 QRangeModelDetails::pointerTo(value)));
1500 roleData.clearData();
1506 for (
auto &roleData : roleDataSpan) {
1507 const int role = roleData.role();
1508 if (isPrimaryRole(role) || isRangeModelRole(role))
1509 roleData.setData(read(value));
1511 roleData.clearData();
1519 bool setData(
const QModelIndex &index,
const QVariant &data,
int role)
1521 if (!index.isValid())
1524 bool success =
false;
1525 if constexpr (isMutable()) {
1526 auto emitDataChanged = qScopeGuard([&success,
this, &index, role]{
1528 Q_EMIT
this->dataChanged(index, index,
1529 role == Qt::EditRole || role == Qt::RangeModelDataRole
1530 || role == Qt::RangeModelAdapterRole
1531 ? QList<
int>{} : QList<
int>{role});
1537 const auto writeData = [
this, column = index.column(), &data, role](
auto &&target) ->
bool {
1538 using value_type = q20::remove_cvref_t<
decltype(target)>;
1539 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1540 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1542 auto setRangeModelDataRole = [&target, &data]{
1543 constexpr auto targetMetaType = QMetaType::fromType<value_type>();
1544 const auto dataMetaType = data.metaType();
1545 constexpr bool isWrapped = QRangeModelDetails::is_wrapped<value_type>();
1546 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>) {
1550 if constexpr (isWrapped) {
1551 constexpr bool is_raw_pointer = std::is_pointer_v<value_type>;
1552 if constexpr (!is_raw_pointer && std::is_copy_assignable_v<value_type>) {
1553 if (data.canConvert(targetMetaType)) {
1554 target = data.value<value_type>();
1557 }
else if constexpr (is_raw_pointer) {
1559 target = data.value<value_type>();
1568 }
else if constexpr (isWrapped) {
1573 if (
const auto mt = QMetaType::fromType<wrapped_value_type>();
1574 data.canConvert(mt)) {
1575 targetRef = data.value<wrapped_value_type>();
1577 }
else if (
const auto mtp = QMetaType::fromType<wrapped_value_type *>();
1578 data.canConvert(mtp)) {
1579 targetRef = *data.value<wrapped_value_type *>();
1583 }
else if (targetMetaType == dataMetaType) {
1584 QRangeModelDetails::refTo(target) = data.value<value_type>();
1586 }
else if (dataMetaType.flags() & QMetaType::PointerToGadget) {
1587 QRangeModelDetails::refTo(target) = *data.value<value_type *>();
1591 qCritical(
"Not able to assign %s to %s",
1592 qPrintable(QDebug::toString(data)), targetMetaType.name());
1597 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1598 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1599 if (isRangeModelRole(role))
1600 return setRangeModelDataRole();
1601 return ItemAccess::writeRole(QRangeModelDetails::refTo(target), data, role);
1602 }
else if constexpr (has_metaobject<value_type>) {
1603 if (row_traits::fixed_size() <= 1) {
1604 if (isRangeModelRole(role))
1605 return setRangeModelDataRole();
1607 }
else if (column <= row_traits::fixed_size()
1608 && (isPrimaryRole(role) || isRangeModelRole(role))) {
1611 }
else if constexpr (multi_role::value) {
1612 Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role);
1615 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1617 if constexpr (!multi_role::int_key)
1618 return this->itemModel().roleNames();
1622 if (role == Qt::EditRole) {
1623 if constexpr (multi_role::int_key) {
1624 if (target.find(roleToSet) == target.end())
1625 roleToSet = Qt::DisplayRole;
1627 if (target.find(roleNames.value(roleToSet)) == target.end())
1628 roleToSet = Qt::DisplayRole;
1631 if constexpr (multi_role::int_key)
1632 return write(target[roleToSet], data);
1634 return write(target[roleNames.value(roleToSet)], data);
1635 }
else if (isPrimaryRole(role) || isRangeModelRole(role)) {
1636 return write(target, data);
1641 success = writeAt(index, writeData);
1644 if (success && isRangeModelRole(role) &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
1645 if (QObject *item = data.value<QObject *>())
1646 Self::connectProperties(index, item, m_data.context, m_data.properties);
1653 template <
typename LHS,
typename RHS>
1656 if constexpr (
std::is_pointer_v<RHS>)
1658 else if constexpr (
std::is_assignable_v<LHS, RHS>)
1659 org =
std::forward<RHS>(copy);
1663 template <
typename LHS,
typename RHS>
1666 updateTarget(*org,
std::forward<RHS>(copy));
1669 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data)
1671 if (!index.isValid() || data.isEmpty())
1674 bool success =
false;
1675 if constexpr (isMutable()) {
1676 auto emitDataChanged = qScopeGuard([&success,
this, &index, &data]{
1678 Q_EMIT
this->dataChanged(index, index, data.keys());
1684 auto writeItemData = [
this, &tried, &data](
auto &target) ->
bool {
1686 using value_type = q20::remove_cvref_t<
decltype(target)>;
1687 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1688 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1692 auto makeCopy = [](
const value_type &original){
1693 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>)
1695 else if constexpr (std::is_pointer_v<
decltype(original)>)
1697 else if constexpr (std::is_copy_assignable_v<value_type>)
1703 const auto roleNames =
this->itemModel().roleNames();
1705 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1707 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1708 const auto roles = roleNames.keys();
1709 auto targetCopy = makeCopy(target);
1710 for (
int role : roles) {
1711 if (!ItemAccess::writeRole(QRangeModelDetails::refTo(targetCopy),
1712 data.value(role), role)) {
1716 updateTarget(target,
std::move(targetCopy));
1718 }
else if constexpr (multi_role()) {
1719 using key_type =
typename value_type::key_type;
1721 const auto roleName = [&roleNames](
int role) {
1722 return roleNames.value(role);
1727 if constexpr (!multi_role::int_key)
1729 auto invalid =
std::find_if(data.keyBegin(), data.keyEnd(),
1730 [&roleName](
int role) {
return roleName(role).isEmpty(); }
1733 if (invalid != data.keyEnd()) {
1735 qWarning(
"No role name set for %d", *invalid);
1741 for (
auto &&[role, value] : data.asKeyValueRange()) {
1742 if constexpr (multi_role::int_key)
1743 target[
static_cast<key_type>(role)] = value;
1745 target[QString::fromUtf8(roleName(role))] = value;
1748 }
else if constexpr (has_metaobject<value_type>) {
1749 if (row_traits::fixed_size() <= 1) {
1751 auto targetCopy = makeCopy(target);
1752 for (
auto &&[role, value] : data.asKeyValueRange()) {
1753 if (isRangeModelRole(role))
1755 if (!writeRole(role, QRangeModelDetails::pointerTo(targetCopy), value)) {
1756 const QByteArray roleName = roleNames.value(role);
1758 qWarning(
"Failed to write value '%s' to role '%s'",
1759 qPrintable(QDebug::toString(value)), roleName.data());
1764 updateTarget(target,
std::move(targetCopy));
1771 success = writeAt(index, writeItemData);
1776 emitDataChanged.dismiss();
1777 success =
this->itemModel().QAbstractItemModel::setItemData(index, data);
1785 if (!index.isValid())
1788 bool success =
false;
1789 if constexpr (isMutable()) {
1790 auto emitDataChanged = qScopeGuard([&success,
this, &index]{
1792 Q_EMIT
this->dataChanged(index, index, {});
1795 auto clearData = [column = index.column()](
auto &&target) {
1796 if constexpr (row_traits::hasMetaObject) {
1797 if (row_traits::fixed_size() <= 1) {
1800 }
else if (column <= row_traits::fixed_size()) {
1810 success = writeAt(index, clearData);
1818 using item_type = QRangeModelDetails::wrapped_t<
typename row_traits::item_type>;
1819 using item_traits =
typename QRangeModelDetails::item_traits<item_type>;
1820 return item_traits::roleNames(
this);
1827 return row_traits::for_each_element(QRangeModelDetails::refTo(row),
1828 this->itemModel().index(rowIndex, 0, parent),
1829 [
this](
const QModelIndex &index,
const QObject *item) {
1830 if constexpr (isMutable())
1831 return Self::connectProperties(index, item, m_data.context, m_data.properties);
1833 return Self::connectPropertiesConst(index, item, m_data.context, m_data.properties);
1841 row_traits::for_each_element(QRangeModelDetails::refTo(row),
1842 this->itemModel().index(rowIndex, 0, parent),
1843 [
this](
const QModelIndex &,
const QObject *item) {
1844 m_data.connections.removeIf([item](
const auto &connection) {
1845 return connection.sender == item;
1854 using item_type = std::remove_pointer_t<
typename row_traits::item_type>;
1855 using Mapping = QRangeModelDetails::AutoConnectContext::AutoConnectMapping;
1857 delete m_data.context;
1858 m_data.connections = {};
1859 switch (
this->autoConnectPolicy()) {
1860 case AutoConnectPolicy::None:
1861 m_data.context =
nullptr;
1863 case AutoConnectPolicy::Full:
1864 m_data.context =
new QRangeModelDetails::AutoConnectContext(&
this->itemModel());
1866 m_data.properties = QRangeModelImplBase::roleProperties(
this->itemModel(),
1867 item_type::staticMetaObject);
1868 m_data.context->mapping = Mapping::Roles;
1870 m_data.properties = QRangeModelImplBase::columnProperties(wrapped_row_type::staticMetaObject);
1871 m_data.context->mapping = Mapping::Columns;
1873 if (!m_data.properties.isEmpty())
1874 that().autoConnectPropertiesImpl();
1876 case AutoConnectPolicy::OnRead:
1877 m_data.context =
new QRangeModelDetails::AutoConnectContext(&
this->itemModel());
1879 m_data.context->mapping = Mapping::Roles;
1881 m_data.properties = QRangeModelImplBase::columnProperties(wrapped_row_type::staticMetaObject);
1882 m_data.context->mapping = Mapping::Columns;
1888 qWarning(
"All items in the range must be QObject subclasses");
1893 template <
typename InsertFn>
1898 range_type *
const children = childRange(parent);
1902 this->beginInsertColumns(parent, column, column + count - 1);
1904 for (
auto &child : *children) {
1905 auto it = QRangeModelDetails::pos(child, column);
1906 (
void)insertFn(QRangeModelDetails::refTo(child), it, count);
1909 this->endInsertColumns();
1915 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
1916 for (
int r = 0; r < that().rowCount(parent); ++r) {
1917 for (
int c = column; c < column + count; ++c) {
1918 const QModelIndex index = that().index(r, c, parent);
1919 writeAt(index, [
this, &index](QObject *item){
1920 return Self::connectProperties(index, item,
1921 m_data.context, m_data.properties);
1933 if constexpr (dynamicColumns() && isMutable() && row_features::has_insert) {
1934 return doInsertColumns(column, count, parent, [](
auto &row,
auto it,
int n){
1935 row.insert(it, n, {});
1945 if constexpr (dynamicColumns() && isMutable() && row_features::has_erase) {
1946 if (column < 0 || column + count > columnCount(parent))
1949 range_type *
const children = childRange(parent);
1954 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead) {
1955 for (
int r = 0; r < that().rowCount(parent); ++r) {
1956 for (
int c = column; c < column + count; ++c) {
1957 const QModelIndex index = that().index(r, c, parent);
1958 writeAt(index, [
this](QObject *item){
1959 m_data.connections.removeIf([item](
const auto &connection) {
1960 return connection.sender == item;
1969 this->beginRemoveColumns(parent, column, column + count - 1);
1970 for (
auto &child : *children) {
1971 const auto start = QRangeModelDetails::pos(child, column);
1972 QRangeModelDetails::refTo(child).erase(start, std::next(start, count));
1974 this->endRemoveColumns();
1980 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
1981 const QModelIndex &destParent,
int destColumn)
1984 if (sourceParent != destParent)
1986 if constexpr (isMutable() && (row_features::has_rotate || row_features::has_splice)) {
1987 if (!Structure::canMoveColumns(sourceParent, destParent))
1993 range_type *
const children = childRange(sourceParent);
1997 if (!
this->beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1,
1998 destParent, destColumn)) {
2002 for (
auto &child : *children)
2003 QRangeModelDetails::rotate(child, sourceColumn, count, destColumn);
2005 this->endMoveColumns();
2012 template <
typename InsertFn>
2013 bool doInsertRows(
int row,
int count,
const QModelIndex &parent, InsertFn &&insertFn)
2015 range_type *children = childRange(parent);
2019 this->beginInsertRows(parent, row, row + count - 1);
2021 row_ptr parentRow = parent.isValid()
2024 (
void)
std::forward<InsertFn>(insertFn)(*children, parentRow, row, count);
2028 that().resetParentInChildren(children);
2030 this->endInsertRows();
2036 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
2038 const auto end =
std::next(begin, count);
2040 for (
auto it = begin; it != end; ++it, ++rowIndex)
2041 autoConnectPropertiesInRow(*it, rowIndex, parent);
2051 return doInsertRows(row, count, parent,
2052 [
this](range_type &children, row_ptr parentRow,
int r,
int n){
2056 if constexpr (range_features::has_insert_range) {
2059 auto start = children.insert(pos, n,
nullptr);
2062 children.insert(pos, n,
std::move(*generator));
2071 bool removeRows(
int row,
int count,
const QModelIndex &parent = {})
2074 const int prevRowCount = rowCount(parent);
2075 if (row < 0 || row + count > prevRowCount)
2078 range_type *children = childRange(parent);
2083 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead) {
2085 const auto end =
std::next(begin, count);
2087 for (
auto it = begin; it != end; ++it, ++rowIndex)
2088 clearConnectionInRow(*it, rowIndex, parent);
2092 this->beginRemoveRows(parent, row, row + count - 1);
2093 [[maybe_unused]]
bool callEndRemoveColumns =
false;
2097 if (prevRowCount == count) {
2098 if (
const int columns = columnCount(parent)) {
2099 callEndRemoveColumns =
true;
2100 this->beginRemoveColumns(parent, 0, columns - 1);
2106 const auto end =
std::next(begin, count);
2107 that().deleteRemovedRows(begin, end);
2108 children->erase(begin, end);
2112 that().resetParentInChildren(children);
2115 if (callEndRemoveColumns) {
2116 Q_ASSERT(columnCount(parent) == 0);
2117 this->endRemoveColumns();
2120 this->endRemoveRows();
2127 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
2128 const QModelIndex &destParent,
int destRow)
2130 if constexpr (isMutable() && (range_features::has_rotate || range_features::has_splice)) {
2131 if (!Structure::canMoveRows(sourceParent, destParent))
2134 if (sourceParent != destParent) {
2135 return that().moveRowsAcross(sourceParent, sourceRow, count,
2136 destParent, destRow);
2139 if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0
2140 || sourceRow < 0 || sourceRow + count - 1 >=
this->rowCount(sourceParent)
2141 || destRow < 0 || destRow >
this->rowCount(destParent)) {
2145 range_type *source = childRange(sourceParent);
2147 if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow))
2152 that().resetParentInChildren(source);
2154 this->endMoveRows();
2166 int rowCount(
const QModelIndex &parent)
const {
return that().rowCountImpl(parent); }
2171 return row_traits::fixed_size();
2175 int columnCount(
const QModelIndex &parent)
const {
return that().columnCountImpl(parent); }
2226 static constexpr bool modelCopied = !QRangeModelDetails::is_wrapped<Range>() &&
2227 (std::is_reference_v<Range> || std::is_const_v<std::remove_reference_t<Range>>);
2229 static constexpr bool modelShared = QRangeModelDetails::is_any_shared_ptr<Range>();
2231 static constexpr bool default_row_deleter = protocol_traits::is_default &&
2232 protocol_traits::has_deleteRow;
2234 static constexpr bool ambiguousRowOwnership = (modelCopied || modelShared) &&
2237 static_assert(!ambiguousRowOwnership,
2238 "Using of copied and shared tree and table models with rows as raw pointers, "
2239 "and the default protocol is not allowed due to ambiguity of rows ownership. "
2240 "Move the model in, use another row type, or implement a custom tree protocol.");
2242 if constexpr (protocol_traits::has_deleteRow && !std::is_pointer_v<Range>
2243 && !QRangeModelDetails::is_any_of<Range, std::reference_wrapper>()) {
2246 that().deleteRemovedRows(begin, end);
2252 if constexpr (dynamicColumns() && !row_features::has_resize) {
2256 }
else if constexpr (!protocol_traits::has_newRow) {
2259 }
else if constexpr (!range_features::has_insert_range
2260 && !std::is_copy_constructible_v<row_type>) {
2266 return Structure::canInsertRowsImpl();
2272 return Structure::canRemoveRowsImpl();
2275 template <
typename F>
2276 bool writeAt(
const QModelIndex &index, F&& writer)
2278 bool result =
false;
2279 row_reference row = rowData(index);
2282 row_traits::for_element_at(row, index.column(), [&writer, &result](
auto &&target) {
2283 using target_type =
decltype(target);
2285 if constexpr (std::is_lvalue_reference_v<target_type>
2286 && !std::is_const_v<std::remove_reference_t<target_type>>) {
2287 result = writer(std::forward<target_type>(target));
2295 template <
typename F>
2296 void readAt(
const QModelIndex &index, F&& reader)
const {
2297 const_row_reference row = rowData(index);
2298 if (QRangeModelDetails::isValid(row))
2299 row_traits::for_element_at(row, index.column(), std::forward<F>(reader));
2302 template <
typename Value>
2305 if constexpr (std::is_constructible_v<QVariant, Value>)
2306 return QVariant(value);
2308 return QVariant::fromValue(value);
2310 template <
typename Value>
2314 if constexpr (std::is_constructible_v<QVariant, Value *>)
2315 return QVariant(value);
2317 return read(*value);
2322 template <
typename Target>
2323 static bool write(Target &target,
const QVariant &value)
2325 using Type = std::remove_reference_t<Target>;
2326 if constexpr (std::is_constructible_v<Target, QVariant>) {
2329 }
else if (value.canConvert<Type>()) {
2330 target = value.value<Type>();
2335 template <
typename Target>
2336 static bool write(Target *target,
const QVariant &value)
2339 return write(*target, value);
2343 template <
typename ItemType>
2347 operator QMetaProperty()
const {
2348 const QByteArray roleName = that.itemModel().roleNames().value(role);
2349 const QMetaObject &mo = ItemType::staticMetaObject;
2350 if (
const int index = mo.indexOfProperty(roleName.data());
2352 return mo.property(index);
2356 const QRangeModelImpl &that;
2358 } findProperty{*
this, role};
2360 if constexpr (ModelData::cachesProperties)
2361 return *m_data.properties.tryEmplace(role, findProperty).iterator;
2363 return findProperty;
2367 const QObject *gadget,
const QMetaProperty &prop)
const
2369 const typename ModelData::Connection connection = {gadget, role};
2370 if (prop.hasNotifySignal() &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead
2371 && !m_data.connections.contains(connection)) {
2372 if constexpr (isMutable())
2373 Self::connectProperty(index, gadget, m_data.context, role, prop);
2375 Self::connectPropertyConst(index, gadget, m_data.context, role, prop);
2376 m_data.connections.insert(connection);
2380 template <
typename ItemType>
2383 using item_type = std::remove_pointer_t<ItemType>;
2385 QMetaProperty prop = roleProperty<item_type>(role);
2386 if (!prop.isValid() && role == Qt::EditRole) {
2387 role = Qt::DisplayRole;
2388 prop = roleProperty<item_type>(Qt::DisplayRole);
2391 if (prop.isValid()) {
2392 if constexpr (itemsAreQObjects)
2393 connectPropertyOnRead(index, role, gadget, prop);
2394 result = readProperty(prop, gadget);
2399 template <
typename ItemType>
2402 return readRole(index, role, &gadget);
2405 template <
typename ItemType>
2408 if constexpr (std::is_base_of_v<QObject, ItemType>)
2409 return prop.read(gadget);
2411 return prop.readOnGadget(gadget);
2414 template <
typename ItemType>
2417 using item_type = std::remove_pointer_t<ItemType>;
2418 const QMetaObject &mo = item_type::staticMetaObject;
2419 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
2421 if constexpr (rowsAreQObjects)
2422 connectPropertyOnRead(index, Qt::DisplayRole, gadget, prop);
2424 return readProperty(prop, gadget);
2427 template <
typename ItemType>
2430 return readProperty(index, &gadget);
2433 template <
typename ItemType>
2434 bool writeRole(
int role, ItemType *gadget,
const QVariant &data)
2436 using item_type = std::remove_pointer_t<ItemType>;
2437 auto prop = roleProperty<item_type>(role);
2438 if (!prop.isValid() && role == Qt::EditRole)
2439 prop = roleProperty<item_type>(Qt::DisplayRole);
2441 return prop.isValid() ? writeProperty(prop, gadget, data) :
false;
2444 template <
typename ItemType>
2445 bool writeRole(
int role, ItemType &&gadget,
const QVariant &data)
2447 return writeRole(role, &gadget, data);
2450 template <
typename ItemType>
2451 static bool writeProperty(
const QMetaProperty &prop, ItemType *gadget,
const QVariant &data)
2453 if constexpr (std::is_base_of_v<QObject, ItemType>)
2454 return prop.write(gadget, data);
2456 return prop.writeOnGadget(gadget, data);
2458 template <
typename ItemType>
2461 using item_type = std::remove_pointer_t<ItemType>;
2462 const QMetaObject &mo = item_type::staticMetaObject;
2463 return writeProperty(mo.property(property + mo.propertyOffset()), gadget, data);
2466 template <
typename ItemType>
2467 static bool writeProperty(
int property, ItemType &&gadget,
const QVariant &data)
2469 return writeProperty(property, &gadget, data);
2472 template <
typename ItemType>
2475 using item_type = std::remove_pointer_t<ItemType>;
2476 const QMetaObject &mo = item_type::staticMetaObject;
2477 bool success =
true;
2478 if (property == -1) {
2480 if constexpr (std::is_base_of_v<QObject, item_type>) {
2481 for (
int p = mo.propertyOffset(); p < mo.propertyCount(); ++p)
2482 success = writeProperty(mo.property(p), object, {}) && success;
2487 success = writeProperty(mo.property(property + mo.propertyOffset()), object, {});
2492 template <
typename ItemType>
2495 return resetProperty(property, &object);
2501 Q_ASSERT(index.isValid());
2502 return that().rowDataImpl(index);
2507 Q_ASSERT(index.isValid());
2508 return that().rowDataImpl(index);
2513 if (!index.isValid())
2514 return m_data.model();
2517 return that().childRangeImpl(index);
2522 if (!index.isValid())
2523 return m_data.model();
2526 return that().childRangeImpl(index);
2537template <
typename Range,
typename Protocol>
2544 using range_type =
typename Base::range_type;
2545 using range_features =
typename Base::range_features;
2546 using row_type =
typename Base::row_type;
2547 using row_ptr =
typename Base::row_ptr;
2548 using const_row_ptr =
typename Base::const_row_ptr;
2550 using tree_traits =
typename Base::protocol_traits;
2551 static constexpr bool is_mutable_impl = tree_traits::has_mutable_childRows;
2553 static constexpr bool rows_are_any_refs_or_pointers = Base::rows_are_raw_pointers ||
2554 QRangeModelDetails::is_smart_ptr<row_type>() ||
2555 QRangeModelDetails::is_any_of<row_type,
std::reference_wrapper>();
2556 static_assert(!Base::dynamicColumns(),
"A tree must have a static number of columns!");
2560 : Base(
std::forward<Range>(model),
std::forward<Protocol>(p), itemModel)
2565 for (
auto &&child : children)
2577 auto *children =
this->childRange(parent);
2580 return autoConnectPropertiesRange(QRangeModelDetails::refTo(children), parent);
2586 if (!parent.isValid())
2587 return this->createIndex(row, column);
2589 if (parent.column())
2590 return QModelIndex();
2592 const_row_ptr grandParent =
static_cast<const_row_ptr>(parent.constInternalPointer());
2593 const auto &parentSiblings = childrenOf(grandParent);
2600 if (!child.isValid())
2604 const_row_ptr parentRow =
static_cast<const_row_ptr>(child.constInternalPointer());
2609 auto &&grandParent =
this->protocol().parentRow(
QRangeModelDetails::refTo(parentRow));
2610 const range_type &parentSiblings = childrenOf(
QRangeModelDetails::pointerTo(grandParent));
2614 const auto it =
std::find_if(begin, end, [parentRow](
auto &&s){
2618 return this->createIndex(
std::distance(begin, it), 0,
2625 return Base::size(
this->childRange(parent));
2632 return Base::fixedColumnCount();
2637 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
2645 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2646 && Base::dynamicRows() && range_features::has_insert;
2654 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2655 && Base::dynamicRows() && range_features::has_erase;
2663 static constexpr bool canMoveRows(
const QModelIndex &,
const QModelIndex &)
2669 const QModelIndex &destParent,
int destRow)
2674 if constexpr (!rows_are_any_refs_or_pointers && !tree_traits::has_setParentRow) {
2676 }
else if constexpr (!(range_features::has_insert && range_features::has_erase)) {
2678 }
else if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1,
2679 destParent, destRow)) {
2683 range_type *source =
this->childRange(sourceParent);
2684 range_type *destination =
this->childRange(destParent);
2689 if constexpr (range_features::has_insert_range) {
2691 const auto sourceEnd =
std::next(sourceStart, count);
2693 destination->insert(destStart,
std::move_iterator(sourceStart),
2694 std::move_iterator(sourceEnd));
2695 }
else if constexpr (
std::is_copy_constructible_v<row_type>) {
2697 destination->insert(destStart, count, row_type{});
2700 row_ptr parentRow = destParent.isValid()
2706 if (parentRow ==
static_cast<row_ptr>(sourceParent.internalPointer())) {
2707 if (sourceParent.row() < destRow) {
2708 source =
this->childRange(sourceParent);
2711 source =
this->childRange(
this->createIndex(sourceParent.row() + count, 0,
2712 sourceParent.internalPointer()));
2719 const auto writeEnd =
std::next(writeStart, count);
2721 const auto sourceEnd =
std::next(sourceStart, count);
2723 for (
auto write = writeStart, read = sourceStart; write != writeEnd; ++write, ++read) {
2726 if constexpr (!range_features::has_insert_range)
2727 *write =
std::move(*read);
2731 source->erase(sourceStart, sourceEnd);
2741 this->endMoveRows();
2749 static_assert(tree_traits::has_setParentRow);
2750 row_type empty_row =
this->protocol().newRow();
2756 template <
typename It,
typename Sentinel>
2759 if constexpr (tree_traits::has_deleteRow) {
2760 for (
auto it = begin; it != end; ++it) {
2761 if constexpr (Base::isMutable()) {
2762 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(*it));
2770 this->protocol().deleteRow(
std::move(*it));
2777 if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) {
2780 for (
auto it = begin; it != end; ++it) {
2781 decltype(
auto) maybeChildren =
this->protocol().childRows(*it);
2784 QModelIndexList fromIndexes;
2785 QModelIndexList toIndexes;
2786 fromIndexes.reserve(Base::size(childrenRef));
2787 toIndexes.reserve(Base::size(childrenRef));
2791 for (
auto &child : childrenRef) {
2792 const_row_ptr oldParent =
this->protocol().parentRow(child);
2793 if (oldParent != parentRow) {
2794 fromIndexes.append(
this->createIndex(row, 0, oldParent));
2795 toIndexes.append(
this->createIndex(row, 0, parentRow));
2796 this->protocol().setParentRow(child, parentRow);
2800 this->changePersistentIndexList(fromIndexes, toIndexes);
2810 for (
const auto &row : range) {
2811 if (!
this->autoConnectPropertiesInRow(row, rowIndex, parent))
2816 if (!autoConnectPropertiesRange(QRangeModelDetails::refTo(children),
2817 this->itemModel().index(rowIndex, 0, parent))) {
2828 return autoConnectPropertiesRange(*
this->m_data.model(), {});
2833 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
2834 const range_type &siblings = childrenOf(parentRow);
2835 Q_ASSERT(index.row() <
int(Base::size(siblings)));
2841 row_ptr parentRow =
static_cast<row_ptr>(index.internalPointer());
2842 range_type &siblings = childrenOf(parentRow);
2843 Q_ASSERT(index.row() <
int(Base::size(siblings)));
2849 const auto &row =
this->rowData(index);
2851 return static_cast<
const range_type *>(
nullptr);
2853 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
2859 auto &row =
this->rowData(index);
2861 return static_cast<range_type *>(
nullptr);
2863 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
2864 using Children = std::remove_reference_t<
decltype(children)>;
2866 if constexpr (QRangeModelDetails::is_any_of<Children, std::optional>())
2867 if constexpr (std::is_default_constructible<
typename Children::value_type>()) {
2869 children.emplace(range_type{});
2878 : *
this->m_data.model();
2882 range_type &childrenOf(row_ptr row)
2885 : *
this->m_data.model();
2890template <
typename Range>
2897 static constexpr bool is_mutable_impl =
true;
2914 if constexpr (Base::dynamicColumns()) {
2915 if (column <
int(Base::size(*QRangeModelDetails::pos(*
this->m_data.model(), row))))
2916 return this->createIndex(row, column);
2919 qCritical(
"QRangeModel: Column-range at row %d is not large enough!", row);
2923 return this->createIndex(row, column);
2934 if (parent.isValid())
2936 return int(Base::size(*
this->m_data.model()));
2941 if (parent.isValid())
2945 if constexpr (Base::dynamicColumns()) {
2946 return int(Base::size(*
this->m_data.model()) == 0
2948 : Base::size(*QRangeModelDetails::adl_begin(*
this->m_data.model())));
2950 return Base::fixedColumnCount();
2956 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren;
2961 return Base::dynamicRows() && range_features::has_insert;
2966 return Base::dynamicRows() && range_features::has_erase;
2969 static constexpr bool canMoveColumns(
const QModelIndex &source,
const QModelIndex &destination)
2971 return !source.isValid() && !destination.isValid();
2974 static constexpr bool canMoveRows(
const QModelIndex &source,
const QModelIndex &destination)
2976 return !source.isValid() && !destination.isValid();
2980 const QModelIndex &,
int)
noexcept
2988 row_type empty_row =
this->protocol().newRow();
2991 if constexpr (Base::dynamicColumns() && row_features::has_resize) {
2999 template <
typename It,
typename Sentinel>
3002 if constexpr (Base::protocol_traits::has_deleteRow) {
3003 for (
auto it = begin; it != end; ++it)
3004 this->protocol().deleteRow(
std::move(*it));
3010 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
3016 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
3033 return *
this->m_data.model();
3044 for (
const auto &row : *
this->m_data.model()) {
3045 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()
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)
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 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++()