Skip to content

Commit

Permalink
Merge branch 'expr'
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Aug 27, 2011
2 parents 260bf0c + 25ff28a commit 96f7736
Show file tree
Hide file tree
Showing 17 changed files with 2,266 additions and 175 deletions.
1 change: 1 addition & 0 deletions python/core/core.sip
Expand Up @@ -35,6 +35,7 @@
%Include qgsdataprovider.sip %Include qgsdataprovider.sip
%Include qgsdatasourceuri.sip %Include qgsdatasourceuri.sip
%Include qgsdistancearea.sip %Include qgsdistancearea.sip
%Include qgsexpression.sip
%Include qgsfeature.sip %Include qgsfeature.sip
%Include qgsfield.sip %Include qgsfield.sip
%Include qgsgeometry.sip %Include qgsgeometry.sip
Expand Down
64 changes: 64 additions & 0 deletions python/core/qgsexpression.sip
@@ -0,0 +1,64 @@

class QgsExpression
{
%TypeHeaderCode
#include "qgsexpression.h"
%End

public:
QgsExpression( const QString& expr );
~QgsExpression();

//! Returns true if an error occurred when parsing the input expression
bool hasParserError() const;
//! Returns parser error
QString parserErrorString() const;

//! Get the expression ready for evaluation - find out column indexes.
bool prepare( const QgsFieldMap& fields );

//! Get list of columns referenced by the expression
QStringList referencedColumns();
//! Returns true if the expression uses feature geometry for some computation
bool needsGeometry();

// evaluation

//! Evaluate the feature and return the result
//! @note prepare() should be called before calling this method
QVariant evaluate( QgsFeature* f = NULL );

//! Evaluate the feature and return the result
//! @note this method does not expect that prepare() has been called on this instance
QVariant evaluate( QgsFeature* f, const QgsFieldMap& fields );

//! Returns true if an error occurred when evaluating last input
bool hasEvalError() const;
//! Returns evaluation error
QString evalErrorString() const;
//! Set evaluation error (used internally by evaluation functions)
void setEvalErrorString( QString str );

//! Set the number for $rownum special column
void setCurrentRowNumber( int rowNumber );
//! Return the number used for $rownum special column
int currentRowNumber();

//! Return the parsed expression as a string - useful for debugging
QString dump() const;

//! Return calculator used for distance and area calculations
//! (used by internal functions)
QgsDistanceArea* geomCalculator();

//

// tells whether the identifier is a name of existing function
static bool isFunctionName( QString name );

// return index of the function in BuiltinFunctions array
static int functionIndex( QString name );

//! return quoted column reference (in double quotes)
static QString quotedColumnRef( QString name );
};
3 changes: 2 additions & 1 deletion python/core/symbology-ng-core.sip
Expand Up @@ -407,14 +407,15 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
~Rule(); ~Rule();
QString dump() const; QString dump() const;
QStringList needsFields() const; QStringList needsFields() const;
bool isFilterOK( const QgsFieldMap& fields, QgsFeature& f ) const; bool isFilterOK( QgsFeature& f ) const;
bool isScaleOK( double scale ) const; bool isScaleOK( double scale ) const;


QgsSymbolV2* symbol(); QgsSymbolV2* symbol();
bool dependsOnScale() const; bool dependsOnScale() const;
int scaleMinDenom() const; int scaleMinDenom() const;
int scaleMaxDenom() const; int scaleMaxDenom() const;
QString filterExpression() const; QString filterExpression() const;
QgsExpression* filter() const;


void setScaleMinDenom( int scaleMinDenom ); void setScaleMinDenom( int scaleMinDenom );
void setScaleMaxDenom( int scaleMaxDenom ); void setScaleMaxDenom( int scaleMaxDenom );
Expand Down
38 changes: 18 additions & 20 deletions src/app/attributetable/qgsattributetabledialog.cpp 100755 → 100644
Expand Up @@ -24,8 +24,7 @@
#include <qgsapplication.h> #include <qgsapplication.h>
#include <qgsvectordataprovider.h> #include <qgsvectordataprovider.h>
#include <qgsvectorlayer.h> #include <qgsvectorlayer.h>
#include <qgssearchstring.h> #include <qgsexpression.h>
#include <qgssearchtreenode.h>


#include "qgisapp.h" #include "qgisapp.h"
#include "qgsaddattrdialog.h" #include "qgsaddattrdialog.h"
Expand Down Expand Up @@ -532,23 +531,21 @@ void QgsAttributeTableDialog::updateSelectionFromLayer()
void QgsAttributeTableDialog::doSearch( QString searchString ) void QgsAttributeTableDialog::doSearch( QString searchString )
{ {
// parse search string and build parsed tree // parse search string and build parsed tree
QgsSearchString search; QgsExpression search( searchString );
if ( !search.setString( searchString ) ) if ( search.hasParserError() )
{ {
QMessageBox::critical( this, tr( "Search string parsing error" ), search.parserErrorMsg() ); QMessageBox::critical( this, tr( "Parsing error" ), search.parserErrorString() );
return; return;
} }


QgsSearchTreeNode* searchTree = search.tree(); if ( ! search.prepare( mLayer->pendingFields() ) )
if ( searchTree == NULL )
{ {
QMessageBox::information( this, tr( "Search results" ), tr( "You've supplied an empty search string." ) ); QMessageBox::critical( this, tr( "Evaluation error" ), search.evalErrorString() );
return;
} }


// TODO: fetch only necessary columns // TODO: fetch only necessary columns
// QStringList columns = searchTree->referencedColumns(); //QStringList columns = search.referencedColumns();
bool fetchGeom = searchTree->needsGeometry(); bool fetchGeom = search.needsGeometry();


QApplication::setOverrideCursor( Qt::WaitCursor ); QApplication::setOverrideCursor( Qt::WaitCursor );
mSelectedFeatures.clear(); mSelectedFeatures.clear();
Expand All @@ -558,11 +555,12 @@ void QgsAttributeTableDialog::doSearch( QString searchString )
QgsFeatureList selectedFeatures = mLayer->selectedFeatures(); QgsFeatureList selectedFeatures = mLayer->selectedFeatures();
for ( QgsFeatureList::Iterator it = selectedFeatures.begin(); it != selectedFeatures.end(); ++it ) for ( QgsFeatureList::Iterator it = selectedFeatures.begin(); it != selectedFeatures.end(); ++it )
{ {
if ( searchTree->checkAgainst( mLayer->pendingFields(), *it ) ) QgsFeature& feat = *it;
mSelectedFeatures << it->id(); if ( search.evaluate( &feat ).toInt() != 0 )
mSelectedFeatures << feat.id();


// check if there were errors during evaluating // check if there were errors during evaluating
if ( searchTree->hasError() ) if ( search.hasEvalError() )
break; break;
} }
} }
Expand All @@ -573,20 +571,20 @@ void QgsAttributeTableDialog::doSearch( QString searchString )


while ( mLayer->nextFeature( f ) ) while ( mLayer->nextFeature( f ) )
{ {
if ( searchTree->checkAgainst( mLayer->pendingFields(), f ) ) if ( search.evaluate( &f ).toInt() != 0 )
mSelectedFeatures << f.id(); mSelectedFeatures << f.id();


// check if there were errors during evaluating // check if there were errors during evaluating
if ( searchTree->hasError() ) if ( search.hasEvalError() )
break; break;
} }
} }


QApplication::restoreOverrideCursor(); QApplication::restoreOverrideCursor();


if ( searchTree->hasError() ) if ( search.hasEvalError() )
{ {
QMessageBox::critical( this, tr( "Error during search" ), searchTree->errorMsg() ); QMessageBox::critical( this, tr( "Error during search" ), search.evalErrorString() );
return; return;
} }


Expand Down Expand Up @@ -625,12 +623,12 @@ void QgsAttributeTableDialog::search()
QString str; QString str;
if ( mQuery->displayText() == nullValue ) if ( mQuery->displayText() == nullValue )
{ {
str = QString( "%1 IS NULL" ).arg( QgsSearchTreeNode::quotedColumnRef( fieldName ) ); str = QString( "%1 IS NULL" ).arg( QgsExpression::quotedColumnRef( fieldName ) );
} }
else else
{ {
str = QString( "%1 %2 '%3'" ) str = QString( "%1 %2 '%3'" )
.arg( QgsSearchTreeNode::quotedColumnRef( fieldName ) ) .arg( QgsExpression::quotedColumnRef( fieldName ) )
.arg( numeric ? "=" : sensString ) .arg( numeric ? "=" : sensString )
.arg( numeric .arg( numeric
? mQuery->displayText().replace( "'", "''" ) ? mQuery->displayText().replace( "'", "''" )
Expand Down
33 changes: 17 additions & 16 deletions src/app/qgsattributedialog.cpp
Expand Up @@ -24,8 +24,7 @@
#include "qgssymbol.h" #include "qgssymbol.h"
#include "qgsattributeeditor.h" #include "qgsattributeeditor.h"
#include "qgshighlight.h" #include "qgshighlight.h"
#include "qgssearchstring.h" #include "qgsexpression.h"
#include "qgssearchtreenode.h"
#include "qgspythonrunner.h" #include "qgspythonrunner.h"


#include "qgisapp.h" #include "qgisapp.h"
Expand Down Expand Up @@ -208,15 +207,12 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
QString expr = le->text(); QString expr = le->text();
le->setText( tr( "Error" ) ); le->setText( tr( "Error" ) );


QgsSearchString ss; QgsExpression exp( expr );
if ( !ss.setString( expr ) ) if ( exp.hasParserError() )
continue; continue;


QgsSearchTreeNode *st = ss.tree();
if ( !st )
continue;


if ( !mFeature->geometry() && st->needsGeometry() ) if ( !mFeature->geometry() && exp.needsGeometry() )
{ {
QgsFeature f; QgsFeature f;
if ( vl->featureAtId( mFeature->id(), f, true, false ) && f.geometry() ) if ( vl->featureAtId( mFeature->id(), f, true, false ) && f.geometry() )
Expand All @@ -225,19 +221,24 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
} }
} }


QgsSearchTreeValue value; QVariant value = exp.evaluate( mFeature, vl->pendingFields() );
st->getValue( value, st, vl->pendingFields(), *mFeature );


if ( !value.isError() ) if ( !exp.hasEvalError() )
{ {
if ( value.isNumeric() ) QString text;
le->setText( QString::number( value.number() ) ); switch ( value.type() )
else {
le->setText( value.string() ); case QVariant::Invalid: text = "NULL"; break;
case QVariant::Int: text = QString::number( value.toInt() ); break;
case QVariant::Double: text = QString::number( value.toDouble() ); break;
case QVariant::String:
default: text = value.toString();
}
le->setText( text );
} }
else else
{ {
le->setText( tr( "Error: %1" ).arg( st->errorMsg() ) ); le->setText( tr( "Error: %1" ).arg( exp.evalErrorString() ) );
} }
} }
} }
Expand Down
72 changes: 18 additions & 54 deletions src/app/qgsfieldcalculator.cpp
Expand Up @@ -14,8 +14,7 @@
***************************************************************************/ ***************************************************************************/


#include "qgsfieldcalculator.h" #include "qgsfieldcalculator.h"
#include "qgssearchtreenode.h" #include "qgsexpression.h"
#include "qgssearchstring.h"
#include "qgsvectordataprovider.h" #include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h" #include "qgsvectorlayer.h"


