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
100 using Type = q20::remove_cvref_t<T>;
101 if constexpr (is_any_of<Type, std::optional>())
102 return t ?
std::addressof(*
std::forward<T>(t)) :
nullptr;
103 else if constexpr (std::is_pointer<Type>())
105 else if constexpr (is_smart_ptr<Type>())
107 else if constexpr (is_any_of<Type, std::reference_wrapper>())
108 return std::addressof(t.get());
110 return std::addressof(
std::forward<T>(t));
113 template <
typename T>
123 template <
typename T>
126 template <
typename T>
131 template <
typename T,
typename =
void>
135 template <
typename T>
138 template <
typename T>
141 template <
typename T,
typename =
void>
147 template <
typename T>
150 template <
typename T,
typename =
void>
152 template <
typename T>
155 template <
typename T>
158 template <
typename T>
159 inline constexpr bool isValid(
const T &t)
noexcept
161 if constexpr (
std::is_array_v<T>)
163 else if constexpr (is_validatable<T>())
169 template <
typename T>
170 inline decltype(
auto)
refTo(T&& t) {
173 using Type = q20::remove_cvref_t<T>;
174 if constexpr (is_any_of<T, std::optional>())
175 return *
std::forward<T>(t);
176 if constexpr (!is_wrapped<Type>() || is_any_unique_ptr<Type>())
177 return q23::forward_like<T>(*QRangeModelDetails::pointerTo(t));
182 template <
typename It>
183 auto key(It&& it) ->
decltype(it.key()) {
return std::forward<It>(it).key(); }
184 template <
typename It>
185 auto key(It&& it) ->
decltype((it->first)) {
return std::forward<It>(it)->first; }
187 template <
typename It>
188 auto value(It&& it) ->
decltype(it.value()) {
return std::forward<It>(it).value(); }
189 template <
typename It>
190 auto value(It&& it) ->
decltype((it->second)) {
return std::forward<It>(it)->second; }
196 template <
typename C>
199 template <
typename C>
202 template <
typename C>
203 static auto pos(C &&c,
int i)
211 template <
typename C,
typename =
void>
214 template <
typename C>
225 template <
typename C,
typename =
void>
228 template <
typename C>
237 template <
typename C,
typename =
void>
240 template <
typename C>
248 template <
typename C,
typename =
void>
251 template <
typename C>
262 template <
typename It>
264 std::is_swappable<
decltype(*
std::declval<It>())>,
265 std::is_base_of<
std::forward_iterator_tag,
269 template <
typename C,
typename =
void>
272 template <
typename C>
282 template <
typename C>
283 static void rotate(C& c,
int src,
int count,
int dst) {
285 using Container = std::remove_reference_t<
decltype(container)>;
288 const auto srcEnd =
std::next(srcBegin, count);
291 if constexpr (test_splice<Container>::value) {
292 if (dst > src && dst < src + count)
293 container.splice(srcBegin, container, dstBegin, srcEnd);
295 container.splice(dstBegin, container, srcBegin, srcEnd);
298 std::rotate(srcBegin, srcEnd, dstBegin);
300 std::rotate(dstBegin, srcBegin, srcEnd);
313 template <
typename C>
322 template <
typename C>
327 template <
typename C,
typename =
void>
329 template <
typename C>
332 template <
typename C,
typename =
void>
334 template <
typename C>
339 template <
typename C,
typename =
void>
350 template <
typename C>
391 template <
typename C>
393 template <
typename C>
399 template <
typename T>
408 static constexpr bool hasReadRole = qxp::is_detected_v<hasReadRole_test, ItemAccess, ItemType>;
413 static constexpr bool hasWriteRole = qxp::is_detected_v<hasWriteRole_test, ItemAccess, ItemType>;
415 template <
typename Access,
typename Test>
418 static constexpr bool hasFlags = qxp::is_detected_v<hasFlags_test, ItemAccess, ItemType>;
420 template <
typename Access,
typename Test>
422 static constexpr bool hasMimeTypes = qxp::is_detected_v<hasMimeTypes_test, ItemAccess, ItemType>;
426 static constexpr bool hasMimeData = qxp::is_detected_v<hasMimeData_test, ItemAccess, ItemType>;
428 template <
typename Access>
439 ItemAccess, ItemType>;
442 template <
typename Access>
455 ItemAccess, ItemType>;
462 template <
typename T,
typename =
void>
468 template <
typename T>
482 template <
typename row_type>
485 static constexpr bool hasRowFlags = qxp::is_detected_v<hasRowFlags_test, row_type>;
488 template <
typename row_type>
491 static constexpr bool hasMimeTypes = qxp::is_detected_v<hasMimeTypes_test, row_type>;
519 static constexpr bool hasDropMimeData = qxp::is_detected_v<hasDropMimeData_test, row_type>;
542 template <
typename T,
typename =
void>
559 template <
typename C,
typename Fn>
563 return std::forward<Fn>(fn)(
566 return std::forward<Fn>(fn)(
std::forward<C>(container));
569 template <
typename Fn>
575 int columnIndex = -1;
578 return std::forward<Fn>(fn)(firstIndex.siblingAtColumn(++columnIndex),
586 template <
typename T>
606 template <
typename C,
typename F>
641 template <
typename Fn>
661 template <
typename C,
typename F>
673 template <
typename Fn>
689 template <
typename T>
710 template <
typename C,
typename F>
730 template <
typename Fn>
737 template <
typename T,
typename =
void>
740 template <
typename That>
743 return That::roleNamesForSimpleType();
750 template <
typename That>
757 template <
typename T>
763 template <
typename T>
766 template <
typename That>
773 template <
typename T>
777 template <
typename Range>
783 auto newRow() ->
decltype(R{}) {
return R{}; }
786 template <
typename Range>
814 template <
typename Range,
822 template <
typename Range>
825 template <
typename R >
826 auto parentRow(
const R& row)
const ->
decltype(row.parentRow())
828 return row.parentRow();
831 template <
typename R >
832 auto setParentRow(R &row, R* parent) ->
decltype(row.setParentRow(parent))
834 row.setParentRow(parent);
837 template <
typename R >
838 auto childRows(
const R &row)
const ->
decltype(row.childRows())
840 return row.childRows();
843 template <
typename R >
846 return row.childRows();
850 template <
typename P,
typename R>
853 template <
typename P,
typename R>
856 template <
typename P,
typename R>
859 template <
typename P,
typename R>
862 template <
typename P,
typename R>
866 template <
typename P,
typename R>
869 template <
typename P,
typename R>
872 template <
typename P,
typename R>
875 template <
typename P,
typename =
void>
877 template <
typename P>
881 template <
typename P,
typename R,
typename =
void>
883 template <
typename P,
typename R>
888 template <
typename Range,
900 template <
typename Range>
913 template <
typename Range,
typename Protocol>
937 template <
typename Entry>
942 template<
typename T,
typename =
void>
953 if constexpr (QRangeModelDetails::is_owning_or_raw_pointer<entry_type>()) {
959 qDebug(
"QRangeModel::mimeData: null-entry, test with isValid before accessing");
961 constexpr bool is_constexpr_default_constructible_v =
962 is_constexpr_default_constructible<wrapped_entry>::value;
963 if constexpr (is_constexpr_default_constructible_v) {
964 Q_CONSTINIT
static const wrapped_entry emptyDefault;
968 static const wrapped_entry emptyDefault;
973 return std::as_const(QRangeModelDetails::refTo(m_entry));
978 template <
std::size_t N>
981 if constexpr (N == 0)
982 return entry.entry();
983 else if constexpr (N == 1)
984 return entry.index();
1001template <
typename T>
1030 return !(lhs
== rhs);
1034 template <
typename Entry>
1071 template <
bool cacheProperties,
bool itemsAreQObjects>
1103 return lhs.sender == rhs.sender && lhs
.role == rhs
.role;
1107 return qHashMulti(seed, c.sender, c
.role);
1131 template <
typename ModelStorage,
typename =
void>
1150 template <
typename ModelStorage,
typename PropertyStorage>
1161 template <
typename Model = ModelStorage>
1197 bool setHeaderData(
int section, Qt::Orientation orientation,
const QVariant &data,
int role);
1198 bool setData(
const QModelIndex &index,
const QVariant &data,
int role);
1199 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data);
1203 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
const QModelIndex &destParent,
int destColumn);
1206 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
const QModelIndex &destParent,
int destRow);
1219 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const;
1223 void sort(
int column, Qt::SortOrder order);
1225 int hits, Qt::MatchFlags flags)
const;
1231 const QModelIndex &parent)
const;
1232 bool dropMimeData(
const QMimeData *data, Qt::DropAction action,
int row,
int column,
1233 const QModelIndex &parent);
1277 template <
typename C>
1318 friend class QRangeModelPrivate;
1321 QRangeModel *m_rangeModel;
1325 : m_rangeModel(itemModel)
1331 inline void dataChanged(
const QModelIndex &from,
const QModelIndex &to,
1332 const QList<
int> &roles);
1339 inline bool beginMoveColumns(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1340 const QModelIndex &destParent,
int destRow);
1342 inline void beginInsertRows(
const QModelIndex &parent,
int start,
int count);
1344 inline void beginRemoveRows(
const QModelIndex &parent,
int start,
int count);
1346 inline bool beginMoveRows(
const QModelIndex &sourceParent,
int sourceFirst,
int sourceLast,
1347 const QModelIndex &destParent,
int destRow);
1353 const QCollator *collator);
1371 QRangeModelDetails::AutoConnectContext *context,
1372 int role,
const QMetaProperty &property);
1374 QRangeModelDetails::AutoConnectContext *context,
1375 int role,
const QMetaProperty &property);
1377 QRangeModelDetails::AutoConnectContext *context,
1378 const QHash<
int, QMetaProperty> &properties);
1380 QRangeModelDetails::AutoConnectContext *context,
1381 const QHash<
int, QMetaProperty> &properties);
1388 Qt::MatchFlags flags);
1390 Qt::MatchFlags flags,
const QCollator &collator);
1391 static bool matchValue(
const QVariant &itemData,
const QVariant &value, Qt::MatchFlags flags,
1392 const QCollator &collator)
1394 if ((flags & Qt::MatchTypeMask) == Qt::MatchExactly)
1395 return itemData == value;
1396 return matchValue(itemData.toString(), value, flags, collator);
1402template <
typename Structure,
typename Range,
1403 typename Protocol = QRangeModelDetails::table_protocol_t<Range>>
1439 "Currently, std::optional is not supported for ranges and rows, as "
1440 "it has range semantics in c++26. Once the required behavior is clarified, "
1441 "std::optional for ranges and rows will be supported.");
1448 Structure&
that() {
return static_cast<Structure &>(*
this); }
1449 const Structure&
that()
const {
return static_cast<
const Structure &>(*
this); }
1451 template <
typename C>
1452 static constexpr int size(
const C &c)
1457 if constexpr (QRangeModelDetails::test_size<C>()) {
1459 return int(size(c));
1461#if defined(__cpp_lib_ranges)
1462 using std::ranges::distance;
1464 using std::distance;
1466 using container_type = std::conditional_t<QRangeModelDetails::range_traits<C>::has_cbegin,
1467 const QRangeModelDetails::wrapped_t<C>,
1468 QRangeModelDetails::wrapped_t<C>>;
1469 container_type& container =
const_cast<container_type &>(
QRangeModelDetails::refTo(c));
1485 return this->blockDataChangedDispatch();
1495 template <
typename T>
1515 {
return lhs.n == rhs.n; }
1517 {
return !(lhs == rhs); }
1528 "The range holding a move-only row-type must support insert(pos, start, end)");
1536 return range_features::is_mutable && row_features::is_mutable
1537 && std::is_reference_v<row_reference>
1538 && Structure::is_mutable_impl;
1555 versionNumber = QT_VERSION;
1566 if (row < 0 || column < 0 || column >= columnCount(parent)
1567 || row >= rowCount(parent)) {
1571 return that().indexImpl(row, column, parent);
1576 if (row == index.row() && column == index.column())
1580 if (column >=
this->columnCount({}))
1583 if (row == index.row())
1584 return this->createIndex(row, column, index.constInternalPointer());
1586 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
1587 const auto siblingCount = size(that().childrenOf(parentRow));
1588 if (row < 0 || row >=
int(siblingCount))
1590 return this->createIndex(row, column, parentRow);
1595 if (!index.isValid()) {
1596 if constexpr (isMutable())
1597 return Qt::ItemIsDropEnabled;
1599 return Qt::NoItemFlags;
1603 std::optional<Qt::ItemFlags> customFlags = std::nullopt;
1604 if constexpr (QRangeModelDetails::hasRowFlags<wrapped_row_type>) {
1605 const_row_reference row = rowData(index);
1607 customFlags = QRangeModelDetails::QRangeModelRowOptions<wrapped_row_type>::flags(
1608 QRangeModelDetails::refTo(row)
1613 readAt(index, [&customFlags](
auto &&ref){
1615 using wrapped_value_type = q20::remove_cvref_t<QRangeModelDetails::wrapped_t<
decltype(ref)>>;
1616 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>::hasFlags) {
1617 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1619 customFlags = ItemAccess::flags(QRangeModelDetails::refTo(ref));
1626 Qt::ItemFlags f = customFlags ? *customFlags : Structure::defaultFlags();
1628 if constexpr (!isMutable())
1629 f &= ~(Qt::ItemIsEditable | Qt::ItemIsDropEnabled);
1631 f |= Qt::ItemNeverHasChildren;
1636 if (!
this->itemModel().mimeTypes().isEmpty()) {
1637 f |= Qt::ItemIsDragEnabled;
1638 if constexpr (isMutable())
1639 f |= Qt::ItemIsDropEnabled;
1642 if constexpr (QRangeModelDetails::is_owning_or_raw_pointer<row_type>()) {
1644 const_row_reference row = rowData(index);
1645 if (!QRangeModelDetails::isValid(row))
1646 f &= ~Qt::ItemIsDragEnabled;
1649 if constexpr (isMutable()) {
1654 if constexpr (row_traits::hasMetaObject) {
1655 if (index.column() < row_traits::fixed_size()) {
1656 const QMetaObject mo = wrapped_row_type::staticMetaObject;
1657 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
1658 if (prop.isWritable())
1659 f |= Qt::ItemIsEditable;
1662 using item_type =
typename row_traits::item_type;
1663 if constexpr (QRangeModelDetails::is_owning_or_raw_pointer<item_type>()) {
1665 if (!readAt(index, [](
auto &&i){
return QRangeModelDetails::isValid(i); }))
1666 f &= ~Qt::ItemIsDragEnabled;
1668 f |= Qt::ItemIsEditable;
1669 }
else if constexpr (std::is_reference_v<row_reference> && !std::is_const_v<row_reference>) {
1672 const_row_reference row = rowData(index);
1673 row_reference mutableRow =
const_cast<row_reference>(row);
1675 row_traits::for_element_at(mutableRow, index.column(), [&f](
auto &&ref){
1676 using target_type =
decltype(ref);
1677 if constexpr (QRangeModelDetails::is_owning_or_raw_pointer<target_type>()) {
1679 if (!QRangeModelDetails::isValid(ref))
1680 f &= ~Qt::ItemIsDragEnabled;
1682 if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
1683 f &= ~Qt::ItemIsEditable;
1684 else if constexpr (std::is_lvalue_reference_v<target_type>)
1685 f |= Qt::ItemIsEditable;
1690 f &= ~Qt::ItemIsEditable;
1700 if constexpr (QRangeModelDetails::hasHeaderData<wrapped_row_type>) {
1701 if (orientation == Qt::Horizontal) {
1702 result = QRangeModelDetails::QRangeModelRowOptions<wrapped_row_type>::headerData(
1705 if (result.isValid())
1710 if (role != Qt::DisplayRole || orientation != Qt::Horizontal
1711 || section < 0 || section >= columnCount({})) {
1712 return this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1715 result = row_traits::column_name(section);
1716 if (!result.isValid())
1717 result =
this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1723 if (!index.isValid())
1726 QModelRoleData result(role);
1727 multiData(index, result);
1728 return std::move(result.data());
1733 return role == Qt::RangeModelDataRole
1734 || role == Qt::RangeModelAdapterRole;
1739 return role == Qt::DisplayRole || role == Qt::EditRole;
1744 QMap<
int, QVariant> result;
1746 if (index.isValid()) {
1748 if (!readAt(index, [&result](
const auto &value) {
1749 if constexpr (std::is_convertible_v<
decltype(value),
decltype(result)>) {
1755 const auto roles =
this->itemModel().roleNames().keys();
1756 QVarLengthArray<QModelRoleData, 16> roleDataArray;
1757 roleDataArray.reserve(roles.size());
1758 for (
auto role : roles) {
1759 if (isRangeModelRole(role))
1761 roleDataArray.emplace_back(role);
1763 QModelRoleDataSpan roleDataSpan(roleDataArray);
1764 multiData(index, roleDataSpan);
1766 for (QModelRoleData &roleData : roleDataSpan) {
1767 if (roleData.data().isValid())
1768 result[roleData.role()] = std::move(roleData.data());
1777 template <
typename value_type>
1780 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1781 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1783 const auto readModelData = [&value](QModelRoleData &roleData){
1785 roleData.clearData();
1789 const int role = roleData.role();
1790 if (role == Qt::RangeModelDataRole) {
1794 if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
1795 roleData.setData(QVariant::fromValue(QRangeModelDetails::refTo(value)));
1797 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1798 }
else if (role == Qt::RangeModelAdapterRole) {
1800 if constexpr (
std::is_copy_assignable_v<value_type>)
1801 roleData.setData(QVariant::fromValue(value));
1803 roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
1810 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>::hasReadRole) {
1811 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1812 for (
auto &roleData : roleDataSpan) {
1813 if (!readModelData(roleData)) {
1814 roleData.setData(ItemAccess::readRole(QRangeModelDetails::refTo(value),
1818 }
else if constexpr (multi_role()) {
1819 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1821 if constexpr (!multi_role::int_key)
1822 return that->itemModel().roleNames();
1826 using key_type =
typename value_type::key_type;
1827 for (
auto &roleData : roleDataSpan) {
1828 const auto &it = [&roleNames, &value, role = roleData.role()]{
1829 Q_UNUSED(roleNames);
1830 if constexpr (multi_role::int_key)
1831 return value.find(key_type(role));
1833 return value.find(roleNames.value(role));
1835 if (it != QRangeModelDetails::adl_end(value))
1836 roleData.setData(QRangeModelDetails::value(it));
1838 roleData.clearData();
1840 }
else if constexpr (has_metaobject<value_type>) {
1841 if (row_traits::fixed_size() <= 1) {
1842 for (
auto &roleData : roleDataSpan) {
1843 if (!readModelData(roleData)) {
1844 roleData.setData(that->readRole(index, roleData.role(),
1845 QRangeModelDetails::pointerTo(value)));
1848 }
else if (index.column() <= row_traits::fixed_size()) {
1849 for (
auto &roleData : roleDataSpan) {
1850 const int role = roleData.role();
1851 if (isPrimaryRole(role)) {
1852 roleData.setData(that->readProperty(index,
1853 QRangeModelDetails::pointerTo(value)));
1855 roleData.clearData();
1860 for (
auto &roleData : roleDataSpan) {
1861 const int role = roleData.role();
1862 if (isPrimaryRole(role) || isRangeModelRole(role))
1863 roleData.setData(read(value));
1865 roleData.clearData();
1876 void multiData(
const QModelIndex &index, QModelRoleDataSpan roleDataSpan)
const
1878 if (!readAt(index,
ItemReader{index, roleDataSpan,
this})) {
1879 for (
auto &roleData : roleDataSpan)
1880 roleData.clearData();
1884 bool setData(
const QModelIndex &index,
const QVariant &data,
int role)
1886 if (!index.isValid())
1889 if constexpr (isMutable()) {
1890 auto emitDataChanged = qScopeGuard([
this, &index, role]{
1891 Q_EMIT
this->dataChanged(index, index,
1892 role == Qt::EditRole || role == Qt::RangeModelDataRole
1893 || role == Qt::RangeModelAdapterRole
1894 ? QList<
int>{} : QList<
int>{role});
1899 const auto writeData = [
this, column = index.column(), &data, role](
auto &&target) ->
bool {
1900 using value_type = q20::remove_cvref_t<
decltype(target)>;
1901 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1902 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1904 if constexpr (std::conjunction_v<QRangeModelDetails::is_any_owning_ptr<value_type>,
1905 std::is_default_constructible<wrapped_value_type>>) {
1907 target.reset(
new wrapped_value_type);
1910 auto setRangeModelDataRole = [&target, &data]{
1911 constexpr auto targetMetaType = QMetaType::fromType<value_type>();
1912 const auto dataMetaType = data.metaType();
1913 constexpr bool isWrapped = QRangeModelDetails::is_wrapped<value_type>();
1914 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>) {
1918 if constexpr (isWrapped) {
1919 constexpr bool is_raw_pointer = std::is_pointer_v<value_type>;
1920 if constexpr (!is_raw_pointer && std::is_copy_assignable_v<value_type>) {
1921 if (data.canConvert(targetMetaType)) {
1922 target = data.value<value_type>();
1925 }
else if constexpr (is_raw_pointer) {
1927 target = data.value<value_type>();
1936 }
else if constexpr (isWrapped) {
1941 if (
const auto mt = QMetaType::fromType<wrapped_value_type>();
1942 data.canConvert(mt)) {
1943 targetRef = data.value<wrapped_value_type>();
1945 }
else if (
const auto mtp = QMetaType::fromType<wrapped_value_type *>();
1946 data.canConvert(mtp)) {
1947 targetRef = *data.value<wrapped_value_type *>();
1951 }
else if (targetMetaType == dataMetaType) {
1952 QRangeModelDetails::refTo(target) = data.value<value_type>();
1954 }
else if (dataMetaType.flags() & QMetaType::PointerToGadget) {
1955 QRangeModelDetails::refTo(target) = *data.value<value_type *>();
1959 qCritical(
"Not able to assign %s to %s",
1960 qPrintable(QDebug::toString(data)), targetMetaType.name());
1965 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>::hasWriteRole) {
1966 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
1967 if (isRangeModelRole(role))
1968 return setRangeModelDataRole();
1969 return ItemAccess::writeRole(QRangeModelDetails::refTo(target), data, role);
1970 }
else if constexpr (has_metaobject<value_type>) {
1971 if (row_traits::fixed_size() <= 1) {
1972 if (isRangeModelRole(role))
1973 return setRangeModelDataRole();
1975 }
else if (column <= row_traits::fixed_size()
1976 && (isPrimaryRole(role) || isRangeModelRole(role))) {
1979 }
else if constexpr (multi_role::value) {
1980 Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role);
1983 const auto roleNames = [
this]() -> QHash<
int, QByteArray> {
1985 if constexpr (!multi_role::int_key)
1986 return this->itemModel().roleNames();
1990 if (role == Qt::EditRole) {
1991 if constexpr (multi_role::int_key) {
1992 if (target.find(roleToSet) == target.end())
1993 roleToSet = Qt::DisplayRole;
1995 if (target.find(roleNames.value(roleToSet)) == target.end())
1996 roleToSet = Qt::DisplayRole;
1999 if constexpr (multi_role::int_key)
2000 return write(target[roleToSet], data);
2002 return write(target[roleNames.value(roleToSet)], data);
2003 }
else if (isPrimaryRole(role) || isRangeModelRole(role)) {
2004 return write(target, data);
2009 if (!writeAt(index, writeData)) {
2010 emitDataChanged.dismiss();
2013 if (isRangeModelRole(role) &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
2014 if (QObject *item = data.value<QObject *>())
2015 Self::connectProperties(index, item, m_data.context, m_data.properties);
2023 template <
typename LHS,
typename RHS>
2026 if constexpr (
std::is_pointer_v<RHS>)
2028 else if constexpr (
std::is_assignable_v<LHS, RHS>)
2029 org =
std::forward<RHS>(copy);
2033 template <
typename LHS,
typename RHS>
2036 updateTarget(*org,
std::forward<RHS>(copy));
2039 bool setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &data)
2041 if (!index.isValid() || data.isEmpty())
2044 if constexpr (isMutable()) {
2045 auto emitDataChanged = qScopeGuard([
this, &index, &data]{
2046 Q_EMIT
this->dataChanged(index, index, data.keys());
2052 auto writeItemData = [
this, &tried, &data](
auto &target) ->
bool {
2054 using value_type = q20::remove_cvref_t<
decltype(target)>;
2055 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
2056 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
2060 auto makeCopy = [](
const value_type &original){
2061 if constexpr (!std::is_copy_assignable_v<wrapped_value_type>)
2063 else if constexpr (std::is_pointer_v<
decltype(original)>)
2065 else if constexpr (std::is_copy_assignable_v<value_type>)
2071 const auto roleNames =
this->itemModel().roleNames();
2073 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>::hasWriteRole) {
2075 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
2076 const auto roles = roleNames.keys();
2077 auto targetCopy = makeCopy(target);
2078 for (
int role : roles) {
2079 if (!ItemAccess::writeRole(QRangeModelDetails::refTo(targetCopy),
2080 data.value(role), role)) {
2084 updateTarget(target,
std::move(targetCopy));
2086 }
else if constexpr (multi_role()) {
2087 using key_type =
typename value_type::key_type;
2089 const auto roleName = [&roleNames](
int role) {
2090 return roleNames.value(role);
2095 if constexpr (!multi_role::int_key)
2097 auto invalid =
std::find_if(data.keyBegin(), data.keyEnd(),
2098 [&roleName](
int role) {
return roleName(role).isEmpty(); }
2101 if (invalid != data.keyEnd()) {
2103 qWarning(
"No role name set for %d", *invalid);
2109 for (
auto &&[role, value] : data.asKeyValueRange()) {
2110 if constexpr (multi_role::int_key)
2111 target[
static_cast<key_type>(role)] = value;
2113 target[QString::fromUtf8(roleName(role))] = value;
2116 }
else if constexpr (has_metaobject<value_type>) {
2117 if (row_traits::fixed_size() <= 1) {
2119 auto targetCopy = makeCopy(target);
2120 for (
auto &&[role, value] : data.asKeyValueRange()) {
2121 if (isRangeModelRole(role))
2123 if (!writeRole(role, QRangeModelDetails::pointerTo(targetCopy), value)) {
2124 const QByteArray roleName = roleNames.value(role);
2126 qWarning(
"Failed to write value '%s' to role '%s'",
2127 qPrintable(QDebug::toString(value)), roleName.data());
2132 updateTarget(target,
std::move(targetCopy));
2139 if (!writeAt(index, writeItemData)) {
2140 emitDataChanged.dismiss();
2142 return this->itemModel().QAbstractItemModel::setItemData(index, data);
2151 if (!index.isValid())
2154 if constexpr (isMutable()) {
2155 auto emitDataChanged = qScopeGuard([
this, &index]{
2156 Q_EMIT
this->dataChanged(index, index, {});
2159 auto clearData = [column = index.column()](
auto &&target) {
2160 if constexpr (row_traits::hasMetaObject) {
2161 if (row_traits::fixed_size() <= 1) {
2164 }
else if (column <= row_traits::fixed_size()) {
2174 if (!writeAt(index, clearData)) {
2175 emitDataChanged.dismiss();
2186 using item_type = QRangeModelDetails::wrapped_t<
typename row_traits::item_type>;
2187 using item_traits =
typename QRangeModelDetails::item_traits<item_type>;
2188 return item_traits::roleNames(
this);
2195 return row_traits::for_each_element(QRangeModelDetails::refTo(row),
2196 this->itemModel().index(rowIndex, 0, parent),
2197 [
this](
const QModelIndex &index,
const QObject *item) {
2198 if constexpr (isMutable())
2199 return Self::connectProperties(index, item, m_data.context, m_data.properties);
2201 return Self::connectPropertiesConst(index, item, m_data.context, m_data.properties);
2209 row_traits::for_each_element(QRangeModelDetails::refTo(row),
2210 this->itemModel().index(rowIndex, 0, parent),
2211 [
this](
const QModelIndex &,
const QObject *item) {
2212 m_data.connections.removeIf([item](
const auto &connection) {
2213 return connection.sender == item;
2222 using item_type = std::remove_pointer_t<
typename row_traits::item_type>;
2223 using Mapping = QRangeModelDetails::AutoConnectContext::AutoConnectMapping;
2225 delete m_data.context;
2226 m_data.connections = {};
2227 switch (
this->autoConnectPolicy()) {
2228 case AutoConnectPolicy::None:
2229 m_data.context =
nullptr;
2231 case AutoConnectPolicy::Full:
2232 m_data.context =
new QRangeModelDetails::AutoConnectContext(&
this->itemModel());
2234 m_data.properties = QRangeModelImplBase::roleProperties(
this->itemModel(),
2235 item_type::staticMetaObject);
2236 m_data.context->mapping = Mapping::Roles;
2238 m_data.properties = QRangeModelImplBase::columnProperties(wrapped_row_type::staticMetaObject);
2239 m_data.context->mapping = Mapping::Columns;
2241 if (!m_data.properties.isEmpty())
2242 that().autoConnectPropertiesImpl();
2244 case AutoConnectPolicy::OnRead:
2245 m_data.context =
new QRangeModelDetails::AutoConnectContext(&
this->itemModel());
2247 m_data.context->mapping = Mapping::Roles;
2249 m_data.properties = QRangeModelImplBase::columnProperties(wrapped_row_type::staticMetaObject);
2250 m_data.context->mapping = Mapping::Columns;
2256 qWarning(
"All items in the range must be QObject subclasses");
2270 template <
typename C,
typename LessThan>
2272 static constexpr bool hasSortMember = qxp::is_detected_v<sortMember_test, range_type, Compare>;
2290 template <
typename Item>
2291 auto operator()(
const Item &lhs,
const Item &rhs)
const
2293 auto ordering = compare(lhs, rhs);
2294 return m_order == Qt::AscendingOrder ? ordering < 0 : ordering > 0;
2297 template <
typename Item>
2298 auto compare(
const Item &lhs,
const Item &rhs)
const
2300 using value_type = QRangeModelDetails::wrapped_t<Item>;
2301 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
2303 if constexpr (QRangeModelDetails::item_access<value_type>::hasReadRole
2304 || multi_role() || has_metaobject<value_type>) {
2312 Q_ASSERT(!reader.index.isValid());
2314 const QVariant lhsVariant =
std::move(result.data());
2316 const QVariant rhsVariant =
std::move(result.data());
2317 return QRangeModelImplBase::compareData(lhsVariant, rhsVariant, collator);
2318 }
else if constexpr (std::is_same_v<QVariant, value_type>) {
2319 return QRangeModelImplBase::compareData(lhs, rhs, collator);
2320 }
else if constexpr (QtOrderingPrivate::CompareThreeWayTester::hasCompareThreeWay_v
2321 <value_type, value_type>) {
2323 if constexpr (hasCollatedCompare<value_type>) {
2325 using ordering =
decltype(qCompareThreeWay(lhs, rhs));
2326 int res = collator->compare(lhs, rhs);
2328 return ordering::less;
2330 return ordering::greater;
2331 return ordering::equal;
2334 return qCompareThreeWay(lhs, rhs);
2342 return that->readAt(
that->index(0, 0, {}), [
this](
const auto &item){
2347 using ordering =
decltype(compare(item, item));
2350 const QMetaType itemtype = QMetaType::fromType<QRangeModelDetails::wrapped_t<
2351 q20::remove_cvref_t<
decltype(item)>>
2353 qCritical(
"QRangeModel: Cannot compare items of type %s in column %d!",
2354 itemtype.name(), m_index.column());
2365 template <
typename Item>
2373 return std::nullopt;
2383 void sort(
int column, Qt::SortOrder order)
2385 if constexpr (isMutable() && std::is_swappable_v<row_type>) {
2386 if (rowCount({}) < 2 || column >= columnCount({}))
2388 Compare compare(
this, column, order);
2389 if (!compare.checkComparable())
2392 this->beginLayoutChange();
2393 QScopeGuard endLayoutChange([
this]{
this->endLayoutChange(); });
2394 that().sortImpl([&compare](
const auto &leftRow,
const auto &rightRow) {
2395 if (
auto anyInvalid =
Compare::compareInvalid(leftRow, rightRow))
2397 return row_traits::for_element_at(leftRow, compare.m_index.column(),
2398 [&rightRow, &compare](
const auto &leftItem){
2399 return row_traits::for_element_at(rightRow, compare.m_index.column(),
2400 [&leftItem, &compare](
const auto &rightItem){
2403 if constexpr (std::is_same_v<
decltype(leftItem),
decltype(rightItem)>) {
2404 if (
auto anyInvalid = Compare::compareInvalid(leftItem, rightItem))
2406 return compare(QRangeModelDetails::refTo(leftItem),
2407 QRangeModelDetails::refTo(rightItem));
2418 template <
typename LessThan>
2419 void sortSubRange(range_type &range, row_ptr expectedParent,
const LessThan &lessThan)
2426 QModelIndexList persistentIndexes =
this->persistentIndexList();
2427 that().prunePersistentIndexList(persistentIndexes, expectedParent);
2429 if (persistentIndexes.isEmpty()) {
2430 using It =
typename range_features::iterator;
2431 constexpr bool is_random_access = std::is_base_of_v<std::random_access_iterator_tag,
2432 typename std::iterator_traits<It>::iterator_category>;
2434 if constexpr (
Compare::hasSortMember) {
2435 range.sort(lessThan);
2437 }
else if constexpr (is_random_access) {
2438 std::stable_sort(begin, end, lessThan);
2451 const int rangeSize = size(range);
2454 std::vector<SortTracker> tracked;
2455 tracked.reserve(rangeSize);
2456 std::vector<
int> newRows;
2457 newRows.resize(rangeSize);
2461 for (
auto &&it =
std::move_iterator(begin); it !=
std::move_iterator(end); ++it)
2462 tracked.emplace_back(SortTracker{*it, ++row});
2465 std::stable_sort(tracked.begin(), tracked.end(),
2466 [&lessThan](
const SortTracker &lhs,
const SortTracker &rhs){
2467 return lessThan(lhs.row, rhs.row);
2472 auto sorted =
std::move_iterator(tracked.begin());
2474 qsizetype changedIndexCount = 0;
2475 for (
int newIndex = 0; newIndex < rangeSize; ++write, ++sorted, ++newIndex) {
2476 auto &&tracker = *sorted;
2477 changedIndexCount += (tracker.index != newIndex);
2478 *write =
std::move(tracker.row);
2479 newRows[tracker.index] = newIndex;
2484 tracked.shrink_to_fit();
2487 for (
const auto &fromIndex : std::as_const(persistentIndexes)) {
2488 const int newRow = newRows.at(fromIndex.row());
2489 if (fromIndex.row() == newRow)
2491 const QModelIndex toIndex = that().indexImpl(newRow,
2493 fromIndex.parent());
2494 this->changePersistentIndex(fromIndex, toIndex);
2499 Qt::MatchFlags flags)
const
2501 QCollator collator =
this->matchCollator();
2502 collator.setCaseSensitivity(flags.testFlag(Qt::MatchCaseSensitive) ? Qt::CaseSensitive
2503 : Qt::CaseInsensitive);
2504 return that().matchImpl(start, role,
2505 QRangeModelImplBase::convertMatchValue(value, flags), hits,
2509 bool matchRow(const_row_reference row,
const QModelIndex &index,
int role,
const QVariant &value,
2510 Qt::MatchFlags flags,
const QCollator &collator)
const
2512 const uint matchType = (flags & Qt::MatchTypeMask).toInt();
2514 return row_traits::for_element_at(row, index.column(), [&](
const auto &element) {
2515 using value_type = q20::remove_cvref_t<
decltype(element)>;
2516 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
2517 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
2519 if constexpr (QRangeModelDetails::item_access<wrapped_value_type>::hasReadRole
2520 || multi_role() || has_metaobject<value_type>) {
2521 QModelRoleData roleData(role);
2522 ItemReader reader{index, roleData,
this};
2524 return QRangeModelImplBase::matchValue(roleData.data(), value, flags, collator);
2525 }
else if constexpr (std::is_same_v<wrapped_value_type, QVariant>) {
2526 return QRangeModelImplBase::matchValue(element, value, flags, collator);
2528 constexpr QMetaType mt = QMetaType::fromType<wrapped_value_type>();
2529 if (mt == value.metaType()) {
2530 if (matchType == Qt::MatchExactly)
2531 return mt.equals(QRangeModelDetails::pointerTo(element), value.constData());
2532 else if constexpr (std::is_same_v<wrapped_value_type, QString>)
2533 return QRangeModelImplBase::matchValue(element, value, flags, collator);
2535 return QRangeModelImplBase::matchValue(QVariant::fromValue(QRangeModelDetails::refTo(element)),
2536 value, flags, collator);
2543 template <
typename InsertFn>
2548 range_type *
const children = childRange(parent);
2552 this->beginInsertColumns(parent, column, column + count - 1);
2554 for (
auto &child : *children) {
2555 auto it = QRangeModelDetails::pos(child, column);
2556 (
void)insertFn(QRangeModelDetails::refTo(child), it, count);
2559 this->endInsertColumns();
2565 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
2566 for (
int r = 0; r < that().rowCount(parent); ++r) {
2567 for (
int c = column; c < column + count; ++c) {
2568 const QModelIndex index = that().index(r, c, parent);
2569 writeAt(index, [
this, &index](QObject *item){
2570 return Self::connectProperties(index, item,
2571 m_data.context, m_data.properties);
2583 if constexpr (dynamicColumns() && isMutable() && row_features::has_insert) {
2584 return doInsertColumns(column, count, parent, [](
auto &row,
auto it,
int n){
2585 row.insert(it, n, {});
2595 if constexpr (dynamicColumns() && isMutable() && row_features::has_erase) {
2596 if (column < 0 || column + count > columnCount(parent))
2599 range_type *
const children = childRange(parent);
2604 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead) {
2605 for (
int r = 0; r < that().rowCount(parent); ++r) {
2606 for (
int c = column; c < column + count; ++c) {
2607 const QModelIndex index = that().index(r, c, parent);
2608 writeAt(index, [
this](QObject *item){
2609 m_data.connections.removeIf([item](
const auto &connection) {
2610 return connection.sender == item;
2619 this->beginRemoveColumns(parent, column, column + count - 1);
2620 for (
auto &child : *children) {
2621 const auto start = QRangeModelDetails::pos(child, column);
2622 QRangeModelDetails::refTo(child).erase(start, std::next(start, count));
2624 this->endRemoveColumns();
2630 bool moveColumns(
const QModelIndex &sourceParent,
int sourceColumn,
int count,
2631 const QModelIndex &destParent,
int destColumn)
2634 if (sourceParent != destParent)
2636 if constexpr (isMutable() && (row_features::has_rotate || row_features::has_splice)) {
2637 if (!Structure::canMoveColumns(sourceParent, destParent))
2643 range_type *
const children = childRange(sourceParent);
2647 if (!
this->beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1,
2648 destParent, destColumn)) {
2652 for (
auto &child : *children)
2653 QRangeModelDetails::rotate(child, sourceColumn, count, destColumn);
2655 this->endMoveColumns();
2662 template <
typename InsertFn>
2663 bool doInsertRows(
int row,
int count,
const QModelIndex &parent, InsertFn &&insertFn)
2665 range_type *children = childRange(parent);
2669 this->beginInsertRows(parent, row, row + count - 1);
2671 row_ptr parentRow = parent.isValid()
2674 (
void)
std::forward<InsertFn>(insertFn)(*children, parentRow, row, count);
2678 that().resetParentInChildren(children);
2680 this->endInsertRows();
2686 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::Full) {
2688 const auto end =
std::next(begin, count);
2690 for (
auto it = begin; it != end; ++it, ++rowIndex)
2691 autoConnectPropertiesInRow(*it, rowIndex, parent);
2701 return doInsertRows(row, count, parent,
2702 [
this](range_type &children, row_ptr parentRow,
int r,
int n){
2706 if constexpr (range_features::has_insert_range) {
2709 auto start = children.insert(pos, n,
nullptr);
2712 children.insert(pos, n,
std::move(*generator));
2721 bool removeRows(
int row,
int count,
const QModelIndex &parent = {})
2724 const int prevRowCount = rowCount(parent);
2725 if (row < 0 || row + count > prevRowCount)
2728 range_type *children = childRange(parent);
2733 if (m_data.context &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead) {
2735 const auto end =
std::next(begin, count);
2737 for (
auto it = begin; it != end; ++it, ++rowIndex)
2738 clearConnectionInRow(*it, rowIndex, parent);
2742 this->beginRemoveRows(parent, row, row + count - 1);
2743 [[maybe_unused]]
bool callEndRemoveColumns =
false;
2747 if (prevRowCount == count) {
2748 if (
const int columns = columnCount(parent)) {
2749 callEndRemoveColumns =
true;
2750 this->beginRemoveColumns(parent, 0, columns - 1);
2756 const auto end =
std::next(begin, count);
2757 that().deleteRemovedRows(begin, end);
2758 children->erase(begin, end);
2762 that().resetParentInChildren(children);
2765 if (callEndRemoveColumns) {
2766 Q_ASSERT(columnCount(parent) == 0);
2767 this->endRemoveColumns();
2770 this->endRemoveRows();
2777 bool moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
2778 const QModelIndex &destParent,
int destRow)
2780 if constexpr (isMutable() && (range_features::has_rotate || range_features::has_splice)) {
2781 if (!Structure::canMoveRows(sourceParent, destParent))
2784 if (sourceParent != destParent) {
2785 return that().moveRowsAcross(sourceParent, sourceRow, count,
2786 destParent, destRow);
2789 if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0
2790 || sourceRow < 0 || sourceRow + count - 1 >=
this->rowCount(sourceParent)
2791 || destRow < 0 || destRow >
this->rowCount(destParent)) {
2795 range_type *source = childRange(sourceParent);
2797 if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow))
2802 that().resetParentInChildren(source);
2804 this->endMoveRows();
2816 int rowCount(
const QModelIndex &parent)
const {
return that().rowCountImpl(parent); }
2821 return row_traits::fixed_size();
2825 int columnCount(
const QModelIndex &parent)
const {
return that().columnCountImpl(parent); }
2830 if constexpr (!isMutable())
2831 dragActions &= ~Qt::MoveAction;
2836 if constexpr (!isMutable())
2837 dropActions = Qt::IgnoreAction;
2844 using ItemType = QRangeModelDetails::wrapped_t<
typename row_traits::item_type>;
2845 if constexpr (QRangeModelDetails::item_access<ItemType>::hasMimeTypes)
2846 return QRangeModelDetails::QRangeModelItemAccess<ItemType>::mimeTypes();
2847 else if constexpr (QRangeModelDetails::hasMimeTypes<wrapped_row_type>)
2848 return QRangeModelDetails::QRangeModelRowOptions<wrapped_row_type>::mimeTypes();
2850 return this->itemModel().QAbstractItemModel::mimeTypes();
2854 const QModelIndex &target)
const
2856 if constexpr (isMutable()) {
2858 using RowOptions = QRangeModelDetails::QRangeModelRowOptions<wrapped_row_type>;
2859 using ItemType = QRangeModelDetails::wrapped_t<
typename row_traits::item_type>;
2860 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<ItemType>;
2861 if constexpr (QRangeModelDetails::item_access<ItemType>::hasCanDropMimeDataFull) {
2862 canDrop = ItemAccess::canDropMimeData(data, action, row, column, target);
2863 }
else if constexpr (QRangeModelDetails::hasCanDropMimeDataFull<wrapped_row_type>) {
2864 canDrop = RowOptions::canDropMimeData(data, action, row, column, target);
2866 canDrop =
this->itemModel().QAbstractItemModel::canDropMimeData(data, action, row,
2868 if constexpr (QRangeModelDetails::item_access<ItemType>::hasCanDropMimeData)
2869 canDrop &= ItemAccess::canDropMimeData(data);
2870 else if constexpr (QRangeModelDetails::hasCanDropMimeData<wrapped_row_type>)
2871 canDrop &= RowOptions::canDropMimeData(data);
2880 template <Qt::Orientation orient,
typename Entry>
2881 bool doDropMimeData(std::vector<QRangeModelDetails::DroppedEntry<Entry>> &droppedEntries,
2882 DropOperation dropOperation,
int row,
int column,
const QModelIndex &target)
2885 using Cell =
typename DroppedEntry::Cell;
2886 if (dropOperation == DropOperation::DontDrop)
2889 const bool dropOnTarget = row == -1 && column == -1 && target.isValid();
2890 const QModelIndex parent = dropOperation == DropOperation::InsertAsChildren
2891 ? target.siblingAtColumn(0) : target.parent();
2894 if constexpr (orient == Qt::Horizontal)
2899 int rightColumn = -1;
2902 int maxColumn = that().columnCount(parent) - 1;
2903 for (
auto &droppedEntry : droppedEntries) {
2904 if (droppedEntry.m_cell == Cell{-1, -1}) {
2905 if constexpr (orient == Qt::Horizontal) {
2908 droppedEntry.m_cell = {lastCell.m_row, lastCell.m_column + 1};
2909 if (droppedEntry.m_cell.m_column > maxColumn) {
2910 droppedEntry.m_cell.m_column = 0;
2911 ++droppedEntry.m_cell.m_row;
2914 droppedEntry.m_cell = {lastCell.m_row + 1, lastCell.m_column};
2917 lastCell = droppedEntry.m_cell;
2918 bottomRow = std::max(lastCell.m_row, bottomRow);
2919 rightColumn = std::max(lastCell.m_column, rightColumn);
2922 if (dropOperation == DropOperation::InsertAsChildren) {
2923 row = rowCount(parent);
2925 }
else if (dropOnTarget) {
2927 column = target.column();
2930 row = rowCount(parent);
2935 const bool overwrite = dropOperation == DropOperation::OverwriteAndIgnore
2936 || dropOperation == DropOperation::OverwriteAndExtend;
2939 const int overwriteRows = overwrite
2940 ?
std::min(bottomRow + 1, rowCount(parent) - row)
2942 const int newRows = dropOperation == DropOperation::OverwriteAndExtend
2943 ? bottomRow - overwriteRows + 1
2944 : (dropOperation == DropOperation::InsertAsChildren
2945 || dropOperation == DropOperation::InsertAsSiblings)
2948 if (newRows > 0 && !insertRows(row, newRows, parent))
2952 const int overwriteColumns = overwrite
2953 ?
std::min(rightColumn + 1, columnCount(parent) - column)
2955 const int newColumns = dropOperation == DropOperation::OverwriteAndExtend
2956 ? rightColumn - overwriteColumns + 1 : 0;
2957 if (newColumns > 0 && !insertColumns(column, newColumns, parent))
2961 range_type *parentRange = that().childRange(parent);
2964 range_type &targetRange = *parentRange;
2966 int maxRow = that().rowCount(parent) - 1;
2967 maxColumn = that().columnCount(parent) - 1;
2968 auto begin =
std::move_iterator(droppedEntries.begin());
2969 auto end =
std::move_iterator(droppedEntries.end());
2970 for (; begin != end; ++begin) {
2971 DroppedEntry droppedEntry = *begin;
2972 const Cell cell = {droppedEntry.m_cell.m_row + row, droppedEntry.m_cell.m_column + column};
2973 if (cell.m_row > maxRow || cell.m_column > maxColumn)
2976 if constexpr (orient == Qt::Vertical) {
2977 if constexpr (QRangeModelDetails::is_owning_or_raw_pointer<row_type>()) {
2979 *writeRow =
this->protocol().newRow();
2980 **writeRow =
std::move(droppedEntry);
2982 *writeRow =
std::move(droppedEntry);
2985 row_traits::for_element_at(*writeRow, cell.m_column, [&](
auto &item){
2986 using item_type = q20::remove_cvref_t<
decltype(item)>;
2987 using wrapped_item_type = QRangeModelDetails::wrapped_t<item_type>;
2988 if constexpr (QRangeModelDetails::is_any_owning_ptr<item_type>()) {
2989 if (!QRangeModelDetails::isValid(item))
2990 item.reset(
new wrapped_item_type{std::move(droppedEntry)});
2992 *item = std::move(droppedEntry);
2993 }
else if (!QRangeModelDetails::isValid(item)) {
2996 item = std::move(droppedEntry);
3003 that().resetParentInChildren(&targetRange);
3005 const QModelIndex topLeft = index(row, column, parent);
3006 const QModelIndex bottomRight = orient == Qt::Horizontal
3007 ? sibling(row + bottomRow, column + rightColumn, topLeft)
3008 : sibling(row + bottomRow, maxColumn, topLeft);
3009 this->dataChanged(topLeft, bottomRight, {});
3014 bool dropMimeData(
const QMimeData *data, Qt::DropAction action,
int row,
int column,
3015 const QModelIndex &target)
3017 if constexpr (isMutable()) {
3018 if (!canDropMimeData(data, action, row, column, target))
3021 const bool dropOnTarget = row == -1 && column == -1 && target.isValid();
3023 auto automaticDropOption = [=](
auto dropResult){
3024 DropOperation dropOperation;
3025 if constexpr (
std::is_same_v<
bool,
decltype(dropResult)>) {
3026 dropOperation = dropResult ? DropOperation::Automatic
3027 : DropOperation::DontDrop;
3029 dropOperation =
static_cast<DropOperation>(dropResult);
3032 if (dropOperation == DropOperation::Automatic) {
3033 if constexpr (!canInsertRows())
3034 dropOperation = DropOperation::OverwriteAndIgnore;
3035 else if (!dropOnTarget)
3036 dropOperation = DropOperation::InsertAsSiblings;
3037 else if (target.siblingAtColumn(0).flags().testFlag(Qt::ItemNeverHasChildren))
3038 dropOperation = DropOperation::OverwriteAndExtend;
3040 dropOperation = DropOperation::InsertAsChildren;
3042 return dropOperation;
3045 using ItemType = QRangeModelDetails::wrapped_t<
typename row_traits::item_type>;
3046 if constexpr (QRangeModelDetails::item_access<ItemType>::hasDropMimeDataFull
3047 || QRangeModelDetails::item_access<ItemType>::hasDropMimeData) {
3048 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<ItemType>;
3049 using DroppedItem = QRangeModelDetails::DroppedEntry<ItemType>;
3050 std::vector<DroppedItem> droppedItems;
3051 DropOperation dropOperation = automaticDropOption([&]{
3052 auto inserter =
std::back_inserter(droppedItems);
3053 if constexpr (QRangeModelDetails::item_access<ItemType>::hasDropMimeDataFull)
3054 return ItemAccess::dropMimeData(data, action, row, column, target, inserter);
3056 return ItemAccess::dropMimeData(data, inserter);
3058 if (doDropMimeData<Qt::Horizontal>(droppedItems, dropOperation, row, column, target))
3061 }
else if constexpr (QRangeModelDetails::hasDropMimeDataFull<wrapped_row_type>
3062 || QRangeModelDetails::hasDropMimeData<wrapped_row_type>) {
3063 using RowOptions = QRangeModelDetails::QRangeModelRowOptions<wrapped_row_type>;
3064 using DroppedRow = QRangeModelDetails::DroppedEntry<wrapped_row_type>;
3065 std::vector<DroppedRow> droppedRows;
3066 DropOperation dropOperation = automaticDropOption([&]{
3067 auto inserter =
std::back_inserter(droppedRows);
3068 if constexpr (QRangeModelDetails::hasDropMimeDataFull<wrapped_row_type>)
3069 return RowOptions::dropMimeData(data, action, row, column, target, inserter);
3071 return RowOptions::dropMimeData(data, inserter);
3073 if (doDropMimeData<Qt::Vertical>(droppedRows, dropOperation, row, column, target))
3077 if (dropOnTarget && that().dropOnItem(data, target))
3095 using pointer [[maybe_unused]] =
void;
3101 , m_columnCount(model->columnCount({}))
3103 updateCurrentIndexFullRow();
3108 const QModelIndex &index = *m_it;
3109 return {m_model->rowData(index),
3110 m_currentIndexIsFullRow
3111 ? m_model->createIndex(m_it->row(), -1, m_it->internalPointer()) : index};
3115 if (m_currentIndexIsFullRow)
3116 m_it += m_columnCount;
3119 updateCurrentIndexFullRow();
3126 m_currentIndexIsFullRow =
false;
3127 const int lastColumn = m_columnCount - 1;
3128 if (m_it - m_begin >= lastColumn && m_it->column() == lastColumn) {
3129 const QModelIndex &firstInRow = m_it[-lastColumn];
3130 if (m_it->row() == firstInRow.row()
3131 && firstInRow.internalPointer() == m_it->internalPointer()) {
3132 m_currentIndexIsFullRow =
true;
3142 auto tmp = *
this; tmp.m_it -= n;
return tmp;
3149 void updateCurrentIndexFullRow()
3151 m_currentIndexIsFullRow =
false;
3152 if (m_it == m_end || m_it->column() || m_end - m_it < m_columnCount)
3154 const QModelIndex &lastInRow = m_it[m_columnCount - 1];
3155 m_currentIndexIsFullRow = lastInRow.row() == m_it->row()
3156 && lastInRow.internalPointer() == m_it->internalPointer();
3160 base_iterator m_begin;
3161 base_iterator m_end;
3163 int m_columnCount = 0;
3164 bool m_currentIndexIsFullRow =
false;
3178 using pointer [[maybe_unused]] =
void;
3182 const QModelIndex &index = *m_it;
3184 const item_type *pitem =
nullptr;
3185 const auto &row =
m_model->rowData(index);
3187 row_traits::for_element_at(QRangeModelDetails::refTo(row), index.column(),
3188 [&pitem](
const auto &item){
3193 if constexpr (std::disjunction_v<QRangeModelDetails::is_owning_or_raw_pointer<row_type>,
3194 QRangeModelDetails::is_owning_or_raw_pointer<item_type>>) {
3198 constexpr bool is_constexpr_default_constructible_v =
3199 value_type::
template is_constexpr_default_constructible<item_type>::value;
3200 if constexpr (is_constexpr_default_constructible_v) {
3201 Q_CONSTINIT
static const item_type emptyDefault;
3202 return {emptyDefault, index};
3205 static const item_type emptyDefault;
3206 return {emptyDefault, index};
3211 return {*pitem, index};
3221 auto tmp = *
this; tmp.m_it -= n;
return tmp;
3231 template <
typename Iterator>
3247 QMimeData *result =
nullptr;
3248 using RowOptions = QRangeModelDetails::QRangeModelRowOptions<wrapped_row_type>;
3249 using ItemType = QRangeModelDetails::wrapped_t<
typename row_traits::item_type>;
3251 if constexpr (QRangeModelDetails::item_access<ItemType>::hasMimeData) {
3252 using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<ItemType>;
3255 result = ItemAccess::mimeData(MimeDataRange<MimeDataItemIterator>{begin, end});
3256 }
else if constexpr (QRangeModelDetails::hasMimeDataRowSpan<wrapped_row_type>) {
3257 const auto begin =
MimeDataRowIterator(indexes.begin(), indexes.begin(), indexes.end(),
this);
3258 const auto end =
MimeDataRowIterator(indexes.end(), indexes.begin(), indexes.end(),
this);
3259 result = RowOptions::mimeData(MimeDataRange<MimeDataRowIterator>{begin, end});
3260 }
else if constexpr (QRangeModelDetails::hasMimeDataIndexList<wrapped_row_type>) {
3261 result = RowOptions::mimeData(indexes);
3327 static constexpr bool modelCopied = !QRangeModelDetails::is_wrapped<Range>() &&
3328 (std::is_reference_v<Range> || std::is_const_v<std::remove_reference_t<Range>>);
3330 static constexpr bool modelShared = QRangeModelDetails::is_any_shared_ptr<Range>();
3332 static constexpr bool default_row_deleter = protocol_traits::is_default &&
3333 protocol_traits::has_deleteRow;
3335 static constexpr bool ambiguousRowOwnership = (modelCopied || modelShared) &&
3338 static_assert(!ambiguousRowOwnership,
3339 "Using of copied and shared tree and table models with rows as raw pointers, "
3340 "and the default protocol is not allowed due to ambiguity of rows ownership. "
3341 "Move the model in, use another row type, or implement a custom tree protocol.");
3343 if constexpr (protocol_traits::has_deleteRow && !std::is_pointer_v<Range>
3344 && !QRangeModelDetails::is_any_of<Range, std::reference_wrapper>()) {
3347 that().deleteRemovedRows(begin, end);
3353 if constexpr (dynamicColumns() && !row_features::has_resize) {
3357 }
else if constexpr (!protocol_traits::has_newRow) {
3360 }
else if constexpr (!range_features::has_insert_range
3361 && !std::is_copy_constructible_v<row_type>) {
3367 return Structure::canInsertRowsImpl();
3373 return Structure::canRemoveRowsImpl();
3376 template <
typename F>
3377 bool writeAt(
const QModelIndex &index, F&& writer)
3379 row_reference row = rowData(index);
3382 return row_traits::for_element_at(row, index.column(), [&writer](
auto &&target) {
3383 using target_type =
decltype(target);
3385 if constexpr (std::is_lvalue_reference_v<target_type>
3386 && !std::is_const_v<std::remove_reference_t<target_type>>) {
3387 return writer(std::forward<target_type>(target));
3394 template <
typename F>
3395 bool readAt(
const QModelIndex &index, F&& reader)
const {
3396 const_row_reference row = rowData(index);
3399 return row_traits::for_element_at(row, index.column(), std::forward<F>(reader));
3402 template <
typename Value>
3405 if constexpr (std::is_constructible_v<QVariant, Value>)
3406 return QVariant(value);
3408 return QVariant::fromValue(value);
3410 template <
typename Value>
3414 if constexpr (std::is_constructible_v<QVariant, Value *>)
3415 return QVariant(value);
3417 return read(*value);
3422 template <
typename Target>
3423 static bool write(Target &target,
const QVariant &value)
3425 using Type = std::remove_reference_t<Target>;
3426 if constexpr (std::is_constructible_v<Target, QVariant>) {
3429 }
else if (value.canConvert<Type>()) {
3430 target = value.value<Type>();
3435 template <
typename Target>
3436 static bool write(Target *target,
const QVariant &value)
3439 return write(*target, value);
3443 template <
typename ItemType>
3447 operator QMetaProperty()
const {
3448 const QByteArray roleName = that.itemModel().roleNames().value(role);
3449 const QMetaObject &mo = ItemType::staticMetaObject;
3450 if (
const int index = mo.indexOfProperty(roleName.data());
3452 return mo.property(index);
3456 const QRangeModelImpl &that;
3458 } findProperty{*
this, role};
3460 if constexpr (ModelData::cachesProperties)
3461 return *m_data.properties.tryEmplace(role, findProperty).iterator;
3463 return findProperty;
3467 const QObject *gadget,
const QMetaProperty &prop)
const
3469 if (!index.isValid())
3471 const typename ModelData::Connection connection = {gadget, role};
3472 if (prop.hasNotifySignal() &&
this->autoConnectPolicy() == AutoConnectPolicy::OnRead
3473 && !m_data.connections.contains(connection)) {
3474 if constexpr (isMutable())
3475 Self::connectProperty(index, gadget, m_data.context, role, prop);
3477 Self::connectPropertyConst(index, gadget, m_data.context, role, prop);
3478 m_data.connections.insert(connection);
3482 template <
typename ItemType>
3485 using item_type = std::remove_pointer_t<ItemType>;
3487 QMetaProperty prop = roleProperty<item_type>(role);
3488 if (!prop.isValid() && role == Qt::EditRole) {
3489 role = Qt::DisplayRole;
3490 prop = roleProperty<item_type>(Qt::DisplayRole);
3493 if (prop.isValid()) {
3494 if constexpr (itemsAreQObjects)
3495 connectPropertyOnRead(index, role, gadget, prop);
3496 result = readProperty(prop, gadget);
3501 template <
typename ItemType>
3504 return readRole(index, role, &gadget);
3507 template <
typename ItemType>
3510 if constexpr (std::is_base_of_v<QObject, ItemType>)
3511 return prop.read(gadget);
3513 return prop.readOnGadget(gadget);
3516 template <
typename ItemType>
3519 using item_type = std::remove_pointer_t<ItemType>;
3520 const QMetaObject &mo = item_type::staticMetaObject;
3521 const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
3523 if constexpr (rowsAreQObjects)
3524 connectPropertyOnRead(index, Qt::DisplayRole, gadget, prop);
3526 return readProperty(prop, gadget);
3529 template <
typename ItemType>
3532 return readProperty(index, &gadget);
3535 template <
typename ItemType>
3536 bool writeRole(
int role, ItemType *gadget,
const QVariant &data)
3538 using item_type = std::remove_pointer_t<ItemType>;
3539 auto prop = roleProperty<item_type>(role);
3540 if (!prop.isValid() && role == Qt::EditRole)
3541 prop = roleProperty<item_type>(Qt::DisplayRole);
3543 return prop.isValid() ? writeProperty(prop, gadget, data) :
false;
3546 template <
typename ItemType>
3547 bool writeRole(
int role, ItemType &&gadget,
const QVariant &data)
3549 return writeRole(role, &gadget, data);
3552 template <
typename ItemType>
3553 static bool writeProperty(
const QMetaProperty &prop, ItemType *gadget,
const QVariant &data)
3555 if constexpr (std::is_base_of_v<QObject, ItemType>)
3556 return prop.write(gadget, data);
3558 return prop.writeOnGadget(gadget, data);
3560 template <
typename ItemType>
3563 using item_type = std::remove_pointer_t<ItemType>;
3564 const QMetaObject &mo = item_type::staticMetaObject;
3565 return writeProperty(mo.property(property + mo.propertyOffset()), gadget, data);
3568 template <
typename ItemType>
3569 static bool writeProperty(
int property, ItemType &&gadget,
const QVariant &data)
3571 return writeProperty(property, &gadget, data);
3574 template <
typename ItemType>
3577 using item_type = std::remove_pointer_t<ItemType>;
3578 const QMetaObject &mo = item_type::staticMetaObject;
3579 bool success =
true;
3580 if (property == -1) {
3582 if constexpr (std::is_base_of_v<QObject, item_type>) {
3583 for (
int p = mo.propertyOffset(); p < mo.propertyCount(); ++p)
3584 success = writeProperty(mo.property(p), object, {}) && success;
3589 success = writeProperty(mo.property(property + mo.propertyOffset()), object, {});
3594 template <
typename ItemType>
3597 return resetProperty(property, &object);
3603 Q_ASSERT(index.isValid());
3604 return that().rowDataImpl(index);
3609 Q_ASSERT(index.isValid());
3610 return that().rowDataImpl(index);
3615 if (!index.isValid())
3616 return m_data.model();
3619 return that().childRangeImpl(index);
3624 if (!index.isValid())
3625 return m_data.model();
3628 return that().childRangeImpl(index);
3639template <
typename Range,
typename Protocol>
3646 using range_type =
typename Base::range_type;
3647 using range_features =
typename Base::range_features;
3648 using row_type =
typename Base::row_type;
3649 using row_ptr =
typename Base::row_ptr;
3650 using const_row_ptr =
typename Base::const_row_ptr;
3652 using tree_traits =
typename Base::protocol_traits;
3653 static constexpr bool is_mutable_impl = tree_traits::has_mutable_childRows;
3655 static constexpr bool rows_are_any_refs_or_pointers = Base::rows_are_raw_pointers ||
3656 QRangeModelDetails::is_smart_ptr<row_type>() ||
3657 QRangeModelDetails::is_any_of<row_type,
std::reference_wrapper>();
3658 static_assert(!Base::dynamicColumns(),
"A tree must have a static number of columns!");
3662 : Base(
std::forward<Range>(model),
std::forward<Protocol>(p), itemModel)
3667 for (
auto &&child : children)
3679 auto *children =
this->childRange(parent);
3682 return autoConnectPropertiesRange(QRangeModelDetails::refTo(children), parent);
3688 if (!parent.isValid())
3689 return this->createIndex(row, column);
3691 if (parent.column())
3692 return QModelIndex();
3694 const_row_ptr grandParent =
static_cast<const_row_ptr>(parent.constInternalPointer());
3695 const auto &parentSiblings = childrenOf(grandParent);
3702 if (!child.isValid())
3706 const_row_ptr parentRow =
static_cast<const_row_ptr>(child.constInternalPointer());
3711 auto &&grandParent =
this->protocol().parentRow(
QRangeModelDetails::refTo(parentRow));
3712 const range_type &parentSiblings = childrenOf(
QRangeModelDetails::pointerTo(grandParent));
3716 const auto it =
std::find_if(begin, end, [parentRow](
auto &&s){
3720 return this->createIndex(
std::distance(begin, it), 0,
3727 return Base::size(
this->childRange(parent));
3734 return Base::fixedColumnCount();
3739 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
3747 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
3748 && Base::dynamicRows() && range_features::has_insert;
3756 return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
3757 && Base::dynamicRows() && range_features::has_erase;
3765 static constexpr bool canMoveRows(
const QModelIndex &,
const QModelIndex &)
3771 const QModelIndex &destParent,
int destRow)
3776 if constexpr (!rows_are_any_refs_or_pointers && !tree_traits::has_setParentRow) {
3778 }
else if constexpr (!(range_features::has_insert && range_features::has_erase)) {
3780 }
else if (!
this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1,
3781 destParent, destRow)) {
3785 range_type *source =
this->childRange(sourceParent);
3786 range_type *destination =
this->childRange(destParent);
3791 if constexpr (range_features::has_insert_range) {
3793 const auto sourceEnd =
std::next(sourceStart, count);
3795 destination->insert(destStart,
std::move_iterator(sourceStart),
3796 std::move_iterator(sourceEnd));
3797 }
else if constexpr (
std::is_copy_constructible_v<row_type>) {
3799 destination->insert(destStart, count, row_type{});
3802 row_ptr parentRow = destParent.isValid()
3808 if (parentRow ==
static_cast<row_ptr>(sourceParent.internalPointer())) {
3809 if (sourceParent.row() < destRow) {
3810 source =
this->childRange(sourceParent);
3813 source =
this->childRange(
this->createIndex(sourceParent.row() + count, 0,
3814 sourceParent.internalPointer()));
3821 const auto writeEnd =
std::next(writeStart, count);
3823 const auto sourceEnd =
std::next(sourceStart, count);
3825 for (
auto write = writeStart, read = sourceStart; write != writeEnd; ++write, ++read) {
3828 if constexpr (!range_features::has_insert_range)
3829 *write =
std::move(*read);
3833 source->erase(sourceStart, sourceEnd);
3843 this->endMoveRows();
3851 static_assert(tree_traits::has_setParentRow);
3852 row_type empty_row =
this->protocol().newRow();
3858 template <
typename It,
typename Sentinel>
3861 if constexpr (tree_traits::has_deleteRow) {
3862 for (
auto it = begin; it != end; ++it) {
3863 if constexpr (Base::isMutable()) {
3864 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(*it));
3872 this->protocol().deleteRow(
std::move(*it));
3879 const auto persistentIndexList =
this->persistentIndexList();
3880 const auto [firstColumn, lastColumn] = [&persistentIndexList]{
3881 int first = std::numeric_limits<
int>::max();
3883 for (
const auto &pmi : persistentIndexList) {
3884 first = (
std::min)(pmi.column(), first);
3885 last = (
std::max)(pmi.column(), last);
3887 return std::pair(first, last);
3895 if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) {
3896 const bool changePersistentIndexes = pmiToColumn >= pmiFromColumn;
3899 for (
auto it = begin; it != end; ++it) {
3900 decltype(
auto) maybeChildren =
this->protocol().childRows(*it);
3906 for (
auto &child : childrenRef) {
3907 const_row_ptr oldParent =
this->protocol().parentRow(child);
3908 if (oldParent != parentRow) {
3909 if (changePersistentIndexes) {
3910 for (
int column = pmiFromColumn; column <= pmiToColumn; ++column) {
3911 this->changePersistentIndex(
this->createIndex(row, column, oldParent),
3912 this->createIndex(row, column, parentRow));
3915 this->protocol().setParentRow(child, parentRow);
3928 for (
const auto &row : range) {
3929 if (!
this->autoConnectPropertiesInRow(row, rowIndex, parent))
3934 if (!autoConnectPropertiesRange(QRangeModelDetails::refTo(children),
3935 this->itemModel().index(rowIndex, 0, parent))) {
3946 return autoConnectPropertiesRange(*
this->m_data.model(), {});
3951 const_row_ptr parentRow =
static_cast<const_row_ptr>(index.constInternalPointer());
3952 const range_type &siblings = childrenOf(parentRow);
3953 Q_ASSERT(index.row() <
int(Base::size(siblings)));
3959 row_ptr parentRow =
static_cast<row_ptr>(index.internalPointer());
3960 range_type &siblings = childrenOf(parentRow);
3961 Q_ASSERT(index.row() <
int(Base::size(siblings)));
3967 const auto &row =
this->rowData(index);
3969 return static_cast<
const range_type *>(
nullptr);
3971 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
3977 auto &row =
this->rowData(index);
3979 return static_cast<range_type *>(
nullptr);
3981 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
3982 using Children = std::remove_reference_t<
decltype(children)>;
3984 if constexpr (QRangeModelDetails::is_any_of<Children, std::optional>())
3985 if constexpr (std::is_default_constructible<
typename Children::value_type>()) {
3987 children.emplace(range_type{});
3996 : *
this->m_data.model();
4002 : *
this->m_data.model();
4005 template <
typename LessThan>
4008 for (
auto &row : range) {
4009 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(row));
4015 this->sortSubRange(range, parentRow, lessThan);
4018 template <
typename LessThan>
4021 sortImplRecursive(*
this->m_data.model(),
nullptr, lessThan);
4027 erase_if(list, [expectedParent](
const QModelIndex &index){
4028 return static_cast<row_ptr>(index.internalPointer()) != expectedParent;
4033 int role,
const QVariant &value,
int hits, Qt::MatchFlags flags,
int column,
4034 QModelIndexList &result,
const QCollator &collator)
const
4039 const bool recurse = flags.testAnyFlag(Qt::MatchRecursive);
4040 const bool allHits = (hits == -1);
4042 for (
int r = from; it != end && r < to && (allHits || result.size() < hits); ++it, ++r) {
4043 const QModelIndex index =
this->createIndex(r, column, parentPtr);
4044 if (
this->matchRow(*it, index, role, value, flags, collator))
4045 result.append(index);
4048 decltype(
auto) children =
this->protocol().childRows(
QRangeModelDetails::refTo(*it));
4051 matchImplRecursive(QRangeModelDetails::refTo(children),
4052 QRangeModelDetails::pointerTo(*it), 0,
4053 int(QRangeModelDetails::size(QRangeModelDetails::refTo(children))),
4054 role, value, hits, flags, column, result, collator);
4061 Qt::MatchFlags flags,
const QCollator &collator)
const
4063 QModelIndexList result;
4064 const bool wrap = flags.testAnyFlag(Qt::MatchWrap);
4065 const int column = start.column();
4066 const int from = start.row();
4067 const int to =
this->rowCount(start.parent());
4069 for (
int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) {
4070 const int fromRow = (i == 0) ? from : 0;
4071 const int toRow = (i == 0) ? to : from;
4072 matchImplRecursive(*
this->m_data.model(),
nullptr, fromRow, toRow,
4073 role, value, hits, flags, column, result, collator);
4087template <
typename Range>
4094 static constexpr bool is_mutable_impl =
true;
4112 if constexpr (Base::dynamicColumns()) {
4113 if (column <
int(Base::size(*QRangeModelDetails::pos(*
this->m_data.model(), row))))
4114 return this->createIndex(row, column);
4117 qCritical(
"QRangeModel: Column-range at row %d is not large enough!", row);
4121 return this->createIndex(row, column);
4132 if (parent.isValid())
4134 return int(Base::size(*
this->m_data.model()));
4139 if (parent.isValid())
4143 if constexpr (Base::dynamicColumns()) {
4144 return int(Base::size(*
this->m_data.model()) == 0
4146 : Base::size(*QRangeModelDetails::adl_begin(*
this->m_data.model())));
4148 return Base::fixedColumnCount();
4154 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren;
4159 return Base::dynamicRows() && range_features::has_insert;
4164 return Base::dynamicRows() && range_features::has_erase;
4167 static constexpr bool canMoveColumns(
const QModelIndex &source,
const QModelIndex &destination)
4169 return !source.isValid() && !destination.isValid();
4172 static constexpr bool canMoveRows(
const QModelIndex &source,
const QModelIndex &destination)
4174 return !source.isValid() && !destination.isValid();
4178 const QModelIndex &,
int)
noexcept
4186 row_type empty_row =
this->protocol().newRow();
4189 if constexpr (Base::dynamicColumns() && row_features::has_resize) {
4197 template <
typename It,
typename Sentinel>
4200 if constexpr (Base::protocol_traits::has_deleteRow) {
4201 for (
auto it = begin; it != end; ++it)
4202 this->protocol().deleteRow(
std::move(*it));
4208 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
4214 Q_ASSERT(q20::cmp_less(index.row(), Base::size(*
this->m_data.model())));
4231 return *
this->m_data.model();
4237 return *
this->m_data.model();
4248 for (
const auto &row : *
this->m_data.model()) {
4249 result &=
this->autoConnectPropertiesInRow(row, rowIndex, {});
4255 template <
typename LessThan>
4258 this->sortSubRange(*
this->m_data.model(),
nullptr, lessThan);
4264 int hits, Qt::MatchFlags flags,
const QCollator &collator)
const
4266 QModelIndexList result;
4267 const bool wrap = flags.testAnyFlag(Qt::MatchWrap);
4268 const bool allHits = (hits == -1);
4269 const int column = start.column();
4270 int from = start.row();
4271 int to =
this->rowCount({});
4272 decltype(
auto) siblings = *
this->m_data.model();
4274 for (
int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) {
4277 for (
int r = from; it != end && r < to && (allHits || result.size() < hits);
4281 const QModelIndex index =
this->createIndex(r, column,
nullptr);
4282 if (
this->matchRow(*it, index, role, value, flags, collator))
4283 result.append(index);
4295 return this->dropDataOnItem(data, index);
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()
bool dropOnItem(const QMimeData *data, const QModelIndex &index)
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
QModelIndexList matchImpl(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags, const QCollator &collator) 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
range_type & childrenOf(row_ptr row)
static constexpr Qt::ItemFlags defaultFlags()
void sortImpl(const LessThan &lessThan)
auto makeEmptyRow(typename Base::row_ptr)
static constexpr bool canMoveColumns(const QModelIndex &, const QModelIndex &)
bool dropOnItem(const QMimeData *, 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
range_type & childrenOf(row_ptr row)
QModelIndexList matchImpl(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags, const QCollator &collator) 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)
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 QCollator &collator) const
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)
QStringList mimeTypes() const
static Qt::weak_ordering compareData(const QVariant &lhs, const QVariant &rhs, const QCollator *collator)
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::DropActions adjustSupportedDropActions(Qt::DropActions dropActions)
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
QRangeModelImplBase(QRangeModel *itemModel)
QModelIndexList persistentIndexList() const
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) 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
static Q_CORE_EXPORT bool matchValue(const QString &itemData, const QVariant &value, Qt::MatchFlags flags, const QCollator &collator)
void beginInsertColumns(const QModelIndex &parent, int start, int count)
bool insertColumns(int column, int count, const QModelIndex &parent)
void setAutoConnectPolicy()
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
void sort(int column, Qt::SortOrder order)
bool removeRows(int row, int count, const QModelIndex &parent)
Qt::DropActions adjustSupportedDragActions(Qt::DropActions dragActions)
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)
AutoConnectPolicy autoConnectPolicy() const
bool removeColumns(int column, int count, const QModelIndex &parent)
Q_CORE_EXPORT bool dropDataOnItem(const QMimeData *data, const QModelIndex &index)
static Q_CORE_EXPORT bool connectPropertyConst(const QModelIndex &index, const QObject *item, QRangeModelDetails::AutoConnectContext *context, int role, const QMetaProperty &property)
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, typename C::AdjustSupportedDragActions, typename C::AdjustSupportedDropActions, typename C::MimeTypes, typename C::CanDropMimeData, typename C::DropMimeData, typename C::MimeData > MethodTemplates
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
QMimeData * mimeData(const QModelIndexList &indexes) 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)
bool doDropMimeData(std::vector< QRangeModelDetails::DroppedEntry< Entry > > &droppedEntries, DropOperation dropOperation, int row, int column, const QModelIndex &target)
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
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &target)
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 matchRow(const_row_reference row, const QModelIndex &index, int role, const QVariant &value, Qt::MatchFlags flags, const QCollator &collator) const
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
Qt::DropActions adjustSupportedDragActions(Qt::DropActions dragActions)
QRangeModelImpl< Structure, Range, Protocol > Self
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &target) const
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)
QStringList mimeTypes() const
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
QMimeData * mimeData(const QModelIndexList &indexes) const
Qt::DropActions adjustSupportedDropActions(Qt::DropActions dropActions)
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)
decltype(QRangeModelRowOptions< row_type >::mimeTypes()) hasMimeTypes_test
static auto adl_end(C &&c) -> decltype(end(QRangeModelDetails::refTo(std::forward< C >(c))))
constexpr bool isValid(const T &t) noexcept
decltype(QRangeModelRowOptions< row_type >::flags(std::declval< const row_type & >())) hasRowFlags_test
static constexpr bool hasMimeDataRowSpan
static constexpr bool hasMimeTypes
static constexpr bool has_metaobject_v
decltype(auto) refTo(T &&t)
static constexpr bool is_range_v
static constexpr bool array_like_v
static constexpr bool hasMimeDataIndexList
static void rotate(C &c, int src, int count, int dst)
static constexpr bool hasDropMimeData
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 bool hasDropMimeDataFull
static constexpr int static_size_v
static auto pos(C &&c, int i)
static constexpr bool hasHeaderData
static constexpr bool hasCanDropMimeData
static constexpr bool hasRowFlags
static constexpr bool hasCanDropMimeDataFull
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())
friend bool operator!=(const DroppedEntryCell &lhs, const DroppedEntryCell &rhs) noexcept
friend bool operator==(const DroppedEntryCell &lhs, const DroppedEntryCell &rhs) noexcept
auto newRow() -> decltype(R{})
const QModelIndex & index() const
friend decltype(auto) get(const MimeDataEntry &entry)
const wrapped_entry & entry() const
const QModelIndex m_index
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 hasCanDropMimeDataFull
static constexpr bool hasFlags
static constexpr bool hasMimeData
decltype(Access::flags(std::declval< const Test & >())) hasFlags_test
static constexpr bool hasReadRole
static constexpr bool hasWriteRole
static constexpr bool hasDropMimeData
decltype(Access::mimeTypes()) hasMimeTypes_test
static constexpr bool hasMimeTypes
static constexpr bool hasDropMimeDataFull
static constexpr bool hasCanDropMimeData
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
MimeDataItemIterator operator++(int)
MimeDataItemIterator & operator++()
std::bidirectional_iterator_tag iterator_category
MimeDataItemIterator & operator--()
bool operator!=(const MimeDataItemIterator &other) const
const_reference operator*() const
MimeDataItemIterator operator-(difference_type n) const
MimeDataItemIterator operator--(int)
const QRangeModelImpl * m_model
bool operator==(const MimeDataItemIterator &other) const
MimeDataRowIterator operator--(int)
MimeDataRowIterator operator-(difference_type n) const
bool operator!=(const MimeDataRowIterator &other) const
MimeDataRowIterator & operator--()
MimeDataRowIterator & operator++()
MimeDataRowIterator()=default
MimeDataRowIterator operator++(int)
bool operator==(const MimeDataRowIterator &other) const
MimeDataRowIterator(base_iterator it, base_iterator begin, base_iterator end, const QRangeModelImpl *model)
std::bidirectional_iterator_tag iterator_category
const_reference operator*() const
friend constexpr bool operator<(unordered, QtPrivate::CompareAgainstLiteralZero) noexcept
friend constexpr bool operator>(unordered, QtPrivate::CompareAgainstLiteralZero) noexcept