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() );
77 for (
int idx = 0; idx < fields.
count(); ++idx )
79 QString fieldName = fields[idx].name();
81 QStandardItem *myItem =
new QStandardItem( fieldName );
82 myItem->setEditable(
false );
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 );
115 QString fieldName =
mModelFields->data( lstFields->currentIndex() ).toString();
118 bool numeric = ( field.
type() == QVariant::Int || field.
type() == QVariant::Double );
124 attrs.append( fieldIndex );
128 lstValues->setCursor( Qt::WaitCursor );
131 lstValues->setUpdatesEnabled(
false );
134 QSet<QString> insertedValues;
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 );
153 insertedValues.insert( value );
158 lstValues->setUpdatesEnabled(
true );
161 lstValues->setCursor( Qt::ArrowCursor );
182 QMessageBox::information(
this,
tr(
"Search results" ),
tr(
"Found %n matching feature(s).",
"test result", count ) );
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->toPlainText().trimmed().length() > 0 )
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->insertPlainText(
" = " );
272 txtSQL->insertPlainText(
" < " );
277 txtSQL->insertPlainText(
" > " );
282 txtSQL->insertPlainText(
"%" );
287 txtSQL->insertPlainText(
" IN " );
292 txtSQL->insertPlainText(
" NOT IN " );
297 txtSQL->insertPlainText(
" LIKE " );
302 return txtSQL->toPlainText();
307 txtSQL->setPlainText( searchString );
317 txtSQL->insertPlainText(
mModelValues->data( index ).toString() );
322 txtSQL->insertPlainText(
" <= " );
327 txtSQL->insertPlainText(
" >= " );
332 txtSQL->insertPlainText(
" != " );
337 txtSQL->insertPlainText(
" AND " );
342 txtSQL->insertPlainText(
" NOT " );
347 txtSQL->insertPlainText(
" OR " );
357 txtSQL->insertPlainText(
" 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->toPlainText() );
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 )
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->insertPlainText( 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.
long countRecords(QString sql)
static QString quotedColumnRef(QString name)
return quoted column reference (in double quotes)
QStandardItemModel * mModelFields
Model for fields ListView.
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.
QStandardItemModel * mModelValues
Model for values ListView.
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()
QMap< QString, int > mFieldMap
Map that holds field information, keyed by field name.
void on_btnGetAllValues_clicked()
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()
void getFieldValues(int limit)
Encapsulate a field in an attribute table or data source.
void on_btnLike_clicked()
void on_lstValues_doubleClicked(const QModelIndex &index)
bool needsGeometry()
Returns true if the expression uses feature geometry for some computation.
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.
QgsVectorLayer * mLayer
Layer for which is the query builder opened.
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