Skip to content

Commit 55f6f7f

Browse files
author
mhugent
committed
[FEATURE]: Load/save queries created in the query builder. Added method columnRefNodes() in qgssearchtreenode and added some consts
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@13571 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent c7d91d5 commit 55f6f7f

File tree

5 files changed

+193
-25
lines changed

5 files changed

+193
-25
lines changed

python/core/qgssearchtreenode.sip

+11-7
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,19 @@ class QgsSearchTreeNode
6565
~QgsSearchTreeNode();
6666

6767
//! returns type of current node
68-
Type type();
68+
Type type() const;
6969

7070
//! node value getters
71-
Operator op();
72-
double number();
73-
QString columnRef();
74-
QString string();
71+
Operator op() const;
72+
double number() const;
73+
QString columnRef() const;
74+
QString string() const;
7575

7676
//! node value setters (type is set also)
7777
void setOp( Operator o );
7878
void setNumber( double number );
79-
void setColumnRef( QString& str );
80-
void setString( QString& str );
79+
void setColumnRef( const QString& str );
80+
void setString( const QString& str );
8181

8282
//! children
8383
QgsSearchTreeNode* Left();
@@ -107,6 +107,10 @@ class QgsSearchTreeNode
107107
//! @note added in 1.5
108108
QStringList referencedColumns();
109109

110+
//! return a list of all attribute nodes
111+
//! @note added in 1.5
112+
QList<QgsSearchTreeNode*> columnRefNodes();
113+
110114
//! check whether there are any operators that need geometry (for area, length)
111115
//! @note added in 1.5
112116
bool needsGeometry();

src/app/qgssearchquerybuilder.cpp

+146
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,16 @@
1414
***************************************************************************/
1515
/* $Id$ */
1616

17+
#include <QDomDocument>
18+
#include <QDomElement>
19+
#include <QFileDialog>
20+
#include <QFileInfo>
21+
#include <QInputDialog>
1722
#include <QListView>
1823
#include <QMessageBox>
24+
#include <QSettings>
1925
#include <QStandardItem>
26+
#include <QTextStream>
2027
#include "qgsfeature.h"
2128
#include "qgsfield.h"
2229
#include "qgssearchquerybuilder.h"
@@ -43,6 +50,16 @@ QgsSearchQueryBuilder::QgsSearchQueryBuilder( QgsVectorLayer* layer,
4350
buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
4451
connect( pbn, SIGNAL( clicked() ), this, SLOT( on_btnClear_clicked() ) );
4552

53+
pbn = new QPushButton( tr( "&Save..." ) );
54+
buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
55+
pbn->setToolTip( tr( "Save query to an xml file" ) );
56+
connect( pbn, SIGNAL( clicked() ), this, SLOT( saveQuery() ) );
57+
58+
pbn = new QPushButton( tr( "&Load..." ) );
59+
buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
60+
pbn->setToolTip( tr( "Load query from xml file" ) );
61+
connect( pbn, SIGNAL( clicked() ), this, SLOT( loadQuery() ) );
62+
4663
// disable unsupported operators
4764
btnIn->setHidden( true );
4865
btnNotIn->setHidden( true );
@@ -327,3 +344,132 @@ void QgsSearchQueryBuilder::on_btnILike_clicked()
327344
txtSQL->insertPlainText( " ~ " );
328345
}
329346

347+
void QgsSearchQueryBuilder::saveQuery()
348+
{
349+
QSettings s;
350+
QString lastQueryFileDir = s.value( "/UI/lastQueryFileDir", "" ).toString();
351+
//save as qqt (QGIS query file)
352+
QString saveFileName = QFileDialog::getSaveFileName( 0, tr( "Save query to file" ), lastQueryFileDir, "*.qqf" );
353+
if ( saveFileName.isNull() )
354+
{
355+
return;
356+
}
357+
358+
QFile saveFile( saveFileName );
359+
if ( !saveFile.open( QIODevice::WriteOnly ) )
360+
{
361+
QMessageBox::critical( 0, tr( "Error" ), tr( "Could not open file for writing" ) );
362+
return;
363+
}
364+
365+
QDomDocument xmlDoc;
366+
QDomElement queryElem = xmlDoc.createElement( "Query" );
367+
QDomText queryTextNode = xmlDoc.createTextNode( txtSQL->toPlainText() );
368+
queryElem.appendChild( queryTextNode );
369+
xmlDoc.appendChild( queryElem );
370+
371+
QTextStream fileStream( &saveFile );
372+
xmlDoc.save( fileStream, 2 );
373+
374+
QFileInfo fi( saveFile );
375+
s.setValue( "/UI/lastQueryFileDir", fi.absolutePath() );
376+
}
377+
378+
void QgsSearchQueryBuilder::loadQuery()
379+
{
380+
QSettings s;
381+
QString lastQueryFileDir = s.value( "/UI/lastQueryFileDir", "" ).toString();
382+
383+
QString queryFileName = QFileDialog::getOpenFileName( 0, tr( "Load query from file" ), lastQueryFileDir, tr( "Query files" ) + "(*.qqf);;" + tr( "All files" ) + "(*)" );
384+
if ( queryFileName.isNull() )
385+
{
386+
return;
387+
}
388+
389+
QFile queryFile( queryFileName );
390+
if ( !queryFile.open( QIODevice::ReadOnly ) )
391+
{
392+
QMessageBox::critical( 0, tr( "Error" ), tr( "Could not open file for reading" ) );
393+
return;
394+
}
395+
QDomDocument queryDoc;
396+
if ( !queryDoc.setContent( &queryFile ) )
397+
{
398+
QMessageBox::critical( 0, tr( "Error" ), tr( "File is not a valid xml document" ) );
399+
return;
400+
}
401+
402+
QDomElement queryElem = queryDoc.firstChildElement( "Query" );
403+
if ( queryElem.isNull() )
404+
{
405+
QMessageBox::critical( 0, tr( "Error" ), tr( "File is not a valid query document" ) );
406+
return;
407+
}
408+
409+
QString query = queryElem.text();
410+
411+
//todo: test if all the attributes are valid
412+
QgsSearchString search;
413+
if ( !search.setString( query ) )
414+
{
415+
QMessageBox::critical( this, tr( "Search string parsing error" ), search.parserErrorMsg() );
416+
return;
417+
}
418+
419+
QgsSearchTreeNode* searchTree = search.tree();
420+
if ( !searchTree )
421+
{
422+
QMessageBox::critical( this, tr( "Error creating search tree" ), search.parserErrorMsg() );
423+
return;
424+
}
425+
426+
QStringList attributes = searchTree->referencedColumns();
427+
QMap< QString, QString> attributesToReplace;
428+
QStringList existingAttributes;
429+
430+
//get all existing fields
431+
QMap<QString, int>::const_iterator fieldIt = mFieldMap.constBegin();
432+
for ( ; fieldIt != mFieldMap.constEnd(); ++fieldIt )
433+
{
434+
existingAttributes.push_back( fieldIt.key() );
435+
}
436+
437+
//if a field does not exist, ask what field should be used instead
438+
QStringList::const_iterator attIt = attributes.constBegin();
439+
for ( ; attIt != attributes.constEnd(); ++attIt )
440+
{
441+
//test if attribute is there
442+
if ( !mFieldMap.contains( *attIt ) )
443+
{
444+
bool ok;
445+
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 ),
446+
existingAttributes, 0, false, &ok );
447+
if ( !ok || replaceAttribute.isEmpty() )
448+
{
449+
return;
450+
}
451+
attributesToReplace.insert( *attIt, replaceAttribute );
452+
}
453+
}
454+
455+
//Now replace all the string in the query
456+
QList<QgsSearchTreeNode*> columnRefList = searchTree->columnRefNodes();
457+
QList<QgsSearchTreeNode*>::iterator columnIt = columnRefList.begin();
458+
for ( ; columnIt != columnRefList.end(); ++columnIt )
459+
{
460+
QMap< QString, QString>::const_iterator replaceIt = attributesToReplace.find(( *columnIt )->columnRef() );
461+
if ( replaceIt != attributesToReplace.constEnd() )
462+
{
463+
( *columnIt )->setColumnRef( replaceIt.value() );
464+
}
465+
}
466+
467+
txtSQL->clear();
468+
QString newQueryText = query;
469+
if ( attributesToReplace.size() > 0 )
470+
{
471+
newQueryText = searchTree->makeSearchString();
472+
}
473+
txtSQL->insertPlainText( newQueryText );
474+
}
475+

src/app/qgssearchquerybuilder.h

+3
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ class QgsSearchQueryBuilder : public QDialog, private Ui::QgsQueryBuilderBase
8787
*/
8888
void on_btnSampleValues_clicked();
8989

90+
void saveQuery();
91+
void loadQuery();
92+
9093
private:
9194

9295
/*!

src/core/qgssearchtreenode.cpp

+22-11
Original file line numberDiff line numberDiff line change
@@ -228,25 +228,36 @@ QString QgsSearchTreeNode::makeSearchString()
228228

229229
QStringList QgsSearchTreeNode::referencedColumns()
230230
{
231+
QList<QgsSearchTreeNode*> columnNodeList = columnRefNodes();
232+
QSet<QString> columnStringSet;
233+
234+
QList<QgsSearchTreeNode*>::const_iterator nodeIt = columnNodeList.constBegin();
235+
for ( ; nodeIt != columnNodeList.constEnd(); ++nodeIt )
236+
{
237+
columnStringSet.insert(( *nodeIt )->columnRef() );
238+
}
239+
return columnStringSet.toList();
240+
}
241+
242+
QList<QgsSearchTreeNode*> QgsSearchTreeNode::columnRefNodes()
243+
{
244+
QList<QgsSearchTreeNode*> nodeList;
231245
if ( mType == tOperator )
232246
{
233-
QStringList lst;
234247
if ( mLeft )
235-
lst += mLeft->referencedColumns();
248+
{
249+
nodeList += mLeft->columnRefNodes();
250+
}
236251
if ( mRight )
237-
lst += mRight->referencedColumns();
238-
return lst.toSet().toList(); // make union and convert back to list
252+
{
253+
nodeList += mRight->columnRefNodes();
254+
}
239255
}
240256
else if ( mType == tColumnRef )
241257
{
242-
return QStringList( mText );
258+
nodeList.push_back( this );
243259
}
244-
else
245-
{
246-
// string or number - do nothing
247-
return QStringList();
248-
}
249-
260+
return nodeList;
250261
}
251262

252263
bool QgsSearchTreeNode::needsGeometry()

src/core/qgssearchtreenode.h

+11-7
Original file line numberDiff line numberDiff line change
@@ -103,19 +103,19 @@ class CORE_EXPORT QgsSearchTreeNode
103103
~QgsSearchTreeNode();
104104

105105
//! returns type of current node
106-
Type type() { return mType; }
106+
Type type() const { return mType; }
107107

108108
//! node value getters
109-
Operator op() { return mOp; }
110-
double number() { return mNumber; }
111-
QString columnRef() { return mText; }
112-
QString string() { return mText; }
109+
Operator op() const { return mOp; }
110+
double number() const { return mNumber; }
111+
QString columnRef() const { return mText; }
112+
QString string() const { return mText; }
113113

114114
//! node value setters (type is set also)
115115
void setOp( Operator op ) { mType = tOperator; mOp = op; }
116116
void setNumber( double number ) { mType = tNumber; mNumber = number; }
117-
void setColumnRef( QString& str ) { mType = tColumnRef; mText = str; }
118-
void setString( QString& str ) { mType = tString; mText = str; stripText(); }
117+
void setColumnRef( const QString& str ) { mType = tColumnRef; mText = str; }
118+
void setString( const QString& str ) { mType = tString; mText = str; stripText(); }
119119

120120
//! children
121121
QgsSearchTreeNode* Left() { return mLeft; }
@@ -145,6 +145,10 @@ class CORE_EXPORT QgsSearchTreeNode
145145
//! @note added in 1.5
146146
QStringList referencedColumns();
147147

148+
//! return a list of all attribute nodes
149+
//! @note added in 1.5
150+
QList<QgsSearchTreeNode*> columnRefNodes();
151+
148152
//! check whether there are any operators that need geometry (for area, length)
149153
//! @note added in 1.5
150154
bool needsGeometry();

0 commit comments

Comments
 (0)