Publish tool cleanup and Framework monitoring refinements

This commit is contained in:
ajp_anton
2026-09-12 05:17:02 +00:00
parent db352083cf
commit 7f56368674
51 changed files with 1487 additions and 341 deletions
+2 -1
View File
@@ -15,10 +15,11 @@ include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
find_package(Qt6 6.8 REQUIRED COMPONENTS Core Quick Test)
find_package(Qt6 6.8 REQUIRED COMPONENTS Core Quick)
find_package(KF6 6.0 REQUIRED COMPONENTS Auth Config CoreAddons I18n KCMUtils)
add_subdirectory(src)
if(BUILD_TESTING)
find_package(Qt6 6.8 REQUIRED COMPONENTS Test)
add_subdirectory(tests)
endif()
@@ -1,6 +1,6 @@
Name: fedora-tools-settings
Version: 0.1.0
Release: 12%{?dist}
Release: 13%{?dist}
Summary: Plasma System Settings module for Fedora Tools
License: MIT
@@ -74,6 +74,10 @@ done
%{_datadir}/polkit-1/actions/se.ajpanton.fedoratools.policy
%changelog
* Sat Sep 12 2026 fedora-tools contributors - 0.1.0-13
- Share settings validation and report failed configuration writes
- Simplify ordering and source packaging
* Tue Sep 08 2026 fedora-tools contributors - 0.1.0-12
- Hide unsupported Framework hardware tools and flag incompatible local installs
+9 -9
View File
@@ -11,7 +11,6 @@
#include <KSharedConfig>
#include <QFile>
#include <QRegularExpression>
#include <QTimer>
#include <algorithm>
@@ -212,7 +211,10 @@ void FedoraToolsKcm::saveShortcutSettings(bool startWithFirst,
group.writeEntry("StartWithFirstWindow", startWithFirst);
group.writeEntry("InitialShiftOpensNewInstance", initialShiftOpensNew);
group.writeEntry("ShiftCyclesBackward", shiftCyclesBackward);
group.sync();
if (!group.sync()) {
setMessage(i18n("Could not save shortcut settings."), true);
return;
}
loadToolSettings();
setMessage(i18n("Shortcut settings were saved."));
}
@@ -222,7 +224,10 @@ void FedoraToolsKcm::resetShortcutSettings()
const auto config = KSharedConfig::openConfig(QStringLiteral("plasma-task-group-shortcutsrc"));
KConfigGroup group(config, QStringLiteral("Settings"));
group.deleteGroup();
group.sync();
if (!group.sync()) {
setMessage(i18n("Could not reset shortcut settings."), true);
return;
}
loadToolSettings();
setMessage(i18n("Shortcut settings were reset to their defaults."));
}
@@ -233,15 +238,10 @@ void FedoraToolsKcm::saveTouchpadSettings(int minimumAnchorAge,
int maximumTap,
const QString &outputEvent)
{
static const QRegularExpression eventName(QStringLiteral("^(BTN|KEY)_[A-Z0-9_]+$"));
if (m_busy) {
return;
}
if (minimumAnchorAge < 0 || minimumAnchorAge > 2000
|| minimumPause < 0 || minimumPause > 2000
|| minimumTap < 0 || minimumTap > maximumTap
|| maximumTap < 1 || maximumTap > 2000
|| !eventName.match(outputEvent).hasMatch()) {
if (!validTouchpadSettings(minimumAnchorAge, minimumPause, minimumTap, maximumTap, outputEvent)) {
setMessage(i18n("Enter valid timing values and an evdev BTN_* or KEY_* output event."), true);
return;
}
+7 -11
View File
@@ -8,7 +8,6 @@
#include <QFileInfo>
#include <QObject>
#include <QProcess>
#include <QRegularExpression>
#include <sys/stat.h>
@@ -192,17 +191,14 @@ public Q_SLOTS:
return KAuth::ActionReply::InvalidActionReply();
}
const int minimumAnchorAge = arguments.value(QStringLiteral("minimumAnchorAge")).toInt();
const int minimumPause = arguments.value(QStringLiteral("minimumPause")).toInt();
const int minimumTap = arguments.value(QStringLiteral("minimumTap")).toInt();
const int maximumTap = arguments.value(QStringLiteral("maximumTap")).toInt();
bool ageValid, pauseValid, tapValid, maximumValid;
const int minimumAnchorAge = arguments.value(QStringLiteral("minimumAnchorAge")).toInt(&ageValid);
const int minimumPause = arguments.value(QStringLiteral("minimumPause")).toInt(&pauseValid);
const int minimumTap = arguments.value(QStringLiteral("minimumTap")).toInt(&tapValid);
const int maximumTap = arguments.value(QStringLiteral("maximumTap")).toInt(&maximumValid);
const QString outputEvent = arguments.value(QStringLiteral("outputEvent")).toString();
static const QRegularExpression eventName(QStringLiteral("^(BTN|KEY)_[A-Z0-9_]+$"));
if (minimumAnchorAge < 0 || minimumAnchorAge > 2000
|| minimumPause < 0 || minimumPause > 2000
|| minimumTap < 0 || minimumTap > maximumTap
|| maximumTap < 1 || maximumTap > 2000
|| !eventName.match(outputEvent).hasMatch()) {
if (!ageValid || !pauseValid || !tapValid || !maximumValid
|| !validTouchpadSettings(minimumAnchorAge, minimumPause, minimumTap, maximumTap, outputEvent)) {
KAuth::ActionReply reply = KAuth::ActionReply::HelperErrorReply();
reply.addData(QStringLiteral("message"), QStringLiteral("The requested touchpad settings are invalid."));
return reply;
+12 -1
View File
@@ -36,7 +36,7 @@ QList<PackageRecord> parsePackageRecords(const QByteArray &output)
bool isValidPackageName(const QString &name)
{
static const QRegularExpression expression(QStringLiteral("^[a-z0-9][a-z0-9+._-]*$"));
static const QRegularExpression expression(QStringLiteral("\\A[a-z0-9][a-z0-9+._-]*\\z"));
return expression.match(name).hasMatch();
}
@@ -51,3 +51,14 @@ QString packageCompatibilityError(const QString &name, const QString &sys)
&& read(sys + QStringLiteral("/class/dmi/id/product_name")) == QLatin1String("Laptop 13 Pro (Intel Core Ultra Series 3)")) return {};
return QStringLiteral("Incompatible: requires Framework Laptop 13 Pro (Intel Core Ultra Series 3).");
}
bool validTouchpadSettings(int minimumAnchorAge, int minimumPause, int minimumTap,
int maximumTap, const QString &outputEvent)
{
static const QRegularExpression eventName(QStringLiteral("\\A(BTN|KEY)_[A-Z0-9_]+\\z"));
return minimumAnchorAge >= 0 && minimumAnchorAge <= 2000
&& minimumPause >= 0 && minimumPause <= 2000
&& minimumTap >= 0 && minimumTap <= maximumTap
&& maximumTap >= 1 && maximumTap <= 2000
&& eventName.match(outputEvent).hasMatch();
}
+2
View File
@@ -16,4 +16,6 @@ struct PackageRecord
QList<PackageRecord> parsePackageRecords(const QByteArray &output);
bool isValidPackageName(const QString &name);
bool validTouchpadSettings(int minimumAnchorAge, int minimumPause, int minimumTap,
int maximumTap, const QString &outputEvent);
QString packageCompatibilityError(const QString &name, const QString &sys = QStringLiteral("/sys"));
+1 -6
View File
@@ -150,13 +150,8 @@ void ToolModel::setPackages(const QList<PackageRecord> &installed,
tool.updateAvailable = tool.available && 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);
m_tools = tools.values(); // QMap already orders entries by package name.
endResetModel();
}
@@ -12,6 +12,17 @@ class PackageUtilsTest : public QObject
Q_OBJECT
private Q_SLOTS:
void validatesTouchpadSettings()
{
QVERIFY(validTouchpadSettings(100, 100, 10, 150, QStringLiteral("BTN_MIDDLE")));
QVERIFY(validTouchpadSettings(0, 0, 0, 2000, QStringLiteral("KEY_F13")));
QVERIFY(!validTouchpadSettings(-1, 100, 10, 150, QStringLiteral("BTN_MIDDLE")));
QVERIFY(!validTouchpadSettings(100, 2001, 10, 150, QStringLiteral("BTN_MIDDLE")));
QVERIFY(!validTouchpadSettings(100, 100, 151, 150, QStringLiteral("BTN_MIDDLE")));
QVERIFY(!validTouchpadSettings(100, 100, 0, 0, QStringLiteral("BTN_MIDDLE")));
QVERIFY(!validTouchpadSettings(100, 100, 10, 150, QStringLiteral("BTN_MIDDLE\n")));
QVERIFY(!validTouchpadSettings(100, 100, 10, 150, QStringLiteral("BTN_MIDDLE; reboot")));
}
void frameworkCompatibility() {
QTemporaryDir root;
QVERIFY(packageCompatibilityError(QStringLiteral("touchpad-hold-tap"), root.path()).isEmpty());
@@ -43,6 +54,7 @@ private Q_SLOTS:
QVERIFY(!isValidPackageName(QStringLiteral("--installroot=/tmp")));
QVERIFY(!isValidPackageName(QStringLiteral("tool; reboot")));
QVERIFY(!isValidPackageName(QStringLiteral("Tool")));
QVERIFY(!isValidPackageName(QStringLiteral("touchpad-hold-tap\n")));
}
};