From 985657b9e4d8b2b22a775d34320fc65d14df4858 Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Sat, 31 Jan 2015 14:13:45 +0100 Subject: [PATCH] Add support for Qt5's native command line parser Qt 5.2 finally has grown a way for parsing command line arguments, namely QCommandLineParser. According to the KF5 porting docs, this is also the preferred choice for software using KDE Frameworks. This commit adds a Qt5-based implementation for AbstractCliParser and uses that instead of our own solution if Quassel is built against Qt5. We also add support for naming the values that are shown in the --help output, as QCommandLineParser can make use of that. Once we stop supporting Qt4, the CLI parser abstraction shall be killed, simplifying things a lot. --- src/common/CMakeLists.txt | 6 ++- src/common/abstractcliparser.h | 21 ++++----- src/common/cliparser.cpp | 8 ++-- src/common/main.cpp | 32 ++++++++------ src/common/qt5cliparser.cpp | 72 +++++++++++++++++++++++++++++++ src/common/qt5cliparser.h | 42 ++++++++++++++++++ src/uisupport/kcmdlinewrapper.cpp | 9 +++- 7 files changed, 159 insertions(+), 31 deletions(-) create mode 100644 src/common/qt5cliparser.cpp create mode 100644 src/common/qt5cliparser.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index fa48020d..3f08a2c0 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -9,7 +9,6 @@ set(SOURCES buffersyncer.cpp bufferviewconfig.cpp bufferviewmanager.cpp - cliparser.cpp compressor.cpp ctcpevent.cpp event.cpp @@ -46,6 +45,11 @@ set(SOURCES coreinfo.h ) +if (USE_QT5) + list(APPEND SOURCES qt5cliparser.cpp) +else() + list(APPEND SOURCES cliparser.cpp) +endif() if (QCA2_FOUND) set(SOURCES ${SOURCES} keyevent.cpp) diff --git a/src/common/abstractcliparser.h b/src/common/abstractcliparser.h index 2441a6e8..293ccd92 100644 --- a/src/common/abstractcliparser.h +++ b/src/common/abstractcliparser.h @@ -36,9 +36,9 @@ public: } - inline void addOption(const QString &longName, const char shortName = 0, const QString &help = QString(), const QString &def = QString()) + inline void addOption(const QString &longName, const char shortName = 0, const QString &help = QString(), const QString &valueName = QString(), const QString &def = QString()) { - addArgument(longName, CliParserArg(CliParserArg::CliArgOption, shortName, help, def)); + addArgument(longName, CliParserArg(CliParserArg::CliArgOption, shortName, help, valueName, def)); } @@ -54,20 +54,21 @@ protected: CliArgOption }; - CliParserArg(const CliArgType _type = CliArgInvalid, const char _shortName = 0, const QString _help = QString(), const QString _def = QString()) - : type(_type), - shortName(_shortName), - help(_help), - def(_def), - value(QString()), - boolValue(false) {}; + CliParserArg(const CliArgType type = CliArgInvalid, const char shortName = 0, const QString &help = QString(), const QString &valueName = QString(), const QString def = QString()) + : type(type) + , shortName(shortName) + , help(help) + , valueName(valueName) + , def(def) + {}; CliArgType type; char shortName; QString help; + QString valueName; QString def; QString value; - bool boolValue; + bool boolValue = false; }; virtual void addArgument(const QString &longName, const CliParserArg &arg) = 0; diff --git a/src/common/cliparser.cpp b/src/common/cliparser.cpp index ac70b4a1..2e94e559 100644 --- a/src/common/cliparser.cpp +++ b/src/common/cliparser.cpp @@ -32,10 +32,8 @@ CliParser::CliParser() : AbstractCliParser() } -void CliParser::addArgument(const QString &longName_, const CliParserArg &arg) +void CliParser::addArgument(const QString &longName, const CliParserArg &arg) { - QString longName = longName_; - longName.remove(QRegExp("\\s*<.*>\\s*")); // KCmdLineArgs takes args of the form "arg " if (argsMap.contains(longName)) qWarning() << "Warning: Multiple definition of argument" << longName; if (arg.shortName != 0 && !lnameOfShortArg(arg.shortName).isNull()) qWarning().nospace() << "Warning: Redefining shortName '" << arg.shortName << "' for " << longName << " previously defined for " << lnameOfShortArg(arg.shortName); @@ -189,8 +187,8 @@ void CliParser::usage() } else output.append(" "); lnameField.append(" --").append(arg.key()); - if (arg.value().type == CliParserArg::CliArgOption) { - lnameField.append("=[").append(arg.key().toUpper()).append("]"); + if (arg.value().type == CliParserArg::CliArgOption && !arg.value().valueName.isEmpty()) { + lnameField.append("=<").append(arg.value().valueName).append(">"); } output.append(lnameField.leftJustified(lnameFieldSize)); if (!arg.value().help.isEmpty()) { diff --git a/src/common/main.cpp b/src/common/main.cpp index 65525984..48b45c28 100644 --- a/src/common/main.cpp +++ b/src/common/main.cpp @@ -39,6 +39,10 @@ #ifdef HAVE_KDE4 # include # include "kcmdlinewrapper.h" +#elif defined HAVE_QT5 +# include "qt5cliparser.h" +#else +# include "cliparser.h" #endif #if !defined(BUILD_CORE) && defined(STATIC) @@ -47,13 +51,13 @@ Q_IMPORT_PLUGIN(qjpeg) Q_IMPORT_PLUGIN(qgif) #endif -#include "cliparser.h" #include "quassel.h" int main(int argc, char **argv) { Quassel::setupBuildInfo(); QCoreApplication::setApplicationName(Quassel::buildInfo().applicationName); + QCoreApplication::setApplicationVersion(Quassel::buildInfo().plainVersionString); QCoreApplication::setOrganizationName(Quassel::buildInfo().organizationName); QCoreApplication::setOrganizationDomain(Quassel::buildInfo().organizationDomain); @@ -95,6 +99,8 @@ int main(int argc, char **argv) KCmdLineArgs::init(argc, argv, &aboutData); cliParser = new KCmdLineWrapper(); +#elif defined HAVE_QT5 + cliParser = new Qt5CliParser(); #else cliParser = new CliParser(); #endif @@ -108,35 +114,35 @@ int main(int argc, char **argv) cliParser->addSwitch("help", 'h', "Display this help and exit"); cliParser->addSwitch("version", 'v', "Display version information"); #ifdef BUILD_QTUI - cliParser->addOption("configdir ", 'c', "Specify the directory holding the client configuration"); + cliParser->addOption("configdir", 'c', "Specify the directory holding the client configuration", "path"); #else - cliParser->addOption("configdir ", 'c', "Specify the directory holding configuration files, the SQlite database and the SSL certificate"); + cliParser->addOption("configdir", 'c', "Specify the directory holding configuration files, the SQlite database and the SSL certificate", "path"); #endif - cliParser->addOption("datadir ", 0, "DEPRECATED - Use --configdir instead"); + cliParser->addOption("datadir", 0, "DEPRECATED - Use --configdir instead", "path"); #ifndef BUILD_CORE // put client-only arguments here - cliParser->addOption("icontheme ", 0, "Override the system icon theme ('oxygen' is recommended)"); - cliParser->addOption("qss ", 0, "Load a custom application stylesheet"); + cliParser->addOption("icontheme", 0, "Override the system icon theme ('oxygen' is recommended)", "theme"); + cliParser->addOption("qss", 0, "Load a custom application stylesheet", "file.qss"); cliParser->addSwitch("debugbufferswitches", 0, "Enables debugging for bufferswitches"); cliParser->addSwitch("debugmodel", 0, "Enables debugging for models"); cliParser->addSwitch("hidewindow", 0, "Start the client minimized to the system tray"); #endif #ifndef BUILD_QTUI // put core-only arguments here - cliParser->addOption("listen
[,", 0, "The address(es) quasselcore will listen on", "::,0.0.0.0"); - cliParser->addOption("port ", 'p', "The port quasselcore will listen at", QString("4242")); + cliParser->addOption("listen", 0, "The address(es) quasselcore will listen on", "
[,
[,...]]", "::,0.0.0.0"); + cliParser->addOption("port", 'p', "The port quasselcore will listen at", "port", "4242"); cliParser->addSwitch("norestore", 'n', "Don't restore last core's state"); - cliParser->addOption("loglevel ", 'L', "Loglevel Debug|Info|Warning|Error", "Info"); + cliParser->addOption("loglevel", 'L', "Loglevel Debug|Info|Warning|Error", "level", "Info"); #ifdef HAVE_SYSLOG cliParser->addSwitch("syslog", 0, "Log to syslog"); #endif - cliParser->addOption("logfile ", 'l', "Log to a file"); - cliParser->addOption("select-backend ", 0, "Switch storage backend (migrating data if possible)"); + cliParser->addOption("logfile", 'l', "Log to a file", "path"); + cliParser->addOption("select-backend", 0, "Switch storage backend (migrating data if possible)", "backendidentifier"); cliParser->addSwitch("add-user", 0, "Starts an interactive session to add a new core user"); - cliParser->addOption("change-userpass ", 0, "Starts an interactive session to change the password of the user identified by username"); + cliParser->addOption("change-userpass", 0, "Starts an interactive session to change the password of the user identified by ", "username"); cliParser->addSwitch("oidentd", 0, "Enable oidentd integration"); - cliParser->addOption("oidentd-conffile ", 0, "Set path to oidentd configuration file"); + cliParser->addOption("oidentd-conffile", 0, "Set path to oidentd configuration file", "file"); #ifdef HAVE_SSL cliParser->addSwitch("require-ssl", 0, "Require SSL for client connections"); #endif diff --git a/src/common/qt5cliparser.cpp b/src/common/qt5cliparser.cpp new file mode 100644 index 00000000..e2249112 --- /dev/null +++ b/src/common/qt5cliparser.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2005-2015 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "qt5cliparser.h" + +#include +#include + +bool Qt5CliParser::init(const QStringList &arguments) +{ + _qCliParser.addHelpOption(); + _qCliParser.addVersionOption(); + _qCliParser.setApplicationDescription(QCoreApplication::translate("CliParser", "Quassel IRC is a modern, distributed IRC client.")); + + _qCliParser.process(arguments); + return true; // process() does error handling by itself +} + + +bool Qt5CliParser::isSet(const QString &longName) +{ + + return _qCliParser.isSet(longName); +} + + +QString Qt5CliParser::value(const QString &longName) +{ + return _qCliParser.value(longName); +} + + +void Qt5CliParser::usage() +{ + _qCliParser.showHelp(); +} + + +void Qt5CliParser::addArgument(const QString &longName, const AbstractCliParser::CliParserArg &arg) +{ + QStringList names(longName); + if (arg.shortName != 0) + names << QString(arg.shortName); + + switch(arg.type) { + case CliParserArg::CliArgSwitch: + _qCliParser.addOption(QCommandLineOption(names, arg.help)); + break; + case CliParserArg::CliArgOption: + _qCliParser.addOption(QCommandLineOption(names, arg.help, arg.valueName, arg.def)); + break; + default: + qWarning() << "Warning: Unrecognized argument:" << longName; + } +} diff --git a/src/common/qt5cliparser.h b/src/common/qt5cliparser.h new file mode 100644 index 00000000..1a7e7889 --- /dev/null +++ b/src/common/qt5cliparser.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2005-2015 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#pragma once + +#include + +#include "abstractcliparser.h" + + +class Qt5CliParser : public AbstractCliParser +{ +public: + bool init(const QStringList &arguments = QStringList()); + + QString value(const QString &longName); + bool isSet(const QString &longName); + void usage(); + +private: + void addArgument(const QString &longName, const CliParserArg &arg); + + QCommandLineParser _qCliParser; + +}; diff --git a/src/uisupport/kcmdlinewrapper.cpp b/src/uisupport/kcmdlinewrapper.cpp index fc102ccf..a263e3c3 100644 --- a/src/uisupport/kcmdlinewrapper.cpp +++ b/src/uisupport/kcmdlinewrapper.cpp @@ -27,11 +27,16 @@ KCmdLineWrapper::KCmdLineWrapper() } -void KCmdLineWrapper::addArgument(const QString &longName, const CliParserArg &arg) +void KCmdLineWrapper::addArgument(const QString &longName_, const CliParserArg &arg) { + QString longName = longName_; + if (arg.type == CliParserArg::CliArgOption && !arg.valueName.isEmpty()) + longName += " <" + arg.valueName + ">"; + if (arg.shortName != 0) { - _cmdLineOptions.add(QByteArray().append(arg.shortName)); + _cmdLineOptions.add(QByteArray(1, arg.shortName)); } + _cmdLineOptions.add(longName.toUtf8(), ki18n(arg.help.toUtf8()), arg.def.toUtf8()); } -- 2.20.1