16 #include <QDomDocument> 17 #include <QDomElement> 18 #include <QFileDialog> 20 #include <QInputDialog> 22 #include <QMessageBox> 24 #include <QStandardItem> 25 #include <QTextStream> 34 QWidget *parent, Qt::WindowFlags fl )
35 : QDialog( parent, fl ), mLayer( layer )
40 setWindowTitle(
tr(
"Search query builder" ) );
42 QPushButton *pbn =
new QPushButton(
tr(
"&Test" ) );
43 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
46 pbn =
new QPushButton(
tr(
"&Clear" ) );
47 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
50 pbn =
new QPushButton(
tr(
"&Save..." ) );
51 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
52 pbn->setToolTip(
tr(
"Save query to an xml file" ) );
53 connect( pbn, SIGNAL( clicked() ),
this, SLOT(
saveQuery() ) );
55 pbn =
new QPushButton(
tr(
"&Load..." ) );
56 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
57 pbn->setToolTip(
tr(
"Load query from xml file" ) );
58 connect( pbn, SIGNAL( clicked() ),
this, SLOT(
loadQuery() ) );
61 lblDataUri->setText( layer->
name() );
70 void QgsSearchQueryBuilder::populateFields()
77 for (
int idx = 0; idx < fields.
count(); ++idx )
79 QString fieldName = fields[idx].name();
80 mFieldMap[fieldName] = idx;
81 QStandardItem *myItem =
new QStandardItem( fieldName );
82 myItem->setEditable(
false );
83 mModelFields->insertRow( mModelFields->rowCount(), myItem );
87 void QgsSearchQueryBuilder::setupListViews()
91 mModelFields =
new QStandardItemModel();
92 mModelValues =
new QStandardItemModel();
93 lstFields->setModel( mModelFields );
94 lstValues->setModel( mModelValues );
96 lstFields->setViewMode( QListView::ListMode );
97 lstValues->setViewMode( QListView::ListMode );
98 lstFields->setSelectionBehavior( QAbstractItemView::SelectRows );
99 lstValues->setSelectionBehavior( QAbstractItemView::SelectRows );
101 lstFields->setUniformItemSizes(
true );
102 lstValues->setUniformItemSizes(
true );
105 void QgsSearchQueryBuilder::getFieldValues(
int limit )
112 mModelValues->clear();
115 QString fieldName = mModelFields->data( lstFields->currentIndex() ).toString();
116 int fieldIndex = mFieldMap[fieldName];
118 bool numeric = ( field.
type() == QVariant::Int || field.
type() == QVariant::Double );
124 attrs.append( fieldIndex );
128 lstValues->setCursor( Qt::WaitCursor );
130 mModelValues->blockSignals(
true );
131 lstValues->setUpdatesEnabled(
false );
134 QSet<QString> insertedValues;
137 ( limit == 0 || mModelValues->rowCount() != limit ) )
139 value = feat.
attribute( fieldIndex ).toString();
144 value =
"'" + value.replace(
"'",
"''" ) +
"'";
148 if ( !insertedValues.contains( value ) )
150 QStandardItem *myItem =
new QStandardItem( value );
151 myItem->setEditable(
false );
152 mModelValues->insertRow( mModelValues->rowCount(), myItem );
153 insertedValues.insert( value );
157 mModelValues->blockSignals(
false );
158 lstValues->setUpdatesEnabled(
true );
160 mModelValues->sort( 0 );
161 lstValues->setCursor( Qt::ArrowCursor );
166 getFieldValues( 25 );
176 long count = countRecords( txtSQL->text() );
182 QMessageBox::information(
this,
tr(
"Search results" ),
tr(
"Found %n matching feature(s).",
"test result", count ) );
186 long QgsSearchQueryBuilder::countRecords( QString
searchString )
191 QMessageBox::critical(
this,
tr(
"Search string parsing error" ), search.
parserErrorString() );
204 if ( !search.
prepare( fields ) )
206 QMessageBox::critical(
this,
tr(
"Evaluation error" ), search.
evalErrorString() );
210 QApplication::setOverrideCursor( Qt::WaitCursor );
216 QVariant value = search.
evaluate( &feat );
217 if ( value.toInt() != 0 )
227 QApplication::restoreOverrideCursor();
231 QMessageBox::critical(
this,
tr(
"Error during search" ), search.
evalErrorString() );
242 if ( txtSQL->text().trimmed().length() > 0 )
249 long numRecs = countRecords( txtSQL->text() );
254 else if ( numRecs == 0 )
256 QMessageBox::warning(
this,
tr(
"No Records" ),
tr(
"The query you specified results in zero records being returned." ) );
267 txtSQL->insertText(
" = " );
272 txtSQL->insertText(
" < " );
277 txtSQL->insertText(
" > " );
282 txtSQL->insertText(
"%" );
287 txtSQL->insertText(
" IN " );
292 txtSQL->insertText(
" NOT IN " );
297 txtSQL->insertText(
" LIKE " );
302 return txtSQL->text();
307 txtSQL->setText( searchString );
317 txtSQL->insertText( mModelValues->data( index ).toString() );
322 txtSQL->insertText(
" <= " );
327 txtSQL->insertText(
" >= " );
332 txtSQL->insertText(
" != " );
337 txtSQL->insertText(
" AND " );
342 txtSQL->insertText(
" NOT " );
347 txtSQL->insertText(
" OR " );
357 txtSQL->insertText(
" ILIKE " );
363 QString lastQueryFileDir = s.value(
"/UI/lastQueryFileDir",
"" ).toString();
365 QString saveFileName = QFileDialog::getSaveFileName( 0,
tr(
"Save query to file" ), lastQueryFileDir,
"*.qqf" );
366 if ( saveFileName.isNull() )
371 if ( !saveFileName.endsWith(
".qqf", Qt::CaseInsensitive ) )
373 saveFileName +=
".qqf";
376 QFile saveFile( saveFileName );
377 if ( !saveFile.open( QIODevice::WriteOnly ) )
379 QMessageBox::critical( 0,
tr(
"Error" ),
tr(
"Could not open file for writing" ) );
384 QDomElement queryElem = xmlDoc.createElement(
"Query" );
385 QDomText queryTextNode = xmlDoc.createTextNode( txtSQL->text() );
386 queryElem.appendChild( queryTextNode );
387 xmlDoc.appendChild( queryElem );
389 QTextStream fileStream( &saveFile );
390 xmlDoc.save( fileStream, 2 );
392 QFileInfo fi( saveFile );
393 s.setValue(
"/UI/lastQueryFileDir", fi.absolutePath() );
399 QString lastQueryFileDir = s.value(
"/UI/lastQueryFileDir",
"" ).toString();
401 QString queryFileName = QFileDialog::getOpenFileName( 0,
tr(
"Load query from file" ), lastQueryFileDir,
tr(
"Query files" ) +
" (*.qqf);;" +
tr(
"All files" ) +
" (*)" );
402 if ( queryFileName.isNull() )
407 QFile queryFile( queryFileName );
408 if ( !queryFile.open( QIODevice::ReadOnly ) )
410 QMessageBox::critical( 0,
tr(
"Error" ),
tr(
"Could not open file for reading" ) );
413 QDomDocument queryDoc;
414 if ( !queryDoc.setContent( &queryFile ) )
416 QMessageBox::critical( 0,
tr(
"Error" ),
tr(
"File is not a valid xml document" ) );
420 QDomElement queryElem = queryDoc.firstChildElement(
"Query" );
421 if ( queryElem.isNull() )
423 QMessageBox::critical( 0,
tr(
"Error" ),
tr(
"File is not a valid query document" ) );
427 QString query = queryElem.text();
433 QMessageBox::critical(
this,
tr(
"Search string parsing error" ), search.
parserErrorString() );
437 QString newQueryText = query;
442 QStringList attributes = searchTree->referencedColumns();
443 QMap< QString, QString> attributesToReplace;
444 QStringList existingAttributes;
447 QMap<QString, int>::const_iterator fieldIt = mFieldMap.constBegin();
448 for ( ; fieldIt != mFieldMap.constEnd(); ++fieldIt )
450 existingAttributes.push_back( fieldIt.key() );
454 QStringList::const_iterator attIt = attributes.constBegin();
455 for ( ; attIt != attributes.constEnd(); ++attIt )
458 if ( !mFieldMap.contains( *attIt ) )
461 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 ),
462 existingAttributes, 0,
false, &ok );
463 if ( !ok || replaceAttribute.isEmpty() )
467 attributesToReplace.insert( *attIt, replaceAttribute );
472 QList<QgsSearchTreeNode*> columnRefList = searchTree->columnRefNodes();
473 QList<QgsSearchTreeNode*>::iterator columnIt = columnRefList.begin();
474 for ( ; columnIt != columnRefList.end(); ++columnIt )
476 QMap< QString, QString>::const_iterator replaceIt = attributesToReplace.find(( *columnIt )->columnRef() );
477 if ( replaceIt != attributesToReplace.constEnd() )
479 ( *columnIt )->setColumnRef( replaceIt.value() );
483 if ( attributesToReplace.size() > 0 )
485 newQueryText = query;
490 txtSQL->insertText( newQueryText );
Class for parsing and evaluation of expressions (formerly called "search strings").
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
Wrapper for iterator of features from vector data provider or vector layer.
void setSearchString(QString searchString)
change search string shown in text field
void on_btnEqual_clicked()
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
static QString quotedColumnRef(QString name)
return quoted column reference (in double quotes)
void on_btnNotEqual_clicked()
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
void on_lstFields_doubleClicked(const QModelIndex &index)
bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
void on_btnLessEqual_clicked()
void on_btnGreaterEqual_clicked()
Container of fields for a vector layer.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
void on_btnLessThan_clicked()
const QString & name() const
Get the display name of the layer.
void on_btnSampleValues_clicked()
void on_btnGetAllValues_clicked()
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
void on_btnClear_clicked()
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
int count() const
Return number of items.
void on_btnTest_clicked()
Encapsulate a field in an attribute table or data source.
void on_btnLike_clicked()
void on_lstValues_doubleClicked(const QModelIndex &index)
void on_btnILike_clicked()
void on_btnGreaterThan_clicked()
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
void on_btnNotIn_clicked()
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
bool nextFeature(QgsFeature &f)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Represents a vector layer which manages a vector based data sets.
QString parserErrorString() const
Returns parser error.
QString evalErrorString() const
Returns evaluation error.
QgsSearchQueryBuilder(QgsVectorLayer *layer, QWidget *parent=0, Qt::WindowFlags fl=QgisGui::ModalDialogFlags)
Constructor - takes pointer to vector layer as a parameter.
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
QString searchString()
returns newly created search string