feat: update qwfassoc
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
#include <QApplication>
|
||||
#include <QCommandLineOption>
|
||||
#include <QCommandLineParser>
|
||||
#include <QLocale>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTranslator>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <wfassoc++.h>
|
||||
|
||||
#include "main_window.h"
|
||||
#include "manifest_parser.h"
|
||||
#include "scope.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Context used for translatable strings that live outside of any QObject.
|
||||
constexpr const char* kTranslationContext = "qwfassoc-standalone";
|
||||
|
||||
// Show a modal error dialog with the given message and return a non-zero
|
||||
// exit code. Used for the various fatal conditions that may occur before the
|
||||
// main dialog can be shown.
|
||||
int fatal(QWidget* parent, const QString& message) {
|
||||
QMessageBox::critical(parent, QApplication::applicationName(), message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Convert the --for command line value to a TargetScope. Throws if the value
|
||||
// is not one of the accepted strings.
|
||||
qwfassoc::TargetScope parseScope(const QString& value) {
|
||||
const QString normalized = value.trimmed().toLower();
|
||||
if (normalized == QStringLiteral("user")) {
|
||||
return qwfassoc::TargetScope::User;
|
||||
}
|
||||
if (normalized == QStringLiteral("system")) {
|
||||
return qwfassoc::TargetScope::System;
|
||||
}
|
||||
throw std::runtime_error(
|
||||
"Invalid value for --for. Use \"user\" or \"system\".");
|
||||
}
|
||||
|
||||
// Install the translation(s) matching the user's preferred UI language, if
|
||||
// any. Both the qwfassoc library's .qm and this executable's .qm are loaded
|
||||
// (their .ts files live under the per-project i18n/ directories and are
|
||||
// embedded under the ":/i18n" resource prefix by qt6_add_translations).
|
||||
void installTranslators(QApplication& app) {
|
||||
const QStringList uiLanguages = QLocale::system().uiLanguages();
|
||||
for (const QString& locale : uiLanguages) {
|
||||
const QString name = QLocale(locale).name();
|
||||
|
||||
QTranslator* libTranslator = new QTranslator(&app);
|
||||
if (libTranslator->load(QStringLiteral(":/i18n/qwfassoc_") + name)) {
|
||||
app.installTranslator(libTranslator);
|
||||
}
|
||||
|
||||
QTranslator* appTranslator = new QTranslator(&app);
|
||||
if (appTranslator->load(
|
||||
QStringLiteral(":/i18n/qwfassoc-standalone_") + name)) {
|
||||
app.installTranslator(appTranslator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
QApplication app(argc, argv);
|
||||
QApplication::setApplicationName(QStringLiteral("qwfassoc-standalone"));
|
||||
|
||||
// Install available translations before any translatable string is
|
||||
// resolved so that tr() and QCoreApplication::translate() pick up the
|
||||
// right language.
|
||||
installTranslators(app);
|
||||
|
||||
QApplication::setApplicationDisplayName(
|
||||
QCoreApplication::translate(kTranslationContext,
|
||||
"qwfassoc - wfassoc Configurator"));
|
||||
|
||||
// Parse command line arguments using Qt's built-in parser.
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(
|
||||
QCoreApplication::translate(
|
||||
kTranslationContext,
|
||||
"Qt-based GUI executable for the wfassoc library."));
|
||||
parser.addHelpOption();
|
||||
|
||||
QCommandLineOption manifestOption(
|
||||
QStringList() << QStringLiteral("c") << QStringLiteral("manifest"),
|
||||
QCoreApplication::translate(kTranslationContext,
|
||||
"Path to the application manifest TOML file."),
|
||||
QStringLiteral("manifest"));
|
||||
QCommandLineOption forOption(
|
||||
QStringList() << QStringLiteral("f") << QStringLiteral("for"),
|
||||
QCoreApplication::translate(kTranslationContext,
|
||||
"Target scope: \"user\" or \"system\"."),
|
||||
QStringLiteral("scope"));
|
||||
|
||||
parser.addOption(manifestOption);
|
||||
parser.addOption(forOption);
|
||||
parser.process(app);
|
||||
|
||||
// Validate that both mandatory options were provided with sane values.
|
||||
const QString manifestPath = parser.value(manifestOption);
|
||||
const QString forValue = parser.value(forOption);
|
||||
|
||||
if (manifestPath.isEmpty()) {
|
||||
return fatal(nullptr,
|
||||
QCoreApplication::translate(
|
||||
kTranslationContext,
|
||||
"The --manifest/-c option is required."));
|
||||
}
|
||||
if (forValue.isEmpty()) {
|
||||
return fatal(nullptr,
|
||||
QCoreApplication::translate(
|
||||
kTranslationContext,
|
||||
"The --for/-f option is required."));
|
||||
}
|
||||
|
||||
qwfassoc::TargetScope scope;
|
||||
try {
|
||||
scope = parseScope(forValue);
|
||||
} catch (const std::exception& e) {
|
||||
return fatal(nullptr, QString::fromUtf8(e.what()));
|
||||
}
|
||||
|
||||
// Initialize the wfassoc runtime. WFStartup must run before most other
|
||||
// wfassoc calls; if it fails we cannot proceed.
|
||||
if (!wfassoc::WFStartup()) {
|
||||
return fatal(nullptr,
|
||||
QString::fromUtf8(wfassoc::WFGetLastError()));
|
||||
}
|
||||
|
||||
// Build the manifest -> schema -> program pipeline and run the dialog.
|
||||
// Program construction consumes the schema (move) and performs the deep
|
||||
// validation (identifier format, dangling references, etc.).
|
||||
int exitCode = 0;
|
||||
try {
|
||||
qwfassoc::Manifest manifest =
|
||||
qwfassoc::parseManifestFile(manifestPath.toStdString());
|
||||
wfassocpp::Schema schema = qwfassoc::buildSchema(manifest);
|
||||
wfassocpp::Program program(std::move(schema));
|
||||
|
||||
qwfassoc::MainWindow window(std::move(program), scope);
|
||||
exitCode = window.exec();
|
||||
} catch (const std::exception& e) {
|
||||
wfassoc::WFShutdown();
|
||||
return fatal(nullptr, QString::fromUtf8(e.what()));
|
||||
}
|
||||
|
||||
wfassoc::WFShutdown();
|
||||
return exitCode;
|
||||
}
|
||||
Reference in New Issue
Block a user