From 30f6aea19467aa1dfc91b8fdc46fc244ba619bc4 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Wed, 1 Apr 2015 15:51:54 +0300 Subject: [PATCH] Hide warnings, minimal requirements for build is Qt 5.0.0. --HG-- branch : develop --- Valentina.pri | 2 +- Valentina.pro | 4 +- src/app/app.pro | 1 + src/app/container/vcontainer.cpp | 5 +- src/app/core/core.pri | 8 +- src/app/core/qcommandlineoption.cpp | 381 ++++++ src/app/core/qcommandlineoption.h | 87 ++ src/app/core/qcommandlineparser.cpp | 1119 +++++++++++++++++ src/app/core/qcommandlineparser.h | 101 ++ src/app/core/vapplication.cpp | 2 +- .../app/dialogstandardmeasurements.cpp | 9 +- src/app/dialogs/tools/dialogtool.h | 5 +- src/app/main.cpp | 8 +- src/app/mainwindow.cpp | 2 +- src/app/tools/drawTools/vtoolpoint.cpp | 5 +- src/app/tools/vdatatool.h | 2 +- src/app/undocommands/vundocommand.h | 3 +- src/app/visualization/visualization.h | 3 +- src/libs/ifc/exception/vexception.cpp | 3 +- src/libs/ifc/ifc.pro | 3 +- src/libs/ifc/xml/vdomdocument.h | 2 +- src/utils/logging.h | 100 ++ src/utils/utils.pri | 2 + 23 files changed, 1832 insertions(+), 25 deletions(-) create mode 100644 src/app/core/qcommandlineoption.cpp create mode 100644 src/app/core/qcommandlineoption.h create mode 100644 src/app/core/qcommandlineparser.cpp create mode 100644 src/app/core/qcommandlineparser.h create mode 100644 src/utils/logging.h create mode 100644 src/utils/utils.pri diff --git a/Valentina.pri b/Valentina.pri index 7d1a0fd8c..c374c02c5 100644 --- a/Valentina.pri +++ b/Valentina.pri @@ -150,7 +150,7 @@ GCC_DEBUG_CXXFLAGS += \ -Wmissing-format-attribute \ -Wswitch-default \ -Wuninitialized \ - -Wvariadic-macros \ + -Wno-variadic-macros \ -Wlogical-op \ -Wnoexcept \ -Wmissing-noreturn \ diff --git a/Valentina.pro b/Valentina.pro index 900c5dd70..f6d285335 100644 --- a/Valentina.pro +++ b/Valentina.pro @@ -1,9 +1,9 @@ include(Valentina.pri) -#Check if Qt version >= 5.2.0 +#Check if Qt version >= 5.0.0 !minQtVersion(5, 2, 0) { message("Cannot build Valentina with Qt version $${QT_VERSION}.") - error("Use at least Qt 5.2.0.") + error("Use at least Qt 5.0.0.") } TEMPLATE = subdirs diff --git a/src/app/app.pro b/src/app/app.pro index ce97be295..6434b95be 100644 --- a/src/app/app.pro +++ b/src/app/app.pro @@ -46,6 +46,7 @@ UI_DIR = uic # Suport subdirectories. Just better project code tree. include(app.pri) +include(../utils/utils.pri) # This include path help promoute VMainGraphicsView on main window. Without it compiler can't find path to custom view INCLUDEPATH += "$${PWD}/widgets" diff --git a/src/app/container/vcontainer.cpp b/src/app/container/vcontainer.cpp index ebcbf9354..9e2b51a36 100644 --- a/src/app/container/vcontainer.cpp +++ b/src/app/container/vcontainer.cpp @@ -27,13 +27,14 @@ *************************************************************************/ #include "vcontainer.h" -#include #include "../core/vapplication.h" #include "../geometry/varc.h" #include "../geometry/vsplinepath.h" +#include "../../utils/logging.h" + #include #include -#include +#include Q_LOGGING_CATEGORY(vCon, "v.container") diff --git a/src/app/core/core.pri b/src/app/core/core.pri index aa1e04485..406758bf8 100644 --- a/src/app/core/core.pri +++ b/src/app/core/core.pri @@ -4,9 +4,13 @@ HEADERS += \ $$PWD/vapplication.h \ $$PWD/undoevent.h \ - $$PWD/vsettings.h + $$PWD/vsettings.h \ + $$PWD/qcommandlineoption.h \ + $$PWD/qcommandlineparser.h SOURCES += \ $$PWD/vapplication.cpp \ $$PWD/undoevent.cpp \ - $$PWD/vsettings.cpp + $$PWD/vsettings.cpp \ + $$PWD/qcommandlineoption.cpp \ + $$PWD/qcommandlineparser.cpp diff --git a/src/app/core/qcommandlineoption.cpp b/src/app/core/qcommandlineoption.cpp new file mode 100644 index 000000000..798c113ce --- /dev/null +++ b/src/app/core/qcommandlineoption.cpp @@ -0,0 +1,381 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Laszlo Papp +** Copyright (C) 2013 David Faure +** Contact: http://www.qt.io/licensing/ +** +** $QT_BEGIN_LICENSE:LGPL21$ +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcommandlineoption.h" + +#include "qset.h" + +#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) + +class QCommandLineOptionPrivate : public QSharedData +{ +public: + inline QCommandLineOptionPrivate() + : hidden(false) + { } + + void setNames(const QStringList &nameList); + + //! The list of names used for this option. + QStringList names; + + //! The documentation name for the value, if one is expected + //! Example: "-o " means valueName == "file" + QString valueName; + + //! The description used for this option. + QString description; + + //! The list of default values used for this option. + QStringList defaultValues; + + //! Show or hide in --help + bool hidden; +}; + +/*! + \since 5.2 + \class QCommandLineOption + \brief The QCommandLineOption class defines a possible command-line option. + \inmodule QtCore + \ingroup shared + \ingroup tools + + This class is used to describe an option on the command line. It allows + different ways of defining the same option with multiple aliases possible. + It is also used to describe how the option is used - it may be a flag (e.g. \c{-v}) + or take a value (e.g. \c{-o file}). + + Examples: + \snippet code/src_corelib_tools_qcommandlineoption.cpp 0 + + \sa QCommandLineParser +*/ + +/*! + \fn QCommandLineOption &QCommandLineOption::operator=(QCommandLineOption &&other) + + Move-assigns \a other to this QCommandLineOption instance. + + \since 5.2 +*/ + +/*! + Constructs a command line option object with the name \a name. + + The name can be either short or long. If the name is one character in + length, it is considered a short name. Option names must not be empty, + must not start with a dash or a slash character, must not contain a \c{=} + and cannot be repeated. + + \sa setDescription(), setValueName(), setDefaultValues() +*/ +QCommandLineOption::QCommandLineOption(const QString &name) + : d(new QCommandLineOptionPrivate) +{ + d->setNames(QStringList(name)); +} + +/*! + Constructs a command line option object with the names \a names. + + This overload allows to set multiple names for the option, for instance + \c{o} and \c{output}. + + The names can be either short or long. Any name in the list that is one + character in length is a short name. Option names must not be empty, + must not start with a dash or a slash character, must not contain a \c{=} + and cannot be repeated. + + \sa setDescription(), setValueName(), setDefaultValues() +*/ +QCommandLineOption::QCommandLineOption(const QStringList &names) + : d(new QCommandLineOptionPrivate) +{ + d->setNames(names); +} + +/*! + Constructs a command line option object with the given arguments. + + The name of the option is set to \a name. + The name can be either short or long. If the name is one character in + length, it is considered a short name. Option names must not be empty, + must not start with a dash or a slash character, must not contain a \c{=} + and cannot be repeated. + + The description is set to \a description. It is customary to add a "." + at the end of the description. + + In addition, the \a valueName can be set if the option expects a value. + The default value for the option is set to \a defaultValue. + + In Qt versions before 5.4, this constructor was \c explicit. In Qt 5.4 + and later, it no longer is and can be used for C++11-style uniform + initialization: + + \snippet code/src_corelib_tools_qcommandlineoption.cpp cxx11-init + + \sa setDescription(), setValueName(), setDefaultValues() +*/ +QCommandLineOption::QCommandLineOption(const QString &name, const QString &description, + const QString &valueName, + const QString &defaultValue) + : d(new QCommandLineOptionPrivate) +{ + d->setNames(QStringList(name)); + setValueName(valueName); + setDescription(description); + setDefaultValue(defaultValue); +} + +/*! + Constructs a command line option object with the given arguments. + + This overload allows to set multiple names for the option, for instance + \c{o} and \c{output}. + + The names of the option are set to \a names. + The names can be either short or long. Any name in the list that is one + character in length is a short name. Option names must not be empty, + must not start with a dash or a slash character, must not contain a \c{=} + and cannot be repeated. + + The description is set to \a description. It is customary to add a "." + at the end of the description. + + In addition, the \a valueName can be set if the option expects a value. + The default value for the option is set to \a defaultValue. + + In Qt versions before 5.4, this constructor was \c explicit. In Qt 5.4 + and later, it no longer is and can be used for C++11-style uniform + initialization: + + \snippet code/src_corelib_tools_qcommandlineoption.cpp cxx11-init-list + + \sa setDescription(), setValueName(), setDefaultValues() +*/ +QCommandLineOption::QCommandLineOption(const QStringList &names, const QString &description, + const QString &valueName, + const QString &defaultValue) + : d(new QCommandLineOptionPrivate) +{ + d->setNames(names); + setValueName(valueName); + setDescription(description); + setDefaultValue(defaultValue); +} + +/*! + Constructs a QCommandLineOption object that is a copy of the QCommandLineOption + object \a other. + + \sa operator=() +*/ +QCommandLineOption::QCommandLineOption(const QCommandLineOption &other) + : d(other.d) +{ +} + +/*! + Destroys the command line option object. +*/ +QCommandLineOption::~QCommandLineOption() +{ +} + +/*! + Makes a copy of the \a other object and assigns it to this QCommandLineOption + object. +*/ +QCommandLineOption &QCommandLineOption::operator=(const QCommandLineOption &other) +{ + d = other.d; + return *this; +} + +/*! + \fn void QCommandLineOption::swap(QCommandLineOption &other) + + Swaps option \a other with this option. This operation is very + fast and never fails. +*/ + +/*! + Returns the names set for this option. + */ +QStringList QCommandLineOption::names() const +{ + return d->names; +} + +void QCommandLineOptionPrivate::setNames(const QStringList &nameList) +{ + QStringList newNames; + newNames.reserve(nameList.size()); + if (nameList.isEmpty()) + qWarning("QCommandLineOption: Options must have at least one name"); + foreach (const QString &name, nameList) { + if (name.isEmpty()) { + qWarning("QCommandLineOption: Option names cannot be empty"); + } else { + const QChar c = name.at(0); + if (c == QLatin1Char('-')) + qWarning("QCommandLineOption: Option names cannot start with a '-'"); + else if (c == QLatin1Char('/')) + qWarning("QCommandLineOption: Option names cannot start with a '/'"); + else if (name.contains(QLatin1Char('='))) + qWarning("QCommandLineOption: Option names cannot contain a '='"); + else + newNames.append(name); + } + } + // commit + names.swap(newNames); +} + +/*! + Sets the name of the expected value, for the documentation, to \a valueName. + + Options without a value assigned have a boolean-like behavior: + either the user specifies --option or they don't. + + Options with a value assigned need to set a name for the expected value, + for the documentation of the option in the help output. An option with names \c{o} and \c{output}, + and a value name of \c{file} will appear as \c{-o, --output }. + + Call QCommandLineParser::value() if you expect the option to be present + only once, and QCommandLineParser::values() if you expect that option + to be present multiple times. + + \sa valueName() + */ +void QCommandLineOption::setValueName(const QString &valueName) +{ + d->valueName = valueName; +} + +/*! + Returns the name of the expected value. + + If empty, the option doesn't take a value. + + \sa setValueName() + */ +QString QCommandLineOption::valueName() const +{ + return d->valueName; +} + +/*! + Sets the description used for this option to \a description. + + It is customary to add a "." at the end of the description. + + The description is used by QCommandLineParser::showHelp(). + + \sa description() + */ +void QCommandLineOption::setDescription(const QString &description) +{ + d->description = description; +} + +/*! + Returns the description set for this option. + + \sa setDescription() + */ +QString QCommandLineOption::description() const +{ + return d->description; +} + +/*! + Sets the default value used for this option to \a defaultValue. + + The default value is used if the user of the application does not specify + the option on the command line. + + If \a defaultValue is empty, the option has no default values. + + \sa defaultValues() setDefaultValues() + */ +void QCommandLineOption::setDefaultValue(const QString &defaultValue) +{ + QStringList newDefaultValues; + if (!defaultValue.isEmpty()) { + newDefaultValues.reserve(1); + newDefaultValues << defaultValue; + } + // commit: + d->defaultValues.swap(newDefaultValues); +} + +/*! + Sets the list of default values used for this option to \a defaultValues. + + The default values are used if the user of the application does not specify + the option on the command line. + + \sa defaultValues() setDefaultValue() + */ +void QCommandLineOption::setDefaultValues(const QStringList &defaultValues) +{ + d->defaultValues = defaultValues; +} + +/*! + Returns the default values set for this option. + + \sa setDefaultValues() + */ +QStringList QCommandLineOption::defaultValues() const +{ + return d->defaultValues; +} + +/*! + Sets whether to hide this option in the user-visible help output. + + All options are visible by default. Setting \a hidden to true for + a particular option makes it internal, i.e. not listed in the help output. + + \since 5.6 + \sa isHidden + */ +void QCommandLineOption::setHidden(bool hide) +{ + d->hidden = hide; +} + +/*! + Returns true if this option is omitted from the help output, + false if the option is listed. + + \since 5.6 + \sa setHidden() + */ +bool QCommandLineOption::isHidden() const +{ + return d->hidden; +} +#endif //QT_VERSION < QT_VERSION_CHECK(5, 2, 0) diff --git a/src/app/core/qcommandlineoption.h b/src/app/core/qcommandlineoption.h new file mode 100644 index 000000000..92fd65109 --- /dev/null +++ b/src/app/core/qcommandlineoption.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Laszlo Papp +** Contact: http://www.qt.io/licensing/ +** +** $QT_BEGIN_LICENSE:LGPL21$ +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOMMANDLINEOPTION_H +#define QCOMMANDLINEOPTION_H + +#include +#include +#include + +#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) + +#ifdef Q_CC_GNU + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Weffc++" +#endif + +class QCommandLineOptionPrivate; + +class QCommandLineOption +{ +public: + explicit QCommandLineOption(const QString &name); + explicit QCommandLineOption(const QStringList &names); + /*implicit*/ QCommandLineOption(const QString &name, const QString &description, + const QString &valueName = QString(), + const QString &defaultValue = QString()); + /*implicit*/ QCommandLineOption(const QStringList &names, const QString &description, + const QString &valueName = QString(), + const QString &defaultValue = QString()); + QCommandLineOption(const QCommandLineOption &other); + + ~QCommandLineOption(); + + QCommandLineOption &operator=(const QCommandLineOption &other); +#ifdef Q_COMPILER_RVALUE_REFS + inline QCommandLineOption &operator=(QCommandLineOption &&other) + { qSwap(d, other.d); return *this; } +#endif + + inline void swap(QCommandLineOption &other) + { qSwap(d, other.d); } + + QStringList names() const; + + void setValueName(const QString &name); + QString valueName() const; + + void setDescription(const QString &description); + QString description() const; + + void setDefaultValue(const QString &defaultValue); + void setDefaultValues(const QStringList &defaultValues); + QStringList defaultValues() const; + + void setHidden(bool hidden); + bool isHidden() const; + +private: + QSharedDataPointer d; +}; + +#ifdef Q_CC_GNU + #pragma GCC diagnostic pop +#endif + +Q_DECLARE_SHARED(QCommandLineOption) + +#endif //QT_VERSION < QT_VERSION_CHECK(5, 2, 0) + +#endif // QCOMMANDLINEOPTION_H diff --git a/src/app/core/qcommandlineparser.cpp b/src/app/core/qcommandlineparser.cpp new file mode 100644 index 000000000..b26868edf --- /dev/null +++ b/src/app/core/qcommandlineparser.cpp @@ -0,0 +1,1119 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Laszlo Papp +** Copyright (C) 2013 David Faure +** Contact: http://www.qt.io/licensing/ +** +** $QT_BEGIN_LICENSE:LGPL21$ +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcommandlineparser.h" + +#include +#include +#include +#include +#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +# include +#endif +#include +#include + +#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) + +typedef QHash NameHash_t; + +#ifdef Q_CC_GNU + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Weffc++" + #pragma GCC diagnostic ignored "-Wswitch-default" + #pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn" +#endif + +class QCommandLineParserPrivate +{ +public: + inline QCommandLineParserPrivate() + : singleDashWordOptionMode(QCommandLineParser::ParseAsCompactedShortOptions), + optionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsOptions), + builtinVersionOption(false), + builtinHelpOption(false), + needsParsing(true) + { } + + bool parse(const QStringList &args); + void checkParsed(const char *method); + QStringList aliases(const QString &name) const; + QString helpText() const; + bool registerFoundOption(const QString &optionName); + bool parseOptionValue(const QString &optionName, const QString &argument, + QStringList::const_iterator *argumentIterator, + QStringList::const_iterator argsEnd); + + //! Error text set when parse() returns false + QString errorText; + + //! The command line options used for parsing + QList commandLineOptionList; + + //! Hash mapping option names to their offsets in commandLineOptionList and optionArgumentList. + NameHash_t nameHash; + + //! Option values found (only for options with a value) + QHash optionValuesHash; + + //! Names of options found on the command line. + QStringList optionNames; + + //! Arguments which did not belong to any option. + QStringList positionalArgumentList; + + //! Names of options which were unknown. + QStringList unknownOptionNames; + + //! Application description + QString description; + + //! Documentation for positional arguments + struct PositionalArgumentDefinition + { + QString name; + QString description; + QString syntax; + }; + QVector positionalArgumentDefinitions; + + //! The parsing mode for "-abc" + QCommandLineParser::SingleDashWordOptionMode singleDashWordOptionMode; + + //! How to parse "arg -option" + QCommandLineParser::OptionsAfterPositionalArgumentsMode optionsAfterPositionalArgumentsMode; + + //! Whether addVersionOption was called + bool builtinVersionOption; + + //! Whether addHelpOption was called + bool builtinHelpOption; + + //! True if parse() needs to be called + bool needsParsing; +}; + +QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const +{ + const NameHash_t::const_iterator it = nameHash.find(optionName); + if (it == nameHash.end()) { + qWarning("QCommandLineParser: option not defined: \"%s\"", qPrintable(optionName)); + return QStringList(); + } + return commandLineOptionList.at(*it).names(); +} + +/*! + \since 5.2 + \class QCommandLineParser + \inmodule QtCore + \ingroup tools + + \brief The QCommandLineParser class provides a means for handling the + command line options. + + QCoreApplication provides the command-line arguments as a simple list of strings. + QCommandLineParser provides the ability to define a set of options, parse the + command-line arguments, and store which options have actually been used, as + well as option values. + + Any argument that isn't an option (i.e. doesn't start with a \c{-}) is stored + as a "positional argument". + + The parser handles short names, long names, more than one name for the same + option, and option values. + + Options on the command line are recognized as starting with a single or + double \c{-} character(s). + The option \c{-} (single dash alone) is a special case, often meaning standard + input, and not treated as an option. The parser will treat everything after the + option \c{--} (double dash) as positional arguments. + + Short options are single letters. The option \c{v} would be specified by + passing \c{-v} on the command line. In the default parsing mode, short options + can be written in a compact form, for instance \c{-abc} is equivalent to \c{-a -b -c}. + The parsing mode for can be set to ParseAsLongOptions, in which case \c{-abc} + will be parsed as the long option \c{abc}. + + Long options are more than one letter long and cannot be compacted together. + The long option \c{verbose} would be passed as \c{--verbose} or \c{-verbose}. + + Passing values to options can be done using the assignment operator: \c{-v=value} + \c{--verbose=value}, or a space: \c{-v value} \c{--verbose value}, i.e. the next + argument is used as value (even if it starts with a \c{-}). + + The parser does not support optional values - if an option is set to + require a value, one must be present. If such an option is placed last + and has no value, the option will be treated as if it had not been + specified. + + The parser does not automatically support negating or disabling long options + by using the format \c{--disable-option} or \c{--no-option}. However, it is + possible to handle this case explicitly by making an option with \c{no-option} + as one of its names, and handling the option explicitly. + + Example: + \snippet code/src_corelib_tools_qcommandlineparser_main.cpp 0 + + If your compiler supports the C++11 standard, the three addOption() calls in + the above example can be simplified: + \snippet code/src_corelib_tools_qcommandlineparser_main.cpp cxx11 + + Known limitation: the parsing of Qt options inside QCoreApplication and subclasses + happens before QCommandLineParser exists, so it can't take it into account. This + means any option value that looks like a builtin Qt option, will be treated by + QCoreApplication as a builtin Qt option. Example: \c{--profile -reverse} will + lead to QGuiApplication seeing the -reverse option set, and removing it from + QCoreApplication::arguments() before QCommandLineParser defines the \c{profile} + option and parses the command line. + + \section2 How to Use QCommandLineParser in Complex Applications + + In practice, additional error checking needs to be performed on the positional + arguments and option values. For example, ranges of numbers should be checked. + + It is then advisable to introduce a function to do the command line parsing + which takes a struct or class receiving the option values returning an + enumeration representing the result. The dnslookup example of the QtNetwork + module illustrates this: + + \snippet dnslookup.h 0 + + \snippet dnslookup.cpp 0 + + In the main function, help should be printed to the standard output if the help option + was passed and the application should return the exit code 0. + + If an error was detected, the error message should be printed to the standard + error output and the application should return an exit code other than 0. + + \snippet dnslookup.cpp 1 + + A special case to consider here are GUI applications on Windows and mobile + platforms. These applications may not use the standard output or error channels + since the output is either discarded or not accessible. + + On Windows, QCommandLineParser uses message boxes to display usage information + and errors if no console window can be obtained. + + For other platforms, it is recommended to display help texts and error messages + using a QMessageBox. To preserve the formatting of the help text, rich text + with \c
 elements should be used:
