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 )
189 if ( search.hasParserError() )
191 QMessageBox::critical(
this,
tr(
"Search string parsing error" ), search.parserErrorString() );
198 bool fetchGeom = search.needsGeometry();
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 )
223 if ( search.hasEvalError() )
227 QApplication::restoreOverrideCursor();
229 if ( search.hasEvalError() )
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 );