[education/rkward] rkward: Move all command-line option handling to dedicated class

Thomas Friedrichsmeier null at kde.org
Sat Jun 8 23:21:01 BST 2024


Git commit cd57c549ca32c7e514e220fcd0929234d14f2b69 by Thomas Friedrichsmeier.
Committed on 08/06/2024 at 22:08.
Pushed by tfry into branch 'master'.

Move all command-line option handling to dedicated class

M  +12   -40   rkward/main.cpp
M  +1    -0    rkward/misc/CMakeLists.txt
A  +63   -0    rkward/misc/rkcommandlineargs.cpp     [License: GPL(v2.0+)]
A  +51   -0    rkward/misc/rkcommandlineargs.h     [License: GPL(v2.0+)]
M  +3    -2    rkward/rbackend/rkfrontendtransmitter.cpp
M  +5    -4    rkward/rkward.cpp
M  +0    -2    rkward/settings/rksettingsmodulegeneral.cpp
M  +0    -6    rkward/settings/rksettingsmodulegeneral.h

https://invent.kde.org/education/rkward/-/commit/cd57c549ca32c7e514e220fcd0929234d14f2b69

diff --git a/rkward/main.cpp b/rkward/main.cpp
index 000e28fb2..b16d7a9b1 100644
--- a/rkward/main.cpp
+++ b/rkward/main.cpp
@@ -1,6 +1,6 @@
 /*
 main.cpp - This file is part of RKWard (https://rkward.kde.org). Created: Tue Oct 29 2002
-SPDX-FileCopyrightText: 2002-2023 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
+SPDX-FileCopyrightText: 2002-2024 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
 SPDX-FileContributor: The RKWard Team <rkward-devel at kde.org>
 SPDX-License-Identifier: GPL-2.0-or-later
 */
@@ -60,7 +60,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
 #include <QThread>
 #include <QApplication>
 #include <QUrl>
-#include <QCommandLineParser>
 #include <QTime>
 #include <QSettings>
 #include <QStandardPaths>
@@ -83,6 +82,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
 #include "windows/rkdebugmessagewindow.h"
 #include "misc/rkcommonfunctions.h"
 #include "../3rdparty/KDSingleApplication/kdsingleapplication.h"
+#include "misc/rkcommandlineargs.h"
 
 #ifdef Q_OS_WIN
 	// these are needed for the exit hack.
