Commit 944123ca authored by Volker Krause's avatar Volker Krause
Browse files

Avoid model resets in ProductModel

This fixes losing the selection on product updates.
parent aa1cf053
......@@ -33,27 +33,33 @@ ProductModel::~ProductModel() = default;
void ProductModel::setRESTClient(RESTClient* client)
{
if (client != m_restClient)
clear();
Q_ASSERT(client);
m_restClient = client;
connect(m_restClient, &RESTClient::clientConnected, this, &ProductModel::reload);
if (m_restClient->isConnected())
reload();
reload();
}
void ProductModel::clear()
{
if (m_products.isEmpty())
return;
beginRemoveRows({}, 0, m_products.size() - 1);
m_products.clear();
endRemoveRows();
}
void ProductModel::reload()
{
qDebug() << Q_FUNC_INFO;
Q_ASSERT(m_restClient);
if (!m_restClient->isConnected())
if (!m_restClient || !m_restClient->isConnected())
return;
auto reply = RESTApi::listProducts(m_restClient);
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
if (reply->error() == QNetworkReply::NoError) {
beginResetModel();
auto json = reply->readAll();
m_products = Product::fromJson(json);
endResetModel();
mergeProducts(Product::fromJson(json));
}
});
}
......@@ -88,3 +94,48 @@ QVariant ProductModel::headerData(int section, Qt::Orientation orientation, int
}
return QAbstractListModel::headerData(section, orientation, role);
}
void ProductModel::mergeProducts(QVector<Product> &&products)
{
std::sort(products.begin(), products.end(), [](const Product &lhs, const Product &rhs) {
Q_ASSERT(lhs.isValid());
Q_ASSERT(rhs.isValid());
return lhs.name() < rhs.name();
});
auto newIt = products.cbegin();
auto it = m_products.begin();
while (it != m_products.end() && newIt != products.cend()) {
const auto row = std::distance(m_products.begin(), it);
if ((*newIt).name() < (*it).name()) {
beginInsertRows({}, row, row);
it = m_products.insert(it, (*newIt));
endInsertRows();
++it;
++newIt;
} else if ((*it).name() < (*newIt).name()) {
beginRemoveRows({}, row, row);
it = m_products.erase(it);
endRemoveRows();
} else {
emit dataChanged(index(row, 0), index(row, 0));
++it;
++newIt;
}
}
if (it == m_products.end() && newIt != products.cend()) { // trailing insert
const auto count = std::distance(newIt, products.cend());
beginInsertRows({}, m_products.size(), m_products.size() + count - 1);
while (newIt != products.cend())
m_products.push_back(*newIt++);
endInsertRows();
} else if (newIt == products.cend() && it != m_products.end()) { // trailing remove
const auto start = std::distance(m_products.begin(), it);
const auto end = m_products.size() - 1;
beginRemoveRows({}, start, end);
m_products.resize(start);
endResetModel();
}
}
......@@ -42,6 +42,7 @@ public:
};
void setRESTClient(RESTClient *client);
void clear();
void reload();
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
......@@ -49,6 +50,8 @@ public:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
private:
void mergeProducts(QVector<Product> &&products);
RESTClient *m_restClient = nullptr;
QVector<Product> m_products;
};
......
......@@ -17,6 +17,7 @@
#include "servercontroller.h"
#include <rest/restapi.h>
#include <rest/restclient.h>
#include <model/productmodel.h>
......@@ -40,11 +41,17 @@ private:
{
ServerInfo s;
s.setUrl(m_server.url());
s.setUserName(QStringLiteral("orwell"));
s.setPassword(QStringLiteral("1984"));
return s;
}
bool waitForFinished(QNetworkReply *reply)
{
Q_ASSERT(reply);
QSignalSpy spy(reply, &QNetworkReply::finished);
Q_ASSERT(spy.isValid());
return spy.wait();
}
private slots:
void initTestCase()
{
......@@ -58,12 +65,40 @@ private slots:
client.connectToServer(testServer());
QVERIFY(client.isConnected());
Product p;
p.setName(QStringLiteral("org.kde.NewUnitTestProduct"));
auto reply = RESTApi::deleteProduct(&client, p);
waitForFinished(reply);
ProductModel model;
ModelTest modelTest(&model);
QSignalSpy resetSpy(&model, &ProductModel::modelReset);
QSignalSpy insertSpy(&model, &ProductModel::rowsInserted);
QSignalSpy removeSpy(&model, &ProductModel::rowsRemoved);
model.setRESTClient(&client);
QSignalSpy spy(&model, &ProductModel::modelReset);
QVERIFY(spy.wait());
QVERIFY(insertSpy.wait());
const auto baseCount = model.rowCount();
insertSpy.clear();
reply = RESTApi::createProduct(&client, p);
QVERIFY(waitForFinished(reply));
resetSpy.clear();
model.reload();
QVERIFY(insertSpy.wait());
QCOMPARE(model.rowCount(), baseCount + 1);
reply = RESTApi::deleteProduct(&client, p);
QVERIFY(waitForFinished(reply));
resetSpy.clear();
model.reload();
QVERIFY(removeSpy.wait());
QCOMPARE(model.rowCount(), baseCount);
removeSpy.clear();
model.clear();
QCOMPARE(removeSpy.size(), 1);
QVERIFY(resetSpy.isEmpty());
}
};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment