File indexing completed on 2024-05-12 05:29:06
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 0053 // Child elements have no children themselves 0054 return 0; 0055 } 0056 0057 QVariant TransactionModel::data(const QModelIndex &index, int role) const 0058 { 0059 if (!index.isValid()) { 0060 return QVariant(); 0061 } 0062 0063 Transaction *transaction = m_transactions[index.row()]; 0064 switch (role) { 0065 case TransactionRoleRole: 0066 return transaction->role(); 0067 case TransactionStatusRole: 0068 return transaction->status(); 0069 case CancellableRole: 0070 return transaction->isCancellable(); 0071 case ProgressRole: 0072 return transaction->progress(); 0073 case StatusTextRole: 0074 switch (transaction->status()) { 0075 case Transaction::SetupStatus: 0076 return i18nc("@info:status", "Starting"); 0077 case Transaction::QueuedStatus: 0078 return i18nc("@info:status", "Waiting"); 0079 case Transaction::DownloadingStatus: 0080 return i18nc("@info:status", "Downloading"); 0081 case Transaction::CommittingStatus: 0082 switch (transaction->role()) { 0083 case Transaction::InstallRole: 0084 return i18nc("@info:status", "Installing"); 0085 case Transaction::RemoveRole: 0086 return i18nc("@info:status", "Removing"); 0087 case Transaction::ChangeAddonsRole: 0088 return i18nc("@info:status", "Changing Addons"); 0089 } 0090 break; 0091 case Transaction::DoneStatus: 0092 return i18nc("@info:status", "Done"); 0093 case Transaction::DoneWithErrorStatus: 0094 return i18nc("@info:status", "Failed"); 0095 case Transaction::CancelledStatus: 0096 return i18nc("@info:status", "Cancelled"); 0097 } 0098 break; 0099 case TransactionRole: 0100 return QVariant::fromValue<QObject *>(transaction); 0101 case ResourceRole: 0102 return QVariant::fromValue<QObject *>(transaction->resource()); 0103 } 0104 0105 return QVariant(); 0106 } 0107 0108 Transaction *TransactionModel::transactionFromResource(AbstractResource *resource) const 0109 { 0110 for (const auto transaction : std::as_const(m_transactions)) { 0111 if (transaction->resource() == resource) { 0112 return transaction; 0113 } 0114 } 0115 0116 return nullptr; 0117 } 0118 0119 QModelIndex TransactionModel::indexOf(Transaction *transaction) const 0120 { 0121 int row = m_transactions.indexOf(transaction); 0122 QModelIndex ret = index(row); 0123 Q_ASSERT(!transaction || ret.isValid()); 0124 return ret; 0125 } 0126 0127 QModelIndex TransactionModel::indexOf(AbstractResource *resource) const 0128 { 0129 Transaction *transaction = transactionFromResource(resource); 0130 0131 return indexOf(transaction); 0132 } 0133 0134 void TransactionModel::addTransaction(Transaction *transaction) 0135 { 0136 if (!transaction) { 0137 return; 0138 } 0139 0140 if (m_transactions.contains(transaction)) { 0141 return; 0142 } 0143 0144 if (m_transactions.isEmpty()) { 0145 Q_EMIT startingFirstTransaction(); 0146 } 0147 0148 int before = m_transactions.size(); 0149 beginInsertRows(QModelIndex(), before, before + 1); 0150 m_transactions.append(transaction); 0151 0152 if (before == 0) { // Should emit before count changes 0153 Q_EMIT mainTransactionTextChanged(); 0154 } 0155 endInsertRows(); 0156 0157 connect(transaction, &Transaction::statusChanged, this, [this, transaction]() { 0158 transactionChanged(transaction, StatusTextRole); 0159 }); 0160 connect(transaction, &Transaction::cancellableChanged, this, [this, transaction]() { 0161 transactionChanged(transaction, CancellableRole); 0162 }); 0163 connect(transaction, &Transaction::progressChanged, this, [this, transaction]() { 0164 transactionChanged(transaction, ProgressRole); 0165 Q_EMIT progressChanged(); 0166 }); 0167 0168 Q_EMIT transactionAdded(transaction); 0169 } 0170 0171 void TransactionModel::removeTransaction(Transaction *transaction) 0172 { 0173 Q_ASSERT(transaction); 0174 transaction->deleteLater(); 0175 int index = m_transactions.indexOf(transaction); 0176 if (index < 0) { 0177 qCWarning(LIBDISCOVER_LOG) << "transaction not part of the model" << transaction; 0178 return; 0179 } 0180 0181 disconnect(transaction, nullptr, this, nullptr); 0182 0183 beginRemoveRows(QModelIndex(), index, index); 0184 m_transactions.removeAt(index); 0185 endRemoveRows(); 0186 0187 Q_EMIT transactionRemoved(transaction); 0188 if (m_transactions.isEmpty()) { 0189 Q_EMIT lastTransactionFinished(); 0190 } 0191 0192 if (index == 0) { 0193 Q_EMIT mainTransactionTextChanged(); 0194 } 0195 } 0196 0197 void TransactionModel::transactionChanged(Transaction *transaction, int role) 0198 { 0199 QModelIndex index = indexOf(transaction); 0200 Q_EMIT dataChanged(index, index, {role}); 0201 } 0202 0203 int TransactionModel::progress() const 0204 { 0205 int sum = 0; 0206 int count = 0; 0207 for (const auto transaction : std::as_const(m_transactions)) { 0208 if (transaction->isActive() && transaction->isVisible()) { 0209 sum += transaction->progress(); 0210 ++count; 0211 } 0212 } 0213 return count == 0 ? 0 : sum / count; 0214 } 0215 0216 QString TransactionModel::mainTransactionText() const 0217 { 0218 return m_transactions.isEmpty() ? QString() : m_transactions.constFirst()->name(); 0219 }