1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
/*
* SPDX-FileCopyrightText: 2020 Alexey Minnekhanov <alexey.min@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "resources/DiscoverAction.h"
#include "AlpineApkAuthActionFactory.h"
#include "AlpineApkSourcesBackend.h"
#include "alpineapk_backend_logging.h" // generated by ECM
#include <QAction>
#include <QDebug>
#include <QVector>
// KF5
#include <KAuth/ExecuteJob>
#include <KLocalizedString>
// libapk-qt
#include <QtApk>
AlpineApkSourcesBackend::AlpineApkSourcesBackend(AbstractResourcesBackend *parent)
: AbstractSourcesBackend(parent)
, m_sourcesModel(new QStandardItemModel(this))
, m_refreshAction(new DiscoverAction(QStringLiteral("view-refresh"), QStringLiteral("Reload"), this))
, m_saveAction(new DiscoverAction(QStringLiteral("document-save"), QStringLiteral("Save"), this))
{
loadSources();
QObject::connect(m_refreshAction, &DiscoverAction::triggered, this, &AlpineApkSourcesBackend::loadSources);
QObject::connect(m_saveAction, &DiscoverAction::triggered, this, &AlpineApkSourcesBackend::saveSources);
// track enabling/disabling repo source
QObject::connect(m_sourcesModel, &QStandardItemModel::itemChanged, this, &AlpineApkSourcesBackend::onItemChanged);
}
QAbstractItemModel *AlpineApkSourcesBackend::sources()
{
return m_sourcesModel;
}
QStandardItem *AlpineApkSourcesBackend::sourceForId(const QString &id) const
{
for (int i = 0; i < m_sourcesModel->rowCount(); ++i) {
QStandardItem *item = m_sourcesModel->item(i, 0);
if (item->data(AbstractSourcesBackend::IdRole) == id) {
return item;
}
}
return nullptr;
}
bool AlpineApkSourcesBackend::addSource(const QString &id)
{
m_repos.append(QtApk::Repository(id, QString(), true));
fillModelFromRepos();
return true;
}
void AlpineApkSourcesBackend::loadSources()
{
m_repos = QtApk::Database::getRepositories();
fillModelFromRepos();
}
void AlpineApkSourcesBackend::fillModelFromRepos()
{
m_sourcesModel->clear();
for (const QtApk::Repository &repo : m_repos) {
if (repo.url.isEmpty()) {
continue;
}
qCDebug(LOG_ALPINEAPK) << "source backend: Adding source:" << repo.url << repo.enabled;
QStandardItem *it = new QStandardItem(repo.url);
it->setData(repo.url, AbstractSourcesBackend::IdRole);
it->setData(repo.comment, Qt::ToolTipRole);
it->setCheckable(true);
it->setCheckState(repo.enabled ? Qt::Checked : Qt::Unchecked);
m_sourcesModel->appendRow(it);
}
}
void AlpineApkSourcesBackend::saveSources()
{
const QVariant repoUrls = QVariant::fromValue<QVector<QtApk::Repository>>(m_repos);
// run with elevated privileges
KAuth::ExecuteJob *reply = ActionFactory::createRepoconfigAction(repoUrls);
if (!reply)
return;
QObject::connect(reply, &KAuth::ExecuteJob::result, this, [this](KJob *job) {
KAuth::ExecuteJob *reply = static_cast<KAuth::ExecuteJob *>(job);
if (reply->error() != 0) {
const QString errMessage = reply->errorString();
qCWarning(LOG_ALPINEAPK) << "KAuth helper returned error:" << reply->error() << errMessage;
if (reply->error() == KAuth::ActionReply::Error::AuthorizationDeniedError) {
Q_EMIT passiveMessage(i18n("Authorization denied"));
} else {
Q_EMIT passiveMessage(i18n("Error: ") + errMessage);
}
}
this->loadSources();
});
reply->start();
}
void AlpineApkSourcesBackend::onItemChanged(QStandardItem *item)
{
// update internal storage vector and reload model from it
// otherwise checks state are not updated in UI
const Qt::CheckState cs = item->checkState();
const QModelIndex idx = m_sourcesModel->indexFromItem(item);
m_repos[idx.row()].enabled = (cs == Qt::Checked);
fillModelFromRepos();
}
bool AlpineApkSourcesBackend::removeSource(const QString &id)
{
const QStandardItem *it = sourceForId(id);
if (!it) {
qCWarning(LOG_ALPINEAPK) << "source backend: couldn't find " << id;
return false;
}
m_repos.remove(it->row());
return m_sourcesModel->removeRow(it->row());
}
QString AlpineApkSourcesBackend::idDescription()
{
return i18nc("Adding repo",
"Enter Alpine repository URL, for example: "
"http://dl-cdn.alpinelinux.org/alpine/edge/testing/");
}
QVariantList AlpineApkSourcesBackend::actions() const
{
static const QVariantList s_actions{
QVariant::fromValue<QObject *>(m_saveAction),
QVariant::fromValue<QObject *>(m_refreshAction),
};
return s_actions;
}
bool AlpineApkSourcesBackend::supportsAdding() const
{
return true;
}
bool AlpineApkSourcesBackend::canMoveSources() const
{
return true;
}
bool AlpineApkSourcesBackend::moveSource(const QString &sourceId, int delta)
{
int row = sourceForId(sourceId)->row();
QList<QStandardItem *> prevRow = m_sourcesModel->takeRow(row);
if (prevRow.isEmpty()) {
return false;
}
const int destRow = row + delta;
m_sourcesModel->insertRow(destRow, prevRow);
if (destRow == 0 || row == 0) {
Q_EMIT firstSourceIdChanged();
}
if (destRow == (m_sourcesModel->rowCount() - 1) || row == (m_sourcesModel->rowCount() - 1)) {
Q_EMIT lastSourceIdChanged();
}
// swap also items in internal storage vector
m_repos.swapItemsAt(row, destRow);
return true;
}
|