+
+    \code
+
+    switch (parseCommandLine(parser, &query, &errorMessage)) {
+    case CommandLineOk:
+        break;
+    case CommandLineError:
+        QMessageBox::warning(0, QGuiApplication::applicationDisplayName(),
+                             "

" + errorMessage + "

"
+                             + parser.helpText() + "
"); + return 1; + case CommandLineVersionRequested: + QMessageBox::information(0, QGuiApplication::applicationDisplayName(), + QGuiApplication::applicationDisplayName() + ' ' + + QCoreApplication::applicationVersion()); + return 0; + case CommandLineHelpRequested: + QMessageBox::warning(0, QGuiApplication::applicationDisplayName(), + "
"
+                             + parser.helpText() + "
"); + return 0; + } + \endcode + + However, this does not apply to the dnslookup example, because it is a + console application. + + \sa QCommandLineOption, QCoreApplication +*/ + +/*! + Constructs a command line parser object. +*/ +QCommandLineParser::QCommandLineParser() + : d(new QCommandLineParserPrivate) +{ +} + +/*! + Destroys the command line parser object. +*/ +QCommandLineParser::~QCommandLineParser() +{ + delete d; +} + +/*! + \enum QCommandLineParser::SingleDashWordOptionMode + + This enum describes the way the parser interprets command-line + options that use a single dash followed by multiple letters, as as \c{-abc}. + + \value ParseAsCompactedShortOptions \c{-abc} is interpreted as \c{-a -b -c}, + i.e. as three short options that have been compacted on the command-line, + if none of the options take a value. If \c{a} takes a value, then it + is interpreted as \c{-a bc}, i.e. the short option \c{a} followed by the value \c{bc}. + This is typically used in tools that behave like compilers, in order + to handle options such as \c{-DDEFINE=VALUE} or \c{-I/include/path}. + This is the default parsing mode. New applications are recommended to + use this mode. + + \value ParseAsLongOptions \c{-abc} is interpreted as \c{--abc}, + i.e. as the long option named \c{abc}. This is how Qt's own tools + (uic, rcc...) have always been parsing arguments. This mode should be + used for preserving compatibility in applications that were parsing + arguments in such a way. + + \sa setSingleDashWordOptionMode() +*/ + +/*! + Sets the parsing mode to \a singleDashWordOptionMode. + This must be called before process() or parse(). +*/ +void QCommandLineParser::setSingleDashWordOptionMode(QCommandLineParser::SingleDashWordOptionMode singleDashWordOptionMode) +{ + d->singleDashWordOptionMode = singleDashWordOptionMode; +} + +/*! + \enum QCommandLineParser::OptionsAfterPositionalArgumentsMode + + This enum describes the way the parser interprets options that + occur after positional arguments. + + \value ParseAsOptions \c{application argument --opt -t} is interpreted as setting + the options \c{opt} and \c{t}, just like \c{application --opt -t argument} would do. + This is the default parsing mode. In order to specify that \c{--opt} and \c{-t} + are positional arguments instead, the user can use \c{--}, as in + \c{application argument -- --opt -t}. + + \value ParseAsPositionalArguments \c{application argument --opt} is interpreted as + having two positional arguments, \c{argument} and \c{--opt}. + This mode is useful for executables that aim to launch other executables + (e.g. wrappers, debugging tools, etc.) or that support internal commands + followed by options for the command. \c{argument} is the name of the command, + and all options occurring after it can be collected and parsed by another + command line parser, possibly in another executable. + + \sa setOptionsAfterPositionalArgumentsMode() + + \since 5.5 +*/ + +/*! + Sets the parsing mode to \a parsingMode. + This must be called before process() or parse(). + \since 5.5 +*/ +void QCommandLineParser::setOptionsAfterPositionalArgumentsMode(QCommandLineParser::OptionsAfterPositionalArgumentsMode parsingMode) +{ + d->optionsAfterPositionalArgumentsMode = parsingMode; +} + +/*! + Adds the option \a option to look for while parsing. + + Returns \c true if adding the option was successful; otherwise returns \c false. + + Adding the option fails if there is no name attached to the option, or + the option has a name that clashes with an option name added before. + */ +bool QCommandLineParser::addOption(const QCommandLineOption &option) +{ + QStringList optionNames = option.names(); + + if (!optionNames.isEmpty()) { + foreach (const QString &name, optionNames) { + if (d->nameHash.contains(name)) + return false; + } + + d->commandLineOptionList.append(option); + + const int offset = d->commandLineOptionList.size() - 1; + foreach (const QString &name, optionNames) + d->nameHash.insert(name, offset); + + return true; + } + + return false; +} + +/*! + \since 5.4 + + Adds the options to look for while parsing. The options are specified by + the parameter \a options. + + Returns \c true if adding all of the options was successful; otherwise + returns \c false. + + See the documentation for addOption() for when this function may fail. +*/ +bool QCommandLineParser::addOptions(const QList &options) +{ + // should be optimized (but it's no worse than what was possible before) + bool result = true; + for (QList::const_iterator it = options.begin(), end = options.end(); it != end; ++it) + result &= addOption(*it); + return result; +} + +/*! + Adds the \c{-v} / \c{--version} option, which displays the version string of the application. + + This option is handled automatically by QCommandLineParser. + + You can set the actual version string by using QCoreApplication::setApplicationVersion(). + + Returns the option instance, which can be used to call isSet(). +*/ +QCommandLineOption QCommandLineParser::addVersionOption() +{ + QCommandLineOption opt(QStringList() << QStringLiteral("v") << QStringLiteral("version"), tr("Displays version information.")); + addOption(opt); + d->builtinVersionOption = true; + return opt; +} + +/*! + Adds the help option (\c{-h}, \c{--help} and \c{-?} on Windows) + This option is handled automatically by QCommandLineParser. + + Remember to use setApplicationDescription to set the application description, + which will be displayed when this option is used. + + Example: + \snippet code/src_corelib_tools_qcommandlineparser_main.cpp 0 + + Returns the option instance, which can be used to call isSet(). +*/ +QCommandLineOption QCommandLineParser::addHelpOption() +{ + QCommandLineOption opt(QStringList() +#ifdef Q_OS_WIN + << QStringLiteral("?") +#endif + << QStringLiteral("h") + << QStringLiteral("help"), tr("Displays this help.")); + addOption(opt); + d->builtinHelpOption = true; + return opt; +} + +/*! + Sets the application \a description shown by helpText(). +*/ +void QCommandLineParser::setApplicationDescription(const QString &description) +{ + d->description = description; +} + +/*! + Returns the application description set in setApplicationDescription(). +*/ +QString QCommandLineParser::applicationDescription() const +{ + return d->description; +} + +/*! + Defines an additional argument to the application, for the benefit of the help text. + + The argument \a name and \a description will appear under the \c{Arguments:} section + of the help. If \a syntax is specified, it will be appended to the Usage line, otherwise + the \a name will be appended. + + Example: + \snippet code/src_corelib_tools_qcommandlineparser.cpp 2 + + \sa addHelpOption(), helpText() +*/ +void QCommandLineParser::addPositionalArgument(const QString &name, const QString &description, const QString &syntax) +{ + QCommandLineParserPrivate::PositionalArgumentDefinition arg; + arg.name = name; + arg.description = description; + arg.syntax = syntax.isEmpty() ? name : syntax; + d->positionalArgumentDefinitions.append(arg); +} + +/*! + Clears the definitions of additional arguments from the help text. + + This is only needed for the special case of tools which support multiple commands + with different options. Once the actual command has been identified, the options + for this command can be defined, and the help text for the command can be adjusted + accordingly. + + Example: + \snippet code/src_corelib_tools_qcommandlineparser.cpp 3 +*/ +void QCommandLineParser::clearPositionalArguments() +{ + d->positionalArgumentDefinitions.clear(); +} + +/*! + Parses the command line \a arguments. + + Most programs don't need to call this, a simple call to process() is enough. + + parse() is more low-level, and only does the parsing. The application will have to + take care of the error handling, using errorText() if parse() returns \c false. + This can be useful for instance to show a graphical error message in graphical programs. + + Calling parse() instead of process() can also be useful in order to ignore unknown + options temporarily, because more option definitions will be provided later on + (depending on one of the arguments), before calling process(). + + Don't forget that \a arguments must start with the name of the executable (ignored, though). + + Returns \c false in case of a parse error (unknown option or missing value); returns \c true otherwise. + + \sa process() +*/ +bool QCommandLineParser::parse(const QStringList &arguments) +{ + return d->parse(arguments); +} + +/*! + Returns a translated error text for the user. + This should only be called when parse() returns \c false. +*/ +QString QCommandLineParser::errorText() const +{ + if (!d->errorText.isEmpty()) + return d->errorText; + if (d->unknownOptionNames.count() == 1) + return tr("Unknown option '%1'.").arg(d->unknownOptionNames.first()); + if (d->unknownOptionNames.count() > 1) + return tr("Unknown options: %1.").arg(d->unknownOptionNames.join(QStringLiteral(", "))); + return QString(); +} + +enum MessageType { UsageMessage, ErrorMessage }; + +#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +// Return whether to use a message box. Use handles if a console can be obtained +// or we are run with redirected handles (for example, by QProcess). +static inline bool displayMessageBox() +{ + if (GetConsoleWindow()) + return false; + STARTUPINFO startupInfo; + startupInfo.cb = sizeof(STARTUPINFO); + GetStartupInfo(&startupInfo); + return !(startupInfo.dwFlags & STARTF_USESTDHANDLES); +} +#endif // Q_OS_WIN && !QT_BOOTSTRAPPED && !Q_OS_WIN && !Q_OS_WINRT + +static void showParserMessage(const QString &message, MessageType type) +{ +#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) + if (displayMessageBox()) { + const UINT flags = MB_OK | MB_TOPMOST | MB_SETFOREGROUND + | (type == UsageMessage ? MB_ICONINFORMATION : MB_ICONERROR); + QString title; + if (QCoreApplication::instance()) + title = QCoreApplication::instance()->property("applicationDisplayName").toString(); + if (title.isEmpty()) + title = QCoreApplication::applicationName(); + MessageBoxW(0, reinterpret_cast(message.utf16()), + reinterpret_cast(title.utf16()), flags); + return; + } +#endif // Q_OS_WIN && !QT_BOOTSTRAPPED && !Q_OS_WIN && !Q_OS_WINRT + fputs(qPrintable(message), type == UsageMessage ? stdout : stderr); +} + +/*! + Processes the command line \a arguments. + + In addition to parsing the options (like parse()), this function also handles the builtin + options and handles errors. + + The builtin options are \c{--version} if addVersionOption was called and \c{--help} if addHelpOption was called. + + When invoking one of these options, or when an error happens (for instance an unknown option was + passed), the current process will then stop, using the exit() function. + + \sa QCoreApplication::arguments(), parse() + */ +void QCommandLineParser::process(const QStringList &arguments) +{ + if (!d->parse(arguments)) { + showParserMessage(errorText() + QLatin1Char('\n'), ErrorMessage); + ::exit(EXIT_FAILURE); + } + + if (d->builtinVersionOption && isSet(QStringLiteral("version"))) + showVersion(); + + if (d->builtinHelpOption && isSet(QStringLiteral("help"))) + showHelp(EXIT_SUCCESS); +} + +/*! + \overload + + The command line is obtained from the QCoreApplication instance \a app. + */ +void QCommandLineParser::process(const QCoreApplication &app) +{ + // QCoreApplication::arguments() is static, but the app instance must exist so we require it as parameter + Q_UNUSED(app); + process(QCoreApplication::arguments()); +} + +void QCommandLineParserPrivate::checkParsed(const char *method) +{ + if (needsParsing) + qWarning("QCommandLineParser: call process() or parse() before %s", method); +} + +/*! + \internal + Looks up the option \a optionName (found on the command line) and register it as found. + Returns \c true on success. + */ +bool QCommandLineParserPrivate::registerFoundOption(const QString &optionName) +{ + if (nameHash.contains(optionName)) { + optionNames.append(optionName); + return true; + } else { + unknownOptionNames.append(optionName); + return false; + } +} + +/*! + \internal + \brief Parse the value for a given option, if it was defined to expect one. + + The value is taken from the next argument, or after the equal sign in \a argument. + + \param optionName the short option name + \param argument the argument from the command line currently parsed. Only used for -k=value parsing. + \param argumentIterator iterator to the currently parsed argument. Incremented if the next argument contains the value. + \param argsEnd args.end(), to check if ++argumentIterator goes out of bounds + Returns \c true on success. + */ +bool QCommandLineParserPrivate::parseOptionValue(const QString &optionName, const QString &argument, + QStringList::const_iterator *argumentIterator, QStringList::const_iterator argsEnd) +{ + const QLatin1Char assignChar('='); + const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName); + if (nameHashIt != nameHash.constEnd()) { + const int assignPos = argument.indexOf(assignChar); + const NameHash_t::mapped_type optionOffset = *nameHashIt; + const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty(); + if (withValue) { + if (assignPos == -1) { + ++(*argumentIterator); + if (*argumentIterator == argsEnd) { + errorText = QCommandLineParser::tr("Missing value after '%1'.").arg(argument); + return false; + } + optionValuesHash[optionOffset].append(*(*argumentIterator)); + } else { + optionValuesHash[optionOffset].append(argument.mid(assignPos + 1)); + } + } else { + if (assignPos != -1) { + errorText = QCommandLineParser::tr("Unexpected value after '%1'.").arg(argument.left(assignPos)); + return false; + } + } + } + return true; +} + +/*! + \internal + + Parse the list of arguments \a args, and fills in + optionNames, optionValuesHash, unknownOptionNames, positionalArguments, and errorText. + + Any results from a previous parse operation are removed. + + The parser will not look for further options once it encounters the option + \c{--}; this does not include when \c{--} follows an option that requires a value. + */ +bool QCommandLineParserPrivate::parse(const QStringList &args) +{ + needsParsing = false; + bool error = false; + + const QString doubleDashString(QStringLiteral("--")); + const QLatin1Char dashChar('-'); + const QLatin1Char assignChar('='); + + bool forcePositional = false; + errorText.clear(); + positionalArgumentList.clear(); + optionNames.clear(); + unknownOptionNames.clear(); + optionValuesHash.clear(); + + if (args.isEmpty()) { + qWarning("QCommandLineParser: argument list cannot be empty, it should contain at least the executable name"); + return false; + } + + QStringList::const_iterator argumentIterator = args.begin(); + ++argumentIterator; // skip executable name + + for (; argumentIterator != args.end() ; ++argumentIterator) { + QString argument = *argumentIterator; + + if (forcePositional) { + positionalArgumentList.append(argument); + } else if (argument.startsWith(doubleDashString)) { + if (argument.length() > 2) { + QString optionName = argument.mid(2).section(assignChar, 0, 0); + if (registerFoundOption(optionName)) { + if (!parseOptionValue(optionName, argument, &argumentIterator, args.end())) + error = true; + } else { + error = true; + } + } else { + forcePositional = true; + } + } else if (argument.startsWith(dashChar)) { + if (argument.size() == 1) { // single dash ("stdin") + positionalArgumentList.append(argument); + continue; + } + switch (singleDashWordOptionMode) { + case QCommandLineParser::ParseAsCompactedShortOptions: + { + QString optionName; + bool valueFound = false; + for (int pos = 1 ; pos < argument.size(); ++pos) { + optionName = argument.mid(pos, 1); + if (!registerFoundOption(optionName)) { + error = true; + } else { + const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName); + Q_ASSERT(nameHashIt != nameHash.constEnd()); // checked by registerFoundOption + const NameHash_t::mapped_type optionOffset = *nameHashIt; + const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty(); + if (withValue) { + if (pos + 1 < argument.size()) { + if (argument.at(pos + 1) == assignChar) + ++pos; + optionValuesHash[optionOffset].append(argument.mid(pos + 1)); + valueFound = true; + } + break; + } + if (pos + 1 < argument.size() && argument.at(pos + 1) == assignChar) + break; + } + } + if (!valueFound && !parseOptionValue(optionName, argument, &argumentIterator, args.end())) + error = true; + break; + } + case QCommandLineParser::ParseAsLongOptions: + { + const QString optionName = argument.mid(1).section(assignChar, 0, 0); + if (registerFoundOption(optionName)) { + if (!parseOptionValue(optionName, argument, &argumentIterator, args.end())) + error = true; + } else { + error = true; + } + break; + } + } + } else { + positionalArgumentList.append(argument); + if (optionsAfterPositionalArgumentsMode == QCommandLineParser::ParseAsPositionalArguments) + forcePositional = true; + } + if (argumentIterator == args.end()) + break; + } + return !error; +} + +/*! + Checks whether the option \a name was passed to the application. + + Returns \c true if the option \a name was set, false otherwise. + + The name provided can be any long or short name of any option that was + added with \c addOption(). All the options names are treated as being + equivalent. If the name is not recognized or that option was not present, + false is returned. + + Example: + \snippet code/src_corelib_tools_qcommandlineparser.cpp 0 + */ + +bool QCommandLineParser::isSet(const QString &name) const +{ + d->checkParsed("isSet"); + if (d->optionNames.contains(name)) + return true; + const QStringList aliases = d->aliases(name); + foreach (const QString &optionName, d->optionNames) { + if (aliases.contains(optionName)) + return true; + } + return false; +} + +/*! + Returns the option value found for the given option name \a optionName, or + an empty string if not found. + + The name provided can be any long or short name of any option that was + added with \c addOption(). All the option names are treated as being + equivalent. If the name is not recognized or that option was not present, an + empty string is returned. + + For options found by the parser, the last value found for + that option is returned. If the option wasn't specified on the command line, + the default value is returned. + + An empty string is returned if the option does not take a value. + + \sa values(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues() + */ + +QString QCommandLineParser::value(const QString &optionName) const +{ + d->checkParsed("value"); + const QStringList valueList = values(optionName); + + if (!valueList.isEmpty()) + return valueList.last(); + + return QString(); +} + +/*! + Returns a list of option values found for the given option name \a + optionName, or an empty list if not found. + + The name provided can be any long or short name of any option that was + added with \c addOption(). All the options names are treated as being + equivalent. If the name is not recognized or that option was not present, an + empty list is returned. + + For options found by the parser, the list will contain an entry for + each time the option was encountered by the parser. If the option wasn't + specified on the command line, the default values are returned. + + An empty list is returned if the option does not take a value. + + \sa value(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues() + */ + +QStringList QCommandLineParser::values(const QString &optionName) const +{ + d->checkParsed("values"); + const NameHash_t::const_iterator it = d->nameHash.find(optionName); + if (it != d->nameHash.end()) { + const int optionOffset = *it; + QStringList values = d->optionValuesHash.value(optionOffset); + if (values.isEmpty()) + values = d->commandLineOptionList.at(optionOffset).defaultValues(); + return values; + } + + qWarning("QCommandLineParser: option not defined: \"%s\"", qPrintable(optionName)); + return QStringList(); +} + +/*! + \overload + Checks whether the \a option was passed to the application. + + Returns \c true if the \a option was set, false otherwise. + + This is the recommended way to check for options with no values. + + Example: + \snippet code/src_corelib_tools_qcommandlineparser.cpp 1 +*/ +bool QCommandLineParser::isSet(const QCommandLineOption &option) const +{ + // option.names() might be empty if the constructor failed + return !option.names().isEmpty() && isSet(option.names().first()); +} + +/*! + \overload + Returns the option value found for the given \a option, or + an empty string if not found. + + For options found by the parser, the last value found for + that option is returned. If the option wasn't specified on the command line, + the default value is returned. + + An empty string is returned if the option does not take a value. + + \sa values(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues() +*/ +QString QCommandLineParser::value(const QCommandLineOption &option) const +{ + return value(option.names().first()); +} + +/*! + \overload + Returns a list of option values found for the given \a option, + or an empty list if not found. + + For options found by the parser, the list will contain an entry for + each time the option was encountered by the parser. If the option wasn't + specified on the command line, the default values are returned. + + An empty list is returned if the option does not take a value. + + \sa value(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues() +*/ +QStringList QCommandLineParser::values(const QCommandLineOption &option) const +{ + return values(option.names().first()); +} + +/*! + Returns a list of positional arguments. + + These are all of the arguments that were not recognized as part of an + option. + */ + +QStringList QCommandLineParser::positionalArguments() const +{ + d->checkParsed("positionalArguments"); + return d->positionalArgumentList; +} + +/*! + Returns a list of option names that were found. + + This returns a list of all the recognized option names found by the + parser, in the order in which they were found. For any long options + that were in the form {--option=value}, the value part will have been + dropped. + + The names in this list do not include the preceding dash characters. + Names may appear more than once in this list if they were encountered + more than once by the parser. + + Any entry in the list can be used with \c value() or with + \c values() to get any relevant option values. + */ + +QStringList QCommandLineParser::optionNames() const +{ + d->checkParsed("optionNames"); + return d->optionNames; +} + +/*! + Returns a list of unknown option names. + + This list will include both long an short name options that were not + recognized. For any long options that were in the form {--option=value}, + the value part will have been dropped and only the long name is added. + + The names in this list do not include the preceding dash characters. + Names may appear more than once in this list if they were encountered + more than once by the parser. + + \sa optionNames() + */ + +QStringList QCommandLineParser::unknownOptionNames() const +{ + d->checkParsed("unknownOptionNames"); + return d->unknownOptionNames; +} + +/*! + Displays the version information from QCoreApplication::applicationVersion(), + and exits the application. + This is automatically triggered by the --version option, but can also + be used to display the version when not using process(). + The exit code is set to EXIT_SUCCESS (0). + + \sa addVersionOption() + \since 5.4 +*/ +Q_NORETURN void QCommandLineParser::showVersion() +{ + showParserMessage(QCoreApplication::applicationName() + QLatin1Char(' ') + + QCoreApplication::applicationVersion() + QLatin1Char('\n'), + UsageMessage); + ::exit(EXIT_SUCCESS); +} + +/*! + Displays the help information, and exits the application. + This is automatically triggered by the --help option, but can also + be used to display the help when the user is not invoking the + application correctly. + The exit code is set to \a exitCode. It should be set to 0 if the + user requested to see the help, and to any other value in case of + an error. + + \sa helpText() +*/ +Q_NORETURN void QCommandLineParser::showHelp(int exitCode) +{ + showParserMessage(d->helpText(), UsageMessage); + ::exit(exitCode); +} + +/*! + Returns a string containing the complete help information. + + \sa showHelp() +*/ +QString QCommandLineParser::helpText() const +{ + return d->helpText(); +} + +static QString wrapText(const QString &names, int longestOptionNameString, const QString &description) +{ + const QLatin1Char nl('\n'); + QString text = QStringLiteral(" ") + names.leftJustified(longestOptionNameString) + QLatin1Char(' '); + const int indent = text.length(); + int lineStart = 0; + int lastBreakable = -1; + const int max = 79 - indent; + int x = 0; + const int len = description.length(); + + for (int i = 0; i < len; ++i) { + ++x; + const QChar c = description.at(i); + if (c.isSpace()) + lastBreakable = i; + + int breakAt = -1; + int nextLineStart = -1; + if (x > max && lastBreakable != -1) { + // time to break and we know where + breakAt = lastBreakable; + nextLineStart = lastBreakable + 1; + } else if ((x > max - 1 && lastBreakable == -1) || i == len - 1) { + // time to break but found nowhere [-> break here], or end of last line + breakAt = i + 1; + nextLineStart = breakAt; + } else if (c == nl) { + // forced break + breakAt = i; + nextLineStart = i + 1; + } + + if (breakAt != -1) { + const int numChars = breakAt - lineStart; + //qDebug() << "breakAt=" << description.at(breakAt) << "breakAtSpace=" << breakAtSpace << lineStart << "to" << breakAt << description.mid(lineStart, numChars); + if (lineStart > 0) + text += QString(indent, QLatin1Char(' ')); + text += description.midRef(lineStart, numChars) + nl; + x = 0; + lastBreakable = -1; + lineStart = nextLineStart; + if (lineStart < len && description.at(lineStart).isSpace()) + ++lineStart; // don't start a line with a space + i = lineStart; + } + } + + return text; +} + +QString QCommandLineParserPrivate::helpText() const +{ + const QLatin1Char nl('\n'); + QString text; + const QString exeName = QCoreApplication::instance()->arguments().first(); + QString usage = exeName; + if (!commandLineOptionList.isEmpty()) { + usage += QLatin1Char(' '); + usage += QCommandLineParser::tr("[options]"); + } + foreach (const PositionalArgumentDefinition &arg, positionalArgumentDefinitions) { + usage += QLatin1Char(' '); + usage += arg.syntax; + } + text += QCommandLineParser::tr("Usage: %1").arg(usage) + nl; + if (!description.isEmpty()) + text += description + nl; + text += nl; + if (!commandLineOptionList.isEmpty()) + text += QCommandLineParser::tr("Options:") + nl; + QStringList optionNameList; + int longestOptionNameString = 0; + foreach (const QCommandLineOption &option, commandLineOptionList) { + QStringList optionNames; + foreach (const QString &optionName, option.names()) { + if (optionName.length() == 1) + optionNames.append(QLatin1Char('-') + optionName); + else + optionNames.append(QStringLiteral("--") + optionName); + } + QString optionNamesString = optionNames.join(QStringLiteral(", ")); + if (!option.valueName().isEmpty()) + optionNamesString += QStringLiteral(" <") + option.valueName() + QLatin1Char('>'); + optionNameList.append(optionNamesString); + longestOptionNameString = qMax(longestOptionNameString, optionNamesString.length()); + } + ++longestOptionNameString; + for (int i = 0; i < commandLineOptionList.count(); ++i) { + const QCommandLineOption &option = commandLineOptionList.at(i); + if (option.isHidden()) + continue; + text += wrapText(optionNameList.at(i), longestOptionNameString, option.description()); + } + if (!positionalArgumentDefinitions.isEmpty()) { + if (!commandLineOptionList.isEmpty()) + text += nl; + text += QCommandLineParser::tr("Arguments:") + nl; + foreach (const PositionalArgumentDefinition &arg, positionalArgumentDefinitions) { + text += wrapText(arg.name, longestOptionNameString, arg.description); + } + } + return text; +} + +#ifdef Q_CC_GNU + #pragma GCC diagnostic pop +#endif + +#endif //QT_VERSION < QT_VERSION_CHECK(5, 2, 0) diff --git a/src/app/core/qcommandlineparser.h b/src/app/core/qcommandlineparser.h new file mode 100644 index 000000000..c67b36bf1 --- /dev/null +++ b/src/app/core/qcommandlineparser.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Laszlo Papp +** Contact: http://www.qt.io/licensing/ +** +** $QT_BEGIN_LICENSE:LGPL21$ +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOMMANDLINEPARSER_H +#define QCOMMANDLINEPARSER_H + +#include +#include +#include +#include "qcommandlineoption.h" + +#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) + +class QCommandLineParserPrivate; +class QCoreApplication; + +#ifdef Q_CC_GNU + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Weffc++" +#endif + +class QCommandLineParser +{ + Q_DECLARE_TR_FUNCTIONS(QCommandLineParser) +public: + QCommandLineParser(); + ~QCommandLineParser(); + + enum SingleDashWordOptionMode { + ParseAsCompactedShortOptions, + ParseAsLongOptions + }; + void setSingleDashWordOptionMode(SingleDashWordOptionMode parsingMode); + + enum OptionsAfterPositionalArgumentsMode { + ParseAsOptions, + ParseAsPositionalArguments + }; + void setOptionsAfterPositionalArgumentsMode(OptionsAfterPositionalArgumentsMode mode); + + bool addOption(const QCommandLineOption &commandLineOption); + bool addOptions(const QList &options); + + QCommandLineOption addVersionOption(); + QCommandLineOption addHelpOption(); + void setApplicationDescription(const QString &description); + QString applicationDescription() const; + void addPositionalArgument(const QString &name, const QString &description, const QString &syntax = QString()); + void clearPositionalArguments(); + + void process(const QStringList &arguments); + void process(const QCoreApplication &app); + + bool parse(const QStringList &arguments); + QString errorText() const; + + bool isSet(const QString &name) const; + QString value(const QString &name) const; + QStringList values(const QString &name) const; + + bool isSet(const QCommandLineOption &option) const; + QString value(const QCommandLineOption &option) const; + QStringList values(const QCommandLineOption &option) const; + + QStringList positionalArguments() const; + QStringList optionNames() const; + QStringList unknownOptionNames() const; + + Q_NORETURN void showVersion(); + Q_NORETURN void showHelp(int exitCode = 0); + QString helpText() const; + +private: + Q_DISABLE_COPY(QCommandLineParser) + + QCommandLineParserPrivate * const d; +}; + +#ifdef Q_CC_GNU + #pragma GCC diagnostic pop +#endif + +#endif //QT_VERSION < QT_VERSION_CHECK(5, 2, 0) + +#endif // QCOMMANDLINEPARSER_H diff --git a/src/app/core/vapplication.cpp b/src/app/core/vapplication.cpp index e3b86942e..742dfc208 100644 --- a/src/app/core/vapplication.cpp +++ b/src/app/core/vapplication.cpp @@ -35,6 +35,7 @@ #include "vmaingraphicsview.h" #include "../container/calculator.h" #include "../version.h" +#include "../../utils/logging.h" #include #include @@ -46,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/src/app/dialogs/app/dialogstandardmeasurements.cpp b/src/app/dialogs/app/dialogstandardmeasurements.cpp index 4ad4c72f9..e8574de98 100644 --- a/src/app/dialogs/app/dialogstandardmeasurements.cpp +++ b/src/app/dialogs/app/dialogstandardmeasurements.cpp @@ -28,14 +28,15 @@ #include "dialogstandardmeasurements.h" #include "ui_dialogstandardmeasurements.h" -#include -#include -#include #include "../../xml/vstandardmeasurements.h" #include "../../core/vapplication.h" #include "../../core/vsettings.h" #include "../../container/vcontainer.h" -#include +#include "../../utils/logging.h" + +#include +#include +#include Q_LOGGING_CATEGORY(vStMeasur, "v.st.measurements") diff --git a/src/app/dialogs/tools/dialogtool.h b/src/app/dialogs/tools/dialogtool.h index 0aec9afd9..2bf30d7e2 100644 --- a/src/app/dialogs/tools/dialogtool.h +++ b/src/app/dialogs/tools/dialogtool.h @@ -29,15 +29,16 @@ #ifndef DIALOGTOOL_H #define DIALOGTOOL_H +#include "../../core/vapplication.h" +#include "../../utils/logging.h" + #include #include #include #include #include -#include "../../core/vapplication.h" #include #include -#include Q_DECLARE_LOGGING_CATEGORY(vDialog) diff --git a/src/app/main.cpp b/src/app/main.cpp index 16cb4f758..83e2e85f8 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -35,7 +35,11 @@ #include #include #include -#include +#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) +# include "../core/qcommandlineparser.h" +#else +# include +#endif #include #include @@ -48,7 +52,7 @@ int main(int argc, char *argv[]) Q_INIT_RESOURCE(theme); Q_INIT_RESOURCE(flags); - QT_REQUIRE_VERSION(argc, argv, "5.2.0"); + QT_REQUIRE_VERSION(argc, argv, "5.0.0"); VApplication app(argc, argv); diff --git a/src/app/mainwindow.cpp b/src/app/mainwindow.cpp index 0a459cf17..4c3509aa7 100644 --- a/src/app/mainwindow.cpp +++ b/src/app/mainwindow.cpp @@ -44,6 +44,7 @@ #include "vtooloptionspropertybrowser.h" #include "options.h" #include "../libs/ifc/xml/vpatternconverter.h" +#include "../../utils/logging.h" #include #include @@ -60,7 +61,6 @@ #include #include #include -#include #include Q_LOGGING_CATEGORY(vMainWindow, "v.mainwindow") diff --git a/src/app/tools/drawTools/vtoolpoint.cpp b/src/app/tools/drawTools/vtoolpoint.cpp index eb32c42e0..938ebb112 100644 --- a/src/app/tools/drawTools/vtoolpoint.cpp +++ b/src/app/tools/drawTools/vtoolpoint.cpp @@ -27,12 +27,13 @@ *************************************************************************/ #include "vtoolpoint.h" -#include -#include +#include "../../utils/logging.h" #include "../../geometry/vpointf.h" #include "../../visualization/vgraphicssimpletextitem.h" #include "../../undocommands/movelabel.h" +#include + Q_LOGGING_CATEGORY(vToolPoint, "v.toolPoint") const QString VToolPoint::TagName = QStringLiteral("point"); diff --git a/src/app/tools/vdatatool.h b/src/app/tools/vdatatool.h index 3af039e2f..75046fe52 100644 --- a/src/app/tools/vdatatool.h +++ b/src/app/tools/vdatatool.h @@ -30,7 +30,7 @@ #define VDATATOOL_H #include "../container/vcontainer.h" -#include +#include "../../utils/logging.h" Q_DECLARE_LOGGING_CATEGORY(vTool) diff --git a/src/app/undocommands/vundocommand.h b/src/app/undocommands/vundocommand.h index 034962541..562ede74d 100644 --- a/src/app/undocommands/vundocommand.h +++ b/src/app/undocommands/vundocommand.h @@ -31,7 +31,8 @@ #include #include -#include + +#include "../../utils/logging.h" #include "../xml/vpattern.h" Q_DECLARE_LOGGING_CATEGORY(vUndo) diff --git a/src/app/visualization/visualization.h b/src/app/visualization/visualization.h index 1c398bfd5..860db38d9 100644 --- a/src/app/visualization/visualization.h +++ b/src/app/visualization/visualization.h @@ -31,9 +31,10 @@ #include #include + #include "../core/vapplication.h" #include "../widgets/vmaingraphicsscene.h" -#include +#include "../../utils/logging.h" Q_DECLARE_LOGGING_CATEGORY(vVis) diff --git a/src/libs/ifc/exception/vexception.cpp b/src/libs/ifc/exception/vexception.cpp index f7fce7b8d..ba78fb87b 100644 --- a/src/libs/ifc/exception/vexception.cpp +++ b/src/libs/ifc/exception/vexception.cpp @@ -27,11 +27,12 @@ *************************************************************************/ #include "vexception.h" +#include "../../../utils/logging.h" + #include #include #include #include -#include Q_LOGGING_CATEGORY(vExcep, "v.excep") diff --git a/src/libs/ifc/ifc.pro b/src/libs/ifc/ifc.pro index 4824d8a0d..04f3efe70 100644 --- a/src/libs/ifc/ifc.pro +++ b/src/libs/ifc/ifc.pro @@ -31,6 +31,7 @@ CONFIG -= debug_and_release debug_and_release_target DEFINES += QT_MESSAGELOGCONTEXT include(ifc.pri) +include(../../utils/utils.pri) # This is static library so no need in "make install" @@ -74,7 +75,7 @@ CONFIG(debug, debug|release){ -isystem "$${OUT_PWD}/$${MOC_DIR}" \ $$CLANG_DEBUG_CXXFLAGS # See Valentina.pri for more details. - # -isystem key works only for headers. In some cases it's not enough. But we can't delete this warnings and + # -isystem key works only for headers. In some cases it's not enough. But we can't delete these warnings and # want them in global list. Compromise decision delete them from local list. QMAKE_CXXFLAGS -= \ -Wmissing-prototypes diff --git a/src/libs/ifc/xml/vdomdocument.h b/src/libs/ifc/xml/vdomdocument.h index 2fc3ef713..f23214dae 100644 --- a/src/libs/ifc/xml/vdomdocument.h +++ b/src/libs/ifc/xml/vdomdocument.h @@ -31,10 +31,10 @@ #include #include -#include #include #include "ifcdef.h" +#include "../../../utils/logging.h" Q_DECLARE_LOGGING_CATEGORY(vXML) diff --git a/src/utils/logging.h b/src/utils/logging.h new file mode 100644 index 000000000..f369658ba --- /dev/null +++ b/src/utils/logging.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc. +** Contact: http://www.qt-project.org/legal +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +****************************************************************************/ + +#ifndef LOGGING_H +#define LOGGING_H + +#include + +#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) + +// +// Qt < 5.2 didn't feature categorized logging: +// Just enable qCWarning, qCCritical, but disable qCDebug +// +class QLoggingCategory +{ + Q_DISABLE_COPY(QLoggingCategory) +public: + explicit QLoggingCategory(const char *category) : name(category) {} + ~QLoggingCategory(); + + bool isDebugEnabled() const { return false; } + bool isWarningEnabled() const { return true; } + bool isCriticalEnabled() const { return true; } + + const char *categoryName() const { return name; } + + QLoggingCategory &operator()() { return *this; } + +private: + const char *name; +}; + +#define Q_DECLARE_LOGGING_CATEGORY(name) \ + extern QLoggingCategory &name(); + +// relies on QLoggingCategory(QString) being thread safe! +#define Q_LOGGING_CATEGORY(name, string) \ + QLoggingCategory &name() \ + { \ + static QLoggingCategory category(string); \ + return category; \ + } + +#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0) + +// +// Qt 5.0, 5.1 do have already support for categories in QMessageLogger +// + +#define qCDebug(category, ...) \ + for (bool q_category_enabled = category().isDebugEnabled(); q_category_enabled; q_category_enabled = false) \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).debug(__VA_ARGS__) +#define qCWarning(category, ...) \ + for (bool q_category_enabled = category().isWarningEnabled(); q_category_enabled; q_category_enabled = false) \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).warning(__VA_ARGS__) +#define qCCritical(category, ...) \ + for (bool q_category_enabled = category().isCriticalEnabled(); q_category_enabled; q_category_enabled = false) \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_QT_VERSION < 0x053000INFO, \ + category().categoryName()).critical(__VA_ARGS__) +# endif // QT_VERSION > QT_VERSION_CHECK(5, 0, 0) + +#else // QT_VERSION < QT_VERSION_CHECK(5, 2, 0) + +#include + +#if QT_VERSION < QT_VERSION_CHECK(5, 3, 0) + +// printf style for qCDebug was only added in Qt 5.3 + +#undef qCDebug +#undef qCWarning +#undef qCCritical + +#define qCDebug(category, ...) \ + for (bool q_category_enabled = category().isDebugEnabled(); q_category_enabled; q_category_enabled = false) \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).debug(__VA_ARGS__) +#define qCWarning(category, ...) \ + for (bool q_category_enabled = category().isWarningEnabled(); q_category_enabled; q_category_enabled = false) \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).warning(__VA_ARGS__) +#define qCCritical(category, ...) \ + for (bool q_category_enabled = category().isCriticalEnabled(); q_category_enabled; q_category_enabled = false) \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).critical(__VA_ARGS__) + +#endif // QT_VERSION < QT_VERSION_CHECK(5, 3, 0) + +#endif // QT_VERSION < QT_VERSION_CHECK(5, 2, 0) + +#endif // LOGGING_H diff --git a/src/utils/utils.pri b/src/utils/utils.pri new file mode 100644 index 000000000..6a0c9a70c --- /dev/null +++ b/src/utils/utils.pri @@ -0,0 +1,2 @@ +HEADERS += \ + $$PWD/logging.h