File indexing completed on 2024-05-05 17:33:23
0001 /* 0002 * SPDX-FileCopyrightText: 2012 Jonathan Thomas <echidnaman@kubuntu.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "TransactionModel.h" 0008 0009 // Qt includes 0010 #include <KLocalizedString> 0011 #include <QDebug> 0012 #include <QMetaProperty> 0013 0014 // Own includes 0015 #include "libdiscover_debug.h" 0016 #include "resources/AbstractResource.h" 0017 0018 Q_GLOBAL_STATIC(TransactionModel, globalTransactionModel) 0019 0020 TransactionModel *TransactionModel::global() 0021 { 0022 return globalTransactionModel; 0023 } 0024 0025 TransactionModel::TransactionModel(QObject *parent) 0026 : QAbstractListModel(parent) 0027 { 0028 connect(this, &QAbstractItemModel::rowsInserted, this, &TransactionModel::countChanged); 0029 connect(this, &QAbstractItemModel::rowsRemoved, this, &TransactionModel::countChanged); 0030 connect(this, &TransactionModel::countChanged, this, &TransactionModel::progressChanged); 0031 } 0032 0033 QHash<int, QByteArray> TransactionModel::roleNames() const 0034 { 0035 QHash<int, QByteArray> roles; 0036 roles[TransactionRoleRole] = "transactionRole"; 0037 roles[TransactionStatusRole] = "status"; 0038 roles[CancellableRole] = "cancellable"; 0039 roles[ProgressRole] = "progress"; 0040 roles[StatusTextRole] = "statusText"; 0041 roles[ResourceRole] = "resource"; 0042 roles[TransactionRole] = "transaction"; 0043 return roles; 0044 } 0045 0046 int TransactionModel::rowCount(const QModelIndex &parent) const 0047 { 0048 // Root element parents all children 0049 if (!parent.isValid()) 0050 return m_transactions.size(); 0051 0052 // Child elements have no children themselves 0053 return 0; 0054 } 0055 0056 QVariant TransactionModel::data(const QModelIndex &index, int role) const 0057 { 0058 if (!index.isValid()) 0059 return QVariant(); 0060 0061 Transaction *trans = m_transactions[index.row()]; 0062 switch (role) { 0063 case TransactionRoleRole: 0064 return trans->role(); 0065 case TransactionStatusRole: 0066 return trans->status(); 0067 case CancellableRole: 0068 return trans->isCancellable(); 0069 case ProgressRole: 0070 return trans->progress(); 0071 case StatusTextRole: 0072 switch (trans->status()) { 0073 case Transaction::SetupStatus: 0074 return i18nc("@info:status", "Starting"); 0075 case Transaction::QueuedStatus: 0076 return i18nc("@info:status", "Waiting"); 0077 case Transaction::DownloadingStatus: 0078 return i18nc("@info:status", "Downloading"); 0079 case Transaction::CommittingStatus: 0080 switch (trans->role()) { 0081 case Transaction::InstallRole: 0082 return i18nc("@info:status", "Installing"); 0083 case Transaction::RemoveRole: 0084 return i18nc("@info:status", "Removing"); 0085 case Transaction::ChangeAddonsRole: 0086 return i18nc("@info:status", "Changing Addons"); 0087 } 0088 break; 0089 case Transaction::DoneStatus: 0090 return i18nc("@info:status", "Done"); 0091 case Transaction::DoneWithErrorStatus: 0092 return i18nc("@info:status", "Failed"); 0093 case Transaction::CancelledStatus: 0094 return i18nc("@info:status", "Cancelled"); 0095 } 0096 break; 0097 case TransactionRole: 0098 return QVariant::fromValue<QObject *>(trans); 0099 case ResourceRole: 0100 return QVariant::fromValue<QObject *>(trans->resource()); 0101 } 0102 0103 return QVariant(); 0104 } 0105 0106 Transaction *TransactionModel::transactionFromResource(AbstractResource *resource) const 0107 { 0108 Transaction *ret = nullptr; 0109 0110 for (Transaction *trans : qAsConst(m_transactions)) { 0111 if (trans->resource() == resource) { 0112 ret = trans; 0113 break; 0114 } 0115 } 0116 0117 return ret; 0118 } 0119 0120 QModelIndex TransactionModel::indexOf(Transaction *trans) const 0121 { 0122 int row = m_transactions.indexOf(trans); 0123 QModelIndex ret = index(row); 0124 Q_ASSERT(!trans || ret.isValid()); 0125 return ret; 0126 } 0127 0128 QModelIndex TransactionModel::indexOf(AbstractResource *res) const 0129 { 0130 Transaction *trans = transactionFromResource(res); 0131 0132 return indexOf(trans); 0133 } 0134 0135 void TransactionModel::addTransaction(Transaction *trans) 0136 { 0137 if (!trans) 0138 return; 0139 0140 if (m_transactions.contains(trans)) 0141 return; 0142 0143 if (m_transactions.isEmpty()) 0144 Q_EMIT startingFirstTransaction(); 0145 0146 int before = m_transactions.size(); 0147 beginInsertRows(QModelIndex(), before, before + 1); 0148 m_transactions.append(trans); 0149 0150 if (before == 0) { // Should emit before count changes 0151 Q_EMIT mainTransactionTextChanged(); 0152 } 0153 endInsertRows(); 0154 0155 connect(trans, &Transaction::statusChanged, this, [this]() { 0156 transactionChanged(StatusTextRole); 0157 }); 0158 connect(trans, &Transaction::cancellableChanged, this, [this]() { 0159 transactionChanged(CancellableRole); 0160 }); 0161 connect(trans, &Transaction::progressChanged, this, [this]() { 0162 transactionChanged(ProgressRole); 0163 Q_EMIT progressChanged(); 0164 }); 0165 0166 Q_EMIT transactionAdded(trans); 0167 } 0168 0169 void TransactionModel::removeTransaction(Transaction *trans) 0170 { 0171 Q_ASSERT(trans); 0172 trans->deleteLater(); 0173 int r = m_transactions.indexOf(trans); 0174 if (r < 0) { 0175 qCWarning(LIBDISCOVER_LOG) << "transaction not part of the model" << trans; 0176 return; 0177 } 0178 0179 disconnect(trans, nullptr, this, nullptr); 0180 0181 beginRemoveRows(QModelIndex(), r, r); 0182 m_transactions.removeAt(r); 0183 endRemoveRows(); 0184 0185 Q_EMIT transactionRemoved(trans); 0186 if (m_transactions.isEmpty()) 0187 Q_EMIT lastTransactionFinished(); 0188 0189 if (r == 0) { 0190 Q_EMIT mainTransactionTextChanged(); 0191 } 0192 } 0193 0194 void TransactionModel::transactionChanged(int role) 0195 { 0196 Transaction *trans = qobject_cast<Transaction *>(sender()); 0197 QModelIndex transIdx = indexOf(trans); 0198 Q_EMIT dataChanged(transIdx, transIdx, {role}); 0199 } 0200 0201 int TransactionModel::progress() const 0202 { 0203 int sum = 0; 0204 int count = 0; 0205 for (Transaction *t : qAsConst(m_transactions)) { 0206 if (t->isActive() && t->isVisible()) { 0207 sum += t->progress(); 0208 ++count; 0209 } 0210 } 0211 return count == 0 ? 0 : sum / count; 0212 } 0213 0214 QString TransactionModel::mainTransactionText() const 0215 { 0216 return m_transactions.isEmpty() ? QString() : m_transactions.constFirst()->name(); 0217 }