diff options
author | Joni Poikelin <joni.poikelin@theqtcompany.com> | 2016-04-06 13:50:08 +0300 |
---|---|---|
committer | Joni Poikelin <joni.poikelin@qt.io> | 2016-08-26 07:59:40 +0000 |
commit | 69b3136bae16897492d27558c5909cd61a5e598e (patch) | |
tree | 94be91dcdff8a14bc42a203022157924f447c739 /src | |
parent | f44ef9daf9f0f9db6775fdb6d3fc8703b6ce77e4 (diff) | |
download | qtquickcontrols-69b3136bae16897492d27558c5909cd61a5e598e.tar.gz |
Fix moving of TreeView items
Property binding for row property in styleData causes an update which
tries to read new value for the index property, but index is changed
afterwards which causes old value to be read. This may lead to crashes
and other unwanted behavior.
Depth changes are now delivered to update item depths in visible
items and model index changes though role instead of looking for a row
change.
Task-number: QTBUG-47523
Change-Id: I540cd06a25281f18e4628f4b030cf969dc8e0a7f
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/controls/Private/TreeViewItemDelegateLoader.qml | 2 | ||||
-rw-r--r-- | src/controls/Private/qquicktreemodeladaptor.cpp | 51 | ||||
-rw-r--r-- | src/controls/Private/qquicktreemodeladaptor_p.h | 5 |
3 files changed, 51 insertions, 7 deletions
diff --git a/src/controls/Private/TreeViewItemDelegateLoader.qml b/src/controls/Private/TreeViewItemDelegateLoader.qml index 8b8801fc..01492eda 100644 --- a/src/controls/Private/TreeViewItemDelegateLoader.qml +++ b/src/controls/Private/TreeViewItemDelegateLoader.qml @@ -78,7 +78,7 @@ TableViewItemDelegateLoader { readonly property color textColor: __rowItem ? __rowItem.itemTextColor : "black" readonly property string role: __column ? __column.role : "" readonly property var value: model && model.hasOwnProperty(role) ? model[role] : "" - readonly property var index: __treeModel.mapRowToModelIndex(row) + readonly property var index: model ? model["_q_TreeView_ModelIndex"] : __treeModel.index(-1,-1,null) readonly property int depth: model && column === 0 ? model["_q_TreeView_ItemDepth"] : 0 readonly property bool hasChildren: model ? model["_q_TreeView_HasChildren"] : false readonly property bool hasSibling: model ? model["_q_TreeView_HasSibling"] : false diff --git a/src/controls/Private/qquicktreemodeladaptor.cpp b/src/controls/Private/qquicktreemodeladaptor.cpp index 666fafc9..52b231d0 100644 --- a/src/controls/Private/qquicktreemodeladaptor.cpp +++ b/src/controls/Private/qquicktreemodeladaptor.cpp @@ -153,6 +153,7 @@ QHash<int, QByteArray> QQuickTreeModelAdaptor::roleNames() const modelRoleNames.insert(ExpandedRole, "_q_TreeView_ItemExpanded"); modelRoleNames.insert(HasChildrenRole, "_q_TreeView_HasChildren"); modelRoleNames.insert(HasSiblingRole, "_q_TreeView_HasSibling"); + modelRoleNames.insert(ModelIndexRole, "_q_TreeView_ModelIndex"); return modelRoleNames; } @@ -177,6 +178,8 @@ QVariant QQuickTreeModelAdaptor::data(const QModelIndex &index, int role) const return !(modelIndex.flags() & Qt::ItemNeverHasChildren) && m_model->hasChildren(modelIndex); case HasSiblingRole: return modelIndex.row() != m_model->rowCount(modelIndex.parent()) - 1; + case ModelIndexRole: + return modelIndex; default: return m_model->data(modelIndex, role); } @@ -192,6 +195,7 @@ bool QQuickTreeModelAdaptor::setData(const QModelIndex &index, const QVariant &v case ExpandedRole: case HasChildrenRole: case HasSiblingRole: + case ModelIndexRole: return false; default: { const QModelIndex &pmi = mapToModel(index); @@ -716,8 +720,11 @@ void QQuickTreeModelAdaptor::modelRowsAboutToBeMoved(const QModelIndex & sourceP destIndex = itemIndex(m_model->index(destinationRow, 0, destinationParent)); } - beginMoveRows(QModelIndex(), startIndex, endIndex, QModelIndex(), destIndex); int totalMovedCount = endIndex - startIndex + 1; + + const bool visibleRowsMoved = startIndex != destIndex && + beginMoveRows(QModelIndex(), startIndex, endIndex, QModelIndex(), destIndex); + const QList<TreeItem> &buffer = m_items.mid(startIndex, totalMovedCount); int bufferCopyOffset; if (destIndex > endIndex) { @@ -726,6 +733,7 @@ void QQuickTreeModelAdaptor::modelRowsAboutToBeMoved(const QModelIndex & sourceP } bufferCopyOffset = destIndex - totalMovedCount; } else { + // NOTE: we will not enter this loop if startIndex == destIndex for (int i = startIndex - 1; i >= destIndex; i--) { m_items.swap(i, i + totalMovedCount); // Fast move from 1st to 2nd position } @@ -736,14 +744,49 @@ void QQuickTreeModelAdaptor::modelRowsAboutToBeMoved(const QModelIndex & sourceP item.depth += depthDifference; m_items.replace(bufferCopyOffset + i, item); } - endMoveRows(); + + if (visibleRowsMoved) + endMoveRows(); + + if (depthDifference != 0) { + const QModelIndex &topLeft = index(bufferCopyOffset, 0, QModelIndex()); + const QModelIndex &bottomRight = index(bufferCopyOffset + totalMovedCount - 1, 0, QModelIndex()); + const QVector<int> changedRole(1, DepthRole); + emit dataChanged(topLeft, bottomRight, changedRole); + } } } void QQuickTreeModelAdaptor::modelRowsMoved(const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow) { - if (!childrenVisible(sourceParent) && childrenVisible(destinationParent)) - modelRowsInserted(destinationParent, destinationRow, destinationRow + sourceEnd - sourceStart); + if (childrenVisible(destinationParent)) { + if (!childrenVisible(sourceParent)) + modelRowsInserted(destinationParent, destinationRow, destinationRow + sourceEnd - sourceStart); + else { + int destIndex = -1; + if (destinationRow == m_model->rowCount(destinationParent)) { + const QModelIndex &emi = m_model->index(destinationRow - 1, 0, destinationParent); + destIndex = lastChildIndex(emi) + 1; + } else { + destIndex = itemIndex(m_model->index(destinationRow, 0, destinationParent)); + } + + const QModelIndex &emi = m_model->index(destinationRow + sourceEnd - sourceStart, 0, destinationParent); + int endIndex = -1; + if (isExpanded(emi)) { + int rowCount = m_model->rowCount(emi); + if (rowCount > 0) + endIndex = lastChildIndex(m_model->index(rowCount - 1, 0, emi)); + } + if (endIndex == -1) + endIndex = itemIndex(emi); + + const QModelIndex &topLeft = index(destIndex, 0, QModelIndex()); + const QModelIndex &bottomRight = index(endIndex, 0, QModelIndex()); + const QVector<int> changedRole(1, ModelIndexRole); + emit dataChanged(topLeft, bottomRight, changedRole); + } + } ASSERT_CONSISTENCY(); } diff --git a/src/controls/Private/qquicktreemodeladaptor_p.h b/src/controls/Private/qquicktreemodeladaptor_p.h index 3eefbe77..56c6ea08 100644 --- a/src/controls/Private/qquicktreemodeladaptor_p.h +++ b/src/controls/Private/qquicktreemodeladaptor_p.h @@ -74,10 +74,11 @@ public: void resetRootIndex(); enum { - DepthRole = Qt::UserRole - 4, + DepthRole = Qt::UserRole - 5, ExpandedRole, HasChildrenRole, - HasSiblingRole + HasSiblingRole, + ModelIndexRole }; QHash<int, QByteArray> roleNames() const; |