16 #include <QDomDocument> 
   17 #include <QDomElement> 
   18 #include <QFileDialog> 
   20 #include <QInputDialog> 
   22 #include <QMessageBox> 
   23 #include <QStandardItem> 
   24 #include <QTextStream> 
   39     QWidget *parent, Qt::WindowFlags fl )
 
   40   : QDialog( parent, fl )
 
   44   connect( btnEqual, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnEqual_clicked );
 
   45   connect( btnLessThan, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnLessThan_clicked );
 
   46   connect( btnGreaterThan, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnGreaterThan_clicked );
 
   47   connect( btnLike, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnLike_clicked );
 
   48   connect( btnILike, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnILike_clicked );
 
   49   connect( btnPct, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnPct_clicked );
 
   50   connect( btnIn, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnIn_clicked );
 
   51   connect( btnNotIn, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnNotIn_clicked );
 
   52   connect( lstFields, &QListView::doubleClicked, 
this, &QgsSearchQueryBuilder::lstFields_doubleClicked );
 
   53   connect( lstValues, &QListView::doubleClicked, 
this, &QgsSearchQueryBuilder::lstValues_doubleClicked );
 
   54   connect( btnLessEqual, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnLessEqual_clicked );
 
   55   connect( btnGreaterEqual, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnGreaterEqual_clicked );
 
   56   connect( btnNotEqual, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnNotEqual_clicked );
 
   57   connect( btnAnd, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnAnd_clicked );
 
   58   connect( btnNot, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnNot_clicked );
 
   59   connect( btnOr, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnOr_clicked );
 
   60   connect( btnGetAllValues, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnGetAllValues_clicked );
 
   61   connect( btnSampleValues, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnSampleValues_clicked );
 
   63   connect( buttonBox, &QDialogButtonBox::helpRequested, 
this, &QgsSearchQueryBuilder::showHelp );
 
   65   setWindowTitle( tr( 
"Search Query Builder" ) );
 
   67   QPushButton *pbn = 
new QPushButton( tr( 
"&Test" ) );
 
   68   buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
 
   69   connect( pbn, &QAbstractButton::clicked, 
this, &QgsSearchQueryBuilder::btnTest_clicked );
 
   71   pbn = 
new QPushButton( tr( 
"&Clear" ) );
 
   72   buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
 
   73   connect( pbn, &QAbstractButton::clicked, 
this, &QgsSearchQueryBuilder::btnClear_clicked );
 
   75   pbn = 
new QPushButton( tr( 
"&Save…" ) );
 
   76   buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
 
   77   pbn->setToolTip( tr( 
"Save query to an xml file" ) );
 
   80   pbn = 
new QPushButton( tr( 
"&Load…" ) );
 
   81   buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
 
   82   pbn->setToolTip( tr( 
"Load query from xml file" ) );
 
   86     lblDataUri->setText( layer->
name() );
 
   90 void QgsSearchQueryBuilder::populateFields()
 
   96   for ( 
int idx = 0; idx < fields.
count(); ++idx )
 
   98     QString fieldName = fields.
at( idx ).
name();
 
   99     mFieldMap[fieldName] = idx;
 
  100     QStandardItem *myItem = 
new QStandardItem( fieldName );
 
  101     myItem->setEditable( 
false );
 
  102     mModelFields->insertRow( mModelFields->rowCount(), myItem );
 
  106 void QgsSearchQueryBuilder::setupListViews()
 
  109   mModelFields = 
new QStandardItemModel();
 
  110   mModelValues = 
new QStandardItemModel();
 
  111   lstFields->setModel( mModelFields );
 
  112   lstValues->setModel( mModelValues );
 
  114   lstFields->setViewMode( QListView::ListMode );
 
  115   lstValues->setViewMode( QListView::ListMode );
 
  116   lstFields->setSelectionBehavior( QAbstractItemView::SelectRows );
 
  117   lstValues->setSelectionBehavior( QAbstractItemView::SelectRows );
 
  119   lstFields->setUniformItemSizes( 
true );
 
  120   lstValues->setUniformItemSizes( 
true );
 
  123 void QgsSearchQueryBuilder::getFieldValues( 
int limit )
 
  130   mModelValues->clear();
 
  133   QString fieldName = mModelFields->data( lstFields->currentIndex() ).toString();
 
  134   int fieldIndex = mFieldMap[fieldName];
 
  142   attrs.append( fieldIndex );
 
  146   lstValues->setCursor( Qt::WaitCursor );
 
  148   mModelValues->blockSignals( 
true );
 
  149   lstValues->setUpdatesEnabled( 
false );
 
  152   QSet<QString> insertedValues;
 
  155           ( limit == 0 || mModelValues->rowCount() != limit ) )
 
  157     value = feat.
attribute( fieldIndex ).toString();
 
  162       value = 
'\'' + value.replace( 
'\'', QLatin1String( 
"''" ) ) + 
'\'';
 
  166     if ( !insertedValues.contains( value ) )
 
  168       QStandardItem *myItem = 
new QStandardItem( value );
 
  169       myItem->setEditable( 
false );
 
  170       mModelValues->insertRow( mModelValues->rowCount(), myItem );
 
  171       insertedValues.insert( value );
 
  175   mModelValues->blockSignals( 
false );
 
  176   lstValues->setUpdatesEnabled( 
true );
 
  178   mModelValues->sort( 0 );
 
  179   lstValues->setCursor( Qt::ArrowCursor );
 
  182 void QgsSearchQueryBuilder::btnSampleValues_clicked()
 
  184   getFieldValues( 25 );
 
  187 void QgsSearchQueryBuilder::btnGetAllValues_clicked()
 
  192 void QgsSearchQueryBuilder::btnTest_clicked()
 
  194   long count = countRecords( mTxtSql->text() );
 
  200   QMessageBox::information( 
this, tr( 
"Test Query" ), tr( 
"Found %n matching feature(s).", 
"test result", count ) );
 
  204 long QgsSearchQueryBuilder::countRecords( 
const QString &searchString )
 
  207   if ( search.hasParserError() )
 
  209     QMessageBox::critical( 
this, tr( 
"Query Result" ), search.parserErrorString() );
 
  216   bool fetchGeom = search.needsGeometry();
 
  223   if ( !search.prepare( &context ) )
 
  225     QMessageBox::critical( 
this, tr( 
"Query Result" ), search.evalErrorString() );
 
  229   QApplication::setOverrideCursor( Qt::WaitCursor );
 
  235     context.setFeature( feat );
 
  236     QVariant value = search.evaluate( &context );
 
  237     if ( value.toInt() != 0 )
 
  243     if ( search.hasEvalError() )
 
  247   QApplication::restoreOverrideCursor();
 
  249   if ( search.hasEvalError() )
 
  251     QMessageBox::critical( 
this, tr( 
"Query Result" ), search.evalErrorString() );
 
  259 void QgsSearchQueryBuilder::btnOk_clicked()
 
  262   if ( mTxtSql->text().trimmed().length() > 0 )
 
  269   long numRecs = countRecords( mTxtSql->text() );
 
  274   else if ( numRecs == 0 )
 
  276     QMessageBox::warning( 
this, tr( 
"Query Result" ), tr( 
"The query you specified results in zero records being returned." ) );
 
  285 void QgsSearchQueryBuilder::btnEqual_clicked()
 
  287   mTxtSql->insertText( QStringLiteral( 
" = " ) );
 
  290 void QgsSearchQueryBuilder::btnLessThan_clicked()
 
  292   mTxtSql->insertText( QStringLiteral( 
" < " ) );
 
  295 void QgsSearchQueryBuilder::btnGreaterThan_clicked()
 
  297   mTxtSql->insertText( QStringLiteral( 
" > " ) );
 
  300 void QgsSearchQueryBuilder::btnPct_clicked()
 
  302   mTxtSql->insertText( QStringLiteral( 
"%" ) );
 
  305 void QgsSearchQueryBuilder::btnIn_clicked()
 
  307   mTxtSql->insertText( QStringLiteral( 
" IN " ) );
 
  310 void QgsSearchQueryBuilder::btnNotIn_clicked()
 
  312   mTxtSql->insertText( QStringLiteral( 
" NOT IN " ) );
 
  315 void QgsSearchQueryBuilder::btnLike_clicked()
 
  317   mTxtSql->insertText( QStringLiteral( 
" LIKE " ) );
 
  322   return mTxtSql->text();
 
  330 void QgsSearchQueryBuilder::lstFields_doubleClicked( 
const QModelIndex &index )
 
  335 void QgsSearchQueryBuilder::lstValues_doubleClicked( 
const QModelIndex &index )
 
  337   mTxtSql->insertText( mModelValues->data( index ).toString() );
 
  340 void QgsSearchQueryBuilder::btnLessEqual_clicked()
 
  342   mTxtSql->insertText( QStringLiteral( 
" <= " ) );
 
  345 void QgsSearchQueryBuilder::btnGreaterEqual_clicked()
 
  347   mTxtSql->insertText( QStringLiteral( 
" >= " ) );
 
  350 void QgsSearchQueryBuilder::btnNotEqual_clicked()
 
  352   mTxtSql->insertText( QStringLiteral( 
" != " ) );
 
  355 void QgsSearchQueryBuilder::btnAnd_clicked()
 
  357   mTxtSql->insertText( QStringLiteral( 
" AND " ) );
 
  360 void QgsSearchQueryBuilder::btnNot_clicked()
 
  362   mTxtSql->insertText( QStringLiteral( 
" NOT " ) );
 
  365 void QgsSearchQueryBuilder::btnOr_clicked()
 
  367   mTxtSql->insertText( QStringLiteral( 
" OR " ) );
 
  370 void QgsSearchQueryBuilder::btnClear_clicked()
 
  375 void QgsSearchQueryBuilder::btnILike_clicked()
 
  377   mTxtSql->insertText( QStringLiteral( 
" ILIKE " ) );
 
  383   QString lastQueryFileDir = s.
