30#include <Qsci/qscilexer.h>
32#include "moc_qgssqlcomposerdialog.cpp"
34using namespace Qt::StringLiterals;
45 connect( mTablesCombo,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsSQLComposerDialog::mTablesCombo_currentIndexChanged );
46 connect( mColumnsCombo,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsSQLComposerDialog::mColumnsCombo_currentIndexChanged );
47 connect( mSpatialPredicatesCombo,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsSQLComposerDialog::mSpatialPredicatesCombo_currentIndexChanged );
48 connect( mFunctionsCombo,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsSQLComposerDialog::mFunctionsCombo_currentIndexChanged );
49 connect( mOperatorsCombo,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsSQLComposerDialog::mOperatorsCombo_currentIndexChanged );
50 connect( mAddJoinButton, &QPushButton::clicked,
this, &QgsSQLComposerDialog::mAddJoinButton_clicked );
51 connect( mRemoveJoinButton, &QPushButton::clicked,
this, &QgsSQLComposerDialog::mRemoveJoinButton_clicked );
52 connect( mTableJoins, &QTableWidget::itemSelectionChanged,
this, &QgsSQLComposerDialog::mTableJoins_itemSelectionChanged );
54 mQueryEdit->setWrapMode( QsciScintilla::WrapWord );
55 mQueryEdit->installEventFilter(
this );
56 mColumnsEditor->installEventFilter(
this );
57 mTablesEditor->installEventFilter(
this );
58 mTableJoins->installEventFilter(
this );
59 mWhereEditor->installEventFilter(
this );
60 mOrderEditor->installEventFilter(
this );
61 mTablesCombo->view()->installEventFilter(
this );
64 connect( mButtonBox->button( QDialogButtonBox::Reset ), &QAbstractButton::clicked,
this, &QgsSQLComposerDialog::reset );
66 connect( mQueryEdit, &QsciScintilla::textChanged,
this, &QgsSQLComposerDialog::splitSQLIntoFields );
67 connect( mColumnsEditor, &QTextEdit::textChanged,
this, &QgsSQLComposerDialog::buildSQLFromFields );
68 connect( mTablesEditor, &QLineEdit::textChanged,
this, &QgsSQLComposerDialog::buildSQLFromFields );
69 connect( mWhereEditor, &QTextEdit::textChanged,
this, &QgsSQLComposerDialog::buildSQLFromFields );
70 connect( mOrderEditor, &QTextEdit::textChanged,
this, &QgsSQLComposerDialog::buildSQLFromFields );
71 connect( mTableJoins, &QTableWidget::cellChanged,
this, &QgsSQLComposerDialog::buildSQLFromFields );
72 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, &QgsSQLComposerDialog::showHelp );
75 baseList << u
"SELECT"_s;
76 baseList << u
"FROM"_s;
77 baseList << u
"JOIN"_s;
79 baseList << u
"USING"_s;
80 baseList << u
"WHERE"_s;
85 baseList << u
"NULL"_s;
86 baseList << u
"LIKE"_s;
87 baseList << u
"ORDER"_s;
91 QStringList operatorsList;
92 operatorsList << u
"AND"_s;
93 operatorsList << u
"OR"_s;
94 operatorsList << u
"NOT"_s;
95 operatorsList << u
"="_s;
96 operatorsList << u
"<"_s;
97 operatorsList << u
"<="_s;
98 operatorsList << u
">"_s;
99 operatorsList << u
">="_s;
100 operatorsList << u
"<>"_s;
101 operatorsList << u
"BETWEEN"_s;
102 operatorsList << u
"NOT BETWEEN"_s;
103 operatorsList << u
"IS"_s;
104 operatorsList << u
"IS NOT"_s;
105 operatorsList << u
"IN"_s;
106 operatorsList << u
"LIKE"_s;
109 mAggregatesCombo->hide();
110 mFunctionsCombo->hide();
111 mSpatialPredicatesCombo->hide();
112 mStringFunctionsCombo->hide();
114 delete mPageColumnsValues;
115 mPageColumnsValues =
nullptr;
117 mRemoveJoinButton->setEnabled(
false );
119 mTableJoins->setRowCount( 0 );
120 mTableJoins->setItem( 0, 0,
new QTableWidgetItem( QString() ) );
121 mTableJoins->setItem( 0, 1,
new QTableWidgetItem( QString() ) );
129 delete mQueryEdit->lexer()->apis();
130 mQueryEdit->lexer()->setAPIs(
nullptr );
135 if ( event->type() == QEvent::FocusIn )
137 if ( obj == mTablesCombo->view() )
138 lastSearchedText.clear();
140 mFocusedObject = obj;
144 if ( event->type() == QEvent::KeyPress && obj == mTablesCombo->view() )
146 QString currentString = ( ( QKeyEvent * ) event )->text();
147 if ( !currentString.isEmpty()
148 && ( ( currentString[0] >=
'a' && currentString[0] <=
'z' ) || ( currentString[0] >=
'A' && currentString[0] <=
'Z' ) || ( currentString[0] >=
'0' && currentString[0] <=
'9' ) || currentString[0] ==
':' || currentString[0] ==
'_' || currentString[0] ==
' ' || currentString[0] ==
'(' || currentString[0] ==
')' ) )
152 const int attemptCount = ( lastSearchedText.isEmpty() ) ? 1 : 2;
153 for (
int attempt = 0; attempt < attemptCount; attempt++ )
156 lastSearchedText += currentString;
158 lastSearchedText = currentString;
163 int iBestCandidate = 0;
164 int idxInTextOfBestCandidate = 1000;
165 for (
int i = 1; i < mTablesCombo->count(); i++ )
167 const int idxInText = mTablesCombo->itemText( i ).indexOf( lastSearchedText, Qt::CaseInsensitive );
168 if ( idxInText >= 0 && idxInText < idxInTextOfBestCandidate )
171 idxInTextOfBestCandidate = idxInText;
174 if ( iBestCandidate > 0 )
176 mTablesCombo->view()->setCurrentIndex( mTablesCombo->model()->index( 0, 0 ).sibling( iBestCandidate, 0 ) );
180 lastSearchedText.clear();
184 return QDialog::eventFilter( obj, event );
189 mTableSelectedCallback = tableSelectedCallback;
194 mSQLValidatorCallback = sqlValidatorCallback;
200 mQueryEdit->setText(
sql );
205 return mQueryEdit->text();
208void QgsSQLComposerDialog::accept()
210 if ( mSQLValidatorCallback )
212 QString errorMsg, warningMsg;
213 if ( !mSQLValidatorCallback->
isValid(
sql(), errorMsg, warningMsg ) )
215 if ( errorMsg.isEmpty() )
216 errorMsg = tr(
"An error occurred during evaluation of the SQL statement." );
217 QMessageBox::critical(
this, tr(
"SQL Evaluation" ), errorMsg );
220 if ( !warningMsg.isEmpty() )
222 QMessageBox::warning(
this, tr(
"SQL Evaluation" ), warningMsg );
227 mLayer->setSubsetString(
sql() );
232void QgsSQLComposerDialog::buildSQLFromFields()
234 if ( mAlreadyModifyingFields )
236 mAlreadyModifyingFields =
true;
237 QString
sql( u
"SELECT "_s );
239 sql +=
"DISTINCT "_L1;
240 sql += mColumnsEditor->toPlainText();
242 sql += mTablesEditor->text();
244 const int rows = mTableJoins->rowCount();
245 for (
int i = 0; i < rows; i++ )
247 QTableWidgetItem *itemTable = mTableJoins->item( i, 0 );
248 QTableWidgetItem *itemOn = mTableJoins->item( i, 1 );
249 if ( itemTable && !itemTable->text().isEmpty() && itemOn && !itemOn->text().isEmpty() )
252 sql += itemTable->text();
254 sql += itemOn->text();
258 if ( !mWhereEditor->toPlainText().isEmpty() )
261 sql += mWhereEditor->toPlainText();
263 if ( !mOrderEditor->toPlainText().isEmpty() )
265 sql +=
" ORDER BY "_L1;
266 sql += mOrderEditor->toPlainText();
268 mQueryEdit->setText(
sql );
270 mAlreadyModifyingFields =
false;
273void QgsSQLComposerDialog::splitSQLIntoFields()
275 if ( mAlreadyModifyingFields )
277 const QgsSQLStatement
sql( mQueryEdit->text() );
278 if (
sql.hasParserError() )
280 const QgsSQLStatement::NodeSelect *nodeSelect =
dynamic_cast<const QgsSQLStatement::NodeSelect *
>(
sql.rootNode() );
284 const QList<QgsSQLStatement::NodeSelectedColumn *> columns = nodeSelect->
columns();
286 const auto constColumns = columns;
287 for ( QgsSQLStatement::NodeSelectedColumn *column : constColumns )
289 if ( !columnText.isEmpty() )
290 columnText +=
", "_L1;
291 columnText += column->dump();
294 const QList<QgsSQLStatement::NodeTableDef *> tables = nodeSelect->
tables();
296 const auto constTables = tables;
297 for ( QgsSQLStatement::NodeTableDef *table : constTables )
299 if ( !tablesText.isEmpty() )
300 tablesText +=
", "_L1;
302 tablesText += table->dump();
306 QgsSQLStatement::Node *where = nodeSelect->
where();
308 whereText = where->
dump();
311 const QList<QgsSQLStatement::NodeColumnSorted *> orderColumns = nodeSelect->
orderBy();
312 const auto constOrderColumns = orderColumns;
313 for ( QgsSQLStatement::NodeColumnSorted *column : constOrderColumns )
315 if ( !orderText.isEmpty() )
316 orderText +=
", "_L1;
317 orderText += column->dump();
320 const QList<QgsSQLStatement::NodeJoin *> joins = nodeSelect->
joins();
322 mAlreadyModifyingFields =
true;
323 mColumnsEditor->setPlainText( columnText );
324 mTablesEditor->setText( tablesText );
325 mWhereEditor->setPlainText( whereText );
326 mOrderEditor->setPlainText( orderText );
328 mTableJoins->setRowCount( joins.size() + 1 );
330 const auto constJoins = joins;
331 for ( QgsSQLStatement::NodeJoin *join : constJoins )
334 mTableJoins->setItem( iRow, 0,
new QTableWidgetItem( join->tableDef()->dump() ) );
335 if ( join->onExpr() )
336 mTableJoins->setItem( iRow, 1,
new QTableWidgetItem( join->onExpr()->dump() ) );
338 mTableJoins->setItem( iRow, 1,
new QTableWidgetItem( QString() ) );
341 mTableJoins->setItem( iRow, 0,
new QTableWidgetItem( QString() ) );
342 mTableJoins->setItem( iRow, 1,
new QTableWidgetItem( QString() ) );
344 mAlreadyModifyingFields =
false;
349 const auto constList = list;
350 for (
const QString &name : constList )
351 mapTableEntryTextToName[name] = name;
352 mTablesCombo->addItems( list );
358 QStringList listCombo;
360 const auto constListNameTitle = listNameTitle;
363 listApi << pair.first;
364 QString entryText( pair.first );
365 if ( !pair.second.isEmpty() && pair.second != pair.first )
367 if ( pair.second.size() < 40 )
368 entryText +=
" (" + pair.second +
")";
370 entryText +=
" (" + pair.second.mid( 0, 20 ) + QChar( 0x2026 ) + pair.second.mid( pair.second.size() - 20 ) +
")";
372 listCombo << entryText;
373 mapTableEntryTextToName[entryText] = pair.first;
375 mTablesCombo->addItems( listCombo );
381 QList<PairNameType> listPair;
382 const auto constList = list;
383 for (
const QString &name : constList )
388static QString sanitizeType( QString type )
390 if ( type.startsWith(
"xs:"_L1 ) )
391 return type.mid( 3 );
392 if ( type.startsWith(
"xsd:"_L1 ) )
393 return type.mid( 4 );
394 if ( type ==
"gml:AbstractGeometryType"_L1 )
395 return u
"geometry"_s;
401 mAlreadySelectedTables.insert( tableName );
402 if ( mColumnsCombo->count() > 1 )
403 mColumnsCombo->insertSeparator( mColumnsCombo->count() );
405 QStringList listCombo;
407 const auto constList = list;
410 listApi << pair.first;
411 QString entryText( pair.first );
412 if ( !pair.second.isEmpty() )
414 entryText +=
" (" + sanitizeType( pair.second ) +
")";
416 listCombo << entryText;
417 mapColumnEntryTextToName[entryText] = pair.first;
419 mColumnsCombo->addItems( listCombo );
426 mOperatorsCombo->addItems( list );
434 return QObject::tr(
"%1 to %n argument(s)",
nullptr, f.
maxArgs ).arg( f.
minArgs );
441 return QObject::tr(
"%n argument(s)",
nullptr, f.
minArgs );
445 return QObject::tr(
"%n argument(s) or more",
nullptr, f.
minArgs );
451void QgsSQLComposerDialog::getFunctionList(
const QList<Function> &list, QStringList &listApi, QStringList &listCombo, QMap<QString, QString> &mapEntryTextToName )
453 const auto constList = list;
454 for (
const Function &f : constList )
457 QString entryText( f.
name );
466 entryText +=
", "_L1;
474 const QString sanitizedType( sanitizeType( f.
argumentList[i].type ) );
477 entryText +=
": "_L1;
478 entryText += sanitizedType;
484 if ( entryText.size() > 60 )
488 entryText += getFunctionAbbridgedParameters( f );
493 entryText += getFunctionAbbridgedParameters( f );
497 entryText +=
": " + sanitizeType( f.
returnType );
498 listCombo << entryText;
499 mapEntryTextToName[entryText] = f.
name +
"(";
505 QList<Function> listFunction;
506 const auto constList = list;
507 for (
const QString &name : constList )
519 QStringList listCombo;
520 getFunctionList( list, listApi, listCombo, mapSpatialPredicateEntryTextToName );
521 mSpatialPredicatesCombo->addItems( listCombo );
522 mSpatialPredicatesCombo->show();
528 QList<Function> listFunction;
529 const auto constList = list;
530 for (
const QString &name : constList )
542 QStringList listCombo;
543 getFunctionList( list, listApi, listCombo, mapFunctionEntryTextToName );
544 mFunctionsCombo->addItems( listCombo );
545 mFunctionsCombo->show();
549void QgsSQLComposerDialog::loadTableColumns(
const QString &table )
551 if ( mTableSelectedCallback )
553 if ( !mAlreadySelectedTables.contains( table ) )
556 mAlreadySelectedTables.insert( table );
561static void resetCombo( QComboBox *combo )
568 QMetaObject::invokeMethod( combo,
"setCurrentIndex", Qt::QueuedConnection, Q_ARG(
int, 0 ) );
571void QgsSQLComposerDialog::mTablesCombo_currentIndexChanged(
int )
573 const int index = mTablesCombo->currentIndex();
576 QObject *obj = mFocusedObject;
577 const QString newText = mapTableEntryTextToName[mTablesCombo->currentText()];
578 loadTableColumns( newText );
579 if ( obj == mTablesEditor )
581 const QString currentText = mTablesEditor->text();
582 if ( currentText.isEmpty() )
583 mTablesEditor->setText( newText );
585 mTablesEditor->setText( currentText +
", " + newText );
587 else if ( obj == mTableJoins )
589 if ( mTableJoins->selectedItems().size() == 1 )
591 mTableJoins->selectedItems().at( 0 )->setText( newText );
594 else if ( obj == mWhereEditor )
596 mWhereEditor->insertPlainText( newText );
598 else if ( obj == mOrderEditor )
600 mOrderEditor->insertPlainText( newText );
602 else if ( obj == mQueryEdit )
604 mQueryEdit->insertText( newText );
606 resetCombo( mTablesCombo );
609void QgsSQLComposerDialog::mColumnsCombo_currentIndexChanged(
int )
611 const int index = mColumnsCombo->currentIndex();
614 QObject *obj = mFocusedObject;
615 const QString newText = mapColumnEntryTextToName[mColumnsCombo->currentText()];
616 if ( obj == mColumnsEditor )
618 const QString currentText = mColumnsEditor->toPlainText();
619 if ( currentText.isEmpty() )
620 mColumnsEditor->insertPlainText( newText );
622 mColumnsEditor->insertPlainText(
",\n" + newText );
624 else if ( obj == mTableJoins )
626 if ( mTableJoins->selectedItems().size() == 1 && mTableJoins->selectedItems().at( 0 )->column() == 1 )
628 const QString currentText( mTableJoins->selectedItems().at( 0 )->text() );
629 if ( !currentText.isEmpty() && !currentText.contains(
"="_L1 ) )
630 mTableJoins->selectedItems().at( 0 )->setText( currentText +
" = " + newText );
632 mTableJoins->selectedItems().at( 0 )->setText( currentText + newText );
635 else if ( obj == mWhereEditor )
637 mWhereEditor->insertPlainText( newText );
639 else if ( obj == mOrderEditor )
641 mOrderEditor->insertPlainText( newText );
643 else if ( obj == mQueryEdit )
645 mQueryEdit->insertText( newText );
647 resetCombo( mColumnsCombo );
650void QgsSQLComposerDialog::mFunctionsCombo_currentIndexChanged(
int )
652 functionCurrentIndexChanged( mFunctionsCombo, mapFunctionEntryTextToName );
655void QgsSQLComposerDialog::mSpatialPredicatesCombo_currentIndexChanged(
int )
657 functionCurrentIndexChanged( mSpatialPredicatesCombo, mapSpatialPredicateEntryTextToName );
660void QgsSQLComposerDialog::functionCurrentIndexChanged( QComboBox *combo,
const QMap<QString, QString> &mapEntryTextToName )
662 const int index = combo->currentIndex();
665 QObject *obj = mFocusedObject;
666 const QString newText = mapEntryTextToName[combo->currentText()];
667 if ( obj == mColumnsEditor )
669 mColumnsEditor->insertPlainText( newText );
671 else if ( obj == mWhereEditor )
673 mWhereEditor->insertPlainText( newText );
675 else if ( obj == mQueryEdit )
677 mQueryEdit->insertText( newText );
682void QgsSQLComposerDialog::mOperatorsCombo_currentIndexChanged(
int )
684 const int index = mOperatorsCombo->currentIndex();
687 QObject *obj = mFocusedObject;
688 const QString newText = mOperatorsCombo->currentText();
689 if ( obj == mColumnsEditor )
691 mColumnsEditor->insertPlainText( newText );
693 else if ( obj == mWhereEditor )
695 mWhereEditor->insertPlainText( newText );
697 else if ( obj == mTableJoins )
699 if ( mTableJoins->selectedItems().size() == 1 && mTableJoins->selectedItems().at( 0 )->column() == 1 )
701 const QString currentText( mTableJoins->selectedItems().at( 0 )->text() );
702 mTableJoins->selectedItems().at( 0 )->setText( currentText + newText );
705 else if ( obj == mQueryEdit )
707 mQueryEdit->insertText( newText );
709 resetCombo( mOperatorsCombo );
712void QgsSQLComposerDialog::mAddJoinButton_clicked()
714 int insertRow = mTableJoins->currentRow();
715 const int rowCount = mTableJoins->rowCount();
717 insertRow = rowCount;
718 mTableJoins->setRowCount( rowCount + 1 );
719 for (
int row = rowCount; row > insertRow + 1; row-- )
721 mTableJoins->setItem( row, 0, mTableJoins->takeItem( row - 1, 0 ) );
722 mTableJoins->setItem( row, 1, mTableJoins->takeItem( row - 1, 1 ) );
724 mTableJoins->setItem( ( insertRow == rowCount ) ? insertRow : insertRow + 1, 0,
new QTableWidgetItem( QString() ) );
725 mTableJoins->setItem( ( insertRow == rowCount ) ? insertRow : insertRow + 1, 1,
new QTableWidgetItem( QString() ) );
728void QgsSQLComposerDialog::mRemoveJoinButton_clicked()
730 int row = mTableJoins->currentRow();
733 const int rowCount = mTableJoins->rowCount();
734 for ( ; row < rowCount - 1; row++ )
736 mTableJoins->setItem( row, 0, mTableJoins->takeItem( row + 1, 0 ) );
737 mTableJoins->setItem( row, 1, mTableJoins->takeItem( row + 1, 1 ) );
739 mTableJoins->setRowCount( rowCount - 1 );
741 buildSQLFromFields();
744void QgsSQLComposerDialog::reset()
746 mQueryEdit->setText( mResetSql );
749void QgsSQLComposerDialog::mTableJoins_itemSelectionChanged()
751 mRemoveJoinButton->setEnabled( mTableJoins->selectedItems().size() == 1 );
758 delete mQueryEdit->lexer()->apis();
759 QsciAPIs *apis =
new QsciAPIs( mQueryEdit->lexer() );
761 const auto constMApiList = mApiList;
762 for (
const QString &str : constMApiList )
768 mQueryEdit->lexer()->setAPIs( apis );
773 mJoinsLabels->setVisible( on );
774 mTableJoins->setVisible( on );
775 mAddJoinButton->setVisible( on );
776 mRemoveJoinButton->setVisible( on );
777 mTablesCombo->setVisible( on );
779 QString mainTypenameFormatted;
780 if ( !mainTypename.isEmpty() )
781 mainTypenameFormatted =
"(" + mainTypename +
")";
782 mQueryEdit->setToolTip( tr(
783 "This is the SQL query editor. The SQL statement can select data from several tables, \n"
784 "but it must compulsory include the main typename %1 in the selected tables, \n"
785 "and only the geometry column of the main typename can be used as the geometry column of the resulting layer."
787 .arg( mainTypenameFormatted ) );
790void QgsSQLComposerDialog::showHelp()
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Callback to do validation check on dialog validation.
virtual bool isValid(const QString &sql, QString &errorReason, QString &warningMsg)=0
method should return true if the SQL is valid. Otherwise return false and set the errorReason
Callback to do actions on table selection.
virtual void tableSelected(const QString &name)=0
method called when a table is selected
bool eventFilter(QObject *obj, QEvent *event) override
QgsSQLComposerDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
constructor
void addSpatialPredicates(const QStringList &list)
add a list of spatial predicates
void setSQLValidatorCallback(SQLValidatorCallback *sqlValidatorCallback)
Set a callback that will be called when the OK button is pushed.
void setTableSelectedCallback(TableSelectedCallback *tableSelectedCallback)
Set a callback that will be called when a new table is selected, so that new column names can be adde...
QPair< QString, QString > PairNameType
pair (name, type)
void addOperators(const QStringList &list)
add a list of operators
~QgsSQLComposerDialog() override
void addColumnNames(const QStringList &list, const QString &tableName)
add a list of column names
void setSupportMultipleTables(bool bMultipleTables, const QString &mainTypename=QString())
Sets if multiple tables/joins are supported. Default is false.
void addApis(const QStringList &list)
add a list of API for autocompletion
void setSql(const QString &sql)
initialize the SQL statement
void addFunctions(const QStringList &list)
add a list of functions
void addTableNames(const QStringList &list)
add a list of table names
QPair< QString, QString > PairNameTitle
pair (name, title)
QString sql() const
Gets the SQL statement.
QList< QgsSQLStatement::NodeColumnSorted * > orderBy() const
Returns the list of order by columns.
QList< QgsSQLStatement::NodeSelectedColumn * > columns() const
Returns the list of columns.
bool distinct() const
Returns if the SELECT is DISTINCT.
QList< QgsSQLStatement::NodeJoin * > joins() const
Returns the list of joins.
QgsSQLStatement::Node * where() const
Returns the where clause.
QList< QgsSQLStatement::NodeTableDef * > tables() const
Returns the list of tables.
virtual QString dump() const =0
Abstract virtual dump method.
static QString quotedIdentifierIfNeeded(const QString &name)
Returns a quoted column reference (in double quotes) if needed, or otherwise the original string.
QgsSubsetStringEditorInterface(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
Constructor.
Represents a vector layer which manages a vector based dataset.
description of server functions
QString returnType
Returns type, or empty if unknown.
int maxArgs
maximum number of argument (or -1 if unknown)
int minArgs
minimum number of argument (or -1 if unknown)
QList< Argument > argumentList
list of arguments. May be empty despite minArgs > 0