Expand Down Expand Up @@ -81,19 +80,18 @@ void QgsFieldCalculator::accept()
{ {
QString calcString = mExpressionTextEdit->toPlainText(); QString calcString = mExpressionTextEdit->toPlainText();


//create QgsSearchString //create QgsExpression
QgsSearchString searchString; QgsExpression exp( calcString );
if ( !searchString.setString( calcString ) ) if ( exp.hasParserError() )
{ {
//expression not valid //expression not valid
QMessageBox::critical( 0, tr( "Syntax error" ), tr( QString( "Invalid expression syntax. The error message of the parser is: '" + searchString.parserErrorMsg() + "'" ).toLocal8Bit().data() ) ); QMessageBox::critical( 0, tr( "Syntax error" ), tr( QString( "Invalid expression syntax. The error message of the parser is: '" + exp.parserErrorString() + "'" ).toLocal8Bit().data() ) );
return; return;
} }


//get QgsSearchTreeNode if ( ! exp.prepare( mVectorLayer->pendingFields() ) )
QgsSearchTreeNode* searchTree = searchString.tree();
if ( !searchTree )
{ {
QMessageBox::critical( 0, tr( "Evaluation error" ), exp.evalErrorString() );
return; return;
} }


Expand Down Expand Up @@ -156,7 +154,7 @@ void QgsFieldCalculator::accept()
// block layerModified signals (that would trigger table update) // block layerModified signals (that would trigger table update)
mVectorLayer->blockSignals( true ); mVectorLayer->blockSignals( true );


bool useGeometry = searchTree->needsGeometry(); bool useGeometry = exp.needsGeometry();
int rownum = 1; int rownum = 1;


mVectorLayer->select( mVectorLayer->pendingAllAttributesList(), QgsRectangle(), useGeometry, false ); mVectorLayer->select( mVectorLayer->pendingAllAttributesList(), QgsRectangle(), useGeometry, false );
Expand All @@ -170,52 +168,18 @@ void QgsFieldCalculator::accept()
} }
} }


searchTree->setCurrentRowNumber( rownum ); exp.setCurrentRowNumber( rownum );


QgsSearchTreeValue value; QVariant value = exp.evaluate( &feature );
searchTree->getValue( value, searchTree, mVectorLayer->pendingFields(), feature ); if ( exp.hasEvalError() )
if ( value.isError() )
{ {
//insert NULL value for this feature and continue the calculation calculationSuccess = false;
if ( searchTree->errorMsg() == QObject::tr( "Division by zero." ) ) error = exp.evalErrorString();
{ break;
mVectorLayer->changeAttributeValue( feature.id(), mAttributeId, QVariant(), false );
}
else
{
calculationSuccess = false;
error = searchTree->errorMsg();
break;
}
}
else if ( value.isNumeric() )
{
const QgsField &f = mVectorLayer->pendingFields()[ mAttributeId ];
QVariant v;

if ( f.type() == QVariant::Double && f.precision() > 0 )
{
v = QString::number( value.number(), 'f', f.precision() );
}
else if ( f.type() == QVariant::Double && f.precision() == 0 )
{
v = QString::number( qRound( value.number() ) );
}
else
{
v = value.number();
}

v.convert( f.type() );
mVectorLayer->changeAttributeValue( feature.id(), mAttributeId, v, false );
}
else if ( value.isNull() )
{
mVectorLayer->changeAttributeValue( feature.id(), mAttributeId, QVariant(), false );
} }
else else
{ {
mVectorLayer->changeAttributeValue( feature.id(), mAttributeId, value.string(), false ); mVectorLayer->changeAttributeValue( feature.id(), mAttributeId, value, false );
} }


rownum++; rownum++;
Expand Down Expand Up @@ -385,17 +349,17 @@ void QgsFieldCalculator::on_mCloseBracketPushButton_clicked()


void QgsFieldCalculator::on_mToRealButton_clicked() void QgsFieldCalculator::on_mToRealButton_clicked()
{ {
mExpressionTextEdit->insertPlainText( " to real ( " ); mExpressionTextEdit->insertPlainText( " toreal ( " );
} }


void QgsFieldCalculator::on_mToIntButton_clicked() void QgsFieldCalculator::on_mToIntButton_clicked()
{ {
mExpressionTextEdit->insertPlainText( " to int ( " ); mExpressionTextEdit->insertPlainText( " toint ( " );
} }


void QgsFieldCalculator::on_mToStringButton_clicked() void QgsFieldCalculator::on_mToStringButton_clicked()
{ {
mExpressionTextEdit->insertPlainText( " to string ( " ); mExpressionTextEdit->insertPlainText( " tostring ( " );
} }


void QgsFieldCalculator::on_mLengthButton_clicked() void QgsFieldCalculator::on_mLengthButton_clicked()
Expand Down

0 comments on commit 96f7736

Please sign in to comment.