16 #include <QDomDocument>    17 #include <QDomElement>    18 #include <QFileDialog>    20 #include <QInputDialog>    22 #include <QMessageBox>    23 #include <QStandardItem>    24 #include <QTextStream>    37     QWidget *parent, Qt::WindowFlags fl )
    38   : QDialog( parent, fl )
    42   connect( btnEqual, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnEqual_clicked );
    43   connect( btnLessThan, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnLessThan_clicked );
    44   connect( btnGreaterThan, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnGreaterThan_clicked );
    45   connect( btnLike, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnLike_clicked );
    46   connect( btnILike, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnILike_clicked );
    47   connect( btnPct, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnPct_clicked );
    48   connect( btnIn, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnIn_clicked );
    49   connect( btnNotIn, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnNotIn_clicked );
    50   connect( lstFields, &QListView::doubleClicked, 
this, &QgsSearchQueryBuilder::lstFields_doubleClicked );
    51   connect( lstValues, &QListView::doubleClicked, 
this, &QgsSearchQueryBuilder::lstValues_doubleClicked );
    52   connect( btnLessEqual, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnLessEqual_clicked );
    53   connect( btnGreaterEqual, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnGreaterEqual_clicked );
    54   connect( btnNotEqual, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnNotEqual_clicked );
    55   connect( btnAnd, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnAnd_clicked );
    56   connect( btnNot, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnNot_clicked );
    57   connect( btnOr, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnOr_clicked );
    58   connect( btnGetAllValues, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnGetAllValues_clicked );
    59   connect( btnSampleValues, &QPushButton::clicked, 
this, &QgsSearchQueryBuilder::btnSampleValues_clicked );
    61   connect( buttonBox, &QDialogButtonBox::helpRequested, 
this, &QgsSearchQueryBuilder::showHelp );
    63   setWindowTitle( tr( 
"Search Query Builder" ) );
    65   QPushButton *pbn = 
new QPushButton( tr( 
"&Test" ) );
    66   buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
    67   connect( pbn, &QAbstractButton::clicked, 
this, &QgsSearchQueryBuilder::btnTest_clicked );
    69   pbn = 
new QPushButton( tr( 
"&Clear" ) );
    70   buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
    71   connect( pbn, &QAbstractButton::clicked, 
this, &QgsSearchQueryBuilder::btnClear_clicked );
    73   pbn = 
new QPushButton( tr( 
"&Save…" ) );
    74   buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
    75   pbn->setToolTip( tr( 
"Save query to an xml file" ) );
    78   pbn = 
new QPushButton( tr( 
"&Load…" ) );
    79   buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
    80   pbn->setToolTip( tr( 
"Load query from xml file" ) );
    84     lblDataUri->setText( layer->
name() );
    88 void QgsSearchQueryBuilder::populateFields()
    94   for ( 
int idx = 0; idx < fields.
count(); ++idx )
    96     QString fieldName = fields.
at( idx ).
name();
    97     mFieldMap[fieldName] = idx;
    98     QStandardItem *myItem = 
new QStandardItem( fieldName );
    99     myItem->setEditable( 
false );
   100     mModelFields->insertRow( mModelFields->rowCount(), myItem );
   104 void QgsSearchQueryBuilder::setupListViews()
   107   mModelFields = 
new QStandardItemModel();
   108   mModelValues = 
new QStandardItemModel();
   109   lstFields->setModel( mModelFields );
   110   lstValues->setModel( mModelValues );
   112   lstFields->setViewMode( QListView::ListMode );
   113   lstValues->setViewMode( QListView::ListMode );
   114   lstFields->setSelectionBehavior( QAbstractItemView::SelectRows );
   115   lstValues->setSelectionBehavior( QAbstractItemView::SelectRows );
   117   lstFields->setUniformItemSizes( 
true );
   118   lstValues->setUniformItemSizes( 
true );
   121 void QgsSearchQueryBuilder::getFieldValues( 
int limit )
   128   mModelValues->clear();
   131   QString fieldName = mModelFields->data( lstFields->currentIndex() ).toString();
   132   int fieldIndex = mFieldMap[fieldName];
   134   bool numeric = ( field.
type() == QVariant::Int || field.
type() == QVariant::Double );
   140   attrs.append( fieldIndex );
   144   lstValues->setCursor( Qt::WaitCursor );
   146   mModelValues->blockSignals( 
true );
   147   lstValues->setUpdatesEnabled( 
false );
   150   QSet<QString> insertedValues;
   153           ( limit == 0 || mModelValues->rowCount() != limit ) )
   155     value = feat.
attribute( fieldIndex ).toString();
   160       value = 
'\'' + value.replace( 
'\'', QLatin1String( 
"''" ) ) + 
'\'';
   164     if ( !insertedValues.contains( value ) )
   166       QStandardItem *myItem = 
new QStandardItem( value );
   167       myItem->setEditable( 
false );
   168       mModelValues->insertRow( mModelValues->rowCount(), myItem );
   169       insertedValues.insert( value );
   173   mModelValues->blockSignals( 
false );
   174   lstValues->setUpdatesEnabled( 
true );
   176   mModelValues->sort( 0 );
   177   lstValues->setCursor( Qt::ArrowCursor );
   180 void QgsSearchQueryBuilder::btnSampleValues_clicked()
   182   getFieldValues( 25 );
   185 void QgsSearchQueryBuilder::btnGetAllValues_clicked()
   190 void QgsSearchQueryBuilder::btnTest_clicked()
   192   long count = countRecords( txtSQL->text() );
   198   QMessageBox::information( 
this, tr( 
"Test Query" ), tr( 
"Found %n matching feature(s).", 
"test result", count ) );
   202 long QgsSearchQueryBuilder::countRecords( 
const QString &
searchString )
   221   if ( !search.
prepare( &context ) )
   223     QMessageBox::critical( 
this, tr( 
"Query Result" ), search.
evalErrorString() );
   227   QApplication::setOverrideCursor( Qt::WaitCursor );
   234     QVariant value = search.
evaluate( &context );
   235     if ( value.toInt() != 0 )
   245   QApplication::restoreOverrideCursor();
   249     QMessageBox::critical( 
this, tr( 
"Query Result" ), search.
evalErrorString() );
   257 void QgsSearchQueryBuilder::btnOk_clicked()
   260   if ( txtSQL->text().trimmed().length() > 0 )
   267   long numRecs = countRecords( txtSQL->text() );
   272   else if ( numRecs == 0 )
   274     QMessageBox::warning( 
this, tr( 
"Query Result" ), tr( 
"The query you specified results in zero records being returned." ) );
   283 void QgsSearchQueryBuilder::btnEqual_clicked()
   285   txtSQL->insertText( QStringLiteral( 
" = " ) );
   288 void QgsSearchQueryBuilder::btnLessThan_clicked()
   290   txtSQL->insertText( QStringLiteral( 
" < " ) );
   293 void QgsSearchQueryBuilder::btnGreaterThan_clicked()
   295   txtSQL->insertText( QStringLiteral( 
" > " ) );
   298 void QgsSearchQueryBuilder::btnPct_clicked()
   300   txtSQL->insertText( QStringLiteral( 
"%" ) );
   303 void QgsSearchQueryBuilder::btnIn_clicked()
   305   txtSQL->insertText( QStringLiteral( 
" IN " ) );
   308 void QgsSearchQueryBuilder::btnNotIn_clicked()
   310   txtSQL->insertText( QStringLiteral( 
" NOT IN " ) );
   313 void QgsSearchQueryBuilder::btnLike_clicked()
   315   txtSQL->insertText( QStringLiteral( 
" LIKE " ) );
   320   return txtSQL->text();
   325   txtSQL->setText( searchString );
   328 void QgsSearchQueryBuilder::lstFields_doubleClicked( 
const QModelIndex &index )
   333 void QgsSearchQueryBuilder::lstValues_doubleClicked( 
const QModelIndex &index )
   335   txtSQL->insertText( mModelValues->data( index ).toString() );
   338 void QgsSearchQueryBuilder::btnLessEqual_clicked()
   340   txtSQL->insertText( QStringLiteral( 
" <= " ) );
   343 void QgsSearchQueryBuilder::btnGreaterEqual_clicked()
   345   txtSQL->insertText( QStringLiteral( 
" >= " ) );
   348 void QgsSearchQueryBuilder::btnNotEqual_clicked()
   350   txtSQL->insertText( QStringLiteral( 
" != " ) );
   353 void QgsSearchQueryBuilder::btnAnd_clicked()
   355   txtSQL->insertText( QStringLiteral( 
" AND " ) );
   358 void QgsSearchQueryBuilder::btnNot_clicked()
   360   txtSQL->insertText( QStringLiteral( 
" NOT " ) );
   363 void QgsSearchQueryBuilder::btnOr_clicked()
   365   txtSQL->insertText( QStringLiteral( 
" OR " ) );
   368 void QgsSearchQueryBuilder::btnClear_clicked()
   373 void QgsSearchQueryBuilder::btnILike_clicked()
   375   txtSQL->insertText( QStringLiteral( 
" ILIKE " ) );
   381   QString lastQueryFileDir = s.
value( QStringLiteral( 
"/UI/lastQueryFileDir" ), QDir::homePath() ).toString();
   383   QString saveFileName = QFileDialog::getSaveFileName( 
nullptr, tr( 
"Save Query to File" ), lastQueryFileDir, QStringLiteral( 
"*.qqf" ) );
   384   if ( saveFileName.isNull() )
   389   if ( !saveFileName.endsWith( QLatin1String( 
".qqf" ), Qt::CaseInsensitive ) )
   391     saveFileName += QLatin1String( 
".qqf" );
   394   QFile saveFile( saveFileName );
   395   if ( !saveFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
   397     QMessageBox::critical( 
nullptr, tr( 
"Save Query to File" ), tr( 
"Could not open file for writing." ) );
   402   QDomElement queryElem = xmlDoc.createElement( QStringLiteral( 
"Query" ) );
   403   QDomText queryTextNode = xmlDoc.createTextNode( txtSQL->text() );
   404   queryElem.appendChild( queryTextNode );
   405   xmlDoc.appendChild( queryElem );
   407   QTextStream fileStream( &saveFile );
   408   xmlDoc.save( fileStream, 2 );
   410   QFileInfo fi( saveFile );
   411   s.
setValue( QStringLiteral( 
"/UI/lastQueryFileDir" ), fi.absolutePath() );
   417   QString lastQueryFileDir = s.
value( QStringLiteral( 
"/UI/lastQueryFileDir" ), QDir::homePath() ).toString();
   419   QString queryFileName = QFileDialog::getOpenFileName( 
nullptr, tr( 
"Load Query from File" ), lastQueryFileDir, tr( 
"Query files" ) + 
" (*.qqf);;" + tr( 
"All files" ) + 
" (*)" );
   420   if ( queryFileName.isNull() )
   425   QFile queryFile( queryFileName );
   426   if ( !queryFile.open( QIODevice::ReadOnly ) )
   428     QMessageBox::critical( 
nullptr, tr( 
"Load Query from File" ), tr( 
"Could not open file for reading." ) );
   431   QDomDocument queryDoc;
   432   if ( !queryDoc.setContent( &queryFile ) )
   434     QMessageBox::critical( 
nullptr, tr( 
"Load Query from File" ), tr( 
"File is not a valid xml document." ) );
   438   QDomElement queryElem = queryDoc.firstChildElement( QStringLiteral( 
"Query" ) );
   439   if ( queryElem.isNull() )
   441     QMessageBox::critical( 
nullptr, tr( 
"Load Query from File" ), tr( 
"File is not a valid query document." ) );
   445   QString query = queryElem.text();
   455   QString newQueryText = query;
   460   QStringList attributes = searchTree->referencedColumns();
   461   QMap< QString, QString> attributesToReplace;
   462   QStringList existingAttributes;
   465   QMap<QString, int>::const_iterator fieldIt = mFieldMap.constBegin();
   466   for ( ; fieldIt != mFieldMap.constEnd(); ++fieldIt )
   468     existingAttributes.push_back( fieldIt.key() );
   472   QStringList::const_iterator attIt = attributes.constBegin();
   473   for ( ; attIt != attributes.constEnd(); ++attIt )
   476     if ( !mFieldMap.contains( attIt ) )
   479       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 ),
   480                                  existingAttributes, 0, 
false, &ok );
   481       if ( !ok || replaceAttribute.isEmpty() )
   485       attributesToReplace.insert( *attIt, replaceAttribute );
   490   QList<QgsSearchTreeNode *> columnRefList = searchTree->columnRefNodes();
   491   QList<QgsSearchTreeNode *>::iterator columnIt = columnRefList.begin();
   492   for ( ; columnIt != columnRefList.end(); ++columnIt )
   494     QMap< QString, QString>::const_iterator replaceIt = attributesToReplace.find( ( *columnIt )->columnRef() );
   495     if ( replaceIt != attributesToReplace.constEnd() )
   497       ( *columnIt )->setColumnRef( replaceIt.value() );
   501   if ( attributesToReplace.size() > 0 )
   503     newQueryText = query;
   508   txtSQL->insertText( newQueryText );
   511 void QgsSearchQueryBuilder::showHelp()
   513   QgsHelp::openHelp( QStringLiteral( 
"working_with_vector/vector_properties.html#query-builder" ) );
 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. 
 
Wrapper for iterator of features from vector data provider or vector layer. 
 
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes) 
 
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 setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context. 
 
void setSearchString(const QString &searchString)
change search string shown in text field 
 
QVariant evaluate()
Evaluate the feature and return the result. 
 
QString evalErrorString() const
Returns evaluation error. 
 
Container of fields for a vector layer. 
 
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation. 
 
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
 
int count() const
Returns number of items. 
 
QString parserErrorString() const
Returns parser error. 
 
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1) 
 
QgsFields fields() const override
Returns the list of fields of this layer. 
 
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
 
This class wraps a request for features to a vector layer (or directly its vector data provider)...
 
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer. 
 
Encapsulate a field in an attribute table or data source. 
 
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Query the layer for features specified in request. 
 
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value. 
 
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes. 
 
QgsSearchQueryBuilder(QgsVectorLayer *layer, QWidget *parent SIP_TRANSFERTHIS=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
Constructor - takes pointer to vector layer as a parameter. 
 
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser. 
 
QList< int > QgsAttributeList
 
bool nextFeature(QgsFeature &f)
 
Geometry is not required. It may still be returned if e.g. required for a filter condition. 
 
bool hasEvalError() const
Returns true if an error occurred when evaluating last input. 
 
Represents a vector layer which manages a vector based data sets. 
 
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name. 
 
QString searchString()
returns newly created search string