File indexing completed on 2024-12-15 03:45:01
0001 /* 0002 SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: MIT 0005 */ 0006 0007 #include "productmodel.h" 0008 0009 #include <rest/restapi.h> 0010 #include <rest/restclient.h> 0011 0012 #include <QNetworkReply> 0013 0014 using namespace KUserFeedback::Console; 0015 0016 ProductModel::ProductModel(QObject *parent) : 0017 QAbstractListModel(parent) 0018 { 0019 } 0020 0021 ProductModel::~ProductModel() = default; 0022 0023 void ProductModel::setRESTClient(RESTClient* client) 0024 { 0025 if (client != m_restClient) 0026 clear(); 0027 Q_ASSERT(client); 0028 m_restClient = client; 0029 connect(m_restClient, &RESTClient::clientConnected, this, &ProductModel::reload); 0030 reload(); 0031 } 0032 0033 void ProductModel::clear() 0034 { 0035 if (m_products.isEmpty()) 0036 return; 0037 beginRemoveRows({}, 0, m_products.size() - 1); 0038 m_products.clear(); 0039 endRemoveRows(); 0040 } 0041 0042 void ProductModel::reload() 0043 { 0044 if (!m_restClient || !m_restClient->isConnected()) 0045 return; 0046 0047 auto reply = RESTApi::listProducts(m_restClient); 0048 connect(reply, &QNetworkReply::finished, this, [this, reply]() { 0049 if (reply->error() == QNetworkReply::NoError) { 0050 auto json = reply->readAll(); 0051 mergeProducts(Product::fromJson(json)); 0052 } 0053 reply->deleteLater(); 0054 }); 0055 } 0056 0057 int ProductModel::rowCount(const QModelIndex& parent) const 0058 { 0059 if (parent.isValid()) 0060 return 0; 0061 return m_products.size(); 0062 } 0063 0064 QVariant ProductModel::data(const QModelIndex& index, int role) const 0065 { 0066 if (!index.isValid()) 0067 return {}; 0068 0069 switch (role) { 0070 case Qt::DisplayRole: 0071 return m_products.at(index.row()).name(); 0072 case ProductRole: 0073 return QVariant::fromValue(m_products.at(index.row())); 0074 } 0075 return {}; 0076 } 0077 0078 QVariant ProductModel::headerData(int section, Qt::Orientation orientation, int role) const 0079 { 0080 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { 0081 switch (section) { 0082 case 0: return tr("Products"); 0083 } 0084 } 0085 return QAbstractListModel::headerData(section, orientation, role); 0086 } 0087 0088 void ProductModel::mergeProducts(QVector<Product> &&products) 0089 { 0090 std::sort(products.begin(), products.end(), [](const Product &lhs, const Product &rhs) { 0091 Q_ASSERT(lhs.isValid()); 0092 Q_ASSERT(rhs.isValid()); 0093 return lhs.name() < rhs.name(); 0094 }); 0095 0096 auto newIt = products.cbegin(); 0097 auto it = m_products.begin(); 0098 0099 while (it != m_products.end() && newIt != products.cend()) { 0100 const auto row = std::distance(m_products.begin(), it); 0101 if ((*newIt).name() < (*it).name()) { 0102 beginInsertRows({}, row, row); 0103 it = m_products.insert(it, (*newIt)); 0104 endInsertRows(); 0105 ++it; 0106 ++newIt; 0107 } else if ((*it).name() < (*newIt).name()) { 0108 beginRemoveRows({}, row, row); 0109 it = m_products.erase(it); 0110 endRemoveRows(); 0111 } else { 0112 *it = *newIt; 0113 Q_EMIT dataChanged(index(row, 0), index(row, 0)); 0114 ++it; 0115 ++newIt; 0116 } 0117 } 0118 0119 if (it == m_products.end() && newIt != products.cend()) { // trailing insert 0120 const auto count = std::distance(newIt, products.cend()); 0121 beginInsertRows({}, m_products.size(), m_products.size() + count - 1); 0122 while (newIt != products.cend()) 0123 m_products.push_back(*newIt++); 0124 endInsertRows(); 0125 } else if (newIt == products.cend() && it != m_products.end()) { // trailing remove 0126 const auto start = std::distance(m_products.begin(), it); 0127 const auto end = m_products.size() - 1; 0128 beginRemoveRows({}, start, end); 0129 m_products.resize(start); 0130 endResetModel(); 0131 } 0132 } 0133 0134 #include "moc_productmodel.cpp"