File indexing completed on 2024-05-19 09:21:27
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 *transaction = m_transactions[index.row()]; 0062 switch (role) { 0063 case TransactionRoleRole: 0064 return transaction->role(); 0065 case TransactionStatusRole: 0066 return transaction->status(); 0067 case CancellableRole: 0068 return transaction->isCancellable(); 0069 case ProgressRole: 0070 return transaction->progress(); 0071 case StatusTextRole: 0072 switch (transaction->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 (transaction->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 *>(transaction); 0099 case ResourceRole: 0100 return QVariant::fromValue<QObject *>(transaction->resource()); 0101 } 0102 0103 return QVariant(); 0104 } 0105 0106 Transaction *TransactionModel::transactionFromResource(AbstractResource *resource) const 0107 { 0108 for (const auto transaction : std::as_const(m_transactions)) { 0109 if (transaction->resource() == resource) { 0110 return transaction; 0111 } 0112 } 0113 0114 return nullptr; 0115 } 0116 0117 QModelIndex TransactionModel::indexOf(Transaction *transaction) const 0118 { 0119 int row = m_transactions.indexOf(transaction); 0120 QModelIndex ret = index(row); 0121 Q_ASSERT(!transaction || ret.isValid()); 0122 return ret; 0123 } 0124 0125 QModelIndex TransactionModel::indexOf(AbstractResource *resource) const 0126 { 0127 Transaction *transaction = transactionFromResource(resource); 0128 0129 return indexOf(transaction); 0130 } 0131 0132 void TransactionModel::addTransaction(Transaction *transaction) 0133 { 0134 if (!transaction) { 0135 return; 0136 } 0137 0138 if (m_transactions.contains(transaction)) { 0139 return; 0140 } 0141 0142 if (m_transactions.isEmpty()) { 0143 Q_EMIT startingFirstTransaction(); 0144 } 0145 0146 int before = m_transactions.size(); 0147 beginInsertRows(QModelIndex(), before, before + 1); 0148 m_transactions.append(transaction); 0149 0150 if (before == 0) { // Should emit before count changes 0151 Q_EMIT mainTransactionTextChanged(); 0152 } 0153 endInsertRows(); 0154 0155 connect(transaction, &Transaction::statusChanged, this, [this, transaction]() { 0156 transactionChanged(transaction, StatusTextRole); 0157 }); 0158 connect(transaction, &Transaction::cancellableChanged, this, [this, transaction]() { 0159 transactionChanged(transaction, CancellableRole); 0160 }); 0161 connect(transaction, &Transaction::progressChanged, this, [this, transaction]() { 0162 transactionChanged(transaction, ProgressRole); 0163 Q_EMIT progressChanged(); 0164 }); 0165 0166 Q_EMIT transactionAdded(transaction); 0167 } 0168 0169 void TransactionModel::removeTransaction(Transaction *transaction) 0170 { 0171 Q_ASSERT(transaction); 0172 transaction->deleteLater(); 0173 int index = m_transactions.indexOf(transaction); 0174 if (index < 0) { 0175 qCWarning(LIBDISCOVER_LOG) << "transaction not part of the model" << transaction; 0176 return; 0177 } 0178 0179 disconnect(transaction, nullptr, this, nullptr); 0180 0181 beginRemoveRows(QModelIndex(), index, index); 0182 m_transactions.removeAt(index); 0183 endRemoveRows(); 0184 0185 Q_EMIT transactionRemoved(transaction); 0186 if (m_transactions.isEmpty()) { 0187 Q_EMIT lastTransactionFinished(); 0188 } 0189 0190 if (index == 0) { 0191 Q_EMIT mainTransactionTextChanged(); 0192 } 0193 } 0194 0195 void TransactionModel::transactionChanged(Transaction *transaction, int role) 0196 { 0197 QModelIndex index = indexOf(transaction); 0198 Q_EMIT dataChanged(index, index, {role}); 0199 } 0200 0201 int TransactionModel::progress() const 0202 { 0203 int sum = 0; 0204 int count = 0; 0205 for (const auto transaction : std::as_const(m_transactions)) { 0206 if (transaction->isActive() && transaction->isVisible()) { 0207 sum += transaction->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 }