qBittorrent
cmdoptions.cpp
Go to the documentation of this file.
1 /*
2  * Bittorrent Client using Qt and libtorrent.
3  * Copyright (C) 2016 Eugene Shalygin <eugene.shalygin@gmail.com>
4  * Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
5  * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * In addition, as a special exception, the copyright holders give permission to
22  * link this program with the OpenSSL project's "OpenSSL" library (or with
23  * modified versions of it that use the same license as the "OpenSSL" library),
24  * and distribute the linked executables. You must obey the GNU General Public
25  * License in all respects for all of the code used other than "OpenSSL". If you
26  * modify file(s), you may extend this exception to your version of the file(s),
27  * but you are not obligated to do so. If you do not wish to do so, delete this
28  * exception statement from your version.
29  */
30 
31 #include "cmdoptions.h"
32 
33 #include <cstdio>
34 
35 #include <QDebug>
36 #include <QFileInfo>
37 #include <QProcessEnvironment>
38 #include <QTextStream>
39 
40 #if defined(Q_OS_WIN) && !defined(DISABLE_GUI)
41 #include <QMessageBox>
42 #endif
43 
44 #include "base/global.h"
45 #include "base/utils/misc.h"
46 #include "base/utils/string.h"
47 
48 #ifndef DISABLE_GUI
49 #include "gui/utils.h"
50 #endif
51 
52 namespace
53 {
54  const int USAGE_INDENTATION = 4;
55  const int USAGE_TEXT_COLUMN = 31;
56  const int WRAP_AT_COLUMN = 80;
57 
58  // Base option class. Encapsulates name operations.
59  class Option
60  {
61  protected:
62  explicit constexpr Option(const char *name, char shortcut = 0)
63  : m_name {name}
64  , m_shortcut {shortcut}
65  {
66  }
67 
68  QString fullParameter() const
69  {
70  return QLatin1String("--") + QLatin1String(m_name);
71  }
72 
73  QString shortcutParameter() const
74  {
75  return QLatin1String("-") + QLatin1Char(m_shortcut);
76  }
77 
78  bool hasShortcut() const
79  {
80  return m_shortcut != 0;
81  }
82 
83  QString envVarName() const
84  {
85  return QLatin1String("QBT_")
86  + QString::fromLatin1(m_name).toUpper().replace(QLatin1Char('-'), QLatin1Char('_'));
87  }
88 
89  public:
90  static QString padUsageText(const QString &usage)
91  {
92  QString res = QString(USAGE_INDENTATION, ' ') + usage;
93 
94  if ((USAGE_TEXT_COLUMN - usage.length() - 4) > 0)
95  return res + QString(USAGE_TEXT_COLUMN - usage.length() - 4, ' ');
96 
97  return res;
98  }
99 
100  private:
101  const char *m_name;
102  const char m_shortcut;
103  };
104 
105  // Boolean option.
106  class BoolOption : protected Option
107  {
108  public:
109  explicit constexpr BoolOption(const char *name, char shortcut = 0)
110  : Option {name, shortcut}
111  {
112  }
113 
114  bool operator==(const QString &arg) const
115  {
116  return (hasShortcut() && ((arg.size() == 2) && (arg == shortcutParameter())))
117  || (arg == fullParameter());
118  }
119 
120  bool value(const QProcessEnvironment &env) const
121  {
122  QString val = env.value(envVarName());
123  // we accept "1" and "true" (upper or lower cased) as boolean 'true' values
124  return ((val == QLatin1String("1")) || (val.toUpper() == QLatin1String("TRUE")));
125  }
126 
127  QString usage() const
128  {
129  QString res;
130  if (hasShortcut())
131  res += shortcutParameter() + QLatin1String(" | ");
132  res += fullParameter();
133  return padUsageText(res);
134  }
135  };
136 
137  bool operator==(const QString &s, const BoolOption &o)
138  {
139  return o == s;
140  }
141 
142  // Option with string value. May not have a shortcut
143  struct StringOption : protected Option
144  {
145  public:
146  explicit constexpr StringOption(const char *name)
147  : Option {name, 0}
148  {
149  }
150 
151  bool operator==(const QString &arg) const
152  {
153  return arg.startsWith(parameterAssignment());
154  }
155 
156  QString value(const QString &arg) const
157  {
158  QStringList parts = arg.split(QLatin1Char('='));
159  if (parts.size() == 2)
160  return Utils::String::unquote(parts[1], QLatin1String("'\""));
161  throw CommandLineParameterError(QObject::tr("Parameter '%1' must follow syntax '%1=%2'",
162  "e.g. Parameter '--webui-port' must follow syntax '--webui-port=value'")
163  .arg(fullParameter(), QLatin1String("<value>")));
164  }
165 
166  QString value(const QProcessEnvironment &env, const QString &defaultValue = {}) const
167  {
168  QString val = env.value(envVarName());
169  return val.isEmpty() ? defaultValue : Utils::String::unquote(val, QLatin1String("'\""));
170  }
171 
172  QString usage(const QString &valueName) const
173  {
174  return padUsageText(parameterAssignment() + QLatin1Char('<') + valueName + QLatin1Char('>'));
175  }
176 
177  private:
178  QString parameterAssignment() const
179  {
180  return fullParameter() + QLatin1Char('=');
181  }
182  };
183 
184  bool operator==(const QString &s, const StringOption &o)
185  {
186  return o == s;
187  }
188 
189  // Option with integer value. May not have a shortcut
190  class IntOption : protected StringOption
191  {
192  public:
193  explicit constexpr IntOption(const char *name)
194  : StringOption {name}
195  {
196  }
197 
198  using StringOption::operator==;
199  using StringOption::usage;
200 
201  int value(const QString &arg) const
202  {
203  QString val = StringOption::value(arg);
204  bool ok = false;
205  int res = val.toInt(&ok);
206  if (!ok)
207  throw CommandLineParameterError(QObject::tr("Parameter '%1' must follow syntax '%1=%2'",
208  "e.g. Parameter '--webui-port' must follow syntax '--webui-port=<value>'")
209  .arg(fullParameter(), QLatin1String("<integer value>")));
210  return res;
211  }
212 
213  int value(const QProcessEnvironment &env, int defaultValue) const
214  {
215  QString val = env.value(envVarName());
216  if (val.isEmpty()) return defaultValue;
217 
218  bool ok;
219  int res = val.toInt(&ok);
220  if (!ok)
221  {
222  qDebug() << QObject::tr("Expected integer number in environment variable '%1', but got '%2'")
223  .arg(envVarName(), val);
224  return defaultValue;
225  }
226  return res;
227  }
228  };
229 
230  bool operator==(const QString &s, const IntOption &o)
231  {
232  return o == s;
233  }
234 
235  // Option that is explicitly set to true or false, and whose value is undefined when unspecified.
236  // May not have a shortcut.
237  class TriStateBoolOption : protected Option
238  {
239  public:
240  constexpr TriStateBoolOption(const char *name, bool defaultValue)
241  : Option {name, 0}
242  , m_defaultValue(defaultValue)
243  {
244  }
245 
246  bool operator==(const QString &arg) const
247  {
248  QStringList parts = arg.split(QLatin1Char('='));
249  return parts[0] == fullParameter();
250  }
251 
252  QString usage() const
253  {
254  return padUsageText(fullParameter() + QLatin1String("=<true|false>"));
255  }
256 
257  std::optional<bool> value(const QString &arg) const
258  {
259  QStringList parts = arg.split(QLatin1Char('='));
260 
261  if (parts.size() == 1)
262  {
263  return m_defaultValue;
264  }
265  if (parts.size() == 2)
266  {
267  QString val = parts[1];
268 
269  if ((val.toUpper() == QLatin1String("TRUE")) || (val == QLatin1String("1")))
270  {
271  return true;
272  }
273  if ((val.toUpper() == QLatin1String("FALSE")) || (val == QLatin1String("0")))
274  {
275  return false;
276  }
277  }
278 
279  throw CommandLineParameterError(QObject::tr("Parameter '%1' must follow syntax '%1=%2'",
280  "e.g. Parameter '--add-paused' must follow syntax "
281  "'--add-paused=<true|false>'")
282  .arg(fullParameter(), QLatin1String("<true|false>")));
283  }
284 
285  std::optional<bool> value(const QProcessEnvironment &env) const
286  {
287  const QString val = env.value(envVarName(), "-1");
288 
289  if (val.isEmpty())
290  {
291  return m_defaultValue;
292  }
293  if (val == QLatin1String("-1"))
294  {
295  return std::nullopt;
296  }
297  if ((val.toUpper() == QLatin1String("TRUE")) || (val == QLatin1String("1")))
298  {
299  return true;
300  }
301  if ((val.toUpper() == QLatin1String("FALSE")) || (val == QLatin1String("0")))
302  {
303  return false;
304  }
305 
306  qDebug() << QObject::tr("Expected %1 in environment variable '%2', but got '%3'")
307  .arg(QLatin1String("true|false"), envVarName(), val);
308  return std::nullopt;
309  }
310 
312  };
313 
314  bool operator==(const QString &s, const TriStateBoolOption &o)
315  {
316  return o == s;
317  }
318 
319  constexpr const BoolOption SHOW_HELP_OPTION {"help", 'h'};
320  constexpr const BoolOption SHOW_VERSION_OPTION {"version", 'v'};
321 #if defined(DISABLE_GUI) && !defined(Q_OS_WIN)
322  constexpr const BoolOption DAEMON_OPTION {"daemon", 'd'};
323 #else
324  constexpr const BoolOption NO_SPLASH_OPTION {"no-splash"};
325 #endif
326  constexpr const IntOption WEBUI_PORT_OPTION {"webui-port"};
327  constexpr const StringOption PROFILE_OPTION {"profile"};
328  constexpr const StringOption CONFIGURATION_OPTION {"configuration"};
329  constexpr const BoolOption RELATIVE_FASTRESUME {"relative-fastresume"};
330  constexpr const StringOption SAVE_PATH_OPTION {"save-path"};
331  constexpr const TriStateBoolOption PAUSED_OPTION {"add-paused", true};
332  constexpr const BoolOption SKIP_HASH_CHECK_OPTION {"skip-hash-check"};
333  constexpr const StringOption CATEGORY_OPTION {"category"};
334  constexpr const BoolOption SEQUENTIAL_OPTION {"sequential"};
335  constexpr const BoolOption FIRST_AND_LAST_OPTION {"first-and-last"};
336  constexpr const TriStateBoolOption SKIP_DIALOG_OPTION {"skip-dialog", true};
337 }
338 
340  : showHelp(false)
341  , relativeFastresumePaths(RELATIVE_FASTRESUME.value(env))
342  , skipChecking(SKIP_HASH_CHECK_OPTION.value(env))
343  , sequential(SEQUENTIAL_OPTION.value(env))
344  , firstLastPiecePriority(FIRST_AND_LAST_OPTION.value(env))
345 #if !defined(Q_OS_WIN) || defined(DISABLE_GUI)
346  , showVersion(false)
347 #endif
348 #ifndef DISABLE_GUI
349  , noSplash(NO_SPLASH_OPTION.value(env))
350 #elif !defined(Q_OS_WIN)
351  , shouldDaemonize(DAEMON_OPTION.value(env))
352 #endif
353  , webUiPort(WEBUI_PORT_OPTION.value(env, -1))
354  , addPaused(PAUSED_OPTION.value(env))
355  , skipDialog(SKIP_DIALOG_OPTION.value(env))
356  , profileDir(PROFILE_OPTION.value(env))
357  , configurationName(CONFIGURATION_OPTION.value(env))
358  , savePath(SAVE_PATH_OPTION.value(env))
359  , category(CATEGORY_OPTION.value(env))
360 {
361 }
362 
364 {
365  QStringList result;
366  // Because we're passing a string list to the currently running
367  // qBittorrent process, we need some way of passing along the options
368  // the user has specified. Here we place special strings that are
369  // almost certainly not going to collide with a file path or URL
370  // specified by the user, and placing them at the beginning of the
371  // string list so that they will be processed before the list of
372  // torrent paths or URLs.
373 
374  if (!savePath.isEmpty())
375  result.append(QLatin1String("@savePath=") + savePath);
376 
377  if (addPaused.has_value())
378  result.append(*addPaused ? QLatin1String {"@addPaused=1"} : QLatin1String {"@addPaused=0"});
379 
380  if (skipChecking)
381  result.append(QLatin1String("@skipChecking"));
382 
383  if (!category.isEmpty())
384  result.append(QLatin1String("@category=") + category);
385 
386  if (sequential)
387  result.append(QLatin1String("@sequential"));
388 
390  result.append(QLatin1String("@firstLastPiecePriority"));
391 
392  if (skipDialog.has_value())
393  result.append(*skipDialog ? QLatin1String {"@skipDialog=1"} : QLatin1String {"@skipDialog=0"});
394 
395  result += torrents;
396  return result;
397 }
398 
400 {
401  QBtCommandLineParameters result {QProcessEnvironment::systemEnvironment()};
402 
403  for (int i = 1; i < args.count(); ++i)
404  {
405  const QString &arg = args[i];
406 
407  if ((arg.startsWith("--") && !arg.endsWith(".torrent"))
408  || (arg.startsWith('-') && (arg.size() == 2)))
409  {
410  // Parse known parameters
411  if (arg == SHOW_HELP_OPTION)
412  {
413  result.showHelp = true;
414  }
415 #if !defined(Q_OS_WIN) || defined(DISABLE_GUI)
416  else if (arg == SHOW_VERSION_OPTION)
417  {
418  result.showVersion = true;
419  }
420 #endif
421  else if (arg == WEBUI_PORT_OPTION)
422  {
423  result.webUiPort = WEBUI_PORT_OPTION.value(arg);
424  if ((result.webUiPort < 1) || (result.webUiPort > 65535))
425  throw CommandLineParameterError(QObject::tr("%1 must specify a valid port (1 to 65535).")
426  .arg(QLatin1String("--webui-port")));
427  }
428 #ifndef DISABLE_GUI
429  else if (arg == NO_SPLASH_OPTION)
430  {
431  result.noSplash = true;
432  }
433 #elif !defined(Q_OS_WIN)
434  else if (arg == DAEMON_OPTION)
435  {
436  result.shouldDaemonize = true;
437  }
438 #endif
439  else if (arg == PROFILE_OPTION)
440  {
441  result.profileDir = PROFILE_OPTION.value(arg);
442  }
443  else if (arg == RELATIVE_FASTRESUME)
444  {
445  result.relativeFastresumePaths = true;
446  }
447  else if (arg == CONFIGURATION_OPTION)
448  {
449  result.configurationName = CONFIGURATION_OPTION.value(arg);
450  }
451  else if (arg == SAVE_PATH_OPTION)
452  {
453  result.savePath = SAVE_PATH_OPTION.value(arg);
454  }
455  else if (arg == PAUSED_OPTION)
456  {
457  result.addPaused = PAUSED_OPTION.value(arg);
458  }
459  else if (arg == SKIP_HASH_CHECK_OPTION)
460  {
461  result.skipChecking = true;
462  }
463  else if (arg == CATEGORY_OPTION)
464  {
465  result.category = CATEGORY_OPTION.value(arg);
466  }
467  else if (arg == SEQUENTIAL_OPTION)
468  {
469  result.sequential = true;
470  }
471  else if (arg == FIRST_AND_LAST_OPTION)
472  {
473  result.firstLastPiecePriority = true;
474  }
475  else if (arg == SKIP_DIALOG_OPTION)
476  {
477  result.skipDialog = SKIP_DIALOG_OPTION.value(arg);
478  }
479  else
480  {
481  // Unknown argument
482  result.unknownParameter = arg;
483  break;
484  }
485  }
486  else
487  {
488  QFileInfo torrentPath;
489  torrentPath.setFile(arg);
490 
491  if (torrentPath.exists())
492  result.torrents += torrentPath.absoluteFilePath();
493  else
494  result.torrents += arg;
495  }
496  }
497 
498  return result;
499 }
500 
501 QString wrapText(const QString &text, int initialIndentation = USAGE_TEXT_COLUMN, int wrapAtColumn = WRAP_AT_COLUMN)
502 {
503  QStringList words = text.split(' ');
504  QStringList lines = {words.first()};
505  int currentLineMaxLength = wrapAtColumn - initialIndentation;
506 
507  for (const QString &word : asConst(words.mid(1)))
508  {
509  if (lines.last().length() + word.length() + 1 < currentLineMaxLength)
510  {
511  lines.last().append(' ' + word);
512  }
513  else
514  {
515  lines.append(QString(initialIndentation, ' ') + word);
516  currentLineMaxLength = wrapAtColumn;
517  }
518  }
519 
520  return lines.join('\n');
521 }
522 
523 QString makeUsage(const QString &prgName)
524 {
525  QString text;
526  QTextStream stream(&text, QIODevice::WriteOnly);
527  QString indentation = QString(USAGE_INDENTATION, ' ');
528 
529  stream << QObject::tr("Usage:") << '\n'
530  << indentation << prgName << QLatin1String(" [options] [(<filename> | <url>)...]") << '\n'
531 
532  << QObject::tr("Options:") << '\n'
533 #if !defined(Q_OS_WIN) || defined(DISABLE_GUI)
534  << SHOW_VERSION_OPTION.usage() << wrapText(QObject::tr("Display program version and exit")) << '\n'
535 #endif
536  << SHOW_HELP_OPTION.usage() << wrapText(QObject::tr("Display this help message and exit")) << '\n'
537  << WEBUI_PORT_OPTION.usage(QObject::tr("port"))
538  << wrapText(QObject::tr("Change the Web UI port"))
539  << '\n'
540 #ifndef DISABLE_GUI
541  << NO_SPLASH_OPTION.usage() << wrapText(QObject::tr("Disable splash screen")) << '\n'
542 #elif !defined(Q_OS_WIN)
543  << DAEMON_OPTION.usage() << wrapText(QObject::tr("Run in daemon-mode (background)")) << '\n'
544 #endif
545  //: Use appropriate short form or abbreviation of "directory"
546  << PROFILE_OPTION.usage(QObject::tr("dir"))
547  << wrapText(QObject::tr("Store configuration files in <dir>")) << '\n'
548  << CONFIGURATION_OPTION.usage(QObject::tr("name"))
549  << wrapText(QObject::tr("Store configuration files in directories qBittorrent_<name>")) << '\n'
551  << wrapText(QObject::tr("Hack into libtorrent fastresume files and make file paths relative "
552  "to the profile directory")) << '\n'
553  << Option::padUsageText(QObject::tr("files or URLs"))
554  << wrapText(QObject::tr("Download the torrents passed by the user")) << '\n'
555  << '\n'
556 
557  << wrapText(QObject::tr("Options when adding new torrents:"), 0) << '\n'
558  << SAVE_PATH_OPTION.usage(QObject::tr("path")) << wrapText(QObject::tr("Torrent save path")) << '\n'
559  << PAUSED_OPTION.usage() << wrapText(QObject::tr("Add torrents as started or paused")) << '\n'
560  << SKIP_HASH_CHECK_OPTION.usage() << wrapText(QObject::tr("Skip hash check")) << '\n'
561  << CATEGORY_OPTION.usage(QObject::tr("name"))
562  << wrapText(QObject::tr("Assign torrents to category. If the category doesn't exist, it will be "
563  "created.")) << '\n'
564  << SEQUENTIAL_OPTION.usage() << wrapText(QObject::tr("Download files in sequential order")) << '\n'
566  << wrapText(QObject::tr("Download first and last pieces first")) << '\n'
568  << wrapText(QObject::tr("Specify whether the \"Add New Torrent\" dialog opens when adding a "
569  "torrent.")) << '\n'
570  << '\n'
571 
572  << wrapText(QObject::tr("Option values may be supplied via environment variables. For option named "
573  "'parameter-name', environment variable name is 'QBT_PARAMETER_NAME' (in upper "
574  "case, '-' replaced with '_'). To pass flag values, set the variable to '1' or "
575  "'TRUE'. For example, to disable the splash screen: "), 0) << "\n"
576  << QLatin1String("QBT_NO_SPLASH=1 ") << prgName << '\n'
577  << wrapText(QObject::tr("Command line parameters take precedence over environment variables"), 0) << '\n';
578 
579  return text;
580 }
581 
582 void displayUsage(const QString &prgName)
583 {
584 #if defined(Q_OS_WIN) && !defined(DISABLE_GUI)
585  QMessageBox msgBox(QMessageBox::Information, QObject::tr("Help"), makeUsage(prgName), QMessageBox::Ok);
586  msgBox.show(); // Need to be shown or to moveToCenter does not work
587  msgBox.move(Utils::Gui::screenCenter(&msgBox));
588  msgBox.exec();
589 #else
590  printf("%s\n", qUtf8Printable(makeUsage(prgName)));
591 #endif
592 }
QBITTORRENT_HAS_EXECINFO_H if(NOT QBITTORRENT_HAS_EXECINFO_H) message(FATAL_ERROR "execinfo.h header file not found.\n" "Please either disable the STACKTRACE feature or use a libc that has this header file
bool operator==(const QString &arg) const
Definition: cmdoptions.cpp:114
constexpr BoolOption(const char *name, char shortcut=0)
Definition: cmdoptions.cpp:109
bool value(const QProcessEnvironment &env) const
Definition: cmdoptions.cpp:120
int value(const QProcessEnvironment &env, int defaultValue) const
Definition: cmdoptions.cpp:213
QString usage(const QString &valueName) const
Definition: cmdoptions.cpp:172
static QString padUsageText(const QString &usage)
Definition: cmdoptions.cpp:90
constexpr Option(const char *name, char shortcut=0)
Definition: cmdoptions.cpp:62
std::optional< bool > value(const QString &arg) const
Definition: cmdoptions.cpp:257
constexpr TriStateBoolOption(const char *name, bool defaultValue)
Definition: cmdoptions.cpp:240
std::optional< bool > value(const QProcessEnvironment &env) const
Definition: cmdoptions.cpp:285
void displayUsage(const QString &prgName)
Definition: cmdoptions.cpp:582
QString makeUsage(const QString &prgName)
Definition: cmdoptions.cpp:523
QString wrapText(const QString &text, int initialIndentation=USAGE_TEXT_COLUMN, int wrapAtColumn=WRAP_AT_COLUMN)
Definition: cmdoptions.cpp:501
QBtCommandLineParameters parseCommandLine(const QStringList &args)
Definition: cmdoptions.cpp:399
constexpr std::add_const_t< T > & asConst(T &t) noexcept
Definition: global.h:42
QPoint screenCenter(const QWidget *w)
Definition: utils.cpp:119
T unquote(const T &str, const QString &quotes=QChar('"'))
Definition: string.h:45
constexpr const StringOption CATEGORY_OPTION
Definition: cmdoptions.cpp:333
bool operator==(const QString &s, const TriStateBoolOption &o)
Definition: cmdoptions.cpp:314
constexpr const StringOption SAVE_PATH_OPTION
Definition: cmdoptions.cpp:330
constexpr const TriStateBoolOption SKIP_DIALOG_OPTION
Definition: cmdoptions.cpp:336
constexpr const BoolOption NO_SPLASH_OPTION
Definition: cmdoptions.cpp:324
constexpr const BoolOption SHOW_VERSION_OPTION
Definition: cmdoptions.cpp:320
constexpr const BoolOption RELATIVE_FASTRESUME
Definition: cmdoptions.cpp:329
constexpr const StringOption PROFILE_OPTION
Definition: cmdoptions.cpp:327
constexpr const IntOption WEBUI_PORT_OPTION
Definition: cmdoptions.cpp:326
constexpr const BoolOption SEQUENTIAL_OPTION
Definition: cmdoptions.cpp:334
constexpr const BoolOption FIRST_AND_LAST_OPTION
Definition: cmdoptions.cpp:335
constexpr const BoolOption SKIP_HASH_CHECK_OPTION
Definition: cmdoptions.cpp:332
constexpr const BoolOption SHOW_HELP_OPTION
Definition: cmdoptions.cpp:319
constexpr const StringOption CONFIGURATION_OPTION
Definition: cmdoptions.cpp:328
constexpr const TriStateBoolOption PAUSED_OPTION
Definition: cmdoptions.cpp:331
T value(const QString &key, const T &defaultValue={})
Definition: preferences.cpp:64
args
Definition: tstool.py:153
std::optional< bool > addPaused
Definition: cmdoptions.h:58
QStringList paramList() const
Definition: cmdoptions.cpp:363
QBtCommandLineParameters(const QProcessEnvironment &)
Definition: cmdoptions.cpp:339
std::optional< bool > skipDialog
Definition: cmdoptions.h:59
QString value(const QProcessEnvironment &env, const QString &defaultValue={}) const
Definition: cmdoptions.cpp:166
QString value(const QString &arg) const
Definition: cmdoptions.cpp:156
bool operator==(const QString &arg) const
Definition: cmdoptions.cpp:151
QString usage(const QString &valueName) const
Definition: cmdoptions.cpp:172