StatusQ(WritableProxyModel): Handling of layoutChanged/rowsMoved from source models fixed
Closes: #13601
This commit is contained in:
parent
8b46810531
commit
00af1d0e90
|
@ -88,6 +88,7 @@ private:
|
||||||
void onModelReset();
|
void onModelReset();
|
||||||
void onLayoutAboutToBeChanged(const QList<QPersistentModelIndex>& sourceParents, QAbstractItemModel::LayoutChangeHint hint);
|
void onLayoutAboutToBeChanged(const QList<QPersistentModelIndex>& sourceParents, QAbstractItemModel::LayoutChangeHint hint);
|
||||||
void onLayoutChanged(const QList<QPersistentModelIndex>& sourceParents, QAbstractItemModel::LayoutChangeHint hint);
|
void onLayoutChanged(const QList<QPersistentModelIndex>& sourceParents, QAbstractItemModel::LayoutChangeHint hint);
|
||||||
|
void onRowsAboutToBeMoved(const QModelIndex& sourceParent, int sourceStart, int sourceEnd, const QModelIndex& destinationParent, int destinationRow);
|
||||||
void onRowsMoved(const QModelIndex& sourceParent, int sourceStart, int sourceEnd, const QModelIndex& destinationParent, int destinationRow);
|
void onRowsMoved(const QModelIndex& sourceParent, int sourceStart, int sourceEnd, const QModelIndex& destinationParent, int destinationRow);
|
||||||
|
|
||||||
QScopedPointer<WritableProxyModelPrivate> d;
|
QScopedPointer<WritableProxyModelPrivate> d;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#endif
|
#endif
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using IndexedValues = QHash<T /*key*/, QMap<int/*role*/, QVariant/*value*/>>;
|
using IndexedValues = QHash<T /*key*/, QMap<int/*role*/, QVariant/*value*/>>;
|
||||||
|
|
||||||
|
@ -35,6 +36,13 @@ public:
|
||||||
int sourceToProxyRow(int row) const;
|
int sourceToProxyRow(int row) const;
|
||||||
QVector<QPair<int, int>> sourceRowRangesBetween(int start, int end) const;
|
QVector<QPair<int, int>> sourceRowRangesBetween(int start, int end) const;
|
||||||
|
|
||||||
|
// helpers for handling layoutChanged from source
|
||||||
|
QList<QPersistentModelIndex> layoutChangePersistentIndexes;
|
||||||
|
QModelIndexList proxyIndexes;
|
||||||
|
|
||||||
|
void storePersitentIndexes();
|
||||||
|
void updatePersistentIndexes();
|
||||||
|
|
||||||
//Simple mapping. No sorting, no moving
|
//Simple mapping. No sorting, no moving
|
||||||
//TODO: add mapping for temporarily moved rows
|
//TODO: add mapping for temporarily moved rows
|
||||||
void createProxyToSourceRowMap();
|
void createProxyToSourceRowMap();
|
||||||
|
@ -126,6 +134,33 @@ int WritableProxyModelPrivate::sourceToProxyRow(int row) const
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WritableProxyModelPrivate::storePersitentIndexes()
|
||||||
|
{
|
||||||
|
const auto persistentIndexes = q.persistentIndexList();
|
||||||
|
|
||||||
|
for (const QModelIndex& persistentIndex: persistentIndexes) {
|
||||||
|
|
||||||
|
Q_ASSERT(persistentIndex.isValid());
|
||||||
|
const auto srcIndex = q.mapToSource(persistentIndex);
|
||||||
|
|
||||||
|
if (srcIndex.isValid()) {
|
||||||
|
proxyIndexes << persistentIndex;
|
||||||
|
layoutChangePersistentIndexes << srcIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WritableProxyModelPrivate::updatePersistentIndexes()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < proxyIndexes.size(); ++i) {
|
||||||
|
q.changePersistentIndex(proxyIndexes.at(i),
|
||||||
|
q.mapFromSource(layoutChangePersistentIndexes.at(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
layoutChangePersistentIndexes.clear();
|
||||||
|
proxyIndexes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void WritableProxyModelPrivate::createProxyToSourceRowMap()
|
void WritableProxyModelPrivate::createProxyToSourceRowMap()
|
||||||
{
|
{
|
||||||
if (!q.sourceModel())
|
if (!q.sourceModel())
|
||||||
|
@ -142,7 +177,8 @@ void WritableProxyModelPrivate::createProxyToSourceRowMap()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(removedRows.contains(sourceModel->index(sourceIter, 0)) && sourceIter < sourceModel->rowCount())
|
while(removedRows.contains(sourceModel->index(sourceIter, 0))
|
||||||
|
&& sourceIter < sourceModel->rowCount())
|
||||||
++sourceIter;
|
++sourceIter;
|
||||||
|
|
||||||
proxyToSourceRowMapping.append(sourceIter);
|
proxyToSourceRowMapping.append(sourceIter);
|
||||||
|
@ -620,6 +656,7 @@ void WritableProxyModel::setSourceModel(QAbstractItemModel* sourceModel)
|
||||||
connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, &WritableProxyModel::onRowsRemoved);
|
connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, &WritableProxyModel::onRowsRemoved);
|
||||||
connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &WritableProxyModel::onModelAboutToBeReset);
|
connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &WritableProxyModel::onModelAboutToBeReset);
|
||||||
connect(sourceModel, &QAbstractItemModel::modelReset, this, &WritableProxyModel::onModelReset);
|
connect(sourceModel, &QAbstractItemModel::modelReset, this, &WritableProxyModel::onModelReset);
|
||||||
|
connect(sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, &WritableProxyModel::onRowsAboutToBeMoved);
|
||||||
connect(sourceModel, &QAbstractItemModel::rowsMoved, this, &WritableProxyModel::onRowsMoved);
|
connect(sourceModel, &QAbstractItemModel::rowsMoved, this, &WritableProxyModel::onRowsMoved);
|
||||||
connect(sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, &WritableProxyModel::onLayoutAboutToBeChanged);
|
connect(sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, &WritableProxyModel::onLayoutAboutToBeChanged);
|
||||||
connect(sourceModel, &QAbstractItemModel::layoutChanged, this, &WritableProxyModel::onModelReset);
|
connect(sourceModel, &QAbstractItemModel::layoutChanged, this, &WritableProxyModel::onModelReset);
|
||||||
|
@ -927,10 +964,7 @@ void WritableProxyModel::onRowsAboutToBeRemoved(const QModelIndex& parent, int s
|
||||||
auto sourceIndex = sourceModel()->index(row, 0);
|
auto sourceIndex = sourceModel()->index(row, 0);
|
||||||
|
|
||||||
if (d->cache.contains(sourceIndex))
|
if (d->cache.contains(sourceIndex))
|
||||||
{
|
|
||||||
d->moveFromCacheToInserted(sourceIndex);
|
d->moveFromCacheToInserted(sourceIndex);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sourceRemoveRanges = d->sourceRowRangesBetween(start, end);
|
auto sourceRemoveRanges = d->sourceRowRangesBetween(start, end);
|
||||||
|
@ -975,16 +1009,25 @@ void WritableProxyModel::onModelReset()
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WritableProxyModel::onRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
|
||||||
|
{
|
||||||
|
if(sourceParent.isValid() || destinationParent.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
|
||||||
|
d->storePersitentIndexes();
|
||||||
|
}
|
||||||
|
|
||||||
void WritableProxyModel::onRowsMoved(const QModelIndex& sourceParent, int sourceStart, int sourceEnd, const QModelIndex& destinationParent, int destinationRow)
|
void WritableProxyModel::onRowsMoved(const QModelIndex& sourceParent, int sourceStart, int sourceEnd, const QModelIndex& destinationParent, int destinationRow)
|
||||||
{
|
{
|
||||||
if(sourceParent.isValid() || destinationParent.isValid())
|
if(sourceParent.isValid() || destinationParent.isValid())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
emit layoutAboutToBeChanged();
|
|
||||||
d->clearInvalidatedCache();
|
|
||||||
d->createProxyToSourceRowMap();
|
d->createProxyToSourceRowMap();
|
||||||
|
d->updatePersistentIndexes();
|
||||||
|
|
||||||
emit layoutChanged();
|
emit layoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,11 +1037,14 @@ void WritableProxyModel::onLayoutAboutToBeChanged(const QList<QPersistentModelIn
|
||||||
return;
|
return;
|
||||||
|
|
||||||
emit layoutAboutToBeChanged();
|
emit layoutAboutToBeChanged();
|
||||||
|
|
||||||
|
d->storePersitentIndexes();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WritableProxyModel::onLayoutChanged(const QList<QPersistentModelIndex>& sourceParents, QAbstractItemModel::LayoutChangeHint hint)
|
void WritableProxyModel::onLayoutChanged(const QList<QPersistentModelIndex>& sourceParents, QAbstractItemModel::LayoutChangeHint hint)
|
||||||
{
|
{
|
||||||
d->clearInvalidatedCache();
|
|
||||||
d->createProxyToSourceRowMap();
|
d->createProxyToSourceRowMap();
|
||||||
|
d->updatePersistentIndexes();
|
||||||
|
|
||||||
emit layoutChanged();
|
emit layoutChanged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
|
|
||||||
#include "StatusQ/writableproxymodel.h"
|
#include "StatusQ/writableproxymodel.h"
|
||||||
|
|
||||||
|
#include <TestHelpers/persistentindexestester.h>
|
||||||
|
#include <TestHelpers/snapshotmodel.h>
|
||||||
|
#include <TestHelpers/modeltestutils.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class TestSourceModel : public QAbstractListModel {
|
class TestSourceModel : public QAbstractListModel {
|
||||||
|
@ -73,6 +77,10 @@ public:
|
||||||
if(!beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild))
|
if(!beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (destinationChild > sourceRow) {
|
||||||
|
destinationChild -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
for (int j = 0; j < m_data.size(); j++) {
|
for (int j = 0; j < m_data.size(); j++) {
|
||||||
auto& roleVariantList = m_data[j].second;
|
auto& roleVariantList = m_data[j].second;
|
||||||
|
@ -765,7 +773,21 @@ private slots:
|
||||||
QCOMPARE(rowsInsertedSpy.count(), 0);
|
QCOMPARE(rowsInsertedSpy.count(), 0);
|
||||||
QCOMPARE(layoutChangedSpy.count(), 0);
|
QCOMPARE(layoutChangedSpy.count(), 0);
|
||||||
|
|
||||||
|
PersistentIndexesTester indexesTester(&model);
|
||||||
|
|
||||||
|
{
|
||||||
|
SnapshotModel snapshot(model);
|
||||||
|
|
||||||
|
QObject context;
|
||||||
|
connect(&model, &WritableProxyModel::layoutAboutToBeChanged, &context,
|
||||||
|
[&snapshot, &model] {
|
||||||
|
QVERIFY(isSame(snapshot, model));
|
||||||
|
});
|
||||||
|
|
||||||
sourceModel.moveRows({}, 1, 1, {}, 0);
|
sourceModel.moveRows({}, 1, 1, {}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVERIFY(indexesTester.compare());
|
||||||
|
|
||||||
QCOMPARE(model.dirty(), true);
|
QCOMPARE(model.dirty(), true);
|
||||||
QCOMPARE(model.rowCount(), 2);
|
QCOMPARE(model.rowCount(), 2);
|
||||||
|
@ -801,9 +823,11 @@ private slots:
|
||||||
model.setData(model.index(2, 0), "Token 5.1", 0);
|
model.setData(model.index(2, 0), "Token 5.1", 0);
|
||||||
model.setData(model.index(2, 0), "community_5.1", 1);
|
model.setData(model.index(2, 0), "community_5.1", 1);
|
||||||
|
|
||||||
|
PersistentIndexesTester indexesTester(&model);
|
||||||
bool success = sourceModel.moveRows({}, 1, 2, {}, 0);
|
bool success = sourceModel.moveRows({}, 1, 2, {}, 0);
|
||||||
|
|
||||||
QVERIFY(success);
|
QVERIFY(success);
|
||||||
|
QVERIFY(indexesTester.compare());
|
||||||
|
|
||||||
QCOMPARE(sourceModel.data(sourceModel.index(0, 0), 0), "Token 2");
|
QCOMPARE(sourceModel.data(sourceModel.index(0, 0), 0), "Token 2");
|
||||||
QCOMPARE(sourceModel.data(sourceModel.index(1, 0), 0), "Token 3");
|
QCOMPARE(sourceModel.data(sourceModel.index(1, 0), 0), "Token 3");
|
||||||
|
@ -835,11 +859,18 @@ private slots:
|
||||||
model.removeRows(2, 1);
|
model.removeRows(2, 1);
|
||||||
|
|
||||||
QCOMPARE(model.dirty(), true);
|
QCOMPARE(model.dirty(), true);
|
||||||
|
QCOMPARE(model.rowCount(), 2);
|
||||||
QCOMPARE(model.data(model.index(2, 0), 0), {});
|
QCOMPARE(model.data(model.index(2, 0), 0), {});
|
||||||
QCOMPARE(model.data(model.index(1, 0), 0), "Token 2");
|
QCOMPARE(model.data(model.index(1, 0), 0), "Token 2");
|
||||||
QCOMPARE(model.data(model.index(0, 0), 0), "Token 1");
|
QCOMPARE(model.data(model.index(0, 0), 0), "Token 1");
|
||||||
|
|
||||||
sourceModel.moveRows({}, 2, 1, {}, 0);
|
PersistentIndexesTester indexesTester(&model);
|
||||||
|
PersistentIndexesTester sourceIndexesTester(&sourceModel);
|
||||||
|
|
||||||
|
QVERIFY(sourceModel.moveRows({}, 2, 1, {}, 0));
|
||||||
|
QVERIFY(sourceIndexesTester.compare());
|
||||||
|
QVERIFY(indexesTester.compare());
|
||||||
|
QCOMPARE(model.rowCount(), 2);
|
||||||
|
|
||||||
QCOMPARE(sourceModel.data(sourceModel.index(0, 0), 0), "Token 3");
|
QCOMPARE(sourceModel.data(sourceModel.index(0, 0), 0), "Token 3");
|
||||||
QCOMPARE(sourceModel.data(sourceModel.index(1, 0), 0), "Token 1");
|
QCOMPARE(sourceModel.data(sourceModel.index(1, 0), 0), "Token 1");
|
||||||
|
@ -849,7 +880,10 @@ private slots:
|
||||||
QCOMPARE(model.data(model.index(1, 0), 0), "Token 2");
|
QCOMPARE(model.data(model.index(1, 0), 0), "Token 2");
|
||||||
QCOMPARE(model.data(model.index(0, 0), 0), "Token 1");
|
QCOMPARE(model.data(model.index(0, 0), 0), "Token 1");
|
||||||
|
|
||||||
sourceModel.moveRows({}, 1, 1, {}, 0);
|
QVERIFY(sourceModel.moveRows({}, 1, 1, {}, 0));
|
||||||
|
QVERIFY(sourceIndexesTester.compare());
|
||||||
|
QVERIFY(indexesTester.compare());
|
||||||
|
QCOMPARE(model.rowCount(), 2);
|
||||||
|
|
||||||
QCOMPARE(sourceModel.data(sourceModel.index(0, 0), 0), "Token 1");
|
QCOMPARE(sourceModel.data(sourceModel.index(0, 0), 0), "Token 1");
|
||||||
QCOMPARE(sourceModel.data(sourceModel.index(1, 0), 0), "Token 3");
|
QCOMPARE(sourceModel.data(sourceModel.index(1, 0), 0), "Token 3");
|
||||||
|
@ -859,7 +893,12 @@ private slots:
|
||||||
QCOMPARE(model.data(model.index(1, 0), 0), "Token 2");
|
QCOMPARE(model.data(model.index(1, 0), 0), "Token 2");
|
||||||
QCOMPARE(model.data(model.index(0, 0), 0), "Token 1");
|
QCOMPARE(model.data(model.index(0, 0), 0), "Token 1");
|
||||||
|
|
||||||
sourceModel.moveRows({}, 0, 1, {}, 2);
|
indexesTester.storeIndexesAndData();
|
||||||
|
sourceIndexesTester.storeIndexesAndData();
|
||||||
|
QVERIFY(sourceModel.moveRows({}, 0, 1, {}, 3));
|
||||||
|
QVERIFY(sourceIndexesTester.compare());
|
||||||
|
QVERIFY(indexesTester.compare());
|
||||||
|
QCOMPARE(model.rowCount(), 2);
|
||||||
|
|
||||||
QCOMPARE(sourceModel.data(sourceModel.index(0, 0), 0), "Token 3");
|
QCOMPARE(sourceModel.data(sourceModel.index(0, 0), 0), "Token 3");
|
||||||
QCOMPARE(sourceModel.data(sourceModel.index(1, 0), 0), "Token 2");
|
QCOMPARE(sourceModel.data(sourceModel.index(1, 0), 0), "Token 2");
|
||||||
|
|
Loading…
Reference in New Issue