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/qcollator.h>
21#include <QtCore/qquasivirtual_impl.h>
22#include <QtCore/qmetaobject.h>
23#include <QtCore/qvariant.h>
24#include <QtCore/qmap.h>
25#include <QtCore/qscopedvaluerollback.h>
26#include <QtCore/qset.h>
27#include <QtCore/qregularexpression.h>
28#include <QtCore/qvarlengtharray.h>
34#include <QtCore/qxptype_traits.h>
36#include <QtCore/q23utility.h>
42 template <
typename T,
template <
typename...>
typename... Templates>
45 template <
template <
typename...>
typename Template,
47 template <
typename...>
typename...
Templates>
51 template <
typename...>
typename Template,
52 template <
typename...>
typename...
Templates>
55 template <
typename T,
template <
typename...>
typename...
Templates>
58 template <
typename T,
typename =
void>
65 template <
typename T,
typename =
void>
82#ifndef QT_NO_SCOPED_POINTER
98 using Type = q20::remove_cvref_t<T>;
99 if constexpr (is_any_of<Type, std::optional>())
100 return t ?
std::addressof(*
std::forward<T>(t)) :
nullptr;
101 else if constexpr (std::is_pointer<Type>())
103 else if constexpr (is_smart_ptr<Type>())
105 else if constexpr (is_any_of<Type, std::reference_wrapper>())
106 return std::addressof(t.get());
108 return std::addressof(
std::forward<T>(t));
111 template <
typename T>
121 template <
typename T>
124 template <
typename T>
129 template <
typename T,
typename =
void>
133 template <
typename T>
136 template <
typename T>
139 template <
typename T,
typename =
void>
145 template <
typename T>
148 template <
typename T,
typename =
void>
150 template <
typename T>
153 template <
typename T>
156 template <
typename T>
157 static constexpr bool isValid(
const T &t)
noexcept
159 if constexpr (
std::is_array_v<T>)
161 else if constexpr (is_validatable<T>())
167 template <
typename T>
168 static decltype(
auto)
refTo(T&& t) {
171 using Type = q20::remove_cvref_t<T>;
172 if constexpr (is_any_of<T, std::optional>())
173 return *
std::forward<T>(t);
174 if constexpr (!is_wrapped<Type>() || is_any_unique_ptr<Type>())
175 return q23::forward_like<T>(*QRangeModelDetails::pointerTo(t));
180 template <
typename It>
181 auto key(It&& it) ->
decltype(it.key()) {
return std::forward<It>(it).key(); }
182 template <
typename It>
183 auto key(It&& it) ->
decltype((it->first)) {
return std::forward<It>(it)->first; }
185 template <
typename It>
186 auto value(It&& it) ->
decltype(it.value()) {
return std::forward<It>(it).value(); }
187 template <
typename It>
188 auto value(It&& it) ->
decltype((it->second)) {
return std::forward<It>(it)->second; }
194 template <
typename C>
197 template <
typename C>
200 template <
typename C>
201 static auto pos(C &&c,
int i)
209 template <
typename C,
typename =
void>
212 template <
typename C>
223 template <
typename C,
typename =
void>
226 template <
typename C>
235 template <
typename C,
typename =
void>
238 template <
typename C>
246 template <
typename C,
typename =
void>
249 template <
typename C>
260 template <
typename It>
262 std::is_swappable<
decltype(*
std::declval<It>())>,
263 std::is_base_of<
std::forward_iterator_tag,
267 template <
typename C,
typename =
void>
270 template <
typename C>
280 template <
typename C>
281 static void rotate(C& c,
int src,
int count,
int dst) {
283 using Container = std::remove_reference_t<
decltype(container)>;
286 const auto srcEnd =
std::next(srcBegin, count);
289 if constexpr (test_splice<Container>::value) {
290 if (dst > src && dst < src + count)
291 container.splice(srcBegin, container, dstBegin, srcEnd);
293 container.splice(dstBegin, container, srcBegin, srcEnd);
296 std::rotate(srcBegin, srcEnd, dstBegin);
298 std::rotate(dstBegin, srcBegin, srcEnd);
311 template <
typename C>
320 template <
typename C>
325 template <
typename C,
typename =
void>
327 template <
typename C>
330 template <
typename C,
typename =
void>
332 template <
typename C>
337 template <
typename C,
typename =
void>
348 template <
typename C>
389 template <
typename C>
391 template <
typename C>
397 template <
typename T>
406 static constexpr bool hasReadRole = qxp::is_detected_v<hasReadRole_test, ItemAccess, ItemType>;
411 static constexpr bool hasWriteRole = qxp::is_detected_v<hasWriteRole_test, ItemAccess, ItemType>;
413 template <
typename Access,
typename Test>
416 static constexpr bool hasFlags = qxp::is_detected_v<hasFlags_test, ItemAccess, ItemType>;
423 template <
typename T,
typename =
void>
429 template <
typename T>
443 template <
typename row_type>
446 static constexpr bool hasRowFlags = qxp::is_detected_v<hasRowFlags_test, row_type>;
451 template <
typename T,
typename =
void>
468 template <
typename C,
typename Fn>
474 return std::forward<Fn>(fn)(
std::forward<C>(container));
477 template <
typename Fn>
483 int columnIndex = -1;
486 return std::forward<Fn>(fn)(firstIndex.siblingAtColumn(++columnIndex),
494 template <
typename T>
514 template <
typename C,
typename F>
549 template <
typename Fn>
569 template <
typename C,
typename F>
581 template <
typename Fn>
597 template <
typename T>
618 template <
typename C,
typename F>
638 template <
typename Fn>
645 template <
typename T,
typename =
void>
648 template <
typename That>
651 return That::roleNamesForSimpleType();
658 template <
typename That>
665 template <
typename T>
671 template <
typename T>
674 template <
typename That>
681 template <
typename T>
685 template <
typename Range>
691 auto newRow() ->
decltype(R{}) {
return R{}; }
694 template <
typename Range>
722 template <
typename Range,
730 template <
typename Range>
733 template <
typename R >
734 auto parentRow(
const R& row)
const ->
decltype(row.parentRow())
736 return row.parentRow();
739 template <
typename R >
740 auto setParentRow(R &row, R* parent) ->
decltype(row.setParentRow(parent))
742 row.setParentRow(parent);
745 template <
typename R >
746 auto childRows(
const R &row)
const ->
decltype(row.childRows())
748 return row.childRows();
751 template <
typename R >
754 return row.childRows();
758 template <
typename P,
typename R>
761 template <
typename P,
typename R>
764 template <
typename P,
typename R>
767 template <
typename P,
typename R>
770 template <
typename P,
typename R>
774 template <
typename P,
typename R>
777 template <
typename P,
typename R>
780 template <
typename P,
typename R>
783 template <
typename P,
typename =
void>
785 template <
typename P>
789 template <
typename P,
typename R,
typename =
void>
791 template <
typename P,
typename R>
796 template <
typename Range,
808 template <
typename Range>
821 template <
typename Range,
typename Protocol>
857 template <
bool cacheProperties,
bool itemsAreQObjects>
889 return lhs.sender == rhs.sender && lhs
.role == rhs
.role;
893 return qHashMulti(seed, c.sender, c
.role);
917 template <
typename ModelStorage,
typename =
void>
936 template <
typename ModelStorage,
typename PropertyStorage>
947 template <
typename Model = ModelStorage>
973 bool setHeaderData(
int section, Qt::Orientation orientation,
const QVariant &data,
int role);
974 bool setData(
const QModelIndex &index,
const QVariant &data,
int role);
975 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data);
979 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
const QModelIndex &destParent,
int destColumn);
980 bool insertRows(
int row,
int count,
const QModelIndex &parent);
981 bool removeRows(
int row,
int count,
const QModelIndex &parent);
982 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
const QModelIndex &destParent,
int destRow);
995 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const;
999 void sort(
int column, Qt::SortOrder order);
1001 int hits, Qt::MatchFlags flags)
const;
1037 template <
typename C>
1072 friend class QRangeModelPrivate;
1075 QRangeModel *m_rangeModel;
1079 : m_rangeModel(itemModel)
1085 inline void dataChanged(
const QModelIndex &from,
const QModelIndex &to,
1086 const QList<
int> &roles);
1093 inline bool beginMoveColumns(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1094 const QModelIndex &destParent,
int destRow);
1096 inline void beginInsertRows(
const QModelIndex &parent,
int start,
int count);
1098 inline void beginRemoveRows(
const QModelIndex &parent,
int start,
int count);
1100 inline bool beginMoveRows(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1101 const QModelIndex &destParent,
int destRow);
1107 const QCollator *collator);
1125 QRangeModelDetails::AutoConnectContext *context,
1126 int role,
const QMetaProperty &property);
1128 QRangeModelDetails::AutoConnectContext *context,
1129 int role,
const QMetaProperty &property);
1131 QRangeModelDetails::AutoConnectContext *context,
1132 const QHash<
int, QMetaProperty> &properties);
1134 QRangeModelDetails::AutoConnectContext *context,
1135 const QHash<
int, QMetaProperty> &properties);
1141 Qt::MatchFlags flags);
1142 static bool matchValue(
const QVariant &itemData,
const QVariant &value, Qt::MatchFlags flags)
1144 if ((flags & Qt::MatchTypeMask) == Qt::MatchExactly)
1145 return itemData == value;
1146 return matchValue(itemData.toString(), value, flags);
1150template <
typename Structure,
typename Range,
1151 typename Protocol = QRangeModelDetails::table_protocol_t<Range>>
1187 "Currently, std::optional is not supported for ranges and rows, as "
1188 "it has range semantics in c++26. Once the required behavior is clarified, "
1189 "std::optional for ranges and rows will be supported.");
1196 Structure&
that() {
return static_cast<Structure &>(*
this); }
1197 const Structure&
that()
const {
return static_cast<
const Structure &>(*
this); }
1199 template <
typename C>
1200 static constexpr int size(
const C &c)
1205 if constexpr (QRangeModelDetails::test_size<C>()) {
1207 return int(size(c));
1209#if defined(__cpp_lib_ranges)
1210 using std::ranges::distance;
1212 using std::distance;
1214 using container_type = std::conditional_t<QRangeModelDetails::range_traits<C>::has_cbegin,
1215 const QRangeModelDetails::wrapped_t<C>,
1216 QRangeModelDetails::wrapped_t<C>>;
1217 container_type& container =
const_cast<container_type &>(
QRangeModelDetails::refTo(c));
1233 return this->blockDataChangedDispatch();
1243 template <
typename T>
1263 {
return lhs.n == rhs.n; }
1265 {
return !(lhs == rhs); }
1276 "The range holding a move-only row-type must support insert(pos, start, end)");
1283 return range_features::is_mutable && row_features::is_mutable
1284 && std::is_reference_v<row_reference>
1285 && Structure::is_mutable_impl;
1302 versionNumber = QT_VERSION;
1313 if (row < 0 || column < 0 || column >= columnCount(parent)
1314 || row >= rowCount(parent)) {
1318 return that().indexImpl(row, column, parent);
1323 if (row == index.row() && column == index.column())
1326 if (column < 0 || column >=
this->columnCount({}))
1329 if (row == index.row())
1330 return this->createIndex(row, column, index.constInternalPointer());
1332 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
1333 const auto siblingCount = size(that().childrenOf(parentRow));
1334 if (row < 0 || row >=
int(siblingCount))
1336 return this->createIndex(row, column, parentRow);
1341 if (!index.isValid())
1342 return Qt::NoItemFlags;
1345 std::optional<Qt::ItemFlags> customFlags;
1346 if constexpr (QRangeModelDetails::hasRowFlags<wrapped_row_type>) {
1347 const_row_reference row = rowData(index);
1348 customFlags = QRangeModelDetails::QRangeModelRowOptions<wrapped_row_type>::flags(row);
1351 readAt(index, [&customFlags](
auto &&ref){
1353 using wrapped_value_type = q20::remove_cvref_t<QRangeModelDetails::wrapped_t<
decltype(ref)>>;
1354 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>::hasFlags) {
1355 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1356 customFlags = ItemAccess::flags(ref);
1362 Qt::ItemFlags f = customFlags ? *customFlags : Structure::defaultFlags();
1364 if constexpr (!isMutable())
1365 f &= ~Qt::ItemIsEditable;
1367 f |= Qt::ItemNeverHasChildren;
1372 if constexpr (isMutable()) {
1373 if constexpr (row_traits::hasMetaObject) {
1374 if (index.column() < row_traits::fixed_size()) {
1375 const QMetaObject mo = wrapped_row_type::staticMetaObject;
1376 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
1377 if (prop.isWritable())
1378 f |= Qt::ItemIsEditable;
1381 f |= Qt::ItemIsEditable;
1382 }
else if constexpr (std::is_reference_v<row_reference> && !std::is_const_v<row_reference>) {
1385 const_row_reference row = rowData(index);
1386 row_reference mutableRow =
const_cast<row_reference>(row);
1388 row_traits::for_element_at(mutableRow, index.column(), [&f](
auto &&ref){
1389 using target_type =
decltype(ref);
1390 if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
1391 f &= ~Qt::ItemIsEditable;
1392 else if constexpr (std::is_lvalue_reference_v<target_type>)
1393 f |= Qt::ItemIsEditable;
1398 f &= ~Qt::ItemIsEditable;
1408 if constexpr (QRangeModelDetails::hasHeaderData<wrapped_row_type>) {
1409 if (orientation == Qt::Horizontal) {
1410 result = QRangeModelDetails::QRangeModelRowOptions<wrapped_row_type>::headerData(
1413 if (result.isValid())
1418 if (role != Qt::DisplayRole || orientation != Qt::Horizontal
1419 || section < 0 || section >= columnCount({})) {
1420 return this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1423 result = row_traits::column_name(section);
1424 if (!result.isValid())
1425 result =
this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1431 if (!index.isValid())
1434 QModelRoleData result(role);
1435 multiData(index, result);
1436 return std::move(result.data());
1441 return role == Qt::RangeModelDataRole
1442 || role == Qt::RangeModelAdapterRole;
1447 return role == Qt::DisplayRole || role == Qt::EditRole;
1452 QMap<
int, QVariant> result;
1454 if (index.isValid()) {
1456 if (!readAt(index, [&result](
const auto &value) {
1457 if constexpr (std::is_convertible_v<
decltype(value),
decltype(result)>) {
1463 const auto roles =
this->itemModel().roleNames().keys();
1464 QVarLengthArray<QModelRoleData, 16> roleDataArray;
1465 roleDataArray.reserve(roles.size());
1466 for (
auto role : roles) {
1467 if (isRangeModelRole(role))
1469 roleDataArray.emplace_back(role);
1471 QModelRoleDataSpan roleDataSpan(roleDataArray);
1472 multiData(index, roleDataSpan);
1474 for (QModelRoleData &roleData : roleDataSpan) {
1475 if (roleData.data().isValid())
1476 result[roleData.role()] = std::move(roleData.data());
1485 template <
typename value_type>
1488 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1489 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1491 const auto readModelData = [&value](QModelRoleData &roleData){
1492 const int role = roleData.role();
1493 if (role == Qt::RangeModelDataRole) {
1497 if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
1498 roleData.setData(QVariant::fromValue(QRangeModelDetails::refTo(value)));
1500 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1501 }
else if (role == Qt::RangeModelAdapterRole) {
1503 if constexpr (
std::is_copy_assignable_v<value_type>)
1504 roleData.setData(QVariant::fromValue(value));
1506 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1513 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>::hasReadRole) {
1514 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1515 for (
auto &roleData : roleDataSpan) {
1516 if (!readModelData(roleData)) {
1517 roleData.setData(ItemAccess::readRole(QRangeModelDetails::refTo(value),
1521 }
else if constexpr (multi_role()) {
1522 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1524 if constexpr (!multi_role::int_key)
1525 return that->itemModel().roleNames();
1529 using key_type =
typename value_type::key_type;
1530 for (
auto &roleData : roleDataSpan) {
1531 const auto &it = [&roleNames, &value, role = roleData.role()]{
1532 Q_UNUSED(roleNames);
1533 if constexpr (multi_role::int_key)
1534 return value.find(key_type(role));
1536 return value.find(roleNames.value(role));
1538 if (it != QRangeModelDetails::adl_end(value))
1539 roleData.setData(QRangeModelDetails::value(it));
1541 roleData.clearData();
1543 }
else if constexpr (has_metaobject<value_type>) {
1544 if (row_traits::fixed_size() <= 1) {
1545 for (
auto &roleData : roleDataSpan) {
1546 if (!readModelData(roleData)) {
1547 roleData.setData(that->readRole(index, roleData.role(),
1548 QRangeModelDetails::pointerTo(value)));
1551 }
else if (index.column() <= row_traits::fixed_size()) {
1552 for (
auto &roleData : roleDataSpan) {
1553 const int role = roleData.role();
1554 if (isPrimaryRole(role)) {
1555 roleData.setData(that->readProperty(index,
1556 QRangeModelDetails::pointerTo(value)));
1558 roleData.clearData();
1563 for (
auto &roleData : roleDataSpan) {
1564 const int role = roleData.role();
1565 if (isPrimaryRole(role) || isRangeModelRole(role))
1566 roleData.setData(read(value));
1568 roleData.clearData();
1579 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const
1581 if (!readAt(index,
ItemReader{index, roleDataSpan,
this})) {
1582 for (
auto &roleData : roleDataSpan)
1583 roleData.clearData();
1587 bool setData(
const QModelIndex &index,
const QVariant &data,
int role)
1589 if (!index.isValid())
1592 if constexpr (isMutable()) {
1593 auto emitDataChanged = qScopeGuard([
this, &index, role]{
1594 Q_EMIT
this->dataChanged(index, index,
1595 role == Qt::EditRole || role == Qt::RangeModelDataRole
1596 || role == Qt::RangeModelAdapterRole
1597 ? QList<
int>{} : QList<
int>{role});
1602 const auto writeData = [
this, column = index.column(), &data, role](
auto &&target) ->
bool {
1603 using value_type = q20::remove_cvref_t<
decltype(target)>;
1604 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1605 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1607 auto setRangeModelDataRole = [&target, &data]{
1608 constexpr auto targetMetaType = QMetaType::fromType<value_type>();
1609 const auto dataMetaType = data.metaType();
1610 constexpr bool isWrapped = QRangeModelDetails::is_wrapped<value_type>();
1611 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>) {
1615 if constexpr (isWrapped) {
1616 constexpr bool is_raw_pointer = std::is_pointer_v<value_type>;
1617 if constexpr (!is_raw_pointer && std::is_copy_assignable_v<value_type>) {
1618 if (data.canConvert(targetMetaType)) {
1619 target = data.value<value_type>();
1622 }
else if constexpr (is_raw_pointer) {
1624 target = data.value<value_type>();
1633 }
else if constexpr (isWrapped) {
1638 if (
const auto mt = QMetaType::fromType<wrapped_value_type>();
1639 data.canConvert(mt)) {
1640 targetRef = data.value<wrapped_value_type>();
1642 }
else if (
const auto mtp = QMetaType::fromType<wrapped_value_type *>();
1643 data.canConvert(mtp)) {
1644 targetRef = *data.value<wrapped_value_type *>();
1648 }
else if (targetMetaType == dataMetaType) {
1649 QRangeModelDetails::refTo(target) = data.value<value_type>();
1651 }
else if (dataMetaType.flags() & QMetaType::PointerToGadget) {
1652 QRangeModelDetails::refTo(target) = *data.value<value_type *>();
1656 qCritical(
"Not able to assign %s to %s",
1657 qPrintable(QDebug::toString(data)), targetMetaType.name());
1662 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>::hasWriteRole) {
1663 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1664 if (isRangeModelRole(role))
1665 return setRangeModelDataRole();
1666 return ItemAccess::writeRole(QRangeModelDetails::refTo(target), data, role);
1667 }
else if constexpr (has_metaobject<value_type>) {
1668 if (row_traits::fixed_size() <= 1) {
1669 if (isRangeModelRole(role))
1670 return setRangeModelDataRole();
1672 }
else if (column <= row_traits::fixed_size()
1673 && (isPrimaryRole(role) || isRangeModelRole(role))) {
1676 }
else if constexpr (multi_role::value) {
1677 Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role);
1680 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1682 if constexpr (!multi_role::int_key)
1683 return this->itemModel().roleNames();
1687 if (role == Qt::EditRole) {
1688 if constexpr (multi_role::int_key) {
1689 if (target.find(roleToSet) == target.end())
1690 roleToSet = Qt::DisplayRole;
1692 if (target.find(roleNames.value(roleToSet)) == target.end())
1693 roleToSet = Qt::DisplayRole;
1696 if constexpr (multi_role::int_key)
1697 return write(target[roleToSet], data);
1699 return write(target[roleNames.value(roleToSet)], data);
1700 }
else if (isPrimaryRole(role) || isRangeModelRole(role)) {
1701 return write(target, data);
1706 if (!writeAt(index, writeData)) {
1707 emitDataChanged.dismiss();
1710 if (isRangeModelRole(role) &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
1711 if (QObject *item = data.value<QObject *>())
1712 Self::connectProperties(index, item, m_data.context, m_data.properties);
1720 template <
typename LHS,
typename RHS>
1723 if constexpr (
std::is_pointer_v<RHS>)
1725 else if constexpr (
std::is_assignable_v<LHS, RHS>)
1726 org =
std::forward<RHS>(copy);
1730 template <
typename LHS,
typename RHS>
1733 updateTarget(*org,
std::forward<RHS>(copy));
1736 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data)
1738 if (!index.isValid() || data.isEmpty())
1741 if constexpr (isMutable()) {
1742 auto emitDataChanged = qScopeGuard([
this, &index, &data]{
1743 Q_EMIT
this->dataChanged(index, index, data.keys());
1749 auto writeItemData = [
this, &tried, &data](
auto &target) ->
bool {
1751 using value_type = q20::remove_cvref_t<
decltype(target)>;
1752 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1753 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1757 auto makeCopy = [](
const value_type &original){
1758 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>)
1760 else if constexpr (std::is_pointer_v<
decltype(original)>)
1762 else if constexpr (std::is_copy_assignable_v<value_type>)
1768 const auto roleNames =
this->itemModel().roleNames();
1770 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>::hasWriteRole) {
1772 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1773 const auto roles = roleNames.keys();
1774 auto targetCopy = makeCopy(target);
1775 for (
int role : roles) {
1776 if (!ItemAccess::writeRole(QRangeModelDetails::refTo(targetCopy),
1777 data.value(role), role)) {
1781 updateTarget(target,
std::move(targetCopy));
1783 }
else if constexpr (multi_role()) {
1784 using key_type =
typename value_type::key_type;
1786 const auto roleName = [&roleNames](
int role) {
1787 return roleNames.value(role);
1792 if constexpr (!multi_role::int_key)
1794 auto invalid =
std::find_if(data.keyBegin(), data.keyEnd(),
1795 [&roleName](
int role) {
return roleName(role).isEmpty(); }
1798 if (invalid != data.keyEnd()) {
1800 qWarning(
"No role name set for %d", *invalid);
1806 for (
auto &&[role, value] : data.asKeyValueRange()) {
1807 if constexpr (multi_role::int_key)
1808 target[
static_cast<key_type>(role)] = value;
1810 target[QString::fromUtf8(roleName(role))] = value;
1813 }
else if constexpr (has_metaobject<value_type>) {
1814 if (row_traits::fixed_size() <= 1) {
1816 auto targetCopy = makeCopy(target);
1817 for (
auto &&[role, value] : data.asKeyValueRange()) {
1818 if (isRangeModelRole(role))
1820 if (!writeRole(role, QRangeModelDetails::pointerTo(targetCopy), value)) {
1821 const QByteArray roleName = roleNames.value(role);
1823 qWarning(
"Failed to write value '%s' to role '%s'",
1824 qPrintable(QDebug::toString(value)), roleName.data());
1829 updateTarget(target,
std::move(targetCopy));
1836 if (!writeAt(index, writeItemData)) {
1837 emitDataChanged.dismiss();
1839 return this->itemModel().QAbstractItemModel::setItemData(index, data);
1848 if (!index.isValid())
1851 if constexpr (isMutable()) {
1852 auto emitDataChanged = qScopeGuard([
this, &index]{
1853 Q_EMIT
this->dataChanged(index, index, {});
1856 auto clearData = [column = index.column()](
auto &&target) {
1857 if constexpr (row_traits::hasMetaObject) {
1858 if (row_traits::fixed_size() <= 1) {
1861 }
else if (column <= row_traits::fixed_size()) {
1871 if (!writeAt(index, clearData)) {
1872 emitDataChanged.dismiss();
1883 using item_type = QRangeModelDetails::wrapped_t<
typename row_traits::item_type>;
1884 using item_traits =
typename QRangeModelDetails::item_traits<item_type>;
1885 return item_traits::roleNames(
this);
1892 return row_traits::for_each_element(QRangeModelDetails::refTo(row),
1893 this->itemModel().index(rowIndex, 0, parent),
1894 [
this](
const QModelIndex &index,
const QObject *item) {
1895 if constexpr (isMutable())
1896 return Self::connectProperties(index, item, m_data.context, m_data.properties);
1898 return Self::connectPropertiesConst(index, item, m_data.context, m_data.properties);
1906 row_traits::for_each_element(QRangeModelDetails::refTo(row),
1907 this->itemModel().index(rowIndex, 0, parent),
1908 [
this](
const QModelIndex &,
const QObject *item) {
1909 m_data.connections.removeIf([item](
const auto &connection) {
1910 return connection.sender == item;
1919 using item_type = std::remove_pointer_t<
typename row_traits::item_type>;
1920 using Mapping = QRangeModelDetails::AutoConnectContext::AutoConnectMapping;
1922 delete m_data.context;
1923 m_data.connections = {};
1924 switch (
this->autoConnectPolicy()) {
1925 case AutoConnectPolicy::None:
1926 m_data.context =
nullptr;
1928 case AutoConnectPolicy::Full:
1929 m_data.context =
new QRangeModelDetails::AutoConnectContext(&
this->itemModel());
1931 m_data.properties = QRangeModelImplBase::roleProperties(
this->itemModel(),
1932 item_type::staticMetaObject);
1933 m_data.context->mapping = Mapping::Roles;
1935 m_data.properties = QRangeModelImplBase::columnProperties(wrapped_row_type::staticMetaObject);
1936 m_data.context->mapping = Mapping::Columns;
1938 if (!m_data.properties.isEmpty())
1939 that().autoConnectPropertiesImpl();
1941 case AutoConnectPolicy::OnRead:
1942 m_data.context =
new QRangeModelDetails::AutoConnectContext(&
this->itemModel());
1944 m_data.context->mapping = Mapping::Roles;
1946 m_data.properties = QRangeModelImplBase::columnProperties(wrapped_row_type::staticMetaObject);
1947 m_data.context->mapping = Mapping::Columns;
1953 qWarning(
"All items in the range must be QObject subclasses");
1967 template <
typename C,
typename LessThan>
1969 static constexpr bool hasSortMember = qxp::is_detected_v<sortMember_test, range_type, Compare>;
1987 template <
typename Item>
1988 auto operator()(
const Item &lhs,
const Item &rhs)
const
1990 auto ordering = compare(lhs, rhs);
1991 return m_order == Qt::AscendingOrder ? ordering < 0 : ordering > 0;
1994 template <
typename Item>
1995 auto compare(
const Item &lhs,
const Item &rhs)
const
1997 using value_type = QRangeModelDetails::wrapped_t<Item>;
1998 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
2000 if constexpr (QRangeModelDetails::item_access<value_type>::hasReadRole
2001 || multi_role() || has_metaobject<value_type>) {
2009 Q_ASSERT(!reader.index.isValid());
2011 const QVariant lhsVariant =
std::move(result.data());
2013 const QVariant rhsVariant =
std::move(result.data());
2014 return QRangeModelImplBase::compareData(lhsVariant, rhsVariant, collator);
2015 }
else if constexpr (std::is_same_v<QVariant, value_type>) {
2016 return QRangeModelImplBase::compareData(lhs, rhs, collator);
2017 }
else if constexpr (QtOrderingPrivate::CompareThreeWayTester::hasCompareThreeWay_v
2018 <value_type, value_type>) {
2020 if constexpr (hasCollatedCompare<value_type>) {
2022 using ordering =
decltype(qCompareThreeWay(lhs, rhs));
2023 int res = collator->compare(lhs, rhs);
2025 return ordering::less;
2027 return ordering::greater;
2028 return ordering::equal;
2031 return qCompareThreeWay(lhs, rhs);
2039 return that->readAt(
that->index(0, 0, {}), [
this](
const auto &item){
2044 using ordering =
decltype(compare(item, item));
2047 const QMetaType itemtype = QMetaType::fromType<QRangeModelDetails::wrapped_t<
2048 q20::remove_cvref_t<
decltype(item)>>
2050 qCritical(
"QRangeModel: Cannot compare items of type %s in column %d!",
2051 itemtype.name(), m_index.column());
2060 template <
typename Item>
2068 return std::nullopt;
2078 void sort(
int column, Qt::SortOrder order)
2080 if constexpr (isMutable() && std::is_swappable_v<row_type>) {
2081 if (rowCount({}) < 2 || column >= columnCount({}))
2083 Compare compare(
this, column, order);
2084 if (!compare.checkComparable())
2087 this->beginLayoutChange();
2088 QScopeGuard endLayoutChange([
this]{
this->endLayoutChange(); });
2089 that().sortImpl([&compare](
const auto &leftRow,
const auto &rightRow) {
2090 if (
auto anyInvalid =
Compare::compareInvalid(leftRow, rightRow))
2092 return row_traits::for_element_at(leftRow, compare.m_index.column(),
2093 [&rightRow, &compare](
const auto &leftItem){
2094 return row_traits::for_element_at(rightRow, compare.m_index.column(),
2095 [&leftItem, &compare](
const auto &rightItem){
2098 if constexpr (std::is_same_v<
decltype(leftItem),
decltype(rightItem)>) {
2099 if (
auto anyInvalid = Compare::compareInvalid(leftItem, rightItem))
2101 return compare(QRangeModelDetails::refTo(leftItem),
2102 QRangeModelDetails::refTo(rightItem));
2113 template <
typename LessThan>
2114 void sortSubRange(range_type &range, row_ptr expectedParent,
const LessThan &lessThan)
2121 QModelIndexList persistentIndexes =
this->persistentIndexList();
2122 that().prunePersistentIndexList(persistentIndexes, expectedParent);
2124 if (persistentIndexes.isEmpty()) {
2125 using It =
typename range_features::iterator;
2126 constexpr bool is_random_access = std::is_base_of_v<std::random_access_iterator_tag,
2127 typename std::iterator_traits<It>::iterator_category>;
2129 if constexpr (
Compare::hasSortMember) {
2130 range.sort(lessThan);
2132 }
else if constexpr (is_random_access) {
2133 std::stable_sort(begin, end, lessThan);
2146 const int rangeSize = size(range);
2149 std::vector<SortTracker> tracked;
2150 tracked.reserve(rangeSize);
2151 std::vector<
int> newRows;
2152 newRows.resize(rangeSize);
2156 for (
auto &&it =
std::move_iterator(begin); it !=
std::move_iterator(end); ++it)
2157 tracked.emplace_back(SortTracker{*it, ++row});
2160 std::stable_sort(tracked.begin(), tracked.end(),
2161 [&lessThan](
const SortTracker &lhs,
const SortTracker &rhs){
2162 return lessThan(lhs.row, rhs.row);
2167 auto sorted =
std::move_iterator(tracked.begin());
2169 qsizetype changedIndexCount = 0;
2170 for (
int newIndex = 0; newIndex < rangeSize; ++write, ++sorted, ++newIndex) {
2171 auto &&tracker = *sorted;
2172 changedIndexCount += (tracker.index != newIndex);
2173 *write =
std::move(tracker.row);
2174 newRows[tracker.index] = newIndex;
2179 tracked.shrink_to_fit();
2182 for (
const auto &fromIndex : std::as_const(persistentIndexes)) {
2183 const int newRow = newRows.at(fromIndex.row());
2184 if (fromIndex.row() == newRow)
2186 const QModelIndex toIndex = that().indexImpl(newRow,
2188 fromIndex.parent());
2189 this->changePersistentIndex(fromIndex, toIndex);
2194 Qt::MatchFlags flags)
const
2196 return that().matchImpl(start, role,
2197 QRangeModelImplBase::convertMatchValue(value, flags), hits, flags);
2200 bool matchRow(const_row_reference row,
const QModelIndex &index,
int role,
const QVariant &value,
2201 Qt::MatchFlags flags)
const
2203 const uint matchType = (flags & Qt::MatchTypeMask).toInt();
2205 return row_traits::for_element_at(row, index.column(), [&](
const auto &element) {
2206 using value_type = q20::remove_cvref_t<
decltype(element)>;
2207 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
2208 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
2210 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>::hasReadRole
2211 || multi_role() || has_metaobject<value_type>) {
2212 QModelRoleData roleData(role);
2213 ItemReader reader{index, roleData,
this};
2215 return QRangeModelImplBase::matchValue(roleData.data(), value, flags);
2216 }
else if constexpr (std::is_same_v<wrapped_value_type, QVariant>) {
2217 return QRangeModelImplBase::matchValue(element, value, flags);
2219 constexpr QMetaType mt = QMetaType::fromType<wrapped_value_type>();
2220 if (mt == value.metaType()) {
2221 if (matchType == Qt::MatchExactly)
2222 return mt.equals(QRangeModelDetails::pointerTo(element), value.constData());
2223 else if constexpr (std::is_same_v<wrapped_value_type, QString>)
2224 return QRangeModelImplBase::matchValue(element, value, flags);
2226 return QRangeModelImplBase::matchValue(QVariant::fromValue(QRangeModelDetails::refTo(element)),
2234 template <
typename InsertFn>
2239 range_type *
const children = childRange(parent);
2243 this->beginInsertColumns(parent, column, column + count - 1);
2245 for (
auto &child : *children) {
2246 auto it = QRangeModelDetails::pos(child, column);
2247 (
void)insertFn(QRangeModelDetails::refTo(child), it, count);
2250 this->endInsertColumns();
2256 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
2257 for (
int r = 0; r < that().rowCount(parent); ++r) {
2258 for (
int c = column; c < column + count; ++c) {
2259 const QModelIndex index = that().index(r, c, parent);
2260 writeAt(index, [
this, &index](QObject *item){
2261 return Self::connectProperties(index, item,
2262 m_data.context, m_data.properties);
2274 if constexpr (dynamicColumns() && isMutable() && row_features::has_insert) {
2275 return doInsertColumns(column, count, parent, [](
auto &row,
auto it,
int n){
2276 row.insert(it, n, {});
2286 if constexpr (dynamicColumns() && isMutable() && row_features::has_erase) {
2287 if (column < 0 || column + count > columnCount(parent))
2290 range_type *
const children = childRange(parent);
2295 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead) {
2296 for (
int r = 0; r < that().rowCount(parent); ++r) {
2297 for (
int c = column; c < column + count; ++c) {
2298 const QModelIndex index = that().index(r, c, parent);
2299 writeAt(index, [
this](QObject *item){
2300 m_data.connections.removeIf([item](
const auto &connection) {
2301 return connection.sender == item;
2310 this->beginRemoveColumns(parent, column, column + count - 1);
2311 for (
auto &child : *children) {
2312 const auto start = QRangeModelDetails::pos(child, column);
2313 QRangeModelDetails::refTo(child).erase(start, std::next(start, count));
2315 this->endRemoveColumns();
2321 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
2322 const QModelIndex &destParent,
int destColumn)
2325 if (sourceParent != destParent)
2327 if constexpr (isMutable() && (row_features::has_rotate || row_features::has_splice)) {
2328 if (!Structure::canMoveColumns(sourceParent, destParent))
2334 range_type *
const children = childRange(sourceParent);
2338 if (!
this->beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1,
2339 destParent, destColumn)) {
2343 for (
auto &child : *children)
2344 QRangeModelDetails::rotate(child, sourceColumn, count, destColumn);
2346 this->endMoveColumns();
2353 template <
typename InsertFn>
2354 bool doInsertRows(
int row,
int count,
const QModelIndex &parent, InsertFn &&insertFn)
2356 range_type *children = childRange(parent);
2360 this->beginInsertRows(parent, row, row + count - 1);
2362 row_ptr parentRow = parent.isValid()
2365 (
void)
std::forward<InsertFn>(insertFn)(*children, parentRow, row, count);
2369 that().resetParentInChildren(children);
2371 this->endInsertRows();
2377 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
2379 const auto end =
std::next(begin, count);
2381 for (
auto it = begin; it != end; ++it, ++rowIndex)
2382 autoConnectPropertiesInRow(*it, rowIndex, parent);
2392 return doInsertRows(row, count, parent,
2393 [
this](range_type &children, row_ptr parentRow,
int r,
int n){
2397 if constexpr (range_features::has_insert_range) {
2400 auto start = children.insert(pos, n,
nullptr);
2403 children.insert(pos, n,
std::move(*generator));
2412 bool removeRows(
int row,
int count,
const QModelIndex &parent = {})
2415 const int prevRowCount = rowCount(parent);
2416 if (row < 0 || row + count > prevRowCount)
2419 range_type *children = childRange(parent);
2424 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead) {
2426 const auto end =
std::next(begin, count);
2428 for (
auto it = begin; it != end; ++it, ++rowIndex)
2429 clearConnectionInRow(*it, rowIndex, parent);
2433 this->beginRemoveRows(parent, row, row + count - 1);
2434 [[maybe_unused]]
bool callEndRemoveColumns =
false;
2438 if (prevRowCount == count) {
2439 if (
const int columns = columnCount(parent)) {
2440 callEndRemoveColumns =
true;
2441 this->beginRemoveColumns(parent, 0, columns - 1);
2447 const auto end =
std::next(begin, count);
2448 that().deleteRemovedRows(begin, end);
2449 children->erase(begin, end);
2453 that().resetParentInChildren(children);
2456 if (callEndRemoveColumns) {
2457 Q_ASSERT(columnCount(parent) == 0);
2458 this->endRemoveColumns();
2461 this->endRemoveRows();
2468 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
2469 const QModelIndex &destParent,
int destRow)
2471 if constexpr (isMutable() && (range_features::has_rotate || range_features::has_splice)) {
2472 if (!Structure::canMoveRows(sourceParent, destParent))
2475 if (sourceParent != destParent) {
2476 return that().moveRowsAcross(sourceParent, sourceRow, count,
2477 destParent, destRow);
2480 if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0
2481 || sourceRow < 0 || sourceRow + count - 1 >=
this->rowCount(sourceParent)
2482 || destRow < 0 || destRow >
this->rowCount(destParent)) {
2486 range_type *source = childRange(sourceParent);
2488 if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow))
2493 that().resetParentInChildren(source);
2495 this->endMoveRows();
2507 int rowCount(
const QModelIndex &parent)
const {
return that().rowCountImpl(parent); }
2512 return row_traits::fixed_size();
2516 int columnCount(
const QModelIndex &parent)
const {
return that().columnCountImpl(parent); }
2570 static constexpr bool modelCopied = !QRangeModelDetails::is_wrapped<Range>() &&
2571 (std::is_reference_v<Range> || std::is_const_v<std::remove_reference_t<Range>>);
2573 static constexpr bool modelShared = QRangeModelDetails::is_any_shared_ptr<Range>();
2575 static constexpr bool default_row_deleter = protocol_traits::is_default &&
2576 protocol_traits::has_deleteRow;
2578 static constexpr bool ambiguousRowOwnership = (modelCopied || modelShared) &&
2581 static_assert(!ambiguousRowOwnership,
2582 "Using of copied and shared tree and table models with rows as raw pointers, "
2583 "and the default protocol is not allowed due to ambiguity of rows ownership. "
2584 "Move the model in, use another row type, or implement a custom tree protocol.");
2586 if constexpr (protocol_traits::has_deleteRow && !std::is_pointer_v<Range>
2587 && !QRangeModelDetails::is_any_of<Range, std::reference_wrapper>()) {
2590 that().deleteRemovedRows(begin, end);
2596 if constexpr (dynamicColumns() && !row_features::has_resize) {
2600 }
else if constexpr (!protocol_traits::has_newRow) {
2603 }
else if constexpr (!range_features::has_insert_range
2604 && !std::is_copy_constructible_v<row_type>) {
2610 return Structure::canInsertRowsImpl();
2616 return Structure::canRemoveRowsImpl();
2619 template <
typename F>
2620 bool writeAt(
const QModelIndex &index, F&& writer)
2622 row_reference row = rowData(index);
2625 return row_traits::for_element_at(row, index.column(), [&writer](
auto &&target) {
2626 using target_type =
decltype(target);
2628 if constexpr (std::is_lvalue_reference_v<target_type>
2629 && !std::is_const_v<std::remove_reference_t<target_type>>) {
2630 return writer(std::forward<target_type>(target));
2637 template <
typename F>
2638 bool readAt(
const QModelIndex &index, F&& reader)
const {
2639 const_row_reference row = rowData(index);
2642 return row_traits::for_element_at(row, index.column(), std::forward<F>(reader));
2645 template <
typename Value>
2648 if constexpr (std::is_constructible_v<QVariant, Value>)
2649 return QVariant(value);
2651 return QVariant::fromValue(value);
2653 template <
typename Value>
2657 if constexpr (std::is_constructible_v<QVariant, Value *>)
2658 return QVariant(value);
2660 return read(*value);
2665 template <
typename Target>
2666 static bool write(Target &target,
const QVariant &value)
2668 using Type = std::remove_reference_t<Target>;
2669 if constexpr (std::is_constructible_v<Target, QVariant>) {
2672 }
else if (value.canConvert<Type>()) {
2673 target = value.value<Type>();
2678 template <
typename Target>
2679 static bool write(Target *target,
const QVariant &value)
2682 return write(*target, value);
2686 template <
typename ItemType>
2690 operator QMetaProperty()
const {
2691 const QByteArray roleName = that.itemModel().roleNames().value(role);
2692 const QMetaObject &mo = ItemType::staticMetaObject;
2693 if (
const int index = mo.indexOfProperty(roleName.data());
2695 return mo.property(index);
2699 const QRangeModelImpl &that;
2701 } findProperty{*
this, role};
2703 if constexpr (ModelData::cachesProperties)
2704 return *m_data.properties.tryEmplace(role, findProperty).iterator;
2706 return findProperty;
2710 const QObject *gadget,
const QMetaProperty &prop)
const
2712 if (!index.isValid())
2714 const typename ModelData::Connection connection = {gadget, role};
2715 if (prop.hasNotifySignal() &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead
2716 && !m_data.connections.contains(connection)) {
2717 if constexpr (isMutable())
2718 Self::connectProperty(index, gadget, m_data.context, role, prop);
2720 Self::connectPropertyConst(index, gadget, m_data.context, role, prop);
2721 m_data.connections.insert(connection);
2725 template <
typename ItemType>
2728 using item_type = std::remove_pointer_t<ItemType>;
2730 QMetaProperty prop = roleProperty<item_type>(role);
2731 if (!prop.isValid() && role == Qt::EditRole) {
2732 role = Qt::DisplayRole;
2733 prop = roleProperty<item_type>(Qt::DisplayRole);
2736 if (prop.isValid()) {
2737 if constexpr (itemsAreQObjects)
2738 connectPropertyOnRead(index, role, gadget, prop);
2739 result = readProperty(prop, gadget);
2744 template <
typename ItemType>
2747 return readRole(index, role, &gadget);
2750 template <
typename ItemType>
2753 if constexpr (std::is_base_of_v<QObject, ItemType>)
2754 return prop.read(gadget);
2756 return prop.readOnGadget(gadget);
2759 template <
typename ItemType>
2762 using item_type = std::remove_pointer_t<ItemType>;
2763 const QMetaObject &mo = item_type::staticMetaObject;
2764 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
2766 if constexpr (rowsAreQObjects)
2767 connectPropertyOnRead(index, Qt::DisplayRole, gadget, prop);
2769 return readProperty(prop, gadget);
2772 template <
typename ItemType>
2775 return readProperty(index, &gadget);
2778 template <
typename ItemType>
2779 bool writeRole(
int role, ItemType *gadget,
const QVariant &data)
2781 using item_type = std::remove_pointer_t<ItemType>;
2782 auto prop = roleProperty<item_type>(role);
2783 if (!prop.isValid() && role == Qt::EditRole)
2784 prop = roleProperty<item_type>(Qt::DisplayRole);
2786 return prop.isValid() ? writeProperty(prop, gadget, data) :
false;
2789 template <
typename ItemType>
2790 bool writeRole(
int role, ItemType &&gadget,
const QVariant &data)
2792 return writeRole(role, &gadget, data);
2795 template <
typename ItemType>
2796 static bool writeProperty(
const QMetaProperty &prop, ItemType *gadget,
const QVariant &data)
2798 if constexpr (std::is_base_of_v<QObject, ItemType>)
2799 return prop.write(gadget, data);
2801 return prop.writeOnGadget(gadget, data);
2803 template <
typename ItemType>
2806 using item_type = std::remove_pointer_t<ItemType>;
2807 const QMetaObject &mo = item_type::staticMetaObject;
2808 return writeProperty(mo.property(property + mo.propertyOffset()), gadget, data);
2811 template <
typename ItemType>
2812 static bool writeProperty(
int property, ItemType &&gadget,
const QVariant &data)
2814 return writeProperty(property, &gadget, data);
2817 template <
typename ItemType>
2820 using item_type = std::remove_pointer_t<ItemType>;
2821 const QMetaObject &mo = item_type::staticMetaObject;
2822 bool success =
true;
2823 if (property == -1) {
2825 if constexpr (std::is_base_of_v<QObject, item_type>) {
2826 for (
int p = mo.propertyOffset(); p < mo.propertyCount(); ++p)
2827 success = writeProperty(mo.property(p), object, {}) && success;
2832 success = writeProperty(mo.property(property + mo.propertyOffset()), object, {});
2837 template <
typename ItemType>
2840 return resetProperty(property, &object);
2846 Q_ASSERT(index.isValid());
2847 return that().rowDataImpl(index);
2852 Q_ASSERT(index.isValid());
2853 return that().rowDataImpl(index);
2858 if (!index.isValid())
2859 return m_data.model();
2862 return that().childRangeImpl(index);
2867 if (!index.isValid())
2868 return m_data.model();
2871 return that().childRangeImpl(index);
2882template <
typename Range,
typename Protocol>
2889 using range_type =
typename Base::range_type;
2890 using range_features =
typename Base::range_features;
2891 using row_type =
typename Base::row_type;
2892 using row_ptr =
typename Base::row_ptr;
2893 using const_row_ptr =
typename Base::const_row_ptr;
2895 using tree_traits =
typename Base::protocol_traits;
2896 static constexpr bool is_mutable_impl = tree_traits::has_mutable_childRows;
2898 static constexpr bool rows_are_any_refs_or_pointers = Base::rows_are_raw_pointers ||
2899 QRangeModelDetails::is_smart_ptr<row_type>() ||
2900 QRangeModelDetails::is_any_of<row_type,
std::reference_wrapper>();
2901 static_assert(!Base::dynamicColumns(),
"A tree must have a static number of columns!");
2905 : Base(
std::forward<Range>(model),
std::forward<Protocol>(p), itemModel)
2910 for (
auto &&child : children)
2922 auto *children =
this->childRange(parent);
2925 return autoConnectPropertiesRange(QRangeModelDetails::refTo(children), parent);
2931 if (!parent.isValid())
2932 return this->createIndex(row, column);
2934 if (parent.column())
2935 return QModelIndex();
2937 const_row_ptr grandParent =
static_cast<const_row_ptr>(parent.constInternalPointer());
2938 const auto &parentSiblings = childrenOf(grandParent);
2945 if (!child.isValid())
2949 const_row_ptr parentRow =
static_cast<const_row_ptr>(child.constInternalPointer());
2954 auto &&grandParent =
this->protocol().parentRow(
QRangeModelDetails::refTo(parentRow));
2955 const range_type &parentSiblings = childrenOf(
QRangeModelDetails::pointerTo(grandParent));
2959 const auto it =
std::find_if(begin, end, [parentRow](
auto &&s){
2963 return this->createIndex(
std::distance(begin, it), 0,
2970 return Base::size(
this->childRange(parent));
2977 return Base::fixedColumnCount();
2982 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
2990 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2991 && Base::dynamicRows() && range_features::has_insert;
2999 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
3000 && Base::dynamicRows() && range_features::has_erase;
3008 static constexpr bool canMoveRows(
const QModelIndex &,
const QModelIndex &)
3014 const QModelIndex &destParent,
int destRow)
3019 if constexpr (!rows_are_any_refs_or_pointers && !tree_traits::has_setParentRow) {
3021 }
else if constexpr (!(range_features::has_insert && range_features::has_erase)) {
3023 }
else if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1,
3024 destParent, destRow)) {
3028 range_type *source =
this->childRange(sourceParent);
3029 range_type *destination =
this->childRange(destParent);
3034 if constexpr (range_features::has_insert_range) {
3036 const auto sourceEnd =
std::next(sourceStart, count);
3038 destination->insert(destStart,
std::move_iterator(sourceStart),
3039 std::move_iterator(sourceEnd));
3040 }
else if constexpr (
std::is_copy_constructible_v<row_type>) {
3042 destination->insert(destStart, count, row_type{});
3045 row_ptr parentRow = destParent.isValid()
3051 if (parentRow ==
static_cast<row_ptr>(sourceParent.internalPointer())) {
3052 if (sourceParent.row() < destRow) {
3053 source =
this->childRange(sourceParent);
3056 source =
this->childRange(
this->createIndex(sourceParent.row() + count, 0,
3057 sourceParent.internalPointer()));
3064 const auto writeEnd =
std::next(writeStart, count);
3066 const auto sourceEnd =
std::next(sourceStart, count);
3068 for (
auto write = writeStart, read = sourceStart; write != writeEnd; ++write, ++read) {
3071 if constexpr (!range_features::has_insert_range)
3072 *write =
std::move(*read);
3076 source->erase(sourceStart, sourceEnd);
3086 this->endMoveRows();
3094 static_assert(tree_traits::has_setParentRow);
3095 row_type empty_row =
this->protocol().newRow();
3101 template <
typename It,
typename Sentinel>
3104 if constexpr (tree_traits::has_deleteRow) {
3105 for (
auto it = begin; it != end; ++it) {
3106 if constexpr (Base::isMutable()) {
3107 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(*it));
3115 this->protocol().deleteRow(
std::move(*it));
3122 const auto persistentIndexList =
this->persistentIndexList();
3123 const auto [firstColumn, lastColumn] = [&persistentIndexList]{
3124 int first = std::numeric_limits<
int>::max();
3126 for (
const auto &pmi : persistentIndexList) {
3127 first = (
std::min)(pmi.column(), first);
3128 last = (
std::max)(pmi.column(), last);
3130 return std::pair(first, last);
3138 if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) {
3139 const bool changePersistentIndexes = pmiToColumn >= pmiFromColumn;
3142 for (
auto it = begin; it != end; ++it) {
3143 decltype(
auto) maybeChildren =
this->protocol().childRows(*it);
3149 for (
auto &child : childrenRef) {
3150 const_row_ptr oldParent =
this->protocol().parentRow(child);
3151 if (oldParent != parentRow) {
3152 if (changePersistentIndexes) {
3153 for (
int column = pmiFromColumn; column <= pmiToColumn; ++column) {
3154 this->changePersistentIndex(
this->createIndex(row, column, oldParent),
3155 this->createIndex(row, column, parentRow));
3158 this->protocol().setParentRow(child, parentRow);
3171 for (
const auto &row : range) {
3172 if (!
this->autoConnectPropertiesInRow(row, rowIndex, parent))
3177 if (!autoConnectPropertiesRange(QRangeModelDetails::refTo(children),
3178 this->itemModel().index(rowIndex, 0, parent))) {
3189 return autoConnectPropertiesRange(*
this->m_data.model(), {});
3194 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
3195 const range_type &siblings = childrenOf(parentRow);
3196 Q_ASSERT(index.row() <
int(Base::size(siblings)));
3202 row_ptr parentRow =
static_cast<row_ptr>(index.internalPointer());
3203 range_type &siblings = childrenOf(parentRow);
3204 Q_ASSERT(index.row() <
int(Base::size(siblings)));
3210 const auto &row =
this->rowData(index);
3212 return static_cast<
const range_type *>(
nullptr);
3214 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
3220 auto &row =
this->rowData(index);
3222 return static_cast<range_type *>(
nullptr);
3224 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
3225 using Children = std::remove_reference_t<
decltype(children)>;
3227 if constexpr (QRangeModelDetails::is_any_of<Children, std::optional>())
3228 if constexpr (std::is_default_constructible<
typename Children::value_type>()) {
3230 children.emplace(range_type{});
3239 : *
this->m_data.model();
3242 template <
typename LessThan>
3245 for (
auto &row : range) {
3246 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
3252 this->sortSubRange(range, parentRow, lessThan);
3255 template <
typename LessThan>
3258 sortImplRecursive(*
this->m_data.model(),
nullptr, lessThan);
3264 erase_if(list, [expectedParent](
const QModelIndex &index){
3265 return static_cast<row_ptr>(index.internalPointer()) != expectedParent;
3270 int role,
const QVariant &value,
int hits, Qt::MatchFlags flags,
int column,
3271 QModelIndexList &result)
const
3276 const bool recurse = flags.testAnyFlag(Qt::MatchRecursive);
3277 const bool allHits = (hits == -1);
3279 for (
int r = from; it != end && r < to && (allHits || result.size() < hits); ++it, ++r) {
3280 const QModelIndex index =
this->createIndex(r, column, parentPtr);
3281 if (
this->matchRow(*it, index, role, value, flags))
3282 result.append(index);
3285 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(*it));
3288 matchImplRecursive(QRangeModelDetails::refTo(children),
3289 QRangeModelDetails::pointerTo(*it), 0,
3290 int(QRangeModelDetails::size(QRangeModelDetails::refTo(children))),
3291 role, value, hits, flags, column, result);
3298 Qt::MatchFlags flags)
const
3300 QModelIndexList result;
3301 const bool wrap = flags.testAnyFlag(Qt::MatchWrap);
3302 const int column = start.column();
3303 const int from = start.row();
3304 const int to =
this->rowCount(start.parent());
3306 for (
int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) {
3307 const int fromRow = (i == 0) ? from : 0;
3308 const int toRow = (i == 0) ? to : from;
3309 matchImplRecursive(*
this->m_data.model(),
nullptr, fromRow, toRow,
3310 role, value, hits, flags, column, result);
3316 range_type &childrenOf(row_ptr row)
3319 : *
this->m_data.model();
3324template <
typename Range>
3331 static constexpr bool is_mutable_impl =
true;
3348 if constexpr (Base::dynamicColumns()) {
3349 if (column <
int(Base::size(*QRangeModelDetails::pos(*
this->m_data.model(), row))))
3350 return this->createIndex(row, column);
3353 qCritical(
"QRangeModel: Column-range at row %d is not large enough!", row);
3357 return this->createIndex(row, column);
3368 if (parent.isValid())
3370 return int(Base::size(*
this->m_data.model()));
3375 if (parent.isValid())
3379 if constexpr (Base::dynamicColumns()) {
3380 return int(Base::size(*
this->m_data.model()) == 0
3382 : Base::size(*QRangeModelDetails::adl_begin(*
this->m_data.model())));
3384 return Base::fixedColumnCount();
3390 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren;
3395 return Base::dynamicRows() && range_features::has_insert;
3400 return Base::dynamicRows() && range_features::has_erase;
3403 static constexpr bool canMoveColumns(
const QModelIndex &source,
const QModelIndex &destination)
3405 return !source.isValid() && !destination.isValid();
3408 static constexpr bool canMoveRows(
const QModelIndex &source,
const QModelIndex &destination)
3410 return !source.isValid() && !destination.isValid();
3414 const QModelIndex &,
int)
noexcept
3422 row_type empty_row =
this->protocol().newRow();
3425 if constexpr (Base::dynamicColumns() && row_features::has_resize) {
3433 template <
typename It,
typename Sentinel>
3436 if constexpr (Base::protocol_traits::has_deleteRow) {
3437 for (
auto it = begin; it != end; ++it)
3438 this->protocol().deleteRow(
std::move(*it));
3444 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
3450 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
3467 return *
this->m_data.model();
3478 for (
const auto &row : *
this->m_data.model()) {
3479 result &=
this->autoConnectPropertiesInRow(row, rowIndex, {});
3485 template <
typename LessThan>
3488 this->sortSubRange(*
this->m_data.model(),
nullptr, lessThan);
3494 int hits, Qt::MatchFlags flags)
const
3496 QModelIndexList result;
3497 const bool wrap = flags.testAnyFlag(Qt::MatchWrap);
3498 const bool allHits = (hits == -1);
3499 const int column = start.column();
3500 int from = start.row();
3501 int to =
this->rowCount({});
3502 decltype(
auto) siblings = *
this->m_data.model();
3504 for (
int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) {
3507 for (
int r = from; it != end && r < to && (allHits || result.size() < hits);
3511 const QModelIndex index =
this->createIndex(r, column,
nullptr);
3512 if (
this->matchRow(*it, index, role, value, flags))
3513 result.append(index);
QModelIndex parentImpl(const QModelIndex &) const
static constexpr bool canMoveRows(const QModelIndex &source, const QModelIndex &destination)
void deleteRemovedRows(It &&begin, Sentinel &&end)
QModelIndexList matchImpl(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const
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 *)
void prunePersistentIndexList(QModelIndexList &, typename Base::row_ptr)
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()
void sortImpl(const LessThan &lessThan)
auto makeEmptyRow(typename Base::row_ptr)
static constexpr bool canMoveColumns(const QModelIndex &, const QModelIndex &)
void matchImplRecursive(const range_type &range, const_row_ptr parentPtr, int from, int to, int role, const QVariant &value, int hits, Qt::MatchFlags flags, int column, QModelIndexList &result) const
QModelIndexList matchImpl(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const
auto makeEmptyRow(row_ptr parentRow)
void setParentRow(range_type &children, row_ptr parent)
bool autoConnectPropertiesImpl() const
range_type * childRangeImpl(const QModelIndex &index)
bool moveRowsAcross(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destParent, int destRow)
void resetParentInChildren(range_type *children)
int rowCountImpl(const QModelIndex &parent) const
static constexpr bool canRemoveRowsImpl()
void resetParentInChildrenRecursive(range_type *children, int pmiFromColumn, int pmiToColumn)
int columnCountImpl(const QModelIndex &) const
static constexpr bool canMoveRows(const QModelIndex &, const QModelIndex &)
const range_type & childrenOf(const_row_ptr row) const
decltype(auto) rowDataImpl(const QModelIndex &index)
QGenericTreeItemModelImpl(Range &&model, Protocol &&p, QRangeModel *itemModel)
void prunePersistentIndexList(QModelIndexList &list, row_ptr expectedParent)
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
void sortImplRecursive(range_type &range, row_ptr parentRow, const LessThan &lessThan)
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()
void sortImpl(const LessThan &lessThan)
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)
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, typename C::InterfaceVersion, typename C::Sort, typename C::Match > MethodTemplates
QVariant data(const QModelIndex &index, int role) const
QRangeModelImplBase(QRangeModel *itemModel)
QModelIndexList persistentIndexList() const
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()
void sort(int column, Qt::SortOrder order)
bool removeRows(int row, int count, const QModelIndex &parent)
static Q_CORE_EXPORT bool matchValue(const QString &itemData, const QVariant &value, Qt::MatchFlags flags)
QModelIndex parent(const QModelIndex &child) const
void changePersistentIndex(const QModelIndex &from, const QModelIndex &to)
QAbstractItemModel & itemModel()
QModelIndex createIndex(int row, int column, const void *ptr=nullptr) const
QHash< int, QByteArray > roleNames() const
void interfaceVersion(int &version) 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)
static Qt::partial_ordering compareData(const QVariant &lhs, const QVariant &rhs, const QCollator *collator)
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
QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &data, int role)
int rowCount(const QModelIndex &parent) const
Q_CORE_EXPORT int sortRole() 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
bool insertColumns(int column, int count, const QModelIndex &parent)
QVariant data(const QModelIndex &index, int role) const
QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) 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()
void interfaceVersion(int &versionNumber) const
static bool writeProperty(const QMetaProperty &prop, ItemType *gadget, const QVariant &data)
QVariant readProperty(const QModelIndex &index, ItemType *gadget) const
void sort(int column, Qt::SortOrder order)
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)
void sortSubRange(range_type &range, row_ptr expectedParent, const LessThan &lessThan)
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
bool readAt(const QModelIndex &index, F &&reader) 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)
bool matchRow(const_row_reference row, const QModelIndex &index, int role, const QVariant &value, Qt::MatchFlags flags) const
static auto adl_end(C &&c) -> decltype(end(QRangeModelDetails::refTo(std::forward< C >(c))))
decltype(QRangeModelRowOptions< row_type >::flags(std::declval< const row_type & >())) hasRowFlags_test
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 constexpr bool hasRowFlags
static auto pointerTo(T &&t)
static auto adl_begin(C &&c) -> decltype(begin(QRangeModelDetails::refTo(std::forward< C >(c))))
static constexpr bool is_multi_role_v
friend bool operator==(const Connection &lhs, const Connection &rhs) noexcept
friend size_t qHash(const Connection &c, size_t seed) noexcept
QSet< Connection > connections
~ConnectionStorage()=default
AutoConnectContext * context
auto setParentRow(R &row, R *parent) -> decltype(row.setParentRow(parent))
auto childRows(R &row) -> decltype(row.childRows())
auto childRows(const R &row) const -> decltype(row.childRows())
auto parentRow(const R &row) const -> decltype(row.parentRow())
auto newRow() -> decltype(R{})
QHash< int, QMetaProperty > properties
static constexpr bool cachesProperties
QHash< int, QMetaProperty > properties
static constexpr bool cachesProperties
std::remove_const_t< ModelStorage > m_model
static constexpr bool int_key
static constexpr bool hasFlags
decltype(Access::flags(std::declval< const Test & >())) hasFlags_test
static constexpr bool hasReadRole
static constexpr bool hasWriteRole
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 bool for_element_at(C &&container, std::size_t idx, Fn &&fn)
static constexpr int static_size
static constexpr bool is_range
static constexpr bool hasMetaObject
decltype(std::declval< C & >().sort(std::declval< LessThan && >())) sortMember_test
static constexpr bool hasCollatedCompare
const QRangeModelImpl *const that
const QCollator *const collator
auto compare(const Item &lhs, const Item &rhs) const
static constexpr bool hasSortMember
auto operator()(const Item &lhs, const Item &rhs) const
Compare(const QRangeModelImpl *impl, int column, Qt::SortOrder order)
const QModelIndex m_index
const Qt::SortOrder m_order
static std::optional< bool > compareInvalid(const Item &lhs, const Item &rhs)
bool checkComparable() const
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++()
bool operator()(const value_type &value) const
const QRangeModelImpl *const that
QModelRoleDataSpan roleDataSpan
const QModelIndex & index
friend constexpr bool operator<(unordered, QtPrivate::CompareAgainstLiteralZero) noexcept
friend constexpr bool operator>(unordered, QtPrivate::CompareAgainstLiteralZero) noexcept