5#include <QtCore/qstack.h>
6#include <QtCore/qdebug.h>
13#if defined(QQMLTREEMODELADAPTOR_DEBUG) && !defined(QT_TESTLIB_LIB)
14# define ASSERT_CONSISTENCY() Q_ASSERT_X(testConsistency(true ), Q_FUNC_INFO, "Consistency test failed")
16# define ASSERT_CONSISTENCY qt_noop
35 const Cx connections[] = {
37 SLOT(modelHasBeenDestroyed()) },
39 SLOT(modelHasBeenReset()) },
65 for (
const Cx *
c = &connections[0];
c->signal;
c++)
72 if (m_rootIndex.
isValid() && m_rootIndex.
model() != m_model)
76 for (
const Cx *
c = &connections[0];
c->signal;
c++)
77 connect(m_model,
c->signal,
this,
c->slot);
90 m_expandedItems.
clear();
101 if (m_rootIndex == idx)
139 return m_items.
size();
167 return m_model->
headerData(section, orientation, role);
177 if (row < 0 || row >= m_items.
size())
179 return m_items.
at(
row).depth;
188 const int totalCount = m_items.
size();
191 int localCount =
qMin(m_lastItemIndex - 1, totalCount - m_lastItemIndex);
193 for (
int i = 0;
i < localCount; ++
i) {
194 const TreeItem &item1 = m_items.
at(m_lastItemIndex +
i);
195 if (item1.index ==
index) {
196 m_lastItemIndex = m_lastItemIndex +
i;
197 return m_lastItemIndex;
199 const TreeItem &item2 = m_items.
at(m_lastItemIndex -
i - 1);
200 if (item2.index ==
index) {
201 m_lastItemIndex = m_lastItemIndex -
i - 1;
202 return m_lastItemIndex;
206 for (
int j =
qMax(0, m_lastItemIndex + localCount);
j < totalCount; ++
j) {
207 const TreeItem &
item = m_items.
at(
j);
214 for (
int j =
qMin(totalCount, m_lastItemIndex - localCount) - 1;
j >= 0; --
j) {
215 const TreeItem &
item = m_items.
at(
j);
239 if (!
index.isValid())
243 if (row < 0 || row > m_items.
size() - 1)
252 if (!
index.isValid())
256 for (
int i = 0;
i < m_items.
size(); ++
i) {
272 if (row < 0 || row >= m_items.
size())
274 return m_items.
at(
row).index;
293 MI2MIPairHash ranges;
297 bool selectLastRow =
false;
298 for (
int i = from + 1;
i <= to || (selectLastRow =
true);
i++) {
304 if (!selectLastRow) {
308 if (selectLastRow || previousParent !=
parent) {
309 const MI2MIPairHash::iterator &
it = ranges.
find(previousParent);
310 if (
it == ranges.
end())
311 ranges.insert(previousParent, MIPair(firstIndex, lastIndex));
313 it->second = lastIndex;
326 for (
const MIPair &pair : std::as_const(ranges))
339 const long topLevelRowCount = m_model->
rowCount(m_rootIndex);
340 if (topLevelRowCount == 0)
349 int rowIdx = parentIndex.
isValid() && parentIndex != m_rootIndex ?
itemIndex(parentIndex) + 1 : 0;
350 Q_ASSERT(rowIdx == 0 || parentItem.expanded);
351 if (parentIndex.
isValid() && parentIndex != m_rootIndex && (rowIdx == 0 || !parentItem.expanded))
354 if (m_model->
rowCount(parentIndex) == 0) {
368 if (nextSiblingIdx.
isValid()) {
376 int rowDepth = rowIdx == 0 ? 0 : parentItem.depth + 1;
381 for (
int i = 0;
i < insertCount;
i++) {
384 const TreeItem treeItem(cmi, rowDepth,
expanded);
385 m_items.
insert(startIdx +
i, treeItem);
388 m_itemsToExpand.
append(treeItem);
394 if (doExpandPendingRows)
416 m_expandedItems.
insert(idx);
439 m_expandedItems.
remove(idx);
457 if (row < 0 || row >= m_items.
size())
459 return m_items.
at(
row).expanded;
464 if (row < 0 || row >= m_items.
size())
480 TreeItem &
item = m_items[
n];
483 item.expanded =
true;
497 auto expandHelp = [
this,
depth, startDepth] (
const auto expandHelp,
const QModelIndex &
index) ->
void {
506 for (
int childRow = 0; childRow < childCount; ++childRow) {
509 expandHelp(expandHelp, childIndex);
515 expandHelp(expandHelp,
index);
520 while (!m_itemsToExpand.
isEmpty()) {
525 if (childrenCount == 0) {
540 auto collapseHelp = [
this] (
const auto collapseHelp,
const QModelIndex &
index) ->
void {
543 if (rowToCollapse != -1)
550 for (
int childRow = 0; childRow < childCount; ++childRow) {
553 collapseHelp(collapseHelp, childIndex);
559 collapseHelp(collapseHelp,
index);
567 SignalFreezer aggregator(
this);
569 TreeItem &
item = m_items[
n];
570 item.expanded =
false;
573 queueDataChanged(
index(
n, m_column),
index(
n, m_column), changedRole);
597 if (nextSiblingIndex.
isValid())
603 return firstIndex - 1;
608 if (startIndex < 0 || endIndex < 0 || startIndex > endIndex)
613 m_items.
erase(m_items.
begin() + startIndex, m_items.
begin() + endIndex + 1);
618 int lastIndex = m_items.
size() - 1;
619 if (startIndex <= lastIndex) {
623 queueDataChanged(topLeft, bottomRight, changedRole);
628void QQmlTreeModelToTableModel::modelHasBeenDestroyed()
635void QQmlTreeModelToTableModel::modelHasBeenReset()
655 for (
int i = topLeft.
row();
i <= bottomRight.
row();
i++) {
657 int bottomIndex = topIndex;
658 while (bottomIndex < m_items.
size()) {
664 if (idx.
row() == bottomRight.
row())
670 i += bottomIndex - topIndex;
671 if (
i == bottomRight.
row())
673 topIndex = bottomIndex + 1;
674 while (topIndex < m_items.
size()
675 && m_items.
at(topIndex).index.parent() !=
parent)
694 m_modelLayoutChanged =
false;
696 if (parents.
isEmpty() || !parents[0].isValid()) {
699 m_modelLayoutChanged =
true;
714 if (!m_modelLayoutChanged) {
716 m_modelLayoutChanged =
true;
731 if (!m_modelLayoutChanged) {
780 if (parentRow >= 0) {
783 queueDataChanged(parentIndex, parentIndex, changedRole);
784 item = m_items.
at(parentRow);
785 if (!
item.expanded) {
789 }
else if (
parent == m_rootIndex) {
802 enableSignalAggregation();
823 m_expandedItems.
remove(cmi);
832 if (parentRow >= 0) {
835 queueDataChanged(parentIndex, parentIndex, changedRole);
837 disableSignalAggregation();
841void QQmlTreeModelToTableModel::modelRowsAboutToBeMoved(
const QModelIndex & sourceParent,
int sourceStart,
int sourceEnd,
const QModelIndex & destinationParent,
int destinationRow)
844 enableSignalAggregation();
845 m_visibleRowsMoved =
false;
850 modelRowsAboutToBeRemoved(sourceParent, sourceStart, sourceEnd);
857 queueDataChanged(topLeft, bottomRight, changedRole);
860 int depthDifference = -1;
863 depthDifference = m_items.
at(destParentIndex).depth;
866 int sourceParentIndex =
itemIndex(sourceParent);
867 depthDifference -= m_items.
at(sourceParentIndex).depth;
872 int startIndex =
itemIndex(m_model->
index(sourceStart, 0, sourceParent));
891 int totalMovedCount = endIndex - startIndex + 1;
895 m_visibleRowsMoved = startIndex != destIndex &&
899 int bufferCopyOffset;
900 if (destIndex > endIndex) {
901 for (
int i = endIndex + 1;
i < destIndex;
i++) {
904 bufferCopyOffset = destIndex - totalMovedCount;
907 for (
int i = startIndex - 1;
i >= destIndex;
i--) {
910 bufferCopyOffset = destIndex;
912 for (
int i = 0;
i <
buffer.size();
i++) {
914 item.depth += depthDifference;
928 const int top =
qMin(startIndex, bufferCopyOffset);
929 int bottom =
qMax(endIndex, bufferCopyOffset + totalMovedCount - 1);
941 queueDataChanged(topLeft, bottomRight, changedRole);
943 if (depthDifference != 0) {
947 queueDataChanged(topLeft, bottomRight, changedRole);
952void QQmlTreeModelToTableModel::modelRowsMoved(
const QModelIndex & sourceParent,
int sourceStart,
int sourceEnd,
const QModelIndex & destinationParent,
int destinationRow)
955 modelRowsInserted(
destinationParent, destinationRow, destinationRow + sourceEnd - sourceStart);
957 modelRowsRemoved(sourceParent, sourceStart, sourceEnd);
960 if (m_visibleRowsMoved)
969 queueDataChanged(topLeft, bottomRight, changedRole);
972 disableSignalAggregation();
984 int countWidth = floor(log10(
double(
count))) + 1;
985 qInfo() <<
"Dumping" <<
this;
987 const TreeItem &
item = m_items.
at(
i);
990 qInfo().noquote().nospace()
1001 qWarning() <<
"Model inconsistency: No model but stored visible items";
1004 if (!m_expandedItems.
isEmpty()) {
1005 qWarning() <<
"Model inconsistency: No model but stored expanded items";
1013 for (
int i = 0;
i < m_items.
size();
i++) {
1014 bool isConsistent =
true;
1015 const TreeItem &
item = m_items.
at(
i);
1016 if (
item.index != idx) {
1017 qWarning() <<
"QModelIndex inconsistency" <<
i <<
item.index;
1019 isConsistent =
false;
1023 qWarning() <<
" stored index parent" <<
item.index.parent() <<
"model parent" <<
parent;
1024 isConsistent =
false;
1026 if (
item.depth != ancestors.
size()) {
1028 qWarning() <<
" item depth" <<
item.depth <<
"ancestors stack" << ancestors.
size();
1029 isConsistent =
false;
1034 isConsistent =
false;
1036 if (!isConsistent) {
1043 firstChildIndex = m_model->
index(0, 0, idx);
1044 if (firstChildIndex.
isValid()) {
1062void QQmlTreeModelToTableModel::enableSignalAggregation() {
1063 m_signalAggregatorStack++;
1066void QQmlTreeModelToTableModel::disableSignalAggregation() {
1067 m_signalAggregatorStack--;
1068 Q_ASSERT(m_signalAggregatorStack >= 0);
1069 if (m_signalAggregatorStack == 0) {
1070 emitQueuedSignals();
1074void QQmlTreeModelToTableModel::queueDataChanged(
const QModelIndex &topLeft,
1078 if (isAggregatingSignals()) {
1079 m_queuedDataChanged.append(DataChangedParams { topLeft, bottomRight, roles });
1085void QQmlTreeModelToTableModel::emitQueuedSignals()
1093 for (
const DataChangedParams &dataChange :
std::as_const(m_queuedDataChanged)) {
1094 int startRow = dataChange.topLeft.row();
1095 int endRow = dataChange.bottomRight.row();
1096 bool merged =
false;
1097 for (DataChangedParams &combined : combinedUpdates) {
1098 int combinedStartRow = combined.topLeft.row();
1099 int combinedEndRow = combined.bottomRight.row();
1100 if ((startRow <= combinedStartRow && endRow >= combinedStartRow) ||
1101 (startRow <= combinedEndRow && endRow >= combinedEndRow)) {
1102 if (startRow < combinedStartRow) {
1103 combined.topLeft = dataChange.topLeft;
1105 if (endRow > combinedEndRow) {
1106 combined.bottomRight = dataChange.bottomRight;
1108 for (
int role : dataChange.roles) {
1109 if (!combined.roles.contains(role))
1110 combined.roles.
append(role);
1117 combinedUpdates.
append(dataChange);
1122 for (
const DataChangedParams &dataChange : combinedUpdates) {
1123 emit dataChanged(dataChange.topLeft, dataChange.bottomRight, dataChange.roles);
1125 m_queuedDataChanged.clear();
1130#include "moc_qqmltreemodeltotablemodel_p_p.cpp"
void rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow, QPrivateSignal)
Q_INVOKABLE int const QModelIndex & parent
Returns the parent of the model item with the given index.
void endResetModel()
Completes a model reset operation.
bool beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationRow)
LayoutChangeHint
This enum describes the way the model changes layout.
void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted just before rows are inserted into the model.
virtual Q_INVOKABLE QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Returns the data for the given role and section in the header with the specified orientation.
Q_INVOKABLE bool hasIndex(int row, int column, const QModelIndex &parent=QModelIndex()) const
Returns {true} if the model returns a valid QModelIndex for row and column with parent,...
virtual Q_INVOKABLE Qt::ItemFlags flags(const QModelIndex &index) const
Returns the item flags for the given index.
void modelReset(QPrivateSignal)
void endRemoveRows()
Ends a row removal operation.
void endMoveRows()
Ends a row move operation.
Q_INVOKABLE int int const QModelIndex & destinationParent
void layoutAboutToBeChanged(const QList< QPersistentModelIndex > &parents=QList< QPersistentModelIndex >(), QAbstractItemModel::LayoutChangeHint hint=QAbstractItemModel::NoLayoutChangeHint)
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles=QList< int >())
This signal is emitted whenever the data in an existing item changes.
virtual Q_INVOKABLE bool hasChildren(const QModelIndex &parent=QModelIndex()) const
Returns {true} if parent has any children; otherwise returns {false}.
virtual Q_INVOKABLE int rowCount(const QModelIndex &parent=QModelIndex()) const =0
Returns the number of rows under the given parent.
virtual Q_INVOKABLE void fetchMore(const QModelIndex &parent)
Fetches any available data for the items with the parent specified by the parent index.
void layoutChanged(const QList< QPersistentModelIndex > &parents=QList< QPersistentModelIndex >(), QAbstractItemModel::LayoutChangeHint hint=QAbstractItemModel::NoLayoutChangeHint)
virtual Q_INVOKABLE bool canFetchMore(const QModelIndex &parent) const
Returns {true} if there is more data available for parent; otherwise returns {false}.
virtual Q_INVOKABLE bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
Sets the role data for the item at index to value.
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted just before rows are removed from the model.
virtual QHash< int, QByteArray > roleNames() const
void endInsertRows()
Ends a row insertion operation.
void beginResetModel()
Begins a model reset operation.
void rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow, QPrivateSignal)
virtual Q_INVOKABLE int columnCount(const QModelIndex &parent=QModelIndex()) const =0
Returns the number of columns for the children of the given parent.
void rowsInserted(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted after rows have been inserted into the model.
QModelIndex createIndex(int row, int column, const void *data=nullptr) const
Creates a model index for the given row and column with the internal pointer ptr.
virtual Q_INVOKABLE QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const =0
Returns the data stored under the given role for the item referred to by the index.
void beginRemoveRows(const QModelIndex &parent, int first, int last)
Begins a row removal operation.
virtual Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const =0
Returns the index of the item in the model specified by the given row, column and parent index.
void beginInsertRows(const QModelIndex &parent, int first, int last)
Begins a row insertion operation.
void rowsRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted after rows have been removed from the model.
static constexpr QChar fromLatin1(char c) noexcept
Converts the Latin-1 character c to its equivalent QChar.
GraphicsItemFlags flags() const
Returns this item's flags.
qsizetype size() const noexcept
bool isEmpty() const noexcept
iterator erase(const_iterator begin, const_iterator end)
iterator insert(qsizetype i, parameter_type t)
void swapItemsAt(qsizetype i, qsizetype j)
const_reference at(qsizetype i) const noexcept
QList< T > mid(qsizetype pos, qsizetype len=-1) const
void reserve(qsizetype size)
void replace(qsizetype i, parameter_type t)
void append(parameter_type t)
QModelIndex siblingAtColumn(int column) const
Returns the sibling at column for the current row.
constexpr int row() const noexcept
Returns the row this model index refers to.
QModelIndex parent() const
Returns the parent of the model index, or QModelIndex() if it has no parent.
constexpr const QAbstractItemModel * model() const noexcept
Returns a pointer to the model containing the item that this index refers to.
constexpr int column() const noexcept
Returns the column this model index refers to.
constexpr bool isValid() const noexcept
Returns {true} if this model index is valid; otherwise returns {false}.
QModelIndex sibling(int row, int column) const
Returns the sibling at row and column.
const QObjectList & children() const
Returns a list of child objects.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
const QAbstractItemModel * model() const
Returns the model that the index belongs to.
bool isValid() const
Returns {true} if this persistent model index is valid; otherwise returns {false}.
void modelChanged(QAbstractItemModel *model)
bool hasChildren(int row) const
bool childrenVisible(const QModelIndex &index)
void removeVisibleRows(int startIndex, int endIndex, bool doRemoveRows=true)
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
Returns the data for the given role and section in the header with the specified orientation.
QHash< int, QByteArray > roleNames() const override
void setRootIndex(const QModelIndex &idx)
bool isExpanded(const QModelIndex &) const
QModelIndex mapToModel(const QModelIndex &index) const
Qt::ItemFlags flags(const QModelIndex &index) const override
Returns the item flags for the given index.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Returns the index of the item in the model specified by the given row, column and parent index.
void expandPendingRows(bool doInsertRows=true)
bool isVisible(const QModelIndex &index)
void showModelChildItems(const TreeItem &parent, int start, int end, bool doInsertRows=true, bool doExpandPendingRows=true)
Q_INVOKABLE QItemSelection selectionForRowRange(const QModelIndex &fromIndex, const QModelIndex &toIndex) const
bool setData(const QModelIndex &index, const QVariant &value, int role) override
Sets the role data for the item at index to value.
QAbstractItemModel * model
QModelIndex mapFromModel(const QModelIndex &index) const
bool testConsistency(bool dumpOnFail=false) const
QVariant data(const QModelIndex &, int role) const override
Returns the data stored under the given role for the item referred to by the index.
int lastChildIndex(const QModelIndex &index) const
void showModelTopLevelItems(bool doInsertRows=true)
int itemIndex(const QModelIndex &index) const
void collapse(const QModelIndex &)
bool hasSiblings(int row) const
void collapseRecursively(int row)
void expandRecursively(int row, int depth)
void setModel(QAbstractItemModel *model)
void collapsed(const QModelIndex &index)
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of columns for the children of the given parent.
int depthAtRow(int row) const
void expand(const QModelIndex &)
void expanded(const QModelIndex &index)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of rows under the given parent.
QQmlTreeModelToTableModel(QObject *parent=nullptr)
bool remove(const T &value)
iterator find(const T &value)
bool contains(const T &value) const
iterator insert(const T &value)
T pop()
Removes the top item from the stack and returns it.
void push(const T &t)
Adds element t to the top of the stack.
\macro QT_RESTRICTED_CAST_FROM_ASCII
QSet< QString >::iterator it
Combined button and popup list for selecting options.
std::pair< T1, T2 > QPair
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
GLint GLenum GLsizei GLsizei GLsizei depth
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLenum GLenum GLsizei void GLsizei void * column
GLenum GLenum GLsizei void * row
#define ASSERT_CONSISTENCY
QLatin1StringView QLatin1String
#define QStringLiteral(str)
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
static uint toIndex(ExecutionEngine *e, const Value &v)
myObject disconnect()
[26]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent