Skip to content

Commit

Permalink
[FEATURE]: Load/save queries created in the query builder. Added meth…
Browse files Browse the repository at this point in the history
…od columnRefNodes() in qgssearchtreenode and added some consts

git-svn-id: http://svn.osgeo.org/qgis/trunk@13571 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
mhugent committed May 25, 2010
1 parent 61008a6 commit c143ca1
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 25 deletions.
18 changes: 11 additions & 7 deletions python/core/qgssearchtreenode.sip
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,19 @@ class QgsSearchTreeNode
~QgsSearchTreeNode();

//! returns type of current node
Type type();
Type type() const;

//! node value getters
Operator op();
double number();
QString columnRef();
QString string();
Operator op() const;
double number() const;
QString columnRef() const;
QString string() const;

//! node value setters (type is set also)
void setOp( Operator o );
void setNumber( double number );
void setColumnRef( QString& str );
void setString( QString& str );
void setColumnRef( const QString& str );
void setString( const QString& str );

//! children
QgsSearchTreeNode* Left();
Expand Down Expand Up @@ -107,6 +107,10 @@ class QgsSearchTreeNode
//! @note added in 1.5
QStringList referencedColumns();

//! return a list of all attribute nodes
//! @note added in 1.5
QList<QgsSearchTreeNode*> columnRefNodes();

//! check whether there are any operators that need geometry (for area, length)
//! @note added in 1.5
bool needsGeometry();
Expand Down
146 changes: 146 additions & 0 deletions src/app/qgssearchquerybuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@
***************************************************************************/
/* $Id$ */

#include <QDomDocument>
#include <QDomElement>
#include <QFileDialog>
#include <QFileInfo>
#include <QInputDialog>
#include <QListView>
#include <QMessageBox>
#include <QSettings>
#include <QStandardItem>
#include <QTextStream>
#include "qgsfeature.h"
#include "qgsfield.h"
#include "qgssearchquerybuilder.h"
Expand All @@ -43,6 +50,16 @@ QgsSearchQueryBuilder::QgsSearchQueryBuilder( QgsVectorLayer* layer,
buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
connect( pbn, SIGNAL( clicked() ), this, SLOT( on_btnClear_clicked() ) );

pbn = new QPushButton( tr( "&Save..." ) );
buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
pbn->setToolTip( tr( "Save query to an xml file" ) );
connect( pbn, SIGNAL( clicked() ), this, SLOT( saveQuery() ) );

pbn = new QPushButton( tr( "&Load..." ) );
buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
pbn->setToolTip( tr( "Load query from xml file" ) );
connect( pbn, SIGNAL( clicked() ), this, SLOT( loadQuery() ) );

// disable unsupported operators
btnIn->setHidden( true );
btnNotIn->setHidden( true );
Expand Down Expand Up @@ -327,3 +344,132 @@ void QgsSearchQueryBuilder::on_btnILike_clicked()
txtSQL->insertPlainText( " ~ " );
}

void QgsSearchQueryBuilder::saveQuery()
{
QSettings s;
QString lastQueryFileDir = s.value( "/UI/lastQueryFileDir", "" ).toString();
//save as qqt (QGIS query file)
QString saveFileName = QFileDialog::getSaveFileName( 0, tr( "Save query to file" ), lastQueryFileDir, "*.qqf" );
if ( saveFileName.isNull() )
{
return;
}

QFile saveFile( saveFileName );
if ( !saveFile.open( QIODevice::WriteOnly ) )
{
QMessageBox::critical( 0, tr( "Error" ), tr( "Could not open file for writing" ) );
return;
}

QDomDocument xmlDoc;
QDomElement queryElem = xmlDoc.createElement( "Query" );
QDomText queryTextNode = xmlDoc.createTextNode( txtSQL->toPlainText() );
queryElem.appendChild( queryTextNode );
xmlDoc.appendChild( queryElem );

QTextStream fileStream( &saveFile );
xmlDoc.save( fileStream, 2 );

QFileInfo fi( saveFile );
s.setValue( "/UI/lastQueryFileDir", fi.absolutePath() );
}

