ctkCommandLineParser.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0.txt
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // STL includes
  15. #include <stdexcept>
  16. // Qt includes
  17. #include <QHash>
  18. #include <QStringList>
  19. #include <QTextStream>
  20. #include <QDebug>
  21. #include <QSettings>
  22. #include <QPointer>
  23. // CTK includes
  24. #include "ctkCommandLineParser.h"
  25. namespace
  26. {
  27. // --------------------------------------------------------------------------
  28. class CommandLineParserArgumentDescription
  29. {
  30. public:
  31. CommandLineParserArgumentDescription(
  32. const QString& longArg, const QString& longArgPrefix,
  33. const QString& shortArg, const QString& shortArgPrefix,
  34. QVariant::Type type, const QString& argHelp,
  35. const QVariant& defaultValue, bool ignoreRest,
  36. bool deprecated)
  37. : LongArg(longArg), LongArgPrefix(longArgPrefix),
  38. ShortArg(shortArg), ShortArgPrefix(shortArgPrefix),
  39. ArgHelp(argHelp), IgnoreRest(ignoreRest), NumberOfParametersToProcess(0),
  40. Deprecated(deprecated), DefaultValue(defaultValue), Value(type), ValueType(type)
  41. {
  42. if (defaultValue.isValid())
  43. {
  44. Value = defaultValue;
  45. }
  46. switch (type)
  47. {
  48. case QVariant::String:
  49. {
  50. NumberOfParametersToProcess = 1;
  51. RegularExpression = ".*";
  52. }
  53. break;
  54. case QVariant::Bool:
  55. {
  56. NumberOfParametersToProcess = 0;
  57. RegularExpression = "";
  58. }
  59. break;
  60. case QVariant::StringList:
  61. {
  62. NumberOfParametersToProcess = -1;
  63. RegularExpression = ".*";
  64. }
  65. break;
  66. case QVariant::Int:
  67. {
  68. NumberOfParametersToProcess = 1;
  69. RegularExpression = "-?[0-9]+";
  70. ExactMatchFailedMessage = "A negative or positive integer is expected.";
  71. }
  72. break;
  73. case QVariant::Double:
  74. {
  75. NumberOfParametersToProcess = 1;
  76. RegularExpression = "-?[0-9]*\\.?[0-9]+";
  77. ExactMatchFailedMessage = "A double is expected.";
  78. }
  79. break;
  80. default:
  81. ExactMatchFailedMessage = QString("Type %1 not supported.").arg(static_cast<int>(type));
  82. }
  83. }
  84. ~CommandLineParserArgumentDescription(){}
  85. bool addParameter(const QString& value);
  86. QString helpText(int fieldWidth, const char charPad, const QString& settingsValue = "");
  87. QString LongArg;
  88. QString LongArgPrefix;
  89. QString ShortArg;
  90. QString ShortArgPrefix;
  91. QString ArgHelp;
  92. bool IgnoreRest;
  93. int NumberOfParametersToProcess;
  94. QString RegularExpression;
  95. QString ExactMatchFailedMessage;
  96. bool Deprecated;
  97. QVariant DefaultValue;
  98. QVariant Value;
  99. QVariant::Type ValueType;
  100. };
  101. // --------------------------------------------------------------------------
  102. bool CommandLineParserArgumentDescription::addParameter(const QString& value)
  103. {
  104. if (!RegularExpression.isEmpty())
  105. {
  106. // Validate value
  107. QRegExp regexp(this->RegularExpression);
  108. if (!regexp.exactMatch(value))
  109. {
  110. return false;
  111. }
  112. }
  113. switch (Value.type())
  114. {
  115. case QVariant::String:
  116. {
  117. Value.setValue(value);
  118. }
  119. break;
  120. case QVariant::Bool:
  121. {
  122. Value.setValue(!QString::compare(value, "true", Qt::CaseInsensitive));
  123. }
  124. break;
  125. case QVariant::StringList:
  126. {
  127. if (Value.isNull())
  128. {
  129. QStringList list;
  130. list << value;
  131. Value.setValue(list);
  132. }
  133. else
  134. {
  135. QStringList list = Value.toStringList();
  136. list << value;
  137. Value.setValue(list);
  138. }
  139. }
  140. break;
  141. case QVariant::Int:
  142. {
  143. Value.setValue(value.toInt());
  144. }
  145. break;
  146. case QVariant::Double:
  147. {
  148. Value.setValue(value.toDouble());
  149. }
  150. break;
  151. default:
  152. return false;
  153. }
  154. return true;
  155. }
  156. // --------------------------------------------------------------------------
  157. QString CommandLineParserArgumentDescription::helpText(int fieldWidth, const char charPad,
  158. const QString& settingsValue)
  159. {
  160. QString text;
  161. QTextStream stream(&text);
  162. stream.setFieldAlignment(QTextStream::AlignLeft);
  163. stream.setPadChar(charPad);
  164. QString shortAndLongArg;
  165. if (!this->ShortArg.isEmpty())
  166. {
  167. shortAndLongArg += QString(" %1%2").arg(this->ShortArgPrefix).arg(this->ShortArg);
  168. }
  169. if (!this->LongArg.isEmpty())
  170. {
  171. if (this->ShortArg.isEmpty())
  172. {
  173. shortAndLongArg.append(" ");
  174. }
  175. else
  176. {
  177. shortAndLongArg.append(", ");
  178. }
  179. shortAndLongArg += QString("%1%2").arg(this->LongArgPrefix).arg(this->LongArg);
  180. }
  181. if(!this->ArgHelp.isEmpty())
  182. {
  183. stream.setFieldWidth(fieldWidth);
  184. }
  185. stream << shortAndLongArg;
  186. stream.setFieldWidth(0);
  187. stream << this->ArgHelp;
  188. if (!settingsValue.isNull())
  189. {
  190. stream << " (default: " << settingsValue << ")";
  191. }
  192. else if (!this->DefaultValue.isNull())
  193. {
  194. stream << " (default: " << this->DefaultValue.toString() << ")";
  195. }
  196. stream << "\n";
  197. return text;
  198. }
  199. }
  200. // --------------------------------------------------------------------------
  201. // ctkCommandLineParser::ctkInternal class
  202. // --------------------------------------------------------------------------
  203. class ctkCommandLineParser::ctkInternal
  204. {
  205. public:
  206. ctkInternal(QSettings* settings)
  207. : Debug(false), FieldWidth(0), UseQSettings(false),
  208. Settings(settings), MergeSettings(true), StrictMode(false)
  209. {}
  210. ~ctkInternal() { qDeleteAll(ArgumentDescriptionList); }
  211. CommandLineParserArgumentDescription* argumentDescription(const QString& argument);
  212. QList<CommandLineParserArgumentDescription*> ArgumentDescriptionList;
  213. QHash<QString, CommandLineParserArgumentDescription*> ArgNameToArgumentDescriptionMap;
  214. QMap<QString, QList<CommandLineParserArgumentDescription*> > GroupToArgumentDescriptionListMap;
  215. QStringList UnparsedArguments;
  216. QStringList ProcessedArguments;
  217. QString ErrorString;
  218. bool Debug;
  219. int FieldWidth;
  220. QString LongPrefix;
  221. QString ShortPrefix;
  222. QString CurrentGroup;
  223. bool UseQSettings;
  224. QPointer<QSettings> Settings;
  225. QString DisableQSettingsLongArg;
  226. QString DisableQSettingsShortArg;
  227. bool MergeSettings;
  228. bool StrictMode;
  229. };
  230. // --------------------------------------------------------------------------
  231. // ctkCommandLineParser::ctkInternal methods
  232. // --------------------------------------------------------------------------
  233. CommandLineParserArgumentDescription*
  234. ctkCommandLineParser::ctkInternal::argumentDescription(const QString& argument)
  235. {
  236. QString unprefixedArg = argument;
  237. if (!LongPrefix.isEmpty() && argument.startsWith(LongPrefix))
  238. {
  239. // Case when (ShortPrefix + UnPrefixedArgument) matches LongPrefix
  240. if (argument == LongPrefix && !ShortPrefix.isEmpty() && argument.startsWith(ShortPrefix))
  241. {
  242. unprefixedArg = argument.mid(ShortPrefix.length());
  243. }
  244. else
  245. {
  246. unprefixedArg = argument.mid(LongPrefix.length());
  247. }
  248. }
  249. else if (!ShortPrefix.isEmpty() && argument.startsWith(ShortPrefix))
  250. {
  251. unprefixedArg = argument.mid(ShortPrefix.length());
  252. }
  253. else if (!LongPrefix.isEmpty() && !ShortPrefix.isEmpty())
  254. {
  255. return 0;
  256. }
  257. if (this->ArgNameToArgumentDescriptionMap.contains(unprefixedArg))
  258. {
  259. return this->ArgNameToArgumentDescriptionMap[unprefixedArg];
  260. }
  261. return 0;
  262. }
  263. // --------------------------------------------------------------------------
  264. // ctkCommandLineParser methods
  265. // --------------------------------------------------------------------------
  266. ctkCommandLineParser::ctkCommandLineParser(QObject* newParent) : Superclass(newParent)
  267. {
  268. this->Internal = new ctkInternal(0);
  269. }
  270. // --------------------------------------------------------------------------
  271. ctkCommandLineParser::ctkCommandLineParser(QSettings* settings, QObject* newParent) :
  272. Superclass(newParent)
  273. {
  274. this->Internal = new ctkInternal(settings);
  275. }
  276. // --------------------------------------------------------------------------
  277. ctkCommandLineParser::~ctkCommandLineParser()
  278. {
  279. delete this->Internal;
  280. }
  281. // --------------------------------------------------------------------------
  282. QHash<QString, QVariant> ctkCommandLineParser::parseArguments(const QStringList& arguments,
  283. bool* ok)
  284. {
  285. // Reset
  286. this->Internal->UnparsedArguments.clear();
  287. this->Internal->ProcessedArguments.clear();
  288. this->Internal->ErrorString.clear();
  289. foreach (CommandLineParserArgumentDescription* desc,
  290. this->Internal->ArgumentDescriptionList)
  291. {
  292. desc->Value = QVariant(desc->ValueType);
  293. if (desc->DefaultValue.isValid())
  294. {
  295. desc->Value = desc->DefaultValue;
  296. }
  297. }
  298. bool error = false;
  299. bool ignoreRest = false;
  300. bool useSettings = this->Internal->UseQSettings;
  301. CommandLineParserArgumentDescription * currentArgDesc = 0;
  302. QList<CommandLineParserArgumentDescription*> parsedArgDescriptions;
  303. for(int i = 1; i < arguments.size(); ++i)
  304. {
  305. QString argument = arguments.at(i);
  306. if (this->Internal->Debug) { qDebug() << "Processing" << argument; }
  307. // should argument be ignored ?
  308. if (ignoreRest)
  309. {
  310. if (this->Internal->Debug)
  311. {
  312. qDebug() << " Skipping: IgnoreRest flag was been set";
  313. }
  314. this->Internal->UnparsedArguments << argument;
  315. continue;
  316. }
  317. // Skip if the argument does not start with the defined prefix
  318. if (!(argument.startsWith(this->Internal->LongPrefix)
  319. || argument.startsWith(this->Internal->ShortPrefix)))
  320. {
  321. if (this->Internal->StrictMode)
  322. {
  323. this->Internal->ErrorString = QString("Unknown argument %1").arg(argument);
  324. error = true;
  325. break;
  326. }
  327. if (this->Internal->Debug)
  328. {
  329. qDebug() << " Skipping: It does not start with the defined prefix";
  330. }
  331. this->Internal->UnparsedArguments << argument;
  332. continue;
  333. }
  334. // Skip if argument has already been parsed ...
  335. if (this->Internal->ProcessedArguments.contains(argument))
  336. {
  337. if (this->Internal->StrictMode)
  338. {
  339. this->Internal->ErrorString = QString("Argument %1 already processed !").arg(argument);
  340. error = true;
  341. break;
  342. }
  343. if (this->Internal->Debug)
  344. {
  345. qDebug() << " Skipping: Already processed !";
  346. }
  347. continue;
  348. }
  349. // Retrieve corresponding argument description
  350. currentArgDesc = this->Internal->argumentDescription(argument);
  351. // Is there a corresponding argument description ?
  352. if (currentArgDesc)
  353. {
  354. // If the argument is deprecated, print the help text but continue processing
  355. if (currentArgDesc->Deprecated)
  356. {
  357. qWarning().nospace() << "Deprecated argument " << argument << ": " << currentArgDesc->ArgHelp;
  358. }
  359. else
  360. {
  361. parsedArgDescriptions.push_back(currentArgDesc);
  362. }
  363. // Is the argument the special "disable QSettings" argument?
  364. if ((!currentArgDesc->LongArg.isEmpty() && currentArgDesc->LongArg == this->Internal->DisableQSettingsLongArg)
  365. || (!currentArgDesc->ShortArg.isEmpty() && currentArgDesc->ShortArg == this->Internal->DisableQSettingsShortArg))
  366. {
  367. useSettings = false;
  368. }
  369. this->Internal->ProcessedArguments << currentArgDesc->ShortArg << currentArgDesc->LongArg;
  370. int numberOfParametersToProcess = currentArgDesc->NumberOfParametersToProcess;
  371. ignoreRest = currentArgDesc->IgnoreRest;
  372. if (this->Internal->Debug && ignoreRest)
  373. {
  374. qDebug() << " IgnoreRest flag is True";
  375. }
  376. // Is the number of parameters associated with the argument being processed known ?
  377. if (numberOfParametersToProcess == 0)
  378. {
  379. currentArgDesc->addParameter("true");
  380. }
  381. else if (numberOfParametersToProcess > 0)
  382. {
  383. QString missingParameterError =
  384. "Argument %1 has %2 value(s) associated whereas exacly %3 are expected.";
  385. for(int j=1; j <= numberOfParametersToProcess; ++j)
  386. {
  387. if (i + j >= arguments.size())
  388. {
  389. this->Internal->ErrorString =
  390. missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess);
  391. if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; }
  392. if (ok) { *ok = false; }
  393. return QHash<QString, QVariant>();
  394. }
  395. QString parameter = arguments.at(i + j);
  396. if (this->Internal->Debug)
  397. {
  398. qDebug() << " Processing parameter" << j << ", value:" << parameter;
  399. }
  400. if (this->argumentAdded(parameter))
  401. {
  402. this->Internal->ErrorString =
  403. missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess);
  404. if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; }
  405. if (ok) { *ok = false; }
  406. return QHash<QString, QVariant>();
  407. }
  408. if (!currentArgDesc->addParameter(parameter))
  409. {
  410. this->Internal->ErrorString = QString(
  411. "Value(s) associated with argument %1 are incorrect. %2").
  412. arg(argument).arg(currentArgDesc->ExactMatchFailedMessage);
  413. if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; }
  414. if (ok) { *ok = false; }
  415. return QHash<QString, QVariant>();
  416. }
  417. }
  418. // Update main loop increment
  419. i = i + numberOfParametersToProcess;
  420. }
  421. else if (numberOfParametersToProcess == -1)
  422. {
  423. if (this->Internal->Debug)
  424. {
  425. qDebug() << " Proccessing StringList ...";
  426. }
  427. int j = 1;
  428. while(j + i < arguments.size())
  429. {
  430. if (this->argumentAdded(arguments.at(j + i)))
  431. {
  432. if (this->Internal->Debug)
  433. {
  434. qDebug() << " No more parameter for" << argument;
  435. }
  436. break;
  437. }
  438. QString parameter = arguments.at(j + i);
  439. if (this->Internal->Debug)
  440. {
  441. qDebug() << " Processing parameter" << j << ", value:" << parameter;
  442. }
  443. if (!currentArgDesc->addParameter(parameter))
  444. {
  445. this->Internal->ErrorString = QString(
  446. "Value(s) associated with argument %1 are incorrect. %2").
  447. arg(argument).arg(currentArgDesc->ExactMatchFailedMessage);
  448. if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; }
  449. if (ok) { *ok = false; }
  450. return QHash<QString, QVariant>();
  451. }
  452. j++;
  453. }
  454. // Update main loop increment
  455. i = i + j;
  456. }
  457. }
  458. else
  459. {
  460. if (this->Internal->StrictMode)
  461. {
  462. this->Internal->ErrorString = QString("Unknown argument %1").arg(argument);
  463. error = true;
  464. break;
  465. }
  466. if (this->Internal->Debug)
  467. {
  468. qDebug() << " Skipping: Unknown argument";
  469. }
  470. this->Internal->UnparsedArguments << argument;
  471. }
  472. }
  473. if (ok)
  474. {
  475. *ok = !error;
  476. }
  477. QSettings* settings = 0;
  478. if (this->Internal->UseQSettings && useSettings)
  479. {
  480. if (this->Internal->Settings)
  481. {
  482. settings = this->Internal->Settings;
  483. }
  484. else
  485. {
  486. // Use a default constructed QSettings instance
  487. settings = new QSettings();
  488. }
  489. }
  490. QHash<QString, QVariant> parsedArguments;
  491. QListIterator<CommandLineParserArgumentDescription*> it(this->Internal->ArgumentDescriptionList);
  492. while (it.hasNext())
  493. {
  494. QString key;
  495. CommandLineParserArgumentDescription* desc = it.next();
  496. if (!desc->LongArg.isEmpty())
  497. {
  498. key = desc->LongArg;
  499. }
  500. else
  501. {
  502. key = desc->ShortArg;
  503. }
  504. if (parsedArgDescriptions.contains(desc))
  505. {
  506. // The argument was supplied on the command line, so use the given value
  507. if (this->Internal->MergeSettings && settings)
  508. {
  509. // Merge with QSettings
  510. QVariant settingsVal = settings->value(key);
  511. if (desc->ValueType == QVariant::StringList &&
  512. settingsVal.canConvert(QVariant::StringList))
  513. {
  514. QStringList stringList = desc->Value.toStringList();
  515. stringList.append(settingsVal.toStringList());
  516. parsedArguments.insert(key, stringList);
  517. }
  518. else
  519. {
  520. // do a normal insert
  521. parsedArguments.insert(key, desc->Value);
  522. }
  523. }
  524. else
  525. {
  526. // No merging, just insert all user values
  527. parsedArguments.insert(key, desc->Value);
  528. }
  529. }
  530. else
  531. {
  532. if (settings)
  533. {
  534. // If there is a valid QSettings entry for the argument, use the value
  535. QVariant settingsVal = settings->value(key, desc->Value);
  536. if (!settingsVal.isNull())
  537. {
  538. parsedArguments.insert(key, settingsVal);
  539. }
  540. }
  541. else
  542. {
  543. // Just insert the arguments with valid default values
  544. if (!desc->Value.isNull())
  545. {
  546. parsedArguments.insert(key, desc->Value);
  547. }
  548. }
  549. }
  550. }
  551. // If we created a default QSettings instance, delete it
  552. if (settings && !this->Internal->Settings)
  553. {
  554. delete settings;
  555. }
  556. return parsedArguments;
  557. }
  558. // -------------------------------------------------------------------------
  559. QHash<QString, QVariant> ctkCommandLineParser::parseArguments(int argc, char** argv, bool* ok)
  560. {
  561. QStringList arguments;
  562. // Create a QStringList of arguments
  563. for(int i = 0; i < argc; ++i)
  564. {
  565. arguments << argv[i];
  566. }
  567. return this->parseArguments(arguments, ok);
  568. }
  569. // -------------------------------------------------------------------------
  570. QString ctkCommandLineParser::errorString() const
  571. {
  572. return this->Internal->ErrorString;
  573. }
  574. // -------------------------------------------------------------------------
  575. const QStringList& ctkCommandLineParser::unparsedArguments() const
  576. {
  577. return this->Internal->UnparsedArguments;
  578. }
  579. // --------------------------------------------------------------------------
  580. void ctkCommandLineParser::addArgument(const QString& longarg, const QString& shortarg,
  581. QVariant::Type type, const QString& argHelp,
  582. const QVariant& defaultValue, bool ignoreRest,
  583. bool deprecated)
  584. {
  585. Q_ASSERT_X(!(longarg.isEmpty() && shortarg.isEmpty()), "addArgument",
  586. "both long and short argument names are empty");
  587. if (longarg.isEmpty() && shortarg.isEmpty()) { return; }
  588. Q_ASSERT_X(!defaultValue.isValid() || defaultValue.type() == type, "addArgument",
  589. "defaultValue type does not match");
  590. if (defaultValue.isValid() && defaultValue.type() != type)
  591. throw std::logic_error("The QVariant type of defaultValue does not match the specified type");
  592. /* Make sure it's not already added */
  593. bool added = this->Internal->ArgNameToArgumentDescriptionMap.contains(longarg);
  594. Q_ASSERT_X(!added, "addArgument", "long argument already added");
  595. if (added) { return; }
  596. added = this->Internal->ArgNameToArgumentDescriptionMap.contains(shortarg);
  597. Q_ASSERT_X(!added, "addArgument", "short argument already added");
  598. if (added) { return; }
  599. CommandLineParserArgumentDescription* argDesc =
  600. new CommandLineParserArgumentDescription(longarg, this->Internal->LongPrefix,
  601. shortarg, this->Internal->ShortPrefix, type,
  602. argHelp, defaultValue, ignoreRest, deprecated);
  603. int argWidth = 0;
  604. if (!longarg.isEmpty())
  605. {
  606. this->Internal->ArgNameToArgumentDescriptionMap[longarg] = argDesc;
  607. argWidth += longarg.length() + this->Internal->LongPrefix.length();
  608. }
  609. if (!shortarg.isEmpty())
  610. {
  611. this->Internal->ArgNameToArgumentDescriptionMap[shortarg] = argDesc;
  612. argWidth += shortarg.length() + this->Internal->ShortPrefix.length() + 2;
  613. }
  614. argWidth += 5;
  615. // Set the field width for the arguments
  616. if (argWidth > this->Internal->FieldWidth)
  617. {
  618. this->Internal->FieldWidth = argWidth;
  619. }
  620. this->Internal->ArgumentDescriptionList << argDesc;
  621. this->Internal->GroupToArgumentDescriptionListMap[this->Internal->CurrentGroup] << argDesc;
  622. }
  623. // --------------------------------------------------------------------------
  624. void ctkCommandLineParser::addDeprecatedArgument(
  625. const QString& longarg, const QString& shortarg, const QString& argHelp)
  626. {
  627. addArgument(longarg, shortarg, QVariant::StringList, argHelp, QVariant(), false, true);
  628. }
  629. // --------------------------------------------------------------------------
  630. bool ctkCommandLineParser::setExactMatchRegularExpression(
  631. const QString& argument, const QString& expression, const QString& exactMatchFailedMessage)
  632. {
  633. CommandLineParserArgumentDescription * argDesc =
  634. this->Internal->argumentDescription(argument);
  635. if (!argDesc)
  636. {
  637. return false;
  638. }
  639. if (argDesc->Value.type() == QVariant::Bool)
  640. {
  641. return false;
  642. }
  643. argDesc->RegularExpression = expression;
  644. argDesc->ExactMatchFailedMessage = exactMatchFailedMessage;
  645. return true;
  646. }
  647. // --------------------------------------------------------------------------
  648. int ctkCommandLineParser::fieldWidth() const
  649. {
  650. return this->Internal->FieldWidth;
  651. }
  652. // --------------------------------------------------------------------------
  653. void ctkCommandLineParser::beginGroup(const QString& description)
  654. {
  655. this->Internal->CurrentGroup = description;
  656. }
  657. // --------------------------------------------------------------------------
  658. void ctkCommandLineParser::endGroup()
  659. {
  660. this->Internal->CurrentGroup.clear();
  661. }
  662. // --------------------------------------------------------------------------
  663. void ctkCommandLineParser::enableSettings(const QString& disableLongArg, const QString& disableShortArg)
  664. {
  665. this->Internal->UseQSettings = true;
  666. this->Internal->DisableQSettingsLongArg = disableLongArg;
  667. this->Internal->DisableQSettingsShortArg = disableShortArg;
  668. }
  669. // --------------------------------------------------------------------------
  670. void ctkCommandLineParser::mergeSettings(bool merge)
  671. {
  672. this->Internal->MergeSettings = merge;
  673. }
  674. // --------------------------------------------------------------------------
  675. bool ctkCommandLineParser::settingsEnabled() const
  676. {
  677. return this->Internal->UseQSettings;
  678. }
  679. // --------------------------------------------------------------------------
  680. QString ctkCommandLineParser::helpText(const char charPad) const
  681. {
  682. QString text;
  683. QTextStream stream(&text);
  684. QList<CommandLineParserArgumentDescription*> deprecatedArgs;
  685. // Loop over grouped argument descriptions
  686. QMapIterator<QString, QList<CommandLineParserArgumentDescription*> > it(
  687. this->Internal->GroupToArgumentDescriptionListMap);
  688. while(it.hasNext())
  689. {
  690. it.next();
  691. if (!it.key().isEmpty())
  692. {
  693. stream << "\n" << it.key() << "\n";
  694. }
  695. foreach(CommandLineParserArgumentDescription* argDesc, it.value())
  696. {
  697. if (argDesc->Deprecated)
  698. {
  699. deprecatedArgs << argDesc;
  700. }
  701. else
  702. {
  703. // Extract associated value from settings if any
  704. QString settingsValue;
  705. if (this->Internal->Settings)
  706. {
  707. QString key;
  708. if (!argDesc->LongArg.isEmpty())
  709. {
  710. key = argDesc->LongArg;
  711. }
  712. else
  713. {
  714. key = argDesc->ShortArg;
  715. }
  716. settingsValue = this->Internal->Settings->value(key).toString();
  717. }
  718. stream << argDesc->helpText(this->Internal->FieldWidth, charPad, settingsValue);
  719. }
  720. }
  721. }
  722. if (!deprecatedArgs.empty())
  723. {
  724. stream << "\nDeprecated arguments:\n";
  725. foreach(CommandLineParserArgumentDescription* argDesc, deprecatedArgs)
  726. {
  727. stream << argDesc->helpText(this->Internal->FieldWidth, charPad);
  728. }
  729. }
  730. return text;
  731. }
  732. // --------------------------------------------------------------------------
  733. bool ctkCommandLineParser::argumentAdded(const QString& argument) const
  734. {
  735. return this->Internal->ArgNameToArgumentDescriptionMap.contains(argument);
  736. }
  737. // --------------------------------------------------------------------------
  738. bool ctkCommandLineParser::argumentParsed(const QString& argument) const
  739. {
  740. return this->Internal->ProcessedArguments.contains(argument);
  741. }
  742. // --------------------------------------------------------------------------
  743. void ctkCommandLineParser::setArgumentPrefix(const QString& longPrefix, const QString& shortPrefix)
  744. {
  745. this->Internal->LongPrefix = longPrefix;
  746. this->Internal->ShortPrefix = shortPrefix;
  747. }
  748. // --------------------------------------------------------------------------
  749. void ctkCommandLineParser::setStrictModeEnabled(bool strictMode)
  750. {
  751. this->Internal->StrictMode = strictMode;
  752. }