Skip to content

Commit

Permalink
restore missed "Save query" functionality in the Query Builder (fix #…
Browse files Browse the repository at this point in the history
  • Loading branch information
alexbruy committed Aug 10, 2020
1 parent 988ffcf commit dad79f8
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 0 deletions.
14 changes: 14 additions & 0 deletions python/gui/auto_generated/qgsquerybuilder.sip.in
Expand Up @@ -54,6 +54,20 @@ Test the constructed sql statement to see if the vector layer data provider like
The number of rows that would be returned is displayed in a message box.
The test uses a "select count(*) from ..." query to test the SQL
statement.
%End

void saveQuery();
%Docstring
Save query to the XML file

.. versionadded:: 3.16
%End

void loadQuery();
%Docstring
Load query from the XML file

.. versionadded:: 3.16
%End

void setDatasourceDescription( const QString &uri );
Expand Down
149 changes: 149 additions & 0 deletions src/gui/qgsquerybuilder.cpp
Expand Up @@ -22,10 +22,16 @@
#include "qgshelp.h"
#include "qgsgui.h"

#include <QDomDocument>
#include <QDomElement>
#include <QFileDialog>
#include <QInputDialog>
#include <QListView>
#include <QMessageBox>
#include <QRegExp>
#include <QPushButton>
#include <QTextStream>


// constructor used when the query builder must make its own
// connection to the database
Expand Down Expand Up @@ -66,6 +72,16 @@ QgsQueryBuilder::QgsQueryBuilder( QgsVectorLayer *layer,
buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
connect( pbn, &QAbstractButton::clicked, this, &QgsQueryBuilder::clear );

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

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

setupGuiViews();

mOrigSubsetString = layer->subsetString();
Expand Down Expand Up @@ -436,3 +452,136 @@ void QgsQueryBuilder::showHelp()
{
QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html#query-builder" ) );
}

void QgsQueryBuilder::saveQuery()
{
QgsSettings s;
QString lastQueryFileDir = s.value( QStringLiteral( "/UI/lastQueryFileDir" ), QDir::homePath() ).toString();
//save as qqf (QGIS query file)
QString saveFileName = QFileDialog::getSaveFileName( nullptr, tr( "Save Query to File" ), lastQueryFileDir, QStringLiteral( "*.qqf" ) );
if ( saveFileName.isNull() )
{
return;
}

if ( !saveFileName.endsWith( QLatin1String( ".qqf" ), Qt::CaseInsensitive ) )
{
saveFileName += QLatin1String( ".qqf" );
}

QFile saveFile( saveFileName );
if ( !saveFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
{
QMessageBox::critical( nullptr, tr( "Save Query to File" ), tr( "Could not open file for writing." ) );
return;
}

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

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

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

void QgsQueryBuilder::loadQuery()
{
QgsSettings s;
QString lastQueryFileDir = s.value( QStringLiteral( "/UI/lastQueryFileDir" ), QDir::homePath() ).toString();

QString queryFileName = QFileDialog::getOpenFileName( nullptr, 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( nullptr, tr( "Load Query from File" ), tr( "Could not open file for reading." ) );
return;
}
QDomDocument queryDoc;
if ( !queryDoc.setContent( &queryFile ) )
{
QMessageBox::critical( nullptr, tr( "Load Query from File" ), tr( "File is not a valid xml document." ) );
return;
}

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

QString query = queryElem.text();

//TODO: test if all the attributes are valid
QgsExpression search( query );
if ( search.hasParserError() )
{
QMessageBox::critical( this, tr( "Query Result" ), search.parserErrorString() );
return;
}

QString newQueryText = query;

#if 0
// TODO: implement with visitor pattern in QgsExpression

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() );
}
}

if ( attributesToReplace.size() > 0 )
{
newQueryText = query;
}
#endif

txtSQL->clear();
txtSQL->insertText( newQueryText );
}
12 changes: 12 additions & 0 deletions src/gui/qgsquerybuilder.h
Expand Up @@ -72,6 +72,18 @@ class GUI_EXPORT QgsQueryBuilder : public QDialog, private Ui::QgsQueryBuilderBa
*/
void test();

/**
* Save query to the XML file
* \since QGIS 3.16
*/
void saveQuery();

/**
* Load query from the XML file
* \since QGIS 3.16
*/
void loadQuery();

void setDatasourceDescription( const QString &uri );

private slots:
Expand Down

0 comments on commit dad79f8

Please sign in to comment.