@@ -279,51 +279,23 @@ int main (int argc, char *argv[]) {
 	aboutData.setOtherText(QString("<p><b>%1</b></p><ul><li><a href=\"https://www.jstatsoft.org/article/view/v049i09\">%2</a></li><li>Friedrichsmeier, T. & the RKWard Team (%3). RKWard: %4. Version %5. %6</li></ul>").arg(i18n("How to cite:"), i18n("Peer-reviewed article in the Journal of Statistical Software"), aboutData.copyrightStatement().right(4), aboutData.shortDescription(), aboutData.version(), aboutData.homepage()));
 	KAboutData::setApplicationData (aboutData);
 
-	QCommandLineParser parser;
-	aboutData.setupCommandLine(&parser);
-	parser.addOption (QCommandLineOption ("evaluate", i18n ("After starting (and after loading the specified workspace, if applicable), evaluate the given R code."), "Rcode", QString ()));
-	parser.addOption (QCommandLineOption ("debug-level", i18n ("Verbosity of debug messages (0-5)"), "level", "2"));
-	parser.addOption (QCommandLineOption ("debug-flags", i18n ("Mask for components to debug (see debug.h)"), "flags", QString::number (DEBUG_ALL)));
-	parser.addOption (QCommandLineOption ("debug-output", i18n ("Where to send debug message (file|terminal)"), "where", "file"));
-	parser.addOption (QCommandLineOption ("backend-debugger", i18n ("Debugger for the backend. (Enclose any debugger arguments in single quotes ('') together with the command. Make sure to re-direct stdout!)"), "command", QString ()));
-	parser.addOption (QCommandLineOption ("r-executable", i18n ("Use specified R installation, instead of the one configured at compile time (note: rkward R library must be installed to that installation of R)"), "command", QString ()));
-	parser.addOption (QCommandLineOption ("reuse", i18n ("Reuse a running RKWard instance (if available). If a running instance is reused, only the file arguments will be interpreted, all other options will be ignored.")));
-	parser.addOption (QCommandLineOption ("autoreuse", i18n ("Behaves like --reuse, if any file arguments are also given, starts a new instance, otherwise. Intended for use in the .desktop file.")));
-	parser.addOption (QCommandLineOption ("nowarn-external", i18n ("When used in conjunction with rkward://runplugin/-URLs specified on the command line, suppresses the warning about application-external (untrusted) links.")));
-	parser.addOption(QCommandLineOption("quirkmode", i18n("Disable some startup validation code. Experimental option, not intended for regular use.")));
-	parser.addPositionalArgument ("files", i18n ("File or files to open, typically a workspace, or an R script file. When loading several things, you should specify the workspace, first."), "[Files...]");
-
-	parser.process (app);
-	aboutData.processCommandLine (&parser);
+	RKCommandLineArgs args(&aboutData, app);
 
 	// Set up debugging
-	RK_Debug::RK_Debug_Level = DL_FATAL - QString (parser.value ("debug-level")).toInt ();
-	RK_Debug::RK_Debug_Flags = QString (parser.value ("debug-flags")).toInt ();
-	RK_Debug_Terminal = QString (parser.value ("debug-output")) == "terminal";
-	if (RK_Debug::setupLogFile (QDir::tempPath () + "/rkward.frontend")) {
-		RK_DEBUG (APP, DL_INFO, "Full debug output is at %s", qPrintable (RK_Debug::debug_file->fileName ()));
+	RK_Debug::RK_Debug_Level = DL_FATAL - args[RKCommandLineArgs::DebugLevel].toInt();
+	RK_Debug::RK_Debug_Flags = args[RKCommandLineArgs::DebugFlags].toInt();
+	RK_Debug_Terminal = args[RKCommandLineArgs::DebugOutput].toString() == QLatin1String("terminal");
+	if (RK_Debug::setupLogFile(QDir::tempPath() + "/rkward.frontend")) {
+		RK_DEBUG(APP, DL_INFO, "Full debug output is at %s", qPrintable(RK_Debug::debug_file->fileName()));
 	} else {
 		RK_Debug_Terminal = true;
-		RK_DEBUG (APP, DL_INFO, "Failed to open debug file %s", qPrintable (RK_Debug::debug_file->fileName ()));
+		RK_DEBUG(APP, DL_INFO, "Failed to open debug file %s", qPrintable(RK_Debug::debug_file->fileName()));
 	}
-	qInstallMessageHandler (RKDebugMessageOutput);
+	qInstallMessageHandler(RKDebugMessageOutput);
 	RK_DO({
 		RK_DEBUG(APP, DL_DEBUG, "Basic runtime info (expected to be incomplete at this stage):\n%s", qPrintable(RKSessionVars::frontendSessionInfo().join("\n")));
 	}, APP, DL_DEBUG);
 
-	// handle positional (file) arguments, first
-	QStringList url_args = parser.positionalArguments ();
-	if (!url_args.isEmpty ()) {
-		for (int i = 0; i < url_args.size (); ++i) {
-			url_args[i] = QUrl::fromUserInput (url_args[i], QDir::currentPath (), QUrl::AssumeLocalFile).toString ();
-		}
-		RKSettingsModuleGeneral::setStartupOption("initial_urls", url_args);
-		RKSettingsModuleGeneral::setStartupOption("warn_external", !parser.isSet("nowarn-external"));
-	}
-	RKSettingsModuleGeneral::setStartupOption("evaluate", parser.value("evaluate"));
-	RKSettingsModuleGeneral::setStartupOption("backend-debugger", parser.value("backend-debugger"));
-	RKSettingsModuleGeneral::setStartupOption("quirkmode", parser.isSet("quirkmode"));
-
 	// MacOS may need some path adjustments, first
 #if defined(Q_OS_MACOS)
 	QString oldpath = qgetenv ("PATH");
@@ -349,7 +321,7 @@ int main (int argc, char *argv[]) {
 	}
 
 	// Handle --reuse option, by forwarding url arguments to existing RKWard process (if any) and exiting
-	if (parser.isSet ("reuse") || (parser.isSet ("autoreuse") && !url_args.isEmpty ())) {
+	if (args[RKCommandLineArgs::Reuse].toBool() || (args[RKCommandLineArgs::AutoReuse].toBool() && !args[RKCommandLineArgs::UrlArgs].toStringList().isEmpty())) {
 		if (!app_singleton.isPrimaryInstance()) {
 			QByteArray call;
 			QDataStream stream(&call, QIODevice::WriteOnly);
@@ -369,7 +341,7 @@ int main (int argc, char *argv[]) {
 	//- command line parameter
 	//- Specified in cfg file next to rkward executable
 	//- compile-time default
-	QString r_exe = parser.value ("r-executable");
+	QString r_exe = args[RKCommandLineArgs::RExecutable].toString();
 	if (!r_exe.isNull ()) {
 		r_exe = resolveRSpecOrFail (r_exe, i18n ("The R executable specified on the command line (%1) does not exist or is not executable.", r_exe));
 		RK_DEBUG (APP, DL_DEBUG, "Using R specified on command line");
diff --git a/rkward/misc/CMakeLists.txt b/rkward/misc/CMakeLists.txt
index 7575d7303..b040ab9cf 100644
--- a/rkward/misc/CMakeLists.txt
+++ b/rkward/misc/CMakeLists.txt
@@ -10,6 +10,7 @@ SET(misc_STAT_SRCS
    rkobjectlistview.cpp
    xmlhelper.cpp
    multistringselector.cpp
+   rkcommandlineargs.cpp
    rkcommonfunctions.cpp
    rkprogresscontrol.cpp
    rksaveobjectchooser.cpp
diff --git a/rkward/misc/rkcommandlineargs.cpp b/rkward/misc/rkcommandlineargs.cpp
new file mode 100644
index 000000000..6fdb06ae4
--- /dev/null
+++ b/rkward/misc/rkcommandlineargs.cpp
@@ -0,0 +1,63 @@
+/*
+rkcommandlineargs - This file is part of the RKWard project. Created: Tue May 21 2024
+SPDX-FileCopyrightText: 2024 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
+SPDX-FileContributor: The RKWard Team <rkward-devel at kde.org>
+SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#include "rkcommandlineargs.h"
+
+#include <KLocalizedString>
+#include <KAboutData>
+#include <QCommandLineParser>
+#include <QUrl>
+#include <QDir>
+
+#include "../debug.h"
+
+RKCommandLineArgs* RKCommandLineArgs::instance = nullptr;
+
+RKCommandLineArgs::RKCommandLineArgs(KAboutData *about, QCoreApplication &app) {
+	RK_TRACE(MISC);
+	RK_ASSERT(instance == nullptr);
+
+	instance = this;
+	QCommandLineParser parser;
+	about->setupCommandLine(&parser);
+
+	parser.addOption(QCommandLineOption("evaluate", i18n("After starting (and after loading the specified workspace, if applicable), evaluate the given R code."), "Rcode", QString()));
+	parser.addOption(QCommandLineOption("debug-level", i18n("Verbosity of debug messages (0-5)"), "level", "2"));
+	parser.addOption(QCommandLineOption("debug-flags", i18n("Mask for components to debug (see debug.h)"), "flags", QString::number(DEBUG_ALL)));
+	parser.addOption(QCommandLineOption("debug-output", i18n("Where to send debug message (file|terminal)"), "where", "file"));
+	parser.addOption(QCommandLineOption("backend-debugger", i18n("Debugger for the backend. (Enclose any debugger arguments in single quotes ('') together with the command. Make sure to re-direct stdout!)"), "command", QString()));
+	parser.addOption(QCommandLineOption("r-executable", i18n("Use specified R installation, instead of the one configured at compile time (note: rkward R library must be installed to that installation of R)"), "command", QString()));
+	parser.addOption(QCommandLineOption("reuse", i18n("Reuse a running RKWard instance (if available). If a running instance is reused, only the file arguments will be interpreted, all other options will be ignored.")));
+	parser.addOption(QCommandLineOption("autoreuse", i18n("Behaves like --reuse, if any file arguments are also given, starts a new instance, otherwise. Intended for use in the .desktop file.")));
+	parser.addOption(QCommandLineOption("nowarn-external", i18n("When used in conjunction with rkward://runplugin/-URLs specified on the command line, suppresses the warning about application-external (untrusted) links.")));
+	parser.addOption(QCommandLineOption("quirkmode", i18n("Disable some startup validation code. Experimental option, not intended for regular use.")));
+	parser.addPositionalArgument("files", i18n("File or files to open, typically a workspace, or an R script file. When loading several things, you should specify the workspace, first."), "[Files...]");
+
+	parser.process(app);
+	about->processCommandLine(&parser);
+
+	storage.resize(NUM_OPTIONS);
+	storage[Evaluate] = parser.value("evaluate");
+	storage[DebugLevel] = parser.value("debug-level").toInt();
+	storage[DebugFlags] = parser.value("debug-flags").toInt();
+	storage[DebugOutput] = parser.value("debug-output");
+	storage[BackendDebugger] = parser.value("backend-debugger");
+	storage[RExecutable] = parser.value("r-executable");
+	storage[Reuse] = parser.isSet("reuse");
+	storage[AutoReuse] = parser.isSet("autoreuse");
+	storage[NoWarnExternal] = parser.isSet("nowarn-external");
+	storage[QuirkMode] = parser.isSet("quirkmode");
+	QStringList url_args = parser.positionalArguments ();
+	if (!url_args.isEmpty ()) {
+		for (int i = 0; i < url_args.size(); ++i) {
+			url_args[i] = QUrl::fromUserInput(url_args[i], QDir::currentPath(), QUrl::AssumeLocalFile).toString();
+		}
+	}
+	storage[UrlArgs] = url_args;
+}
+
+#include "../debug.h"
diff --git a/rkward/misc/rkcommandlineargs.h b/rkward/misc/rkcommandlineargs.h
new file mode 100644
index 000000000..55bdca6bd
--- /dev/null
+++ b/rkward/misc/rkcommandlineargs.h
@@ -0,0 +1,51 @@
+/*
+rkcommandlineargs - This file is part of the RKWard project. Created: Tue May 21 2024
+SPDX-FileCopyrightText: 2024 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
+SPDX-FileContributor: The RKWard Team <rkward-devel at kde.org>
+SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#ifndef RKCOMMANDLINEARGS_H
+#define RKCOMMANDLINEARGS_H
+
+#include <QVariant>
+#include <QMap>
+#include <QCommandLineOption>
+
+class QCommandLineParser;
+class KAboutData;
+class QCoreApplication;
+
+class RKCommandLineArgs {
+public:
+	explicit RKCommandLineArgs(KAboutData *about, QCoreApplication &app);
+	~RKCommandLineArgs() {};
+	enum Option {
+		UrlArgs,
+		Evaluate,
+		DebugLevel,
+		DebugFlags,
+		DebugOutput,
+		BackendDebugger,
+		RExecutable,
+		Reuse,
+		AutoReuse,
+		NoWarnExternal,
+		QuirkMode,
+		Setup,
+
+		NUM_OPTIONS
+	};
+	void parseArgs(	QCommandLineParser *parser);
+	QVariant operator[](const Option op) const {
+		return storage[op];
+	}
+	static QVariant get(const Option op) {
+		return instance->storage[op];
+	};
+private:
+	QList<QVariant> storage;
+	static RKCommandLineArgs *instance;
+};
+
+#endif
diff --git a/rkward/rbackend/rkfrontendtransmitter.cpp b/rkward/rbackend/rkfrontendtransmitter.cpp
index 90d833a6d..cc8a6d9a7 100644
--- a/rkward/rbackend/rkfrontendtransmitter.cpp
+++ b/rkward/rbackend/rkfrontendtransmitter.cpp
@@ -10,6 +10,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
 #include "rkrbackendprotocol_frontend.h"
 #include "rkwarddevice/rkgraphicsdevice_frontendtransmitter.h"
 #include "rksessionvars.h"
+#include "../misc/rkcommandlineargs.h"
 #include "../settings/rksettingsmodulegeneral.h"
 
 #include <KLocalizedString>
@@ -107,7 +108,7 @@ QString localeDir () {
 void RKFrontendTransmitter::run () {
 	RK_TRACE (RBACKEND);
 
-	quirkmode = RKSettingsModuleGeneral::startupOption("quirkmode").toBool();
+	quirkmode = RKCommandLineArgs::get(RKCommandLineArgs::QuirkMode).toBool();
 
 	// start server
 	server = new QLocalServer (this);
@@ -135,7 +136,7 @@ void RKFrontendTransmitter::run () {
 
 	QStringList args;
 	args.append("CMD");
-	QString debugger = RKSettingsModuleGeneral::startupOption("backend-debugger").toString();
+	QString debugger = RKCommandLineArgs::get(RKCommandLineArgs::BackendDebugger).toString();
 	if (!debugger.isEmpty()) {
 		args += debugger.split(' ');
 	}
diff --git a/rkward/rkward.cpp b/rkward/rkward.cpp
index ac1628b80..a750416e8 100644
--- a/rkward/rkward.cpp
+++ b/rkward/rkward.cpp
@@ -53,6 +53,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
 #include "core/robjectlist.h"
 #include "core/renvironmentobject.h"
 #include "misc/rkstandardicons.h"
+#include "misc/rkcommandlineargs.h"
 #include "misc/rkcommonfunctions.h"
 #include "misc/rkxmlguisyncer.h"
 #include "misc/rkdialogbuttonbox.h"
@@ -222,9 +223,9 @@ void RKWardMainWindow::closeEvent (QCloseEvent *e) {
 void RKWardMainWindow::doPostInit () {
 	RK_TRACE (APP);
 
-	QStringList open_urls = RKSettingsModuleGeneral::takeStartupOption("initial_urls").toStringList();
-	bool warn_external = RKSettingsModuleGeneral::takeStartupOption("warn_external").toBool();
-	QString evaluate_code = RKSettingsModuleGeneral::takeStartupOption("evaluate").toString();
+	QStringList open_urls = RKCommandLineArgs::get(RKCommandLineArgs::UrlArgs).toStringList();
+	bool warn_external = !RKCommandLineArgs::get(RKCommandLineArgs::NoWarnExternal).toBool();
+	QString evaluate_code = RKCommandLineArgs::get(RKCommandLineArgs::Evaluate).toString();
 
 	initPlugins ();
 	gui_rebuild_locked = false;
@@ -650,7 +651,7 @@ void RKWardMainWindow::initActions() {
 				RKConsole::mainConsole()->resetConsole();
 				restart_now();
 			} else {
-				RCommand *c = new RCommand(QString("# Quit (restarting)"), RCommand::App | RCommand::EmptyCommand || RCommand::QuitCommand);
+				RCommand *c = new RCommand(QString("# Quit (restarting)"), RCommand::App | RCommand::EmptyCommand | RCommand::QuitCommand);
 				c->whenFinished(this, [this, restart_now]() { QTimer::singleShot(0, this, restart_now); });
 				RInterface::issueCommand(c);
 			}
diff --git a/rkward/settings/rksettingsmodulegeneral.cpp b/rkward/settings/rksettingsmodulegeneral.cpp
index ccea0e091..27b8207fc 100644
--- a/rkward/settings/rksettingsmodulegeneral.cpp
+++ b/rkward/settings/rksettingsmodulegeneral.cpp
@@ -51,8 +51,6 @@ bool RKSettingsModuleGeneral::installation_moved = false;
 QString RKSettingsModuleGeneral::previous_rkward_data_dir;
 RKConfigValue<int> RKSettingsModuleGeneral::num_recent_files { "Max number of recent files", 8 };
 
-QVariantMap RKSettingsModuleGeneral::startup_options;
-
 RKSettingsModuleGeneral::RKSettingsModuleGeneral (RKSettings *gui, QWidget *parent) : RKSettingsModule (gui, parent) {
 	RK_TRACE (SETTINGS);
 
diff --git a/rkward/settings/rksettingsmodulegeneral.h b/rkward/settings/rksettingsmodulegeneral.h
index 099c1af29..073937d07 100644
--- a/rkward/settings/rksettingsmodulegeneral.h
+++ b/rkward/settings/rksettingsmodulegeneral.h
@@ -92,10 +92,6 @@ public:
 	static bool rkwardVersionChanged () { return rkward_version_changed; };
 	/** Returns true, if rkward seems to have started from a different path than on the previous run. */
 	static bool installationMoved () { return installation_moved; };
-
-	static void setStartupOption(const QString &key, const QVariant &value) { startup_options[key] = value; };
-	static QVariant startupOption(const QString &key) { return startup_options.value(key); };
-	static QVariant takeStartupOption(const QString &key) { return startup_options.take(key); };
 private:
 	GetFileNameWidget *files_choser;
 	QButtonGroup *workplace_save_chooser;
@@ -117,8 +113,6 @@ private:
 	static bool rkward_version_changed;
 	static bool installation_moved;
 	static RKConfigValue<int> num_recent_files;
-
-	static QVariantMap startup_options;
 };
 
 #endif



More information about the rkward-tracker mailing list