mirror of
https://github.com/status-im/status-desktop.git
synced 2025-01-10 14:26:34 +00:00
feat(WritableProxyModel): Add syncedRemoval flag to allow source to remove edited rows
This commit is contained in:
parent
67b81e1953
commit
204bfb30b6
@ -26,6 +26,9 @@ class WritableProxyModel : public QAbstractProxyModel
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(bool dirty READ dirty NOTIFY dirtyChanged)
|
Q_PROPERTY(bool dirty READ dirty NOTIFY dirtyChanged)
|
||||||
|
//If true, the removals are synced with the source model. Removing an edited item from source will also remove it from proxy
|
||||||
|
//If false, eemoving an edited item from source will not remove it from proxy. It will become a newly inserted row
|
||||||
|
Q_PROPERTY(bool syncedRemovals READ syncedRemovals WRITE setSyncedRemovals NOTIFY syncedRemovalsChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit WritableProxyModel(QObject* parent = nullptr);
|
explicit WritableProxyModel(QObject* parent = nullptr);
|
||||||
@ -48,6 +51,7 @@ public:
|
|||||||
Q_INVOKABLE bool set(int at, const QVariantMap& data);
|
Q_INVOKABLE bool set(int at, const QVariantMap& data);
|
||||||
|
|
||||||
bool dirty() const;
|
bool dirty() const;
|
||||||
|
bool syncedRemovals() const;
|
||||||
|
|
||||||
//QAbstractProxyModel overrides
|
//QAbstractProxyModel overrides
|
||||||
void setSourceModel(QAbstractItemModel* sourceModel) override;
|
void setSourceModel(QAbstractItemModel* sourceModel) override;
|
||||||
@ -75,9 +79,11 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void dirtyChanged();
|
void dirtyChanged();
|
||||||
|
void syncedRemovalsChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setDirty(bool flag);
|
void setDirty(bool flag);
|
||||||
|
void setSyncedRemovals(bool syncedRemovals);
|
||||||
|
|
||||||
void onSourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles);
|
void onSourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles);
|
||||||
void onRowsAboutToBeInserted(const QModelIndex& parent, int start, int end);
|
void onRowsAboutToBeInserted(const QModelIndex& parent, int start, int end);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <QAbstractItemModelTester>
|
#include <QAbstractItemModelTester>
|
||||||
#endif
|
#endif
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -23,6 +24,8 @@ public:
|
|||||||
QSet<QPersistentModelIndex> removedRows;
|
QSet<QPersistentModelIndex> removedRows;
|
||||||
QVector<int> proxyToSourceRowMapping;
|
QVector<int> proxyToSourceRowMapping;
|
||||||
bool dirty{false};
|
bool dirty{false};
|
||||||
|
bool syncedRemovals{false};
|
||||||
|
bool syncedRemovalsInitialized{false};
|
||||||
|
|
||||||
void setData(const QModelIndex& index, const QVariant& value, int role);
|
void setData(const QModelIndex& index, const QVariant& value, int role);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -244,11 +247,14 @@ int WritableProxyModelPrivate::countOffset() const
|
|||||||
|
|
||||||
void WritableProxyModelPrivate::moveFromCacheToInserted(const QModelIndex& sourceIndex)
|
void WritableProxyModelPrivate::moveFromCacheToInserted(const QModelIndex& sourceIndex)
|
||||||
{
|
{
|
||||||
if (!q.sourceModel())
|
if (!q.sourceModel() || syncedRemovals)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//User updated this row. Move it in inserted rows. We shouldn't delete it
|
//User updated this row. Move it in inserted rows. We shouldn't delete it
|
||||||
auto proxyIndex = insertedRows.insert(q.mapFromSource(sourceIndex), cache.take(sourceIndex));
|
auto proxyIndex = insertedRows.insert(q.mapFromSource(sourceIndex), cache.take(sourceIndex));
|
||||||
|
// syncedRemovalsInitialized cannot be changed after this point
|
||||||
|
syncedRemovalsInitialized = true;
|
||||||
|
|
||||||
auto itemData = q.sourceModel()->itemData(sourceIndex);
|
auto itemData = q.sourceModel()->itemData(sourceIndex);
|
||||||
for (auto it = itemData.begin(); it != itemData.end(); ++it)
|
for (auto it = itemData.begin(); it != itemData.end(); ++it)
|
||||||
{
|
{
|
||||||
@ -625,6 +631,27 @@ void WritableProxyModel::setDirty(bool flag)
|
|||||||
emit dirtyChanged();
|
emit dirtyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WritableProxyModel::syncedRemovals() const
|
||||||
|
{
|
||||||
|
return d->syncedRemovals;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WritableProxyModel::setSyncedRemovals(bool syncedRemovals)
|
||||||
|
{
|
||||||
|
if (d->syncedRemovalsInitialized)
|
||||||
|
{
|
||||||
|
qWarning() << "WritableProxyModel: syncedRemovals cannot be updated after it has been initialized";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syncedRemovals == d->syncedRemovals)
|
||||||
|
return;
|
||||||
|
|
||||||
|
d->syncedRemovals = syncedRemovals;
|
||||||
|
d->syncedRemovalsInitialized = true;
|
||||||
|
emit syncedRemovalsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void WritableProxyModel::setSourceModel(QAbstractItemModel* sourceModel)
|
void WritableProxyModel::setSourceModel(QAbstractItemModel* sourceModel)
|
||||||
{
|
{
|
||||||
if (sourceModel == QAbstractProxyModel::sourceModel())
|
if (sourceModel == QAbstractProxyModel::sourceModel())
|
||||||
@ -992,6 +1019,12 @@ void WritableProxyModel::onRowsRemoved(const QModelIndex& parent, int first, int
|
|||||||
void WritableProxyModel::onModelAboutToBeReset()
|
void WritableProxyModel::onModelAboutToBeReset()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
if (d->syncedRemovals)
|
||||||
|
{
|
||||||
|
d->clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto iter = d->cache.begin(); iter != d->cache.end();)
|
for (auto iter = d->cache.begin(); iter != d->cache.end();)
|
||||||
{
|
{
|
||||||
auto key = iter.key();
|
auto key = iter.key();
|
||||||
@ -1006,6 +1039,7 @@ void WritableProxyModel::onModelReset()
|
|||||||
d->clearInvalidatedCache();
|
d->clearInvalidatedCache();
|
||||||
d->createProxyToSourceRowMap();
|
d->createProxyToSourceRowMap();
|
||||||
resetInternalData();
|
resetInternalData();
|
||||||
|
d->checkForDirtyRemoval({}, {});
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,6 +732,66 @@ private slots:
|
|||||||
QCOMPARE(model.data(model.index(3, 0), 1), {});
|
QCOMPARE(model.data(model.index(3, 0), 1), {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updaedDataIsNotKeptAfterSourceRemove()
|
||||||
|
{
|
||||||
|
WritableProxyModel model;
|
||||||
|
QAbstractItemModelTester tester(&model);
|
||||||
|
|
||||||
|
TestSourceModel sourceModel({
|
||||||
|
{ "title", { "Token 1", "Token 2", "Token3" }},
|
||||||
|
{ "communityId", { "community_1", "community_2", "community_3" }}});
|
||||||
|
|
||||||
|
model.setSourceModel(&sourceModel);
|
||||||
|
model.setProperty("syncedRemovals", true);
|
||||||
|
|
||||||
|
QSignalSpy rowsRemovedSpy(&model, &WritableProxyModel::rowsRemoved);
|
||||||
|
QSignalSpy modelResetSpy(&model, &WritableProxyModel::modelReset);
|
||||||
|
QSignalSpy dataChangedSpy(&model, &WritableProxyModel::dataChanged);
|
||||||
|
QSignalSpy rowsInsertedSpy(&model, &WritableProxyModel::rowsInserted);
|
||||||
|
|
||||||
|
QCOMPARE(model.dirty(), false);
|
||||||
|
QCOMPARE(model.syncedRemovals(), true);
|
||||||
|
|
||||||
|
model.setData(model.index(0, 0), "Token 1.1", 0);
|
||||||
|
|
||||||
|
QCOMPARE(model.dirty(), true);
|
||||||
|
QCOMPARE(model.rowCount(), 3);
|
||||||
|
|
||||||
|
QCOMPARE(model.data(model.index(0, 0), 0), "Token 1.1");
|
||||||
|
QCOMPARE(dataChangedSpy.count(), 1);
|
||||||
|
|
||||||
|
sourceModel.remove(0);
|
||||||
|
|
||||||
|
QCOMPARE(model.dirty(), false);
|
||||||
|
QCOMPARE(model.rowCount(), 2);
|
||||||
|
QCOMPARE(model.data(model.index(0, 0), 0), "Token 2");
|
||||||
|
|
||||||
|
QCOMPARE(rowsRemovedSpy.count(), 1);
|
||||||
|
QCOMPARE(rowsRemovedSpy.first().at(1), 0);
|
||||||
|
QCOMPARE(rowsRemovedSpy.first().at(2), 0);
|
||||||
|
QCOMPARE(modelResetSpy.count(), 0);
|
||||||
|
QCOMPARE(rowsInsertedSpy.count(), 0);
|
||||||
|
|
||||||
|
model.setData(model.index(0, 0), "Token 2.1", 0);
|
||||||
|
|
||||||
|
QCOMPARE(model.dirty(), true);
|
||||||
|
|
||||||
|
QCOMPARE(model.data(model.index(0, 0), 0), "Token 2.1");
|
||||||
|
|
||||||
|
sourceModel.reset({
|
||||||
|
{ "title", { "Token 3", "Token 4" }},
|
||||||
|
{ "communityId", { "community_3", "community_4" }}
|
||||||
|
});
|
||||||
|
|
||||||
|
QCOMPARE(model.dirty(), false);
|
||||||
|
QCOMPARE(model.rowCount(), 2);
|
||||||
|
|
||||||
|
QCOMPARE(rowsRemovedSpy.count(), 1);
|
||||||
|
QCOMPARE(modelResetSpy.count(), 1);
|
||||||
|
QCOMPARE(dataChangedSpy.count(), 2);
|
||||||
|
QCOMPARE(rowsInsertedSpy.count(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
void dataIsAccessibleAfterSourceModelMove()
|
void dataIsAccessibleAfterSourceModelMove()
|
||||||
{
|
{
|
||||||
WritableProxyModel model;
|
WritableProxyModel model;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user