179 lines
5.4 KiB
C++
179 lines
5.4 KiB
C++
// SPDX-License-Identifier: MIT
|
|
|
|
#include "toolmodel.h"
|
|
|
|
#include <QMap>
|
|
#include <QDebug>
|
|
#include <QFile>
|
|
#include <QFileInfo>
|
|
#include <QJsonArray>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QStandardPaths>
|
|
|
|
#include <algorithm>
|
|
#include <utility>
|
|
|
|
namespace
|
|
{
|
|
QStringList readConfigurationCommand(const QString &packageName)
|
|
{
|
|
const QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
|
|
QStringLiteral("fedora-tools/settings/") + packageName + QStringLiteral(".json"));
|
|
if (path.isEmpty()) {
|
|
return {};
|
|
}
|
|
QFile file(path);
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
|
qWarning() << "Cannot read tool configuration registration:" << path << file.errorString();
|
|
return {};
|
|
}
|
|
QJsonParseError error;
|
|
const auto document = QJsonDocument::fromJson(file.readAll(), &error);
|
|
const auto command = document.object().value(QStringLiteral("command")).toArray();
|
|
if (error.error != QJsonParseError::NoError || command.isEmpty()) {
|
|
qWarning() << "Invalid tool configuration registration:" << path;
|
|
return {};
|
|
}
|
|
QStringList result;
|
|
for (const auto &argument : command) {
|
|
if (!argument.isString()) {
|
|
qWarning() << "Invalid tool configuration argument:" << path;
|
|
return {};
|
|
}
|
|
result.append(argument.toString());
|
|
}
|
|
const QFileInfo executable(result.first());
|
|
if (!executable.isAbsolute() || !executable.isExecutable() || !executable.isFile()) {
|
|
qWarning() << "Tool configuration executable is unavailable:" << result.first();
|
|
return {};
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
ToolModel::ToolModel(QObject *parent)
|
|
: QAbstractListModel(parent)
|
|
{
|
|
}
|
|
|
|
int ToolModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
return parent.isValid() ? 0 : m_tools.size();
|
|
}
|
|
|
|
QVariant ToolModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid() || index.row() < 0 || index.row() >= m_tools.size()) {
|
|
return {};
|
|
}
|
|
|
|
const Tool &tool = m_tools.at(index.row());
|
|
switch (role) {
|
|
case PackageNameRole:
|
|
return tool.packageName;
|
|
case VersionRole:
|
|
return tool.version;
|
|
case AvailableVersionRole:
|
|
return tool.availableVersion;
|
|
case ArchitectureRole:
|
|
return tool.architecture;
|
|
case SummaryRole:
|
|
return tool.summary;
|
|
case InstalledRole:
|
|
return tool.installed;
|
|
case AvailableRole:
|
|
return tool.available;
|
|
case UpdateAvailableRole:
|
|
return tool.updateAvailable;
|
|
case ConfigurableRole:
|
|
return tool.installed
|
|
&& (!tool.configurationCommand.isEmpty()
|
|
|| tool.packageName == QStringLiteral("plasma-fingerprint-workaround")
|
|
|| tool.packageName == QStringLiteral("plasma-task-group-shortcuts")
|
|
|| tool.packageName == QStringLiteral("touchpad-hold-tap"));
|
|
case ExternalConfigurationRole:
|
|
return tool.installed && !tool.configurationCommand.isEmpty();
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
|
|
QHash<int, QByteArray> ToolModel::roleNames() const
|
|
{
|
|
return {
|
|
{PackageNameRole, "packageName"},
|
|
{VersionRole, "version"},
|
|
{AvailableVersionRole, "availableVersion"},
|
|
{ArchitectureRole, "architecture"},
|
|
{SummaryRole, "summary"},
|
|
{InstalledRole, "installed"},
|
|
{AvailableRole, "available"},
|
|
{UpdateAvailableRole, "updateAvailable"},
|
|
{ConfigurableRole, "configurable"},
|
|
{ExternalConfigurationRole, "externalConfiguration"},
|
|
};
|
|
}
|
|
|
|
void ToolModel::setPackages(const QList<PackageRecord> &installed,
|
|
const QList<PackageRecord> &available,
|
|
const QSet<QString> &updates)
|
|
{
|
|
QMap<QString, Tool> tools;
|
|
|
|
for (const PackageRecord &package : installed) {
|
|
Tool &tool = tools[package.name];
|
|
tool.packageName = package.name;
|
|
tool.version = package.version;
|
|
tool.architecture = package.architecture;
|
|
tool.summary = package.summary;
|
|
tool.installed = true;
|
|
tool.configurationCommand = readConfigurationCommand(package.name);
|
|
}
|
|
|
|
for (const PackageRecord &package : available) {
|
|
Tool &tool = tools[package.name];
|
|
tool.packageName = package.name;
|
|
tool.availableVersion = package.version;
|
|
tool.architecture = package.architecture;
|
|
if (!tool.installed) {
|
|
tool.summary = package.summary;
|
|
}
|
|
tool.available = true;
|
|
tool.updateAvailable = tool.installed && updates.contains(package.name);
|
|
}
|
|
|
|
QList<Tool> merged = tools.values();
|
|
std::ranges::sort(merged, [](const Tool &left, const Tool &right) {
|
|
return left.packageName < right.packageName;
|
|
});
|
|
|
|
beginResetModel();
|
|
m_tools = std::move(merged);
|
|
endResetModel();
|
|
}
|
|
|
|
bool ToolModel::mayInstall(const QString &packageName) const
|
|
{
|
|
return std::ranges::any_of(m_tools, [&packageName](const Tool &tool) {
|
|
return tool.packageName == packageName && tool.available;
|
|
});
|
|
}
|
|
|
|
bool ToolModel::mayRemove(const QString &packageName) const
|
|
{
|
|
return std::ranges::any_of(m_tools, [&packageName](const Tool &tool) {
|
|
return tool.packageName == packageName && tool.installed;
|
|
});
|
|
}
|
|
|
|
QStringList ToolModel::configurationCommand(const QString &packageName) const
|
|
{
|
|
for (const Tool &tool : m_tools) {
|
|
if (tool.packageName == packageName && tool.installed) {
|
|
return tool.configurationCommand;
|
|
}
|
|
}
|
|
return {};
|
|
}
|