value( QStringLiteral( 
"/UI/lastQueryFileDir" ), QDir::homePath() ).toString();
 
  385   QString saveFileName = QFileDialog::getSaveFileName( 
nullptr, tr( 
"Save Query to File" ), lastQueryFileDir, tr( 
"Query files (*.qqf *.QQF)" ) );
 
  386   if ( saveFileName.isNull() )
 
  391   if ( !saveFileName.endsWith( QLatin1String( 
".qqf" ), Qt::CaseInsensitive ) )
 
  393     saveFileName += QLatin1String( 
".qqf" );
 
  396   QFile saveFile( saveFileName );
 
  397   if ( !saveFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
 
  399     QMessageBox::critical( 
nullptr, tr( 
"Save Query to File" ), tr( 
"Could not open file for writing." ) );
 
  404   QDomElement queryElem = xmlDoc.createElement( QStringLiteral( 
"Query" ) );
 
  405   QDomText queryTextNode = xmlDoc.createTextNode( mTxtSql->text() );
 
  406   queryElem.appendChild( queryTextNode );
 
  407   xmlDoc.appendChild( queryElem );
 
  409   QTextStream fileStream( &saveFile );
 
  410   xmlDoc.save( fileStream, 2 );
 
  412   QFileInfo fi( saveFile );
 
  413   s.
setValue( QStringLiteral( 
"/UI/lastQueryFileDir" ), fi.absolutePath() );
 
  419   QString lastQueryFileDir = s.
value( QStringLiteral( 
"/UI/lastQueryFileDir" ), QDir::homePath() ).toString();
 
  421   QString queryFileName = QFileDialog::getOpenFileName( 
nullptr, tr( 
"Load Query from File" ), lastQueryFileDir, tr( 
"Query files" ) + 
" (*.qqf *.QQF);;" + tr( 
"All files" ) + 
" (*)" );
 
  422   if ( queryFileName.isNull() )
 
  427   QFile queryFile( queryFileName );
 
  428   if ( !queryFile.open( QIODevice::ReadOnly ) )
 
  430     QMessageBox::critical( 
nullptr, tr( 
"Load Query from File" ), tr( 
"Could not open file for reading." ) );
 
  433   QDomDocument queryDoc;
 
  434   if ( !queryDoc.setContent( &queryFile ) )
 
  436     QMessageBox::critical( 
nullptr, tr( 
"Load Query from File" ), tr( 
"File is not a valid xml document." ) );
 
  440   QDomElement queryElem = queryDoc.firstChildElement( QStringLiteral( 
"Query" ) );
 
  441   if ( queryElem.isNull() )
 
  443     QMessageBox::critical( 
nullptr, tr( 
"Load Query from File" ), tr( 
"File is not a valid query document." ) );
 
  447   QString query = queryElem.text();
 
  457   QString newQueryText = query;
 
  462   QStringList attributes = searchTree->referencedColumns();
 
  463   QMap< QString, QString> attributesToReplace;
 
  464   QStringList existingAttributes;
 
  467   QMap<QString, int>::const_iterator fieldIt = mFieldMap.constBegin();
 
  468   for ( ; fieldIt != mFieldMap.constEnd(); ++fieldIt )
 
  470     existingAttributes.push_back( fieldIt.key() );
 
  474   QStringList::const_iterator attIt = attributes.constBegin();
 
  475   for ( ; attIt != attributes.constEnd(); ++attIt )
 
  478     if ( !mFieldMap.contains( attIt ) )
 
  481       QString replaceAttribute = QInputDialog::getItem( 0, tr( 
"Select Attribute" ), tr( 
"There is no attribute '%1' in the current vector layer. Please select an existing attribute." ).arg( *attIt ),
 
  482                                  existingAttributes, 0, 
false, &ok );
 
  483       if ( !ok || replaceAttribute.isEmpty() )
 
  487       attributesToReplace.insert( *attIt, replaceAttribute );
 
  492   QList<QgsSearchTreeNode *> columnRefList = searchTree->columnRefNodes();
 
  493   QList<QgsSearchTreeNode *>::iterator columnIt = columnRefList.begin();
 
  494   for ( ; columnIt != columnRefList.end(); ++columnIt )
 
  496     QMap< QString, QString>::const_iterator replaceIt = attributesToReplace.find( ( *columnIt )->columnRef() );
 
  497     if ( replaceIt != attributesToReplace.constEnd() )
 
  499       ( *columnIt )->setColumnRef( replaceIt.value() );
 
  503   if ( attributesToReplace.size() > 0 )
 
  505     newQueryText = query;
 
  510   mTxtSql->insertText( newQueryText );
 
  513 void QgsSearchQueryBuilder::showHelp()
 
  515   QgsHelp::openHelp( QStringLiteral( 
"working_with_vector/vector_properties.html#query-builder" ) );
 
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Class for parsing and evaluation of expressions (formerly called "search strings").
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QString parserErrorString() const
Returns parser error.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Encapsulate a field in an attribute table or data source.
Container of fields for a vector layer.
int count() const
Returns number of items.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
QgsSearchQueryBuilder(QgsVectorLayer *layer, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
Constructor - takes pointer to vector layer as a parameter.
void setSearchString(const QString &searchString)
change search string shown in text field
QString searchString()
returns newly created search string
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QList< int > QgsAttributeList