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>
441 template <
typename T,
typename =
void>
458 template <
typename C,
typename Fn>
464 std::forward<Fn>(fn)(
std::forward<C>(container));
467 template <
typename Fn>
473 int columnIndex = -1;
476 return std::forward<Fn>(fn)(firstIndex.siblingAtColumn(++columnIndex),
484 template <
typename T>
504 template <
typename C,
typename F>
539 template <
typename Fn>
559 template <
typename C,
typename F>
571 template <
typename Fn>
587 template <
typename T>
608 template <
typename C,
typename F>
628 template <
typename Fn>
635 template <
typename T,
typename =
void>
638 template <
typename That>
641 return That::roleNamesForSimpleType();
648 template <
typename That>
655 template <
typename T>
661 template <
typename T>
664 template <
typename That>
671 template <
typename T>
675 template <
typename Range>
681 auto newRow() ->
decltype(R{}) {
return R{}; }
684 template <
typename Range>
712 template <
typename Range,
720 template <
typename Range>
723 template <
typename R >
724 auto parentRow(
const R& row)
const ->
decltype(row.parentRow())
726 return row.parentRow();
729 template <
typename R >
730 auto setParentRow(R &row, R* parent) ->
decltype(row.setParentRow(parent))
732 row.setParentRow(parent);
735 template <
typename R >
736 auto childRows(
const R &row)
const ->
decltype(row.childRows())
738 return row.childRows();
741 template <
typename R >
744 return row.childRows();
748 template <
typename P,
typename R>
751 template <
typename P,
typename R>
754 template <
typename P,
typename R>
757 template <
typename P,
typename R>
760 template <
typename P,
typename R>
764 template <
typename P,
typename R>
767 template <
typename P,
typename R>
770 template <
typename P,
typename R>
773 template <
typename P,
typename =
void>
775 template <
typename P>
779 template <
typename P,
typename R,
typename =
void>
781 template <
typename P,
typename R>
786 template <
typename Range,
798 template <
typename Range>
811 template <
typename Range,
typename Protocol>
847 template <
bool cacheProperties,
bool itemsAreQObjects>
879 return lhs.sender == rhs.sender && lhs
.role == rhs
.role;
883 return qHashMulti(seed, c.sender, c
.role);
907 template <
typename ModelStorage,
typename =
void>
926 template <
typename ModelStorage,
typename PropertyStorage>
937 template <
typename Model = ModelStorage>
963 bool setHeaderData(
int section, Qt::Orientation orientation,
const QVariant &data,
int role);
964 bool setData(
const QModelIndex &index,
const QVariant &data,
int role);
965 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data);
969 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
const QModelIndex &destParent,
int destColumn);
970 bool insertRows(
int row,
int count,
const QModelIndex &parent);
971 bool removeRows(
int row,
int count,
const QModelIndex &parent);
972 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
const QModelIndex &destParent,
int destRow);
985 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const;
1017 template <
typename C>
1049 friend class QRangeModelPrivate;
1052 QRangeModel *m_rangeModel;
1056 : m_rangeModel(itemModel)
1061 inline void dataChanged(
const QModelIndex &from,
const QModelIndex &to,
1062 const QList<
int> &roles);
1069 inline bool beginMoveColumns(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1070 const QModelIndex &destParent,
int destRow);
1072 inline void beginInsertRows(
const QModelIndex &parent,
int start,
int count);
1074 inline void beginRemoveRows(
const QModelIndex &parent,
int start,
int count);
1076 inline bool beginMoveRows(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1077 const QModelIndex &destParent,
int destRow);
1097 QRangeModelDetails::AutoConnectContext *context,
1098 int role,
const QMetaProperty &property);
1100 QRangeModelDetails::AutoConnectContext *context,
1101 int role,
const QMetaProperty &property);
1103 QRangeModelDetails::AutoConnectContext *context,
1104 const QHash<
int, QMetaProperty> &properties);
1106 QRangeModelDetails::AutoConnectContext *context,
1107 const QHash<
int, QMetaProperty> &properties);
1110template <
typename Structure,
typename Range,
1111 typename Protocol = QRangeModelDetails::table_protocol_t<Range>>
1147 "Currently, std::optional is not supported for ranges and rows, as "
1148 "it has range semantics in c++26. Once the required behavior is clarified, "
1149 "std::optional for ranges and rows will be supported.");
1156 Structure&
that() {
return static_cast<Structure &>(*
this); }
1157 const Structure&
that()
const {
return static_cast<
const Structure &>(*
this); }
1159 template <
typename C>
1160 static constexpr int size(
const C &c)
1165 if constexpr (QRangeModelDetails::test_size<C>()) {
1167 return int(size(c));
1169#if defined(__cpp_lib_ranges)
1170 using std::ranges::distance;
1172 using std::distance;
1174 using container_type = std::conditional_t<QRangeModelDetails::range_traits<C>::has_cbegin,
1175 const QRangeModelDetails::wrapped_t<C>,
1176 QRangeModelDetails::wrapped_t<C>>;
1177 container_type& container =
const_cast<container_type &>(
QRangeModelDetails::refTo(c));
1193 return this->blockDataChangedDispatch();
1203 template <
typename T>
1223 {
return lhs.n == rhs.n; }
1225 {
return !(lhs == rhs); }
1236 "The range holding a move-only row-type must support insert(pos, start, end)");
1243 return range_features::is_mutable && row_features::is_mutable
1244 && std::is_reference_v<row_reference>
1245 && Structure::is_mutable_impl;
1268 if (row < 0 || column < 0 || column >= columnCount(parent)
1269 || row >= rowCount(parent)) {
1273 return that().indexImpl(row, column, parent);
1278 if (row == index.row() && column == index.column())
1281 if (column < 0 || column >=
this->columnCount({}))
1284 if (row == index.row())
1285 return this->createIndex(row, column, index.constInternalPointer());
1287 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
1288 const auto siblingCount = size(that().childrenOf(parentRow));
1289 if (row < 0 || row >=
int(siblingCount))
1291 return this->createIndex(row, column, parentRow);
1296 if (!index.isValid())
1297 return Qt::NoItemFlags;
1299 Qt::ItemFlags f = Structure::defaultFlags();
1301 if constexpr (isMutable()) {
1302 if constexpr (row_traits::hasMetaObject) {
1303 if (index.column() < row_traits::fixed_size()) {
1304 const QMetaObject mo = wrapped_row_type::staticMetaObject;
1305 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
1306 if (prop.isWritable())
1307 f |= Qt::ItemIsEditable;
1310 f |= Qt::ItemIsEditable;
1311 }
else if constexpr (std::is_reference_v<row_reference> && !std::is_const_v<row_reference>) {
1314 const_row_reference row = rowData(index);
1315 row_reference mutableRow =
const_cast<row_reference>(row);
1317 row_traits::for_element_at(mutableRow, index.column(), [&f](
auto &&ref){
1318 using target_type =
decltype(ref);
1319 if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
1320 f &= ~Qt::ItemIsEditable;
1321 else if constexpr (std::is_lvalue_reference_v<target_type>)
1322 f |= Qt::ItemIsEditable;
1327 f &= ~Qt::ItemIsEditable;
1337 if (role != Qt::DisplayRole || orientation != Qt::Horizontal
1338 || section < 0 || section >= columnCount({})) {
1339 return this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1342 result = row_traits::column_name(section);
1343 if (!result.isValid())
1344 result =
this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1350 if (!index.isValid())
1353 QModelRoleData result(role);
1354 multiData(index, result);
1355 return std::move(result.data());
1360 return role == Qt::RangeModelDataRole
1361 || role == Qt::RangeModelAdapterRole;
1366 return role == Qt::DisplayRole || role == Qt::EditRole;
1371 QMap<
int, QVariant> result;
1373 if (index.isValid()) {
1377 readAt(index, [&result, &tried](
const auto &value) {
1378 if constexpr (std::is_convertible_v<
decltype(value),
decltype(result)>) {
1384 const auto roles =
this->itemModel().roleNames().keys();
1385 QVarLengthArray<QModelRoleData, 16> roleDataArray;
1386 roleDataArray.reserve(roles.size());
1387 for (
auto role : roles) {
1388 if (isRangeModelRole(role))
1390 roleDataArray.emplace_back(role);
1392 QModelRoleDataSpan roleDataSpan(roleDataArray);
1393 multiData(index, roleDataSpan);
1395 for (
auto &&roleData : std::move(roleDataSpan)) {
1396 QVariant data = roleData.data();
1398 result[roleData.role()] = std::move(data);
1405 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const
1408 readAt(index, [
this, &index, roleDataSpan, &tried](
const auto &value) {
1411 using value_type = q20::remove_cvref_t<
decltype(value)>;
1412 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1413 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1415 const auto readModelData = [&value](QModelRoleData &roleData){
1416 const int role = roleData.role();
1417 if (role == Qt::RangeModelDataRole) {
1421 if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
1422 roleData.setData(QVariant::fromValue(QRangeModelDetails::refTo(value)));
1424 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1425 }
else if (role == Qt::RangeModelAdapterRole) {
1427 if constexpr (std::is_copy_assignable_v<value_type>)
1428 roleData.setData(QVariant::fromValue(value));
1430 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1437 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1438 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1440 for (
auto &roleData : roleDataSpan) {
1441 if (!readModelData(roleData)) {
1442 roleData.setData(ItemAccess::readRole(QRangeModelDetails::refTo(value),
1446 }
else if constexpr (multi_role()) {
1448 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1450 if constexpr (!multi_role::int_key)
1451 return this->itemModel().roleNames();
1455 using key_type =
typename value_type::key_type;
1456 for (
auto &roleData : roleDataSpan) {
1457 const auto &it = [&roleNames, &value, role = roleData.role()]{
1458 Q_UNUSED(roleNames);
1459 if constexpr (multi_role::int_key)
1460 return value.find(key_type(role));
1462 return value.find(roleNames.value(role));
1464 if (it != QRangeModelDetails::adl_end(value))
1465 roleData.setData(QRangeModelDetails::value(it));
1467 roleData.clearData();
1469 }
else if constexpr (has_metaobject<value_type>) {
1470 if (row_traits::fixed_size() <= 1) {
1472 for (
auto &roleData : roleDataSpan) {
1473 if (!readModelData(roleData)) {
1474 roleData.setData(readRole(index, roleData.role(),
1475 QRangeModelDetails::pointerTo(value)));
1478 }
else if (index.column() <= row_traits::fixed_size()) {
1480 for (
auto &roleData : roleDataSpan) {
1481 const int role = roleData.role();
1482 if (isPrimaryRole(role)) {
1483 roleData.setData(readProperty(index,
1484 QRangeModelDetails::pointerTo(value)));
1486 roleData.clearData();
1492 for (
auto &roleData : roleDataSpan) {
1493 const int role = roleData.role();
1494 if (isPrimaryRole(role) || isRangeModelRole(role))
1495 roleData.setData(read(value));
1497 roleData.clearData();
1505 bool setData(
const QModelIndex &index,
const QVariant &data,
int role)
1507 if (!index.isValid())
1510 bool success =
false;
1511 if constexpr (isMutable()) {
1512 auto emitDataChanged = qScopeGuard([&success,
this, &index, role]{
1514 Q_EMIT
this->dataChanged(index, index,
1515 role == Qt::EditRole || role == Qt::RangeModelDataRole
1516 || role == Qt::RangeModelAdapterRole
1517 ? QList<
int>{} : QList<
int>{role});
1523 const auto writeData = [
this, column = index.column(), &data, role](
auto &&target) ->
bool {
1524 using value_type = q20::remove_cvref_t<
decltype(target)>;
1525 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1526 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1528 auto setRangeModelDataRole = [&target, &data]{
1529 constexpr auto targetMetaType = QMetaType::fromType<value_type>();
1530 const auto dataMetaType = data.metaType();
1531 constexpr bool isWrapped = QRangeModelDetails::is_wrapped<value_type>();
1532 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>) {
1536 if constexpr (isWrapped) {
1537 constexpr bool is_raw_pointer = std::is_pointer_v<value_type>;
1538 if constexpr (!is_raw_pointer && std::is_copy_assignable_v<value_type>) {
1539 if (data.canConvert(targetMetaType)) {
1540 target = data.value<value_type>();
1543 }
else if constexpr (is_raw_pointer) {
1545 target = data.value<value_type>();
1554 }
else if constexpr (isWrapped) {
1559 if (
const auto mt = QMetaType::fromType<wrapped_value_type>();
1560 data.canConvert(mt)) {
1561 targetRef = data.value<wrapped_value_type>();
1563 }
else if (
const auto mtp = QMetaType::fromType<wrapped_value_type *>();
1564 data.canConvert(mtp)) {
1565 targetRef = *data.value<wrapped_value_type *>();
1569 }
else if (targetMetaType == dataMetaType) {
1570 QRangeModelDetails::refTo(target) = data.value<value_type>();
1572 }
else if (dataMetaType.flags() & QMetaType::PointerToGadget) {
1573 QRangeModelDetails::refTo(target) = *data.value<value_type *>();
1577 qCritical(
"Not able to assign %s to %s",
1578 qPrintable(QDebug::toString(data)), targetMetaType.name());
1583 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1584 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1585 if (isRangeModelRole(role))
1586 return setRangeModelDataRole();
1587 return ItemAccess::writeRole(QRangeModelDetails::refTo(target), data, role);
1588 }
else if constexpr (has_metaobject<value_type>) {
1589 if (row_traits::fixed_size() <= 1) {
1590 if (isRangeModelRole(role))
1591 return setRangeModelDataRole();
1593 }
else if (column <= row_traits::fixed_size()
1594 && (isPrimaryRole(role) || isRangeModelRole(role))) {
1597 }
else if constexpr (multi_role::value) {
1598 Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role);
1601 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1603 if constexpr (!multi_role::int_key)
1604 return this->itemModel().roleNames();
1608 if (role == Qt::EditRole) {
1609 if constexpr (multi_role::int_key) {
1610 if (target.find(roleToSet) == target.end())
1611 roleToSet = Qt::DisplayRole;
1613 if (target.find(roleNames.value(roleToSet)) == target.end())
1614 roleToSet = Qt::DisplayRole;
1617 if constexpr (multi_role::int_key)
1618 return write(target[roleToSet], data);
1620 return write(target[roleNames.value(roleToSet)], data);
1621 }
else if (isPrimaryRole(role) || isRangeModelRole(role)) {
1622 return write(target, data);
1627 success = writeAt(index, writeData);
1630 if (success && isRangeModelRole(role) &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
1631 if (QObject *item = data.value<QObject *>())
1632 Self::connectProperties(index, item, m_data.context, m_data.properties);
1639 template <
typename LHS,
typename RHS>
1642 if constexpr (
std::is_pointer_v<RHS>) {
1646 if constexpr (
std::is_assignable_v<LHS, RHS>)
1647 org =
std::forward<RHS>(copy);
1652 template <
typename LHS,
typename RHS>
1655 updateTarget(*org,
std::forward<RHS>(copy));
1658 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data)
1660 if (!index.isValid() || data.isEmpty())
1663 bool success =
false;
1664 if constexpr (isMutable()) {
1665 auto emitDataChanged = qScopeGuard([&success,
this, &index, &data]{
1667 Q_EMIT
this->dataChanged(index, index, data.keys());
1673 auto writeItemData = [
this, &tried, &data](
auto &target) ->
bool {
1675 using value_type = q20::remove_cvref_t<
decltype(target)>;
1676 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1677 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1681 auto makeCopy = [](
const value_type &original){
1682 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>)
1684 else if constexpr (std::is_pointer_v<
decltype(original)>)
1686 else if constexpr (std::is_copy_assignable_v<value_type>)
1692 const auto roleNames =
this->itemModel().roleNames();
1694 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
1696 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1697 const auto roles = roleNames.keys();
1698 auto targetCopy = makeCopy(target);
1699 for (
int role : roles) {
1700 if (!ItemAccess::writeRole(QRangeModelDetails::refTo(targetCopy),
1701 data.value(role), role)) {
1705 updateTarget(target,
std::move(targetCopy));
1707 }
else if constexpr (multi_role()) {
1708 using key_type =
typename value_type::key_type;
1710 const auto roleName = [&roleNames](
int role) {
1711 return roleNames.value(role);
1716 if constexpr (!multi_role::int_key)
1718 auto invalid =
std::find_if(data.keyBegin(), data.keyEnd(),
1719 [&roleName](
int role) {
return roleName(role).isEmpty(); }
1722 if (invalid != data.keyEnd()) {
1724 qWarning(
"No role name set for %d", *invalid);
1730 for (
auto &&[role, value] : data.asKeyValueRange()) {
1731 if constexpr (multi_role::int_key)
1732 target[
static_cast<key_type>(role)] = value;
1734 target[QString::fromUtf8(roleName(role))] = value;
1737 }
else if constexpr (has_metaobject<value_type>) {
1738 if (row_traits::fixed_size() <= 1) {
1740 auto targetCopy = makeCopy(target);
1741 for (
auto &&[role, value] : data.asKeyValueRange()) {
1742 if (isRangeModelRole(role))
1744 if (!writeRole(role, QRangeModelDetails::pointerTo(targetCopy), value)) {
1745 const QByteArray roleName = roleNames.value(role);
1747 qWarning(
"Failed to write value '%s' to role '%s'",
1748 qPrintable(QDebug::toString(value)), roleName.data());
1753 updateTarget(target,
std::move(targetCopy));
1760 success = writeAt(index, writeItemData);
1765 emitDataChanged.dismiss();
1766 success =
this->itemModel().QAbstractItemModel::setItemData(index, data);
1774 if (!index.isValid())
1777 bool success =
false;
1778 if constexpr (isMutable()) {
1779 auto emitDataChanged = qScopeGuard([&success,
this, &index]{
1781 Q_EMIT
this->dataChanged(index, index, {});
1784 auto clearData = [column = index.column()](
auto &&target) {
1785 if constexpr (row_traits::hasMetaObject) {
1786 if (row_traits::fixed_size() <= 1) {
1789 }
else if (column <= row_traits::fixed_size()) {
1799 success = writeAt(index, clearData);
1807 using item_type = QRangeModelDetails::wrapped_t<
typename row_traits::item_type>;
1808 using item_traits =
typename QRangeModelDetails::item_traits<item_type>;
1809 return item_traits::roleNames(
this);
1816 return row_traits::for_each_element(QRangeModelDetails::refTo(row),
1817 this->itemModel().index(rowIndex, 0, parent),
1818 [
this](
const QModelIndex &index,
const QObject *item) {
1819 if constexpr (isMutable())
1820 return Self::connectProperties(index, item, m_data.context, m_data.properties);
1822 return Self::connectPropertiesConst(index, item, m_data.context, m_data.properties);
1830 row_traits::for_each_element(QRangeModelDetails::refTo(row),
1831 this->itemModel().index(rowIndex, 0, parent),
1832 [
this](
const QModelIndex &,
const QObject *item) {
1833 m_data.connections.removeIf([item](
const auto &connection) {
1834 return connection.sender == item;
1843 using item_type = std::remove_pointer_t<
typename row_traits::item_type>;
1844 using Mapping = QRangeModelDetails::AutoConnectContext::AutoConnectMapping;
1846 delete m_data.context;
1847 m_data.connections = {};
1848 switch (
this->autoConnectPolicy()) {
1849 case AutoConnectPolicy::None:
1850 m_data.context =
nullptr;
1852 case AutoConnectPolicy::Full:
1853 m_data.context =
new QRangeModelDetails::AutoConnectContext(&
this->itemModel());
1855 m_data.properties = QRangeModelImplBase::roleProperties(
this->itemModel(),
1856 item_type::staticMetaObject);
1857 m_data.context->mapping = Mapping::Roles;
1859 m_data.properties = QRangeModelImplBase::columnProperties(wrapped_row_type::staticMetaObject);
1860 m_data.context->mapping = Mapping::Columns;
1862 if (!m_data.properties.isEmpty())
1863 that().autoConnectPropertiesImpl();
1865 case AutoConnectPolicy::OnRead:
1866 m_data.context =
new QRangeModelDetails::AutoConnectContext(&
this->itemModel());
1868 m_data.context->mapping = Mapping::Roles;
1870 m_data.properties = QRangeModelImplBase::columnProperties(wrapped_row_type::staticMetaObject);
1871 m_data.context->mapping = Mapping::Columns;
1877 qWarning(
"All items in the range must be QObject subclasses");
1882 template <
typename InsertFn>
1887 range_type *
const children = childRange(parent);
1891 this->beginInsertColumns(parent, column, column + count - 1);
1893 for (
auto &child : *children) {
1894 auto it = QRangeModelDetails::pos(child, column);
1895 (
void)insertFn(QRangeModelDetails::refTo(child), it, count);
1898 this->endInsertColumns();
1904 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
1905 for (
int r = 0; r < that().rowCount(parent); ++r) {
1906 for (
int c = column; c < column + count; ++c) {
1907 const QModelIndex index = that().index(r, c, parent);
1908 writeAt(index, [
this, &index](QObject *item){
1909 return Self::connectProperties(index, item,
1910 m_data.context, m_data.properties);
1922 if constexpr (dynamicColumns() && isMutable() && row_features::has_insert) {
1923 return doInsertColumns(column, count, parent, [](
auto &row,
auto it,
int n){
1924 row.insert(it, n, {});
1934 if constexpr (dynamicColumns() && isMutable() && row_features::has_erase) {
1935 if (column < 0 || column + count > columnCount(parent))
1938 range_type *
const children = childRange(parent);
1943 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead) {
1944 for (
int r = 0; r < that().rowCount(parent); ++r) {
1945 for (
int c = column; c < column + count; ++c) {
1946 const QModelIndex index = that().index(r, c, parent);
1947 writeAt(index, [
this](QObject *item){
1948 m_data.connections.removeIf([item](
const auto &connection) {
1949 return connection.sender == item;
1958 this->beginRemoveColumns(parent, column, column + count - 1);
1959 for (
auto &child : *children) {
1960 const auto start = QRangeModelDetails::pos(child, column);
1961 QRangeModelDetails::refTo(child).erase(start, std::next(start, count));
1963 this->endRemoveColumns();
1969 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
1970 const QModelIndex &destParent,
int destColumn)
1973 if (sourceParent != destParent)
1975 if constexpr (isMutable() && (row_features::has_rotate || row_features::has_splice)) {
1976 if (!Structure::canMoveColumns(sourceParent, destParent))
1982 range_type *
const children = childRange(sourceParent);
1986 if (!
this->beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1,
1987 destParent, destColumn)) {
1991 for (
auto &child : *children)
1992 QRangeModelDetails::rotate(child, sourceColumn, count, destColumn);
1994 this->endMoveColumns();
2001 template <
typename InsertFn>
2002 bool doInsertRows(
int row,
int count,
const QModelIndex &parent, InsertFn &&insertFn)
2004 range_type *children = childRange(parent);
2008 this->beginInsertRows(parent, row, row + count - 1);
2010 row_ptr parentRow = parent.isValid()
2013 (
void)
std::forward<InsertFn>(insertFn)(*children, parentRow, row, count);
2017 that().resetParentInChildren(children);
2019 this->endInsertRows();
2025 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
2027 const auto end =
std::next(begin, count);
2029 for (
auto it = begin; it != end; ++it, ++rowIndex)
2030 autoConnectPropertiesInRow(*it, rowIndex, parent);
2040 return doInsertRows(row, count, parent,
2041 [
this](range_type &children, row_ptr parentRow,
int r,
int n){
2045 if constexpr (range_features::has_insert_range) {
2048 auto start = children.insert(pos, n,
nullptr);
2051 children.insert(pos, n,
std::move(*generator));
2060 bool removeRows(
int row,
int count,
const QModelIndex &parent = {})
2063 const int prevRowCount = rowCount(parent);
2064 if (row < 0 || row + count > prevRowCount)
2067 range_type *children = childRange(parent);
2072 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead) {
2074 const auto end =
std::next(begin, count);
2076 for (
auto it = begin; it != end; ++it, ++rowIndex)
2077 clearConnectionInRow(*it, rowIndex, parent);
2081 this->beginRemoveRows(parent, row, row + count - 1);
2082 [[maybe_unused]]
bool callEndRemoveColumns =
false;
2086 if (prevRowCount == count) {
2087 if (
const int columns = columnCount(parent)) {
2088 callEndRemoveColumns =
true;
2089 this->beginRemoveColumns(parent, 0, columns - 1);
2095 const auto end =
std::next(begin, count);
2096 that().deleteRemovedRows(begin, end);
2097 children->erase(begin, end);
2101 that().resetParentInChildren(children);
2104 if (callEndRemoveColumns) {
2105 Q_ASSERT(columnCount(parent) == 0);
2106 this->endRemoveColumns();
2109 this->endRemoveRows();
2116 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
2117 const QModelIndex &destParent,
int destRow)
2119 if constexpr (isMutable() && (range_features::has_rotate || range_features::has_splice)) {
2120 if (!Structure::canMoveRows(sourceParent, destParent))
2123 if (sourceParent != destParent) {
2124 return that().moveRowsAcross(sourceParent, sourceRow, count,
2125 destParent, destRow);
2128 if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0
2129 || sourceRow < 0 || sourceRow + count - 1 >=
this->rowCount(sourceParent)
2130 || destRow < 0 || destRow >
this->rowCount(destParent)) {
2134 range_type *source = childRange(sourceParent);
2136 if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow))
2141 that().resetParentInChildren(source);
2143 this->endMoveRows();
2155 int rowCount(
const QModelIndex &parent)
const {
return that().rowCountImpl(parent); }
2160 return row_traits::fixed_size();
2164 int columnCount(
const QModelIndex &parent)
const {
return that().columnCountImpl(parent); }
2215 static constexpr bool modelCopied = !QRangeModelDetails::is_wrapped<Range>() &&
2216 (std::is_reference_v<Range> || std::is_const_v<std::remove_reference_t<Range>>);
2218 static constexpr bool modelShared = QRangeModelDetails::is_any_shared_ptr<Range>();
2220 static constexpr bool default_row_deleter = protocol_traits::is_default &&
2221 protocol_traits::has_deleteRow;
2223 static constexpr bool ambiguousRowOwnership = (modelCopied || modelShared) &&
2226 static_assert(!ambiguousRowOwnership,
2227 "Using of copied and shared tree and table models with rows as raw pointers, "
2228 "and the default protocol is not allowed due to ambiguity of rows ownership. "
2229 "Move the model in, use another row type, or implement a custom tree protocol.");
2231 if constexpr (protocol_traits::has_deleteRow && !std::is_pointer_v<Range>
2232 && !QRangeModelDetails::is_any_of<Range, std::reference_wrapper>()) {
2235 that().deleteRemovedRows(begin, end);
2241 if constexpr (dynamicColumns() && !row_features::has_resize) {
2245 }
else if constexpr (!protocol_traits::has_newRow) {
2248 }
else if constexpr (!range_features::has_insert_range
2249 && !std::is_copy_constructible_v<row_type>) {
2255 return Structure::canInsertRowsImpl();
2261 return Structure::canRemoveRowsImpl();
2264 template <
typename F>
2265 bool writeAt(
const QModelIndex &index, F&& writer)
2267 bool result =
false;
2268 row_reference row = rowData(index);
2271 row_traits::for_element_at(row, index.column(), [&writer, &result](
auto &&target) {
2272 using target_type =
decltype(target);
2274 if constexpr (std::is_lvalue_reference_v<target_type>
2275 && !std::is_const_v<std::remove_reference_t<target_type>>) {
2276 result = writer(std::forward<target_type>(target));
2284 template <
typename F>
2285 void readAt(
const QModelIndex &index, F&& reader)
const {
2286 const_row_reference row = rowData(index);
2287 if (QRangeModelDetails::isValid(row))
2288 row_traits::for_element_at(row, index.column(), std::forward<F>(reader));
2291 template <
typename Value>
2294 if constexpr (std::is_constructible_v<QVariant, Value>)
2295 return QVariant(value);
2297 return QVariant::fromValue(value);
2299 template <
typename Value>
2303 if constexpr (std::is_constructible_v<QVariant, Value *>)
2304 return QVariant(value);
2306 return read(*value);
2311 template <
typename Target>
2312 static bool write(Target &target,
const QVariant &value)
2314 using Type = std::remove_reference_t<Target>;
2315 if constexpr (std::is_constructible_v<Target, QVariant>) {
2318 }
else if (value.canConvert<Type>()) {
2319 target = value.value<Type>();
2324 template <
typename Target>
2325 static bool write(Target *target,
const QVariant &value)
2328 return write(*target, value);
2332 template <
typename ItemType>
2336 operator QMetaProperty()
const {
2337 const QByteArray roleName = that.itemModel().roleNames().value(role);
2338 const QMetaObject &mo = ItemType::staticMetaObject;
2339 if (
const int index = mo.indexOfProperty(roleName.data());
2341 return mo.property(index);
2345 const QRangeModelImpl &that;
2347 } findProperty{*
this, role};
2349 if constexpr (ModelData::cachesProperties)
2350 return *m_data.properties.tryEmplace(role, findProperty).iterator;
2352 return findProperty;
2356 const QObject *gadget,
const QMetaProperty &prop)
const
2358 const typename ModelData::Connection connection = {gadget, role};
2359 if (prop.hasNotifySignal() &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead
2360 && !m_data.connections.contains(connection)) {
2361 if constexpr (isMutable())
2362 Self::connectProperty(index, gadget, m_data.context, role, prop);
2364 Self::connectPropertyConst(index, gadget, m_data.context, role, prop);
2365 m_data.connections.insert(connection);
2369 template <
typename ItemType>
2372 using item_type = std::remove_pointer_t<ItemType>;
2374 QMetaProperty prop = roleProperty<item_type>(role);
2375 if (!prop.isValid() && role == Qt::EditRole) {
2376 role = Qt::DisplayRole;
2377 prop = roleProperty<item_type>(Qt::DisplayRole);
2380 if (prop.isValid()) {
2381 if constexpr (itemsAreQObjects)
2382 connectPropertyOnRead(index, role, gadget, prop);
2383 result = readProperty(prop, gadget);
2388 template <
typename ItemType>
2391 return readRole(index, role, &gadget);
2394 template <
typename ItemType>
2397 if constexpr (std::is_base_of_v<QObject, ItemType>)
2398 return prop.read(gadget);
2400 return prop.readOnGadget(gadget);
2403 template <
typename ItemType>
2406 using item_type = std::remove_pointer_t<ItemType>;
2407 const QMetaObject &mo = item_type::staticMetaObject;
2408 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
2410 if constexpr (rowsAreQObjects)
2411 connectPropertyOnRead(index, Qt::DisplayRole, gadget, prop);
2413 return readProperty(prop, gadget);
2416 template <
typename ItemType>
2419 return readProperty(index, &gadget);
2422 template <
typename ItemType>
2423 bool writeRole(
int role, ItemType *gadget,
const QVariant &data)
2425 using item_type = std::remove_pointer_t<ItemType>;
2426 auto prop = roleProperty<item_type>(role);
2427 if (!prop.isValid() && role == Qt::EditRole)
2428 prop = roleProperty<item_type>(Qt::DisplayRole);
2430 return prop.isValid() ? writeProperty(prop, gadget, data) :
false;
2433 template <
typename ItemType>
2434 bool writeRole(
int role, ItemType &&gadget,
const QVariant &data)
2436 return writeRole(role, &gadget, data);
2439 template <
typename ItemType>
2440 static bool writeProperty(
const QMetaProperty &prop, ItemType *gadget,
const QVariant &data)
2442 if constexpr (std::is_base_of_v<QObject, ItemType>)
2443 return prop.write(gadget, data);
2445 return prop.writeOnGadget(gadget, data);
2447 template <
typename ItemType>
2450 using item_type = std::remove_pointer_t<ItemType>;
2451 const QMetaObject &mo = item_type::staticMetaObject;
2452 return writeProperty(mo.property(property + mo.propertyOffset()), gadget, data);
2455 template <
typename ItemType>
2456 static bool writeProperty(
int property, ItemType &&gadget,
const QVariant &data)
2458 return writeProperty(property, &gadget, data);
2461 template <
typename ItemType>
2464 using item_type = std::remove_pointer_t<ItemType>;
2465 const QMetaObject &mo = item_type::staticMetaObject;
2466 bool success =
true;
2467 if (property == -1) {
2469 if constexpr (std::is_base_of_v<QObject, item_type>) {
2470 for (
int p = mo.propertyOffset(); p < mo.propertyCount(); ++p)
2471 success = writeProperty(mo.property(p), object, {}) && success;
2476 success = writeProperty(mo.property(property + mo.propertyOffset()), object, {});
2481 template <
typename ItemType>
2484 return resetProperty(property, &object);
2490 Q_ASSERT(index.isValid());
2491 return that().rowDataImpl(index);
2496 Q_ASSERT(index.isValid());
2497 return that().rowDataImpl(index);
2502 if (!index.isValid())
2503 return m_data.model();
2506 return that().childRangeImpl(index);
2511 if (!index.isValid())
2512 return m_data.model();
2515 return that().childRangeImpl(index);
2526template <
typename Range,
typename Protocol>
2533 using range_type =
typename Base::range_type;
2534 using range_features =
typename Base::range_features;
2535 using row_type =
typename Base::row_type;
2536 using row_ptr =
typename Base::row_ptr;
2537 using const_row_ptr =
typename Base::const_row_ptr;
2539 using tree_traits =
typename Base::protocol_traits;
2540 static constexpr bool is_mutable_impl = tree_traits::has_mutable_childRows;
2542 static constexpr bool rows_are_any_refs_or_pointers = Base::rows_are_raw_pointers ||
2543 QRangeModelDetails::is_smart_ptr<row_type>() ||
2544 QRangeModelDetails::is_any_of<row_type,
std::reference_wrapper>();
2545 static_assert(!Base::dynamicColumns(),
"A tree must have a static number of columns!");
2549 : Base(
std::forward<Range>(model),
std::forward<Protocol>(p), itemModel)
2554 for (
auto &&child : children)
2566 auto *children =
this->childRange(parent);
2569 return autoConnectPropertiesRange(QRangeModelDetails::refTo(children), parent);
2575 if (!parent.isValid())
2576 return this->createIndex(row, column);
2578 if (parent.column())
2579 return QModelIndex();
2581 const_row_ptr grandParent =
static_cast<const_row_ptr>(parent.constInternalPointer());
2582 const auto &parentSiblings = childrenOf(grandParent);
2589 if (!child.isValid())
2593 const_row_ptr parentRow =
static_cast<const_row_ptr>(child.constInternalPointer());
2598 auto &&grandParent =
this->protocol().parentRow(
QRangeModelDetails::refTo(parentRow));
2599 const range_type &parentSiblings = childrenOf(
QRangeModelDetails::pointerTo(grandParent));
2603 const auto it =
std::find_if(begin, end, [parentRow](
auto &&s){
2607 return this->createIndex(
std::distance(begin, it), 0,
2614 return Base::size(
this->childRange(parent));
2621 return Base::fixedColumnCount();
2626 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
2634 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2635 && Base::dynamicRows() && range_features::has_insert;
2643 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2644 && Base::dynamicRows() && range_features::has_erase;
2652 static constexpr bool canMoveRows(
const QModelIndex &,
const QModelIndex &)
2658 const QModelIndex &destParent,
int destRow)
2663 if constexpr (!rows_are_any_refs_or_pointers && !tree_traits::has_setParentRow) {
2665 }
else if constexpr (!(range_features::has_insert && range_features::has_erase)) {
2667 }
else if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1,
2668 destParent, destRow)) {
2672 range_type *source =
this->childRange(sourceParent);
2673 range_type *destination =
this->childRange(destParent);
2678 if constexpr (range_features::has_insert_range) {
2680 const auto sourceEnd =
std::next(sourceStart, count);
2682 destination->insert(destStart,
std::move_iterator(sourceStart),
2683 std::move_iterator(sourceEnd));
2684 }
else if constexpr (
std::is_copy_constructible_v<row_type>) {
2686 destination->insert(destStart, count, row_type{});
2689 row_ptr parentRow = destParent.isValid()
2695 if (parentRow ==
static_cast<row_ptr>(sourceParent.internalPointer())) {
2696 if (sourceParent.row() < destRow) {
2697 source =
this->childRange(sourceParent);
2700 source =
this->childRange(
this->createIndex(sourceParent.row() + count, 0,
2701 sourceParent.internalPointer()));
2708 const auto writeEnd =
std::next(writeStart, count);
2710 const auto sourceEnd =
std::next(sourceStart, count);
2712 for (
auto write = writeStart, read = sourceStart; write != writeEnd; ++write, ++read) {
2715 if constexpr (!range_features::has_insert_range)
2716 *write =
std::move(*read);
2720 source->erase(sourceStart, sourceEnd);
2730 this->endMoveRows();
2738 static_assert(tree_traits::has_setParentRow);
2739 row_type empty_row =
this->protocol().newRow();
2745 template <
typename It,
typename Sentinel>
2748 if constexpr (tree_traits::has_deleteRow) {
2749 for (
auto it = begin; it != end; ++it) {
2750 if constexpr (Base::isMutable()) {
2751 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(*it));
2759 this->protocol().deleteRow(
std::move(*it));
2766 if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) {
2769 for (
auto it = begin; it != end; ++it) {
2770 decltype(
auto) maybeChildren =
this->protocol().childRows(*it);
2773 QModelIndexList fromIndexes;
2774 QModelIndexList toIndexes;
2775 fromIndexes.reserve(Base::size(childrenRef));
2776 toIndexes.reserve(Base::size(childrenRef));
2780 for (
auto &child : childrenRef) {
2781 const_row_ptr oldParent =
this->protocol().parentRow(child);
2782 if (oldParent != parentRow) {
2783 fromIndexes.append(
this->createIndex(row, 0, oldParent));
2784 toIndexes.append(
this->createIndex(row, 0, parentRow));
2785 this->protocol().setParentRow(child, parentRow);
2789 this->changePersistentIndexList(fromIndexes, toIndexes);
2799 for (
const auto &row : range) {
2800 if (!
this->autoConnectPropertiesInRow(row, rowIndex, parent))
2805 if (!autoConnectPropertiesRange(QRangeModelDetails::refTo(children),
2806 this->itemModel().index(rowIndex, 0, parent))) {
2817 return autoConnectPropertiesRange(*
this->m_data.model(), {});
2822 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
2823 const range_type &siblings = childrenOf(parentRow);
2824 Q_ASSERT(index.row() <
int(Base::size(siblings)));
2830 row_ptr parentRow =
static_cast<row_ptr>(index.internalPointer());
2831 range_type &siblings = childrenOf(parentRow);
2832 Q_ASSERT(index.row() <
int(Base::size(siblings)));
2838 const auto &row =
this->rowData(index);
2840 return static_cast<
const range_type *>(
nullptr);
2842 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
2848 auto &row =
this->rowData(index);
2850 return static_cast<range_type *>(
nullptr);
2852 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
2853 using Children = std::remove_reference_t<
decltype(children)>;
2855 if constexpr (QRangeModelDetails::is_any_of<Children, std::optional>())
2856 if constexpr (std::is_default_constructible<
typename Children::value_type>()) {
2858 children.emplace(range_type{});
2867 : *
this->m_data.model();
2871 range_type &childrenOf(row_ptr row)
2874 : *
this->m_data.model();
2879template <
typename Range>
2886 static constexpr bool is_mutable_impl =
true;
2903 if constexpr (Base::dynamicColumns()) {
2904 if (column <
int(Base::size(*QRangeModelDetails::pos(*
this->m_data.model(), row))))
2905 return this->createIndex(row, column);
2908 qCritical(
"QRangeModel: Column-range at row %d is not large enough!", row);
2912 return this->createIndex(row, column);
2923 if (parent.isValid())
2925 return int(Base::size(*
this->m_data.model()));
2930 if (parent.isValid())
2934 if constexpr (Base::dynamicColumns()) {
2935 return int(Base::size(*
this->m_data.model()) == 0
2937 : Base::size(*QRangeModelDetails::adl_begin(*
this->m_data.model())));
2939 return Base::fixedColumnCount();
2945 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren;
2950 return Base::dynamicRows() && range_features::has_insert;
2955 return Base::dynamicRows() && range_features::has_erase;
2958 static constexpr bool canMoveColumns(
const QModelIndex &source,
const QModelIndex &destination)
2960 return !source.isValid() && !destination.isValid();
2963 static constexpr bool canMoveRows(
const QModelIndex &source,
const QModelIndex &destination)
2965 return !source.isValid() && !destination.isValid();
2969 const QModelIndex &,
int)
noexcept
2977 row_type empty_row =
this->protocol().newRow();
2980 if constexpr (Base::dynamicColumns() && row_features::has_resize) {
2988 template <
typename It,
typename Sentinel>
2991 if constexpr (Base::protocol_traits::has_deleteRow) {
2992 for (
auto it = begin; it != end; ++it)
2993 this->protocol().deleteRow(
std::move(*it));
2999 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
3005 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
3022 return *
this->m_data.model();
3033 for (
const auto &row : *
this->m_data.model()) {
3034 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 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++()