24 #include <QMessageBox> 27 #include <Qsci/qscilexer.h> 39 , mTableSelectedCallback( nullptr )
40 , mSQLValidatorCallback( nullptr )
41 , mFocusedObject( nullptr )
42 , mAlreadyModifyingFields( false )
47 mQueryEdit->setWrapMode( QsciScintilla::WrapWord );
48 mQueryEdit->installEventFilter(
this );
49 mColumnsEditor->installEventFilter(
this );
50 mTablesEditor->installEventFilter(
this );
51 mTableJoins->installEventFilter(
this );
52 mWhereEditor->installEventFilter(
this );
53 mOrderEditor->installEventFilter(
this );
54 mTablesCombo->view()->installEventFilter(
this );
57 connect( mButtonBox->button( QDialogButtonBox::Reset ), SIGNAL( clicked() ),
58 this, SLOT( reset() ) );
60 connect( mQueryEdit, SIGNAL( textChanged() ),
61 this, SLOT( splitSQLIntoFields() ) );
62 connect( mColumnsEditor, SIGNAL( textChanged() ),
63 this, SLOT( buildSQLFromFields() ) );
65 this, SLOT( buildSQLFromFields() ) );
66 connect( mWhereEditor, SIGNAL( textChanged() ),
67 this, SLOT( buildSQLFromFields() ) );
68 connect( mOrderEditor, SIGNAL( textChanged() ),
69 this, SLOT( buildSQLFromFields() ) );
70 connect( mTableJoins, SIGNAL( cellChanged(
int,
int ) ),
71 this, SLOT( buildSQLFromFields() ) );
91 operatorsList <<
"AND";
92 operatorsList <<
"OR";
93 operatorsList <<
"NOT";
96 operatorsList <<
"<=";
98 operatorsList <<
">=";
99 operatorsList <<
"<>";
100 operatorsList <<
"IS";
101 operatorsList <<
"IS NOT";
102 operatorsList <<
"IN";
103 operatorsList <<
"LIKE";
104 operatorsList <<
"BETWEEN";
107 mAggregatesCombo->hide();
108 mFunctionsCombo->hide();
109 mSpatialPredicatesCombo->hide();
110 mStringFunctionsCombo->hide();
112 delete mPageColumnsValues;
113 mPageColumnsValues =
nullptr;
115 mRemoveJoinButton->setEnabled(
false );
117 mTableJoins->setRowCount( 0 );
127 delete mQueryEdit->lexer()->apis();
128 mQueryEdit->lexer()->setAPIs(
nullptr );
133 if ( event->
type() == QEvent::FocusIn )
135 if ( obj == mTablesCombo->view() )
136 lastSearchedText.
clear();
138 mFocusedObject = obj;
142 if ( event->
type() == QEvent::KeyPress && obj == mTablesCombo->view() )
145 if ( !currentString.
isEmpty() && (( currentString[0] >=
'a' && currentString[0] <=
'z' ) ||
146 ( currentString[0] >=
'A' && currentString[0] <=
'Z' ) ||
147 ( currentString[0] >=
'0' && currentString[0] <=
'9' ) ||
148 currentString[0] ==
':' || currentString[0] ==
'_' || currentString[0] ==
' ' ||
149 currentString[0] ==
'(' || currentString[0] ==
')' ) )
153 int attemptCount = ( lastSearchedText.
isEmpty() ) ? 1 : 2;
154 for (
int attempt = 0; attempt < attemptCount; attempt ++ )
157 lastSearchedText += currentString;
159 lastSearchedText = currentString;
164 int iBestCandidate = 0;
165 int idxInTextOfBestCandidate = 1000;
166 for (
int i = 1; i < mTablesCombo->count(); i++ )
168 int idxInText = mTablesCombo->itemText( i ).
indexOf( lastSearchedText, Qt::CaseInsensitive );
169 if ( idxInText >= 0 && idxInText < idxInTextOfBestCandidate )
172 idxInTextOfBestCandidate = idxInText;
175 if ( iBestCandidate > 0 )
177 mTablesCombo->view()->setCurrentIndex( mTablesCombo->model()->index( 0, 0 ).sibling( iBestCandidate, 0 ) );
181 lastSearchedText.
clear();
190 mTableSelectedCallback = tableSelectedCallback;
195 mSQLValidatorCallback = sqlValidatorCallback;
201 mQueryEdit->setText( sql );
206 return mQueryEdit->text();
209 void QgsSQLComposerDialog::accept()
211 if ( mSQLValidatorCallback )
214 if ( !mSQLValidatorCallback->
isValid(
sql(), errorMsg, warningMsg ) )
217 errorMsg =
tr(
"An error occurred during evaluation of the SQL statement" );
229 void QgsSQLComposerDialog::buildSQLFromFields()
231 if ( mAlreadyModifyingFields )
233 mAlreadyModifyingFields =
true;
237 sql += mColumnsEditor->toPlainText();
239 sql += mTablesEditor->text();
241 int rows = mTableJoins->rowCount();
242 for (
int i = 0;i < rows;i++ )
250 sql += itemTable->
text();
252 sql += itemOn->
text();
256 if ( !mWhereEditor->toPlainText().isEmpty() )
259 sql += mWhereEditor->toPlainText();
261 if ( !mOrderEditor->toPlainText().isEmpty() )
264 sql += mOrderEditor->toPlainText();
266 mQueryEdit->setText( sql );
268 mAlreadyModifyingFields =
false;
271 void QgsSQLComposerDialog::splitSQLIntoFields()
273 if ( mAlreadyModifyingFields )
276 if (
sql.hasParserError() )
279 if ( nodeSelect ==
nullptr )
288 columnText += column->
dump();
298 tablesText += table->
dump();
303 if ( where !=
nullptr )
304 whereText = where->
dump();
312 orderText += column->
dump();
317 mAlreadyModifyingFields =
true;
318 mColumnsEditor->setPlainText( columnText );
319 mTablesEditor->setText( tablesText );
320 mWhereEditor->setPlainText( whereText );
321 mOrderEditor->setPlainText( orderText );
323 mTableJoins->setRowCount( joins.
size() + 1 );
338 mAlreadyModifyingFields =
false;
344 mapTableEntryTextToName[
name] =
name;
345 mTablesCombo->addItems( list );
355 listApi << pair.first;
356 QString entryText( pair.first );
357 if ( !pair.second.isEmpty() && pair.second != pair.first )
359 if ( pair.second.size() < 40 )
360 entryText +=
" (" + pair.second +
")";
362 entryText +=
" (" + pair.second.mid( 0, 20 ) +
"..." + pair.second.mid( pair.second.size() - 20 ) +
")";
364 listCombo << entryText;
365 mapTableEntryTextToName[entryText] = pair.first;
367 mTablesCombo->addItems( listCombo );
382 return type.
mid( 3 );
384 return type.
mid( 4 );
385 if ( type ==
"gml:AbstractGeometryType" )
392 mAlreadySelectedTables.
insert( tableName );
393 if ( mColumnsCombo->count() > 1 )
394 mColumnsCombo->insertSeparator( mColumnsCombo->count() );
400 listApi << pair.first;
401 QString entryText( pair.first );
402 if ( !pair.second.isEmpty() )
406 listCombo << entryText;
407 mapColumnEntryTextToName[entryText] = pair.first;
409 mColumnsCombo->addItems( listCombo );
416 mOperatorsCombo->addItems( list );
449 void QgsSQLComposerDialog::getFunctionList(
const QList<Function>& list,
454 Q_FOREACH (
const Function& f, list )
459 if ( f.argumentList.size() )
461 for (
int i = 0;i < f.argumentList.size();i++ )
463 if ( f.minArgs >= 0 && i >= f.minArgs ) entryText +=
"[";
464 if ( i > 0 ) entryText +=
", ";
465 if ( f.argumentList[i].name ==
"number" && !f.argumentList[i].type.isEmpty() )
471 entryText += f.argumentList[i].name;
473 if ( !f.argumentList[i].type.isEmpty() &&
474 f.argumentList[i].name != sanitizedType )
477 entryText += sanitizedType;
480 if ( f.minArgs >= 0 && i >= f.minArgs ) entryText +=
"]";
482 if ( entryText.
size() > 60 )
494 if ( !f.returnType.isEmpty() )
496 listCombo << entryText;
497 mapEntryTextToName[entryText] = f.name +
"(";
517 getFunctionList( list, listApi, listCombo, mapSpatialPredicateEntryTextToName );
518 mSpatialPredicatesCombo->addItems( listCombo );
519 mSpatialPredicatesCombo->show();
539 getFunctionList( list, listApi, listCombo, mapFunctionEntryTextToName );
540 mFunctionsCombo->addItems( listCombo );
541 mFunctionsCombo->show();
545 void QgsSQLComposerDialog::loadTableColumns(
const QString& table )
547 if ( mTableSelectedCallback )
549 if ( !mAlreadySelectedTables.
contains( table ) )
552 mAlreadySelectedTables.
insert( table );
567 void QgsSQLComposerDialog::on_mTablesCombo_currentIndexChanged(
int )
569 int index = mTablesCombo->currentIndex();
573 QString newText = mapTableEntryTextToName[mTablesCombo->currentText()];
574 loadTableColumns( newText );
575 if ( obj == mTablesEditor )
577 QString currentText = mTablesEditor->text();
579 mTablesEditor->setText( newText );
581 mTablesEditor->setText( currentText +
", " + newText );
583 else if ( obj == mTableJoins )
585 if ( mTableJoins->selectedItems().size() == 1 )
587 mTableJoins->selectedItems().
at( 0 )->setText( newText );
590 else if ( obj == mWhereEditor )
592 mWhereEditor->insertPlainText( newText );
594 else if ( obj == mOrderEditor )
596 mOrderEditor->insertPlainText( newText );
598 else if ( obj == mQueryEdit )
600 mQueryEdit->insertText( newText );
605 void QgsSQLComposerDialog::on_mColumnsCombo_currentIndexChanged(
int )
607 int index = mColumnsCombo->currentIndex();
611 QString newText = mapColumnEntryTextToName[mColumnsCombo->currentText()];
612 if ( obj == mColumnsEditor )
614 QString currentText = mColumnsEditor->toPlainText();
616 mColumnsEditor->insertPlainText( newText );
618 mColumnsEditor->insertPlainText(
",\n" + newText );
620 else if ( obj == mTableJoins )
622 if ( mTableJoins->selectedItems().size() == 1 &&
623 mTableJoins->selectedItems().at( 0 )->column() == 1 )
625 QString currentText( mTableJoins->selectedItems().at( 0 )->text() );
626 if ( !currentText.isEmpty() && !currentText.contains(
"=" ) )
627 mTableJoins->selectedItems().
at( 0 )->setText( currentText +
" = " + newText );
629 mTableJoins->selectedItems().at( 0 )->setText( currentText + newText );
632 else if ( obj == mWhereEditor )
634 mWhereEditor->insertPlainText( newText );
636 else if ( obj == mOrderEditor )
638 mOrderEditor->insertPlainText( newText );
640 else if ( obj == mQueryEdit )
642 mQueryEdit->insertText( newText );
647 void QgsSQLComposerDialog::on_mFunctionsCombo_currentIndexChanged(
int )
649 functionCurrentIndexChanged( mFunctionsCombo, mapFunctionEntryTextToName );
652 void QgsSQLComposerDialog::on_mSpatialPredicatesCombo_currentIndexChanged(
int )
654 functionCurrentIndexChanged( mSpatialPredicatesCombo, mapSpatialPredicateEntryTextToName );
657 void QgsSQLComposerDialog::functionCurrentIndexChanged(
QComboBox* combo,
665 if ( obj == mColumnsEditor )
667 mColumnsEditor->insertPlainText( newText );
669 else if ( obj == mWhereEditor )
671 mWhereEditor->insertPlainText( newText );
673 else if ( obj == mQueryEdit )
675 mQueryEdit->insertText( newText );
680 void QgsSQLComposerDialog::on_mOperatorsCombo_currentIndexChanged(
int )
682 int index = mOperatorsCombo->currentIndex();
686 QString newText = mOperatorsCombo->currentText();
687 if ( obj == mColumnsEditor )
689 mColumnsEditor->insertPlainText( newText );
691 else if ( obj == mWhereEditor )
693 mWhereEditor->insertPlainText( newText );
695 else if ( obj == mTableJoins )
697 if ( mTableJoins->selectedItems().size() == 1 &&
698 mTableJoins->selectedItems().at( 0 )->column() == 1 )
700 QString currentText( mTableJoins->selectedItems().at( 0 )->text() );
701 mTableJoins->selectedItems().
at( 0 )->setText( currentText + newText );
704 else if ( obj == mQueryEdit )
706 mQueryEdit->insertText( newText );
711 void QgsSQLComposerDialog::on_mAddJoinButton_clicked()
713 int insertRow = mTableJoins->currentRow();
714 int rowCount = mTableJoins->rowCount();
716 insertRow = rowCount;
717 mTableJoins->setRowCount( rowCount + 1 );
718 for (
int row = rowCount ; row > insertRow + 1; row -- )
720 mTableJoins->setItem( row, 0, mTableJoins->takeItem( row - 1, 0 ) );
721 mTableJoins->setItem( row, 1, mTableJoins->takeItem( row - 1, 1 ) );
723 mTableJoins->setItem(( insertRow == rowCount ) ? insertRow : insertRow + 1, 0,
new QTableWidgetItem(
"" ) );
724 mTableJoins->setItem(( insertRow == rowCount ) ? insertRow : insertRow + 1, 1,
new QTableWidgetItem(
"" ) );
727 void QgsSQLComposerDialog::on_mRemoveJoinButton_clicked()
729 int row = mTableJoins->currentRow();
732 int rowCount = mTableJoins->rowCount();
733 for ( ; row < rowCount - 1; row ++ )
735 mTableJoins->setItem( row, 0, mTableJoins->takeItem( row + 1, 0 ) );
736 mTableJoins->setItem( row, 1, mTableJoins->takeItem( row + 1, 1 ) );
738 mTableJoins->setRowCount( rowCount - 1 );
740 buildSQLFromFields();
743 void QgsSQLComposerDialog::reset()
745 mQueryEdit->setText( mResetSql );
748 void QgsSQLComposerDialog::on_mTableJoins_itemSelectionChanged()
750 mRemoveJoinButton->setEnabled( mTableJoins->selectedItems().size() == 1 );
757 delete mQueryEdit->lexer()->apis();
758 QsciAPIs* apis =
new QsciAPIs( mQueryEdit->lexer() );
760 Q_FOREACH (
const QString& str, mApiList )
766 mQueryEdit->lexer()->setAPIs( apis );
771 mJoinsLabels->setVisible( on );
772 mTableJoins->setVisible( on );
773 mAddJoinButton->setVisible( on );
774 mRemoveJoinButton->setVisible( on );
775 mTablesCombo->setVisible( on );
779 mainTypenameFormatted =
" (" + mainTypename +
")";
780 mQueryEdit->setToolTip(
tr(
"This is the SQL query editor. The SQL statement can select data from several tables, \n" 781 "but it must compulsory include the main typename%1 in the selected tables, \n" 782 "and only the geometry column of the main typename can be used as the geometry column of the resulting layer." ).arg( mainTypenameFormatted ) );
virtual void tableSelected(const QString &name)=0
method called when a table is selected
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
virtual bool event(QEvent *e)
void addOperators(const QStringList &list)
add a list of operators
Callback to do actions on table selection.
void addFunctions(const QStringList &list)
add a list of functions
void setSQLValidatorCallback(SQLValidatorCallback *sqlValidatorCallback)
Set a callback that will be called when the OK button is pushed.
virtual ~TableSelectedCallback()
Node * onExpr() const
On expression.
QgsSQLComposerDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgisGui::ModalDialogFlags)
constructor
void addApis(const QStringList &list)
add a list of API for autocompletion
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...
int maxArgs
maximum number of argument (or -1 if unknown)
NodeTableDef * tableDef() const
Table definition.
const_iterator insert(const T &value)
void addColumnNames(const QStringList &list, const QString &tableName)
add a list of column names
QString tr(const char *sourceText, const char *disambiguation, int n)
bool distinct() const
Return if the SELECT is DISTINCT.
const char * name() const
Class for parsing SQL statements.
virtual ~SQLValidatorCallback()
QString name() const
Table name.
virtual QString dump() const =0
Abstract virtual dump method.
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 ...
void setSupportMultipleTables(bool bMultipleTables, QString mainTypename=QString())
set if multiple tables/joins are supported. Default is false
QPair< QString, QString > PairNameType
pair (name, type)
void addSpatialPredicates(const QStringList &list)
add a list of spatial predicates
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
Node * where() const
Return the where clause.
static void resetCombo(QComboBox *combo)
description of server functions
virtual bool eventFilter(QObject *watched, QEvent *event)
virtual ~QgsSQLComposerDialog()
Callback to do validation check on dialog validation.
virtual QString dump() const override
Abstract virtual dump method.
bool contains(const T &value) const
QString sql() const
get the SQL statement
QList< NodeColumnSorted * > orderBy() const
Return the list of order by columns.
static QString quotedIdentifierIfNeeded(QString name)
Returns a quoted column reference (in double quotes) if needed, or otherwise the original string...
QString mid(int position, int n) const
bool eventFilter(QObject *obj, QEvent *event) override
QList< NodeTableDef * > tables() const
Return the list of tables.
const QChar at(int position) const
virtual QString dump() const override
Abstract virtual dump method.
StandardButton critical(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
StandardButton warning(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
static QString sanitizeType(QString type)
virtual QString dump() const override
Abstract virtual dump method.
static QString getFunctionAbbridgedParameters(const QgsSQLComposerDialog::Function &f)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
void addTableNames(const QStringList &list)
add a list of table names
QList< NodeSelectedColumn * > columns() const
Return the list of columns.
void setSql(const QString &sql)
initialize the SQL statement
int minArgs
minimum number of argument (or -1 if unknown)
QList< NodeJoin * > joins() const
Return the list of joins.