#include #include #include #include #include #include #include #include #include #include #include #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; }