QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgssqlcomposerdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssqlcomposerdialog.cpp
3  Dialog to compose SQL queries
4 
5 begin : Apr 2016
6 copyright : (C) 2016 Even Rouault
7 email : even.rouault at spatialys.com
8 
9  Adapted/ported from DBManager dlg_query_builder
10  ***************************************************************************/
11 
12 /***************************************************************************
13  * *
14  * This program is free software; you can redistribute it and/or modify *
15  * it under the terms of the GNU General Public License as published by *
16  * the Free Software Foundation; either version 2 of the License, or *
17  * (at your option) any later version. *
18  * *
19  ***************************************************************************/
20 
21 #include "qgssqlcomposerdialog.h"
22 #include "qgssqlstatement.h"
23 
24 #include <QMessageBox>
25 #include <QKeyEvent>
26 
27 #include <Qsci/qscilexer.h>
28 
30 {
31 }
32 
34 {
35 }
36 
38  : QDialog( parent, fl )
39  , mTableSelectedCallback( nullptr )
40  , mSQLValidatorCallback( nullptr )
41  , mFocusedObject( nullptr )
42  , mAlreadyModifyingFields( false )
43  , mDistinct( false )
44 {
45  setupUi( this );
46 
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 );
55 
56 
57  connect( mButtonBox->button( QDialogButtonBox::Reset ), SIGNAL( clicked() ),
58  this, SLOT( reset() ) );
59 
60  connect( mQueryEdit, SIGNAL( textChanged() ),
61  this, SLOT( splitSQLIntoFields() ) );
62  connect( mColumnsEditor, SIGNAL( textChanged() ),
63  this, SLOT( buildSQLFromFields() ) );
64  connect( mTablesEditor, SIGNAL( textChanged( const QString & ) ),
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() ) );
72 
73  QStringList baseList;
74  baseList << "SELECT";
75  baseList << "FROM";
76  baseList << "JOIN";
77  baseList << "ON";
78  baseList << "USING";
79  baseList << "WHERE";
80  baseList << "AND";
81  baseList << "OR";
82  baseList << "NOT";
83  baseList << "IS";
84  baseList << "NULL";
85  baseList << "LIKE";
86  baseList << "ORDER";
87  baseList << "BY";
88  addApis( baseList );
89 
90  QStringList operatorsList;
91  operatorsList << "AND";
92  operatorsList << "OR";
93  operatorsList << "NOT";
94  operatorsList << "=";
95  operatorsList << "<";
96  operatorsList << "<=";
97  operatorsList << ">";
98  operatorsList << ">=";
99  operatorsList << "<>";
100  operatorsList << "IS";
101  operatorsList << "IS NOT";
102  operatorsList << "IN";
103  operatorsList << "LIKE";
104  operatorsList << "BETWEEN";
105  addOperators( operatorsList );
106 
107  mAggregatesCombo->hide();
108  mFunctionsCombo->hide();
109  mSpatialPredicatesCombo->hide();
110  mStringFunctionsCombo->hide();
111 
112  delete mPageColumnsValues;
113  mPageColumnsValues = nullptr;
114 
115  mRemoveJoinButton->setEnabled( false );
116 
117  mTableJoins->setRowCount( 0 );
118  mTableJoins->setItem( 0, 0, new QTableWidgetItem( "" ) );
119  mTableJoins->setItem( 0, 1, new QTableWidgetItem( "" ) );
120 }
121 
123 {
124  // Besides avoid memory leaks, this is useful since QSciAPIs::prepare()
125  // starts a thread. If the dialog was killed before the thread had started,
126  // he could run against a dead widget. This can happen in unit tests.
127  delete mQueryEdit->lexer()->apis();
128  mQueryEdit->lexer()->setAPIs( nullptr );
129 }
130 
132 {
133  if ( event->type() == QEvent::FocusIn )
134  {
135  if ( obj == mTablesCombo->view() )
136  lastSearchedText.clear();
137  else
138  mFocusedObject = obj;
139  }
140 
141  // Custom search in table combobox
142  if ( event->type() == QEvent::KeyPress && obj == mTablesCombo->view() )
143  {
144  QString currentString = (( QKeyEvent* )event )->text();
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] == ')' ) )
150  {
151  // First attempt is concatenation of existing search text
152  // Second attempt is just the new character
153  int attemptCount = ( lastSearchedText.isEmpty() ) ? 1 : 2;
154  for ( int attempt = 0; attempt < attemptCount; attempt ++ )
155  {
156  if ( attempt == 0 )
157  lastSearchedText += currentString;
158  else
159  lastSearchedText = currentString;
160 
161  // Find the string that contains the searched text, and in case
162  // of several matches, pickup the one where the searched text is the
163  // most at the beginning.
164  int iBestCandidate = 0;
165  int idxInTextOfBestCandidate = 1000;
166  for ( int i = 1; i < mTablesCombo->count(); i++ )
167  {
168  int idxInText = mTablesCombo->itemText( i ).indexOf( lastSearchedText, Qt::CaseInsensitive );
169  if ( idxInText >= 0 && idxInText < idxInTextOfBestCandidate )
170  {
171  iBestCandidate = i;
172  idxInTextOfBestCandidate = idxInText;
173  }
174  }
175  if ( iBestCandidate > 0 )
176  {
177  mTablesCombo->view()->setCurrentIndex( mTablesCombo->model()->index( 0, 0 ).sibling( iBestCandidate, 0 ) );
178  return true;
179  }
180  }
181  lastSearchedText.clear();
182  }
183  }
184 
185  return QObject::eventFilter( obj, event );
186 }
187 
189 {
190  mTableSelectedCallback = tableSelectedCallback;
191 }
192 
194 {
195  mSQLValidatorCallback = sqlValidatorCallback;
196 }
197 
199 {
200  mResetSql = sql;
201  mQueryEdit->setText( sql );
202 }
203 
205 {
206  return mQueryEdit->text();
207 }
208 
209 void QgsSQLComposerDialog::accept()
210 {
211  if ( mSQLValidatorCallback )
212  {
213  QString errorMsg, warningMsg;
214  if ( !mSQLValidatorCallback->isValid( sql(), errorMsg, warningMsg ) )
215  {
216  if ( errorMsg.isEmpty() )
217  errorMsg = tr( "An error occurred during evaluation of the SQL statement" );
218  QMessageBox::critical( this, tr( "SQL error" ), errorMsg );
219  return;
220  }
221  if ( !warningMsg.isEmpty() )
222  {
223  QMessageBox::warning( this, tr( "SQL warning" ), warningMsg );
224  }
225  }
226  QDialog::accept();
227 }
228 
229 void QgsSQLComposerDialog::buildSQLFromFields()
230 {
231  if ( mAlreadyModifyingFields )
232  return;
233  mAlreadyModifyingFields = true;
234  QString sql( "SELECT " );
235  if ( mDistinct )
236  sql += "DISTINCT ";
237  sql += mColumnsEditor->toPlainText();
238  sql += " FROM ";
239  sql += mTablesEditor->text();
240 
241  int rows = mTableJoins->rowCount();
242  for ( int i = 0;i < rows;i++ )
243  {
244  QTableWidgetItem * itemTable = mTableJoins->item( i, 0 );
245  QTableWidgetItem * itemOn = mTableJoins->item( i, 1 );
246  if ( itemTable && !itemTable->text().isEmpty() &&
247  itemOn && !itemOn->text().isEmpty() )
248  {
249  sql += " JOIN ";
250  sql += itemTable->text();
251  sql += " ON ";
252  sql += itemOn->text();
253  }
254  }
255 
256  if ( !mWhereEditor->toPlainText().isEmpty() )
257  {
258  sql += " WHERE ";
259  sql += mWhereEditor->toPlainText();
260  }
261  if ( !mOrderEditor->toPlainText().isEmpty() )
262  {
263  sql += " ORDER BY ";
264  sql += mOrderEditor->toPlainText();
265  }
266  mQueryEdit->setText( sql );
267 
268  mAlreadyModifyingFields = false;
269 }
270 
271 void QgsSQLComposerDialog::splitSQLIntoFields()
272 {
273  if ( mAlreadyModifyingFields )
274  return;
275  QgsSQLStatement sql( mQueryEdit->text() );
276  if ( sql.hasParserError() )
277  return;
278  const QgsSQLStatement::NodeSelect* nodeSelect = dynamic_cast<const QgsSQLStatement::NodeSelect*>( sql.rootNode() );
279  if ( nodeSelect == nullptr )
280  return;
281  mDistinct = nodeSelect->distinct();
283  QString columnText;
284  Q_FOREACH ( QgsSQLStatement::NodeSelectedColumn* column, columns )
285  {
286  if ( !columnText.isEmpty() )
287  columnText += ", ";
288  columnText += column->dump();
289  }
290 
291  QList<QgsSQLStatement::NodeTableDef*> tables = nodeSelect->tables();
292  QString tablesText;
293  Q_FOREACH ( QgsSQLStatement::NodeTableDef* table, tables )
294  {
295  if ( !tablesText.isEmpty() )
296  tablesText += ", ";
297  loadTableColumns( QgsSQLStatement::quotedIdentifierIfNeeded( table->name() ) );
298  tablesText += table->dump();
299  }
300 
301  QString whereText;
302  QgsSQLStatement::Node* where = nodeSelect->where();
303  if ( where != nullptr )
304  whereText = where->dump();
305 
306  QString orderText;
307  QList<QgsSQLStatement::NodeColumnSorted*> orderColumns = nodeSelect->orderBy();
308  Q_FOREACH ( QgsSQLStatement::NodeColumnSorted* column, orderColumns )
309  {
310  if ( !orderText.isEmpty() )
311  orderText += ", ";
312  orderText += column->dump();
313  }
314 
315  QList<QgsSQLStatement::NodeJoin*> joins = nodeSelect->joins();
316 
317  mAlreadyModifyingFields = true;
318  mColumnsEditor->setPlainText( columnText );
319  mTablesEditor->setText( tablesText );
320  mWhereEditor->setPlainText( whereText );
321  mOrderEditor->setPlainText( orderText );
322 
323  mTableJoins->setRowCount( joins.size() + 1 );
324  int iRow = 0;
325  Q_FOREACH ( QgsSQLStatement::NodeJoin* join, joins )
326  {
327  loadTableColumns( QgsSQLStatement::quotedIdentifierIfNeeded( join->tableDef()->name() ) );
328  mTableJoins->setItem( iRow, 0 , new QTableWidgetItem( join->tableDef()->dump() ) );
329  if ( join->onExpr() )
330  mTableJoins->setItem( iRow, 1 , new QTableWidgetItem( join->onExpr()->dump() ) );
331  else
332  mTableJoins->setItem( iRow, 1 , new QTableWidgetItem( "" ) );
333  iRow ++;
334  }
335  mTableJoins->setItem( iRow, 0, new QTableWidgetItem( "" ) );
336  mTableJoins->setItem( iRow, 1, new QTableWidgetItem( "" ) );
337 
338  mAlreadyModifyingFields = false;
339 }
340 
342 {
343  Q_FOREACH ( const QString& name, list )
344  mapTableEntryTextToName[name] = name;
345  mTablesCombo->addItems( list );
346  addApis( list );
347 }
348 
350 {
351  QStringList listCombo;
352  QStringList listApi;
353  Q_FOREACH ( const PairNameTitle& pair, listNameTitle )
354  {
355  listApi << pair.first;
356  QString entryText( pair.first );
357  if ( !pair.second.isEmpty() && pair.second != pair.first )
358  {
359  if ( pair.second.size() < 40 )
360  entryText += " (" + pair.second + ")";
361  else
362  entryText += " (" + pair.second.mid( 0, 20 ) + "..." + pair.second.mid( pair.second.size() - 20 ) + ")";
363  }
364  listCombo << entryText;
365  mapTableEntryTextToName[entryText] = pair.first;
366  }
367  mTablesCombo->addItems( listCombo );
368  addApis( listApi );
369 }
370 
371 void QgsSQLComposerDialog::addColumnNames( const QStringList& list, const QString& tableName )
372 {
373  QList<PairNameType> listPair;
374  Q_FOREACH ( const QString& name, list )
375  listPair << PairNameType( name, QString() );
376  addColumnNames( listPair, tableName );
377 }
378 
380 {
381  if ( type.startsWith( "xs:" ) )
382  return type.mid( 3 );
383  if ( type.startsWith( "xsd:" ) )
384  return type.mid( 4 );
385  if ( type == "gml:AbstractGeometryType" )
386  return "geometry";
387  return type;
388 }
389 
391 {
392  mAlreadySelectedTables.insert( tableName );
393  if ( mColumnsCombo->count() > 1 )
394  mColumnsCombo->insertSeparator( mColumnsCombo->count() );
395 
396  QStringList listCombo;
397  QStringList listApi;
398  Q_FOREACH ( const PairNameType& pair, list )
399  {
400  listApi << pair.first;
401  QString entryText( pair.first );
402  if ( !pair.second.isEmpty() )
403  {
404  entryText += " (" + sanitizeType( pair.second ) + ")";
405  }
406  listCombo << entryText;
407  mapColumnEntryTextToName[entryText] = pair.first;
408  }
409  mColumnsCombo->addItems( listCombo );
410 
411  addApis( listApi );
412 }
413 
415 {
416  mOperatorsCombo->addItems( list );
417  addApis( list );
418 }
419 
421 {
422  if ( f.minArgs >= 0 && f.maxArgs > f.minArgs )
423  {
424  return QObject::tr( "%1 to %2 arguments" ).arg( f.minArgs ).arg( f.maxArgs );
425  }
426  else if ( f.minArgs == 0 && f.maxArgs == 0 )
427  {
428  }
429  else if ( f.minArgs > 0 && f.maxArgs == f.minArgs )
430  {
431  if ( f.minArgs == 1 )
432  return QObject::tr( "1 argument" );
433  else
434  return QObject::tr( "%1 arguments" ).arg( f.minArgs );
435  }
436  else if ( f.minArgs >= 0 && f.maxArgs < 0 )
437  {
438  if ( f.minArgs > 1 )
439  return QObject::tr( "%1 arguments or more" ).arg( f.minArgs );
440  else if ( f.minArgs == 1 )
441  return QObject::tr( "1 argument or more" );
442  else
443  return QObject::tr( "0 argument or more" );
444  }
445  return QString();
446 }
447 
448 
449 void QgsSQLComposerDialog::getFunctionList( const QList<Function>& list,
450  QStringList& listApi,
451  QStringList& listCombo,
452  QMap<QString, QString>& mapEntryTextToName )
453 {
454  Q_FOREACH ( const Function& f, list )
455  {
456  listApi << f.name;
457  QString entryText( f.name );
458  entryText += "(";
459  if ( f.argumentList.size() )
460  {
461  for ( int i = 0;i < f.argumentList.size();i++ )
462  {
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() )
466  {
467  entryText += sanitizeType( f.argumentList[i].type );
468  }
469  else
470  {
471  entryText += f.argumentList[i].name;
472  QString sanitizedType( sanitizeType( f.argumentList[i].type ) );
473  if ( !f.argumentList[i].type.isEmpty() &&
474  f.argumentList[i].name != sanitizedType )
475  {
476  entryText += ": ";
477  entryText += sanitizedType;
478  }
479  }
480  if ( f.minArgs >= 0 && i >= f.minArgs ) entryText += "]";
481  }
482  if ( entryText.size() > 60 )
483  {
484  entryText = f.name ;
485  entryText += "(";
486  entryText += getFunctionAbbridgedParameters( f );
487  }
488  }
489  else
490  {
491  entryText += getFunctionAbbridgedParameters( f );
492  }
493  entryText += ")";
494  if ( !f.returnType.isEmpty() )
495  entryText += ": " + sanitizeType( f.returnType );
496  listCombo << entryText;
497  mapEntryTextToName[entryText] = f.name + "(";
498  }
499 }
500 
502 {
503  QList<Function> listFunction;
504  Q_FOREACH ( const QString& name, list )
505  {
506  Function f;
507  f.name = name;
508  listFunction << f;
509  }
510  addSpatialPredicates( listFunction );
511 }
512 
514 {
515  QStringList listApi;
516  QStringList listCombo;
517  getFunctionList( list, listApi, listCombo, mapSpatialPredicateEntryTextToName );
518  mSpatialPredicatesCombo->addItems( listCombo );
519  mSpatialPredicatesCombo->show();
520  addApis( listApi );
521 }
522 
524 {
525  QList<Function> listFunction;
526  Q_FOREACH ( const QString& name, list )
527  {
528  Function f;
529  f.name = name;
530  listFunction << f;
531  }
532  addFunctions( listFunction );
533 }
534 
536 {
537  QStringList listApi;
538  QStringList listCombo;
539  getFunctionList( list, listApi, listCombo, mapFunctionEntryTextToName );
540  mFunctionsCombo->addItems( listCombo );
541  mFunctionsCombo->show();
542  addApis( listApi );
543 }
544 
545 void QgsSQLComposerDialog::loadTableColumns( const QString& table )
546 {
547  if ( mTableSelectedCallback )
548  {
549  if ( !mAlreadySelectedTables.contains( table ) )
550  {
551  mTableSelectedCallback->tableSelected( table );
552  mAlreadySelectedTables.insert( table );
553  }
554  }
555 }
556 
557 static void resetCombo( QComboBox* combo )
558 {
559  // We do it in a defered way, otherwise Valgrind complains when using QTest
560  // since basically this call a recursive call to QComboBox::setCurrentIndex()
561  // which cause internal QComboBox logic to operate on a destroyed object
562  // However that isn't reproduce in live session. Anyway this hack is safe
563  // in all modes.
564  QMetaObject::invokeMethod( combo, "setCurrentIndex", Qt::QueuedConnection, Q_ARG( int, 0 ) );
565 }
566 
567 void QgsSQLComposerDialog::on_mTablesCombo_currentIndexChanged( int )
568 {
569  int index = mTablesCombo->currentIndex();
570  if ( index <= 0 )
571  return;
572  QObject* obj = mFocusedObject;
573  QString newText = mapTableEntryTextToName[mTablesCombo->currentText()];
574  loadTableColumns( newText );
575  if ( obj == mTablesEditor )
576  {
577  QString currentText = mTablesEditor->text();
578  if ( currentText.isEmpty() )
579  mTablesEditor->setText( newText );
580  else
581  mTablesEditor->setText( currentText + ", " + newText );
582  }
583  else if ( obj == mTableJoins )
584  {
585  if ( mTableJoins->selectedItems().size() == 1 )
586  {
587  mTableJoins->selectedItems().at( 0 )->setText( newText );
588  }
589  }
590  else if ( obj == mWhereEditor )
591  {
592  mWhereEditor->insertPlainText( newText );
593  }
594  else if ( obj == mOrderEditor )
595  {
596  mOrderEditor->insertPlainText( newText );
597  }
598  else if ( obj == mQueryEdit )
599  {
600  mQueryEdit->insertText( newText );
601  }
602  resetCombo( mTablesCombo );
603 }
604 
605 void QgsSQLComposerDialog::on_mColumnsCombo_currentIndexChanged( int )
606 {
607  int index = mColumnsCombo->currentIndex();
608  if ( index <= 0 )
609  return;
610  QObject* obj = mFocusedObject;
611  QString newText = mapColumnEntryTextToName[mColumnsCombo->currentText()];
612  if ( obj == mColumnsEditor )
613  {
614  QString currentText = mColumnsEditor->toPlainText();
615  if ( currentText.isEmpty() )
616  mColumnsEditor->insertPlainText( newText );
617  else
618  mColumnsEditor->insertPlainText( ",\n" + newText );
619  }
620  else if ( obj == mTableJoins )
621  {
622  if ( mTableJoins->selectedItems().size() == 1 &&
623  mTableJoins->selectedItems().at( 0 )->column() == 1 )
624  {
625  QString currentText( mTableJoins->selectedItems().at( 0 )->text() );
626  if ( !currentText.isEmpty() && !currentText.contains( "=" ) )
627  mTableJoins->selectedItems().at( 0 )->setText( currentText + " = " + newText );
628  else
629  mTableJoins->selectedItems().at( 0 )->setText( currentText + newText );
630  }
631  }
632  else if ( obj == mWhereEditor )
633  {
634  mWhereEditor->insertPlainText( newText );
635  }
636  else if ( obj == mOrderEditor )
637  {
638  mOrderEditor->insertPlainText( newText );
639  }
640  else if ( obj == mQueryEdit )
641  {
642  mQueryEdit->insertText( newText );
643  }
644  resetCombo( mColumnsCombo );
645 }
646 
647 void QgsSQLComposerDialog::on_mFunctionsCombo_currentIndexChanged( int )
648 {
649  functionCurrentIndexChanged( mFunctionsCombo, mapFunctionEntryTextToName );
650 }
651 
652 void QgsSQLComposerDialog::on_mSpatialPredicatesCombo_currentIndexChanged( int )
653 {
654  functionCurrentIndexChanged( mSpatialPredicatesCombo, mapSpatialPredicateEntryTextToName );
655 }
656 
657 void QgsSQLComposerDialog::functionCurrentIndexChanged( QComboBox* combo,
658  const QMap<QString, QString>& mapEntryTextToName )
659 {
660  int index = combo->currentIndex();
661  if ( index <= 0 )
662  return;
663  QObject* obj = mFocusedObject;
664  QString newText = mapEntryTextToName[combo->currentText()];
665  if ( obj == mColumnsEditor )
666  {
667  mColumnsEditor->insertPlainText( newText );
668  }
669  else if ( obj == mWhereEditor )
670  {
671  mWhereEditor->insertPlainText( newText );
672  }
673  else if ( obj == mQueryEdit )
674  {
675  mQueryEdit->insertText( newText );
676  }
677  resetCombo( combo );
678 }
679 
680 void QgsSQLComposerDialog::on_mOperatorsCombo_currentIndexChanged( int )
681 {
682  int index = mOperatorsCombo->currentIndex();
683  if ( index <= 0 )
684  return;
685  QObject* obj = mFocusedObject;
686  QString newText = mOperatorsCombo->currentText();
687  if ( obj == mColumnsEditor )
688  {
689  mColumnsEditor->insertPlainText( newText );
690  }
691  else if ( obj == mWhereEditor )
692  {
693  mWhereEditor->insertPlainText( newText );
694  }
695  else if ( obj == mTableJoins )
696  {
697  if ( mTableJoins->selectedItems().size() == 1 &&
698  mTableJoins->selectedItems().at( 0 )->column() == 1 )
699  {
700  QString currentText( mTableJoins->selectedItems().at( 0 )->text() );
701  mTableJoins->selectedItems().at( 0 )->setText( currentText + newText );
702  }
703  }
704  else if ( obj == mQueryEdit )
705  {
706  mQueryEdit->insertText( newText );
707  }
708  resetCombo( mOperatorsCombo );
709 }
710 
711 void QgsSQLComposerDialog::on_mAddJoinButton_clicked()
712 {
713  int insertRow = mTableJoins->currentRow();
714  int rowCount = mTableJoins->rowCount();
715  if ( insertRow < 0 )
716  insertRow = rowCount;
717  mTableJoins->setRowCount( rowCount + 1 );
718  for ( int row = rowCount ; row > insertRow + 1; row -- )
719  {
720  mTableJoins->setItem( row, 0, mTableJoins->takeItem( row - 1, 0 ) );
721  mTableJoins->setItem( row, 1, mTableJoins->takeItem( row - 1, 1 ) );
722  }
723  mTableJoins->setItem(( insertRow == rowCount ) ? insertRow : insertRow + 1, 0, new QTableWidgetItem( "" ) );
724  mTableJoins->setItem(( insertRow == rowCount ) ? insertRow : insertRow + 1, 1, new QTableWidgetItem( "" ) );
725 }
726 
727 void QgsSQLComposerDialog::on_mRemoveJoinButton_clicked()
728 {
729  int row = mTableJoins->currentRow();
730  if ( row < 0 )
731  return;
732  int rowCount = mTableJoins->rowCount();
733  for ( ; row < rowCount - 1; row ++ )
734  {
735  mTableJoins->setItem( row, 0, mTableJoins->takeItem( row + 1, 0 ) );
736  mTableJoins->setItem( row, 1, mTableJoins->takeItem( row + 1, 1 ) );
737  }
738  mTableJoins->setRowCount( rowCount - 1 );
739 
740  buildSQLFromFields();
741 }
742 
743 void QgsSQLComposerDialog::reset()
744 {
745  mQueryEdit->setText( mResetSql );
746 }
747 
748 void QgsSQLComposerDialog::on_mTableJoins_itemSelectionChanged()
749 {
750  mRemoveJoinButton->setEnabled( mTableJoins->selectedItems().size() == 1 );
751 }
752 
754 {
755  mApiList += list;
756 
757  delete mQueryEdit->lexer()->apis();
758  QsciAPIs* apis = new QsciAPIs( mQueryEdit->lexer() );
759 
760  Q_FOREACH ( const QString& str, mApiList )
761  {
762  apis->add( str );
763  }
764 
765  apis->prepare();
766  mQueryEdit->lexer()->setAPIs( apis );
767 }
768 
770 {
771  mJoinsLabels->setVisible( on );
772  mTableJoins->setVisible( on );
773  mAddJoinButton->setVisible( on );
774  mRemoveJoinButton->setVisible( on );
775  mTablesCombo->setVisible( on );
776 
777  QString mainTypenameFormatted;
778  if ( !mainTypename.isEmpty() )
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 ) );
783 }
virtual void tableSelected(const QString &name)=0
method called when a table is selected
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
static unsigned index
virtual bool event(QEvent *e)
void addOperators(const QStringList &list)
add a list of operators
Callback to do actions on table selection.
Type type() const
void setupUi(QWidget *widget)
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.
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
int size() const
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)
int size() const
bool distinct() const
Return if the SELECT is DISTINCT.
Abstract node class.
void clear()
const char * name() const
Class for parsing SQL statements.
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 isEmpty() const
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 void accept()
Callback to do validation check on dialog validation.
virtual QString dump() const override
Abstract virtual dump method.
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9)
QString text() const
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)
typedef WindowFlags
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)
QObject * parent() const
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.