void QgsSearchQueryBuilder::loadQuery()
{
QSettings s;
QString lastQueryFileDir = s.value( "/UI/lastQueryFileDir", "" ).toString();

QString queryFileName = QFileDialog::getOpenFileName( 0, tr( "Load query from file" ), lastQueryFileDir, tr( "Query files" ) + "(*.qqf);;" + tr( "All files" ) + "(*)" );
if ( queryFileName.isNull() )
{
return;
}

QFile queryFile( queryFileName );
if ( !queryFile.open( QIODevice::ReadOnly ) )
{
QMessageBox::critical( 0, tr( "Error" ), tr( "Could not open file for reading" ) );
return;
}
QDomDocument queryDoc;
if ( !queryDoc.setContent( &queryFile ) )
{
QMessageBox::critical( 0, tr( "Error" ), tr( "File is not a valid xml document" ) );
return;
}

QDomElement queryElem = queryDoc.firstChildElement( "Query" );
if ( queryElem.isNull() )
{
QMessageBox::critical( 0, tr( "Error" ), tr( "File is not a valid query document" ) );
return;
}

QString query = queryElem.text();

//todo: test if all the attributes are valid
QgsSearchString search;
if ( !search.setString( query ) )
{
QMessageBox::critical( this, tr( "Search string parsing error" ), search.parserErrorMsg() );
return;
}

QgsSearchTreeNode* searchTree = search.tree();
if ( !searchTree )
{
QMessageBox::critical( this, tr( "Error creating search tree" ), search.parserErrorMsg() );
return;
}

QStringList attributes = searchTree->referencedColumns();
QMap< QString, QString> attributesToReplace;
QStringList existingAttributes;

//get all existing fields
QMap<QString, int>::const_iterator fieldIt = mFieldMap.constBegin();
for ( ; fieldIt != mFieldMap.constEnd(); ++fieldIt )
{
existingAttributes.push_back( fieldIt.key() );
}

//if a field does not exist, ask what field should be used instead
QStringList::const_iterator attIt = attributes.constBegin();
for ( ; attIt != attributes.constEnd(); ++attIt )
{
//test if attribute is there
if ( !mFieldMap.contains( *attIt ) )
{
bool ok;
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 ),
existingAttributes, 0, false, &ok );
if ( !ok || replaceAttribute.isEmpty() )
{
return;
}
attributesToReplace.insert( *attIt, replaceAttribute );
}
}

//Now replace all the string in the query
QList<QgsSearchTreeNode*> columnRefList = searchTree->columnRefNodes();
QList<QgsSearchTreeNode*>::iterator columnIt = columnRefList.begin();
for ( ; columnIt != columnRefList.end(); ++columnIt )
{
QMap< QString, QString>::const_iterator replaceIt = attributesToReplace.find(( *columnIt )->columnRef() );
if ( replaceIt != attributesToReplace.constEnd() )
{
( *columnIt )->setColumnRef( replaceIt.value() );
}
}

txtSQL->clear();
QString newQueryText = query;
if ( attributesToReplace.size() > 0 )
{
newQueryText = searchTree->makeSearchString();
}
txtSQL->insertPlainText( newQueryText );
}

3 changes: 3 additions & 0 deletions src/app/qgssearchquerybuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ class QgsSearchQueryBuilder : public QDialog, private Ui::QgsQueryBuilderBase
*/
void on_btnSampleValues_clicked();

void saveQuery();
void loadQuery();

private:

/*!
Expand Down
33 changes: 22 additions & 11 deletions src/core/qgssearchtreenode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,25 +228,36 @@ QString QgsSearchTreeNode::makeSearchString()

QStringList QgsSearchTreeNode::referencedColumns()
{
QList<QgsSearchTreeNode*> columnNodeList = columnRefNodes();
QSet<QString> columnStringSet;

QList<QgsSearchTreeNode*>::const_iterator nodeIt = columnNodeList.constBegin();
for ( ; nodeIt != columnNodeList.constEnd(); ++nodeIt )
{
columnStringSet.insert(( *nodeIt )->columnRef() );
}
return columnStringSet.toList();
}

QList<QgsSearchTreeNode*> QgsSearchTreeNode::columnRefNodes()
{
QList<QgsSearchTreeNode*> nodeList;
if ( mType == tOperator )
{
QStringList lst;
if ( mLeft )
lst += mLeft->referencedColumns();
{
nodeList += mLeft->columnRefNodes();
}
if ( mRight )
lst += mRight->referencedColumns();
return lst.toSet().toList(); // make union and convert back to list
{
nodeList += mRight->columnRefNodes();
}
}
else if ( mType == tColumnRef )
{
return QStringList( mText );
nodeList.push_back( this );
}
else
{
// string or number - do nothing
return QStringList();
}

return nodeList;
}

bool QgsSearchTreeNode::needsGeometry()
Expand Down
18 changes: 11 additions & 7 deletions src/core/qgssearchtreenode.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,19 @@ class CORE_EXPORT QgsSearchTreeNode
~QgsSearchTreeNode();

//! returns type of current node
Type type() { return mType; }
Type type() const { return mType; }

//! node value getters
Operator op() { return mOp; }
double number() { return mNumber; }
QString columnRef() { return mText; }
QString string() { return mText; }
Operator op() const { return mOp; }
double number() const { return mNumber; }
QString columnRef() const { return mText; }
QString string() const { return mText; }

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

//! children
QgsSearchTreeNode* Left() { return mLeft; }
Expand Down Expand Up @@ -145,6 +145,10 @@ class CORE_EXPORT QgsSearchTreeNode
//! @note added in 1.5
QStringList referencedColumns();

//! return a list of all attribute nodes
//! @note added in 1.5
QList<QgsSearchTreeNode*> columnRefNodes();

//! check whether there are any operators that need geometry (for area, length)
//! @note added in 1.5
bool needsGeometry();
Expand Down

0 comments on commit c143ca1

Please sign in to comment.