File indexing completed on 2024-05-19 05:29:09
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Aleix Pol Gonzalez <aleixpol@blue-systems.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "PackageKitSourcesBackend.h" 0008 #include "PackageKitBackend.h" 0009 #include "config-paths.h" 0010 #include <KDesktopFile> 0011 #include <KIO/ApplicationLauncherJob> 0012 #include <KLocalizedString> 0013 #include <PackageKit/Daemon> 0014 #include <QDebug> 0015 #include <QProcess> 0016 #include <QRegularExpression> 0017 #include <QStandardItemModel> 0018 #include <resources/AbstractResourcesBackend.h> 0019 #include <resources/DiscoverAction.h> 0020 #include <resources/SourcesModel.h> 0021 0022 class PKSourcesModel : public QStandardItemModel 0023 { 0024 public: 0025 PKSourcesModel(PackageKitSourcesBackend *backend) 0026 : QStandardItemModel(backend) 0027 , m_backend(backend) 0028 { 0029 } 0030 0031 bool setData(const QModelIndex &index, const QVariant &value, int role) override 0032 { 0033 auto item = itemFromIndex(index); 0034 if (!item) { 0035 return false; 0036 } 0037 0038 switch (role) { 0039 case Qt::CheckStateRole: { 0040 auto transaction = PackageKit::Daemon::global()->repoEnable(item->data(AbstractSourcesBackend::IdRole).toString(), value.toInt() == Qt::Checked); 0041 connect(transaction, &PackageKit::Transaction::errorCode, m_backend, &PackageKitSourcesBackend::transactionError); 0042 return true; 0043 } 0044 } 0045 item->setData(value, role); 0046 return true; 0047 } 0048 0049 private: 0050 PackageKitSourcesBackend *m_backend; 0051 }; 0052 0053 static DiscoverAction *createActionForService(const QString &servicePath, PackageKitSourcesBackend *backend) 0054 { 0055 DiscoverAction *action = new DiscoverAction(backend); 0056 KDesktopFile parser(servicePath); 0057 action->setIconName(parser.readIcon()); 0058 action->setText(parser.readName()); 0059 action->setToolTip(parser.readComment()); 0060 QObject::connect(action, &DiscoverAction::triggered, action, [backend, servicePath]() { 0061 KService::Ptr service = KService::serviceByStorageId(servicePath); 0062 if (!service) { 0063 qWarning() << "Failed to find service" << servicePath; 0064 return; 0065 } 0066 0067 auto *job = new KIO::ApplicationLauncherJob(service); 0068 QObject::connect(job, &KJob::finished, backend, [backend, service](KJob *job) { 0069 if (job->error()) { 0070 Q_EMIT backend->passiveMessage(i18n("Failed to start '%1': %2", service->name(), job->errorString())); 0071 } 0072 }); 0073 job->start(); 0074 }); 0075 return action; 0076 } 0077 0078 PackageKitSourcesBackend::PackageKitSourcesBackend(AbstractResourcesBackend *parent) 0079 : AbstractSourcesBackend(parent) 0080 , m_sources(new PKSourcesModel(this)) 0081 { 0082 connect(PackageKit::Daemon::global(), &PackageKit::Daemon::repoListChanged, this, &PackageKitSourcesBackend::resetSources); 0083 connect(SourcesModel::global(), &SourcesModel::showingNow, this, &PackageKitSourcesBackend::resetSources); 0084 0085 // Kubuntu-based 0086 auto addNativeSourcesManager = [this](const QString &file) { 0087 auto service = PackageKitBackend::locateService(file); 0088 if (!service.isEmpty()) { 0089 m_actions += QVariant::fromValue<QObject *>(createActionForService(service, this)); 0090 } 0091 }; 0092 0093 // New Ubuntu 0094 addNativeSourcesManager(QStringLiteral("software-properties-qt.desktop")); 0095 0096 // Old Ubuntu 0097 addNativeSourcesManager(QStringLiteral("software-properties-kde.desktop")); 0098 0099 // OpenSuse 0100 addNativeSourcesManager(QStringLiteral("YaST2/sw_source.desktop")); 0101 } 0102 0103 QString PackageKitSourcesBackend::idDescription() 0104 { 0105 return i18n("Repository URL:"); 0106 } 0107 0108 QStandardItem *PackageKitSourcesBackend::findItemForId(const QString &id) const 0109 { 0110 for (int i = 0, c = m_sources->rowCount(); i < c; ++i) { 0111 auto it = m_sources->item(i); 0112 if (it->data(AbstractSourcesBackend::IdRole).toString() == id) { 0113 return it; 0114 } 0115 } 0116 return nullptr; 0117 } 0118 0119 void PackageKitSourcesBackend::addRepositoryDetails(const QString &id, const QString &description, bool enabled) 0120 { 0121 bool add = false; 0122 QStandardItem *item = findItemForId(id); 0123 0124 if (!item) { 0125 item = new QStandardItem(description); 0126 if (PackageKit::Daemon::backendName() == QLatin1String("aptcc")) { 0127 QRegularExpression exp(QStringLiteral("^/etc/apt/sources.list.d/(.+?).list:.*")); 0128 0129 auto matchIt = exp.globalMatch(id); 0130 if (matchIt.hasNext()) { 0131 auto match = matchIt.next(); 0132 item->setData(match.captured(1), Qt::ToolTipRole); 0133 } 0134 } 0135 item->setCheckable(PackageKit::Daemon::roles() & PackageKit::Transaction::RoleRepoEnable); 0136 add = true; 0137 } 0138 item->setData(id, IdRole); 0139 item->setCheckState(enabled ? Qt::Checked : Qt::Unchecked); 0140 item->setEnabled(true); 0141 0142 if (add) { 0143 m_sources->appendRow(item); 0144 } 0145 } 0146 0147 QAbstractItemModel *PackageKitSourcesBackend::sources() 0148 { 0149 return m_sources; 0150 } 0151 0152 bool PackageKitSourcesBackend::addSource(const QString & /*id*/) 0153 { 0154 return false; 0155 } 0156 0157 bool PackageKitSourcesBackend::removeSource(const QString &id) 0158 { 0159 auto transaction = PackageKit::Daemon::global()->repoRemove(id, false); 0160 connect(transaction, &PackageKit::Transaction::errorCode, this, &PackageKitSourcesBackend::transactionError); 0161 return false; 0162 } 0163 0164 QVariantList PackageKitSourcesBackend::actions() const 0165 { 0166 return m_actions; 0167 } 0168 0169 void PackageKitSourcesBackend::resetSources() 0170 { 0171 disconnect(SourcesModel::global(), &SourcesModel::showingNow, this, &PackageKitSourcesBackend::resetSources); 0172 for (int i = 0, count = m_sources->rowCount(); i < count; ++i) { 0173 m_sources->item(i, 0)->setEnabled(false); 0174 } 0175 auto transaction = PackageKit::Daemon::global()->getRepoList(); 0176 connect(transaction, &PackageKit::Transaction::repoDetail, this, &PackageKitSourcesBackend::addRepositoryDetails); 0177 connect(transaction, &PackageKit::Transaction::errorCode, this, &PackageKitSourcesBackend::transactionError); 0178 connect(transaction, &PackageKit::Transaction::finished, this, [this] { 0179 for (int i = 0; i < m_sources->rowCount();) { 0180 if (!m_sources->item(i, 0)->isEnabled()) { 0181 m_sources->removeRow(i); 0182 } else { 0183 ++i; 0184 } 0185 } 0186 }); 0187 } 0188 0189 void PackageKitSourcesBackend::transactionError(PackageKit::Transaction::Error error, const QString &message) 0190 { 0191 Q_EMIT passiveMessage(message); 0192 qWarning() << "Transaction error: " << error << message << sender(); 0193 }