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