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];
136 bool numeric = ( field.
type() == QVariant::Int || field.
type() == QVariant::Double );
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( txtSQL->text() );
200 QMessageBox::information(
this, tr(
"Test Query" ), tr(
"Found %n matching feature(s).",
"test result", count ) );
204 long QgsSearchQueryBuilder::countRecords(
const QString &
searchString )
223 if ( !search.
prepare( &context ) )
225 QMessageBox::critical(
this, tr(
"Query Result" ), search.
evalErrorString() );
229 QApplication::setOverrideCursor( Qt::WaitCursor );
236 QVariant value = search.
evaluate( &context );
237 if ( value.toInt() != 0 )
247 QApplication::restoreOverrideCursor();
251 QMessageBox::critical(
this, tr(
"Query Result" ), search.
evalErrorString() );
259 void QgsSearchQueryBuilder::btnOk_clicked()
262 if ( txtSQL->text().trimmed().length() > 0 )
269 long numRecs = countRecords( txtSQL->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 txtSQL->insertText( QStringLiteral(
" = " ) );
290 void QgsSearchQueryBuilder::btnLessThan_clicked()
292 txtSQL->insertText( QStringLiteral(
" < " ) );
295 void QgsSearchQueryBuilder::btnGreaterThan_clicked()
297 txtSQL->insertText( QStringLiteral(
" > " ) );
300 void QgsSearchQueryBuilder::btnPct_clicked()
302 txtSQL->insertText( QStringLiteral(
"%" ) );
305 void QgsSearchQueryBuilder::btnIn_clicked()
307 txtSQL->insertText( QStringLiteral(
" IN " ) );
310 void QgsSearchQueryBuilder::btnNotIn_clicked()
312 txtSQL->insertText( QStringLiteral(
" NOT IN " ) );
315 void QgsSearchQueryBuilder::btnLike_clicked()
317 txtSQL->insertText( QStringLiteral(
" LIKE " ) );
322 return txtSQL->text();
327 txtSQL->setText( searchString );
330 void QgsSearchQueryBuilder::lstFields_doubleClicked(
const QModelIndex &index )
335 void QgsSearchQueryBuilder::lstValues_doubleClicked(
const QModelIndex &index )
337 txtSQL->insertText( mModelValues->data( index ).toString() );
340 void QgsSearchQueryBuilder::btnLessEqual_clicked()
342 txtSQL->insertText( QStringLiteral(
" <= " ) );
345 void QgsSearchQueryBuilder::btnGreaterEqual_clicked()
347 txtSQL->insertText( QStringLiteral(
" >= " ) );
350 void QgsSearchQueryBuilder::btnNotEqual_clicked()
352 txtSQL->insertText( QStringLiteral(
" != " ) );
355 void QgsSearchQueryBuilder::btnAnd_clicked()
357 txtSQL->insertText( QStringLiteral(
" AND " ) );
360 void QgsSearchQueryBuilder::btnNot_clicked()
362 txtSQL->insertText( QStringLiteral(
" NOT " ) );
365 void QgsSearchQueryBuilder::btnOr_clicked()
367 txtSQL->insertText( QStringLiteral(
" OR " ) );
370 void QgsSearchQueryBuilder::btnClear_clicked()
375 void QgsSearchQueryBuilder::btnILike_clicked()
377 txtSQL->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, QStringLiteral(
"*.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( txtSQL->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);;" + 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 txtSQL->insertText( newQueryText );
513 void QgsSearchQueryBuilder::showHelp()
515 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 FINAL
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.
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.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
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