Skip to content

Commit 96f7736

Browse files
committed
Merge branch 'expr'
2 parents 260bf0c + 25ff28a commit 96f7736

17 files changed

+2266
-175
lines changed

python/core/core.sip

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
%Include qgsdataprovider.sip
3636
%Include qgsdatasourceuri.sip
3737
%Include qgsdistancearea.sip
38+
%Include qgsexpression.sip
3839
%Include qgsfeature.sip
3940
%Include qgsfield.sip
4041
%Include qgsgeometry.sip

python/core/qgsexpression.sip

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
2+
class QgsExpression
3+
{
4+
%TypeHeaderCode
5+
#include "qgsexpression.h"
6+
%End
7+
8+
public:
9+
QgsExpression( const QString& expr );
10+
~QgsExpression();
11+
12+
//! Returns true if an error occurred when parsing the input expression
13+
bool hasParserError() const;
14+
//! Returns parser error
15+
QString parserErrorString() const;
16+
17+
//! Get the expression ready for evaluation - find out column indexes.
18+
bool prepare( const QgsFieldMap& fields );
19+
20+
//! Get list of columns referenced by the expression
21+
QStringList referencedColumns();
22+
//! Returns true if the expression uses feature geometry for some computation
23+
bool needsGeometry();
24+
25+
// evaluation
26+
27+
//! Evaluate the feature and return the result
28+
//! @note prepare() should be called before calling this method
29+
QVariant evaluate( QgsFeature* f = NULL );
30+
31+
//! Evaluate the feature and return the result
32+
//! @note this method does not expect that prepare() has been called on this instance
33+
QVariant evaluate( QgsFeature* f, const QgsFieldMap& fields );
34+
35+
//! Returns true if an error occurred when evaluating last input
36+
bool hasEvalError() const;
37+
//! Returns evaluation error
38+
QString evalErrorString() const;
39+
//! Set evaluation error (used internally by evaluation functions)
40+
void setEvalErrorString( QString str );
41+
42+
//! Set the number for $rownum special column
43+
void setCurrentRowNumber( int rowNumber );
44+
//! Return the number used for $rownum special column
45+
int currentRowNumber();
46+
47+
//! Return the parsed expression as a string - useful for debugging
48+
QString dump() const;
49+
50+
//! Return calculator used for distance and area calculations
51+
//! (used by internal functions)
52+
QgsDistanceArea* geomCalculator();
53+
54+
//
55+
56+
// tells whether the identifier is a name of existing function
57+
static bool isFunctionName( QString name );
58+
59+
// return index of the function in BuiltinFunctions array
60+
static int functionIndex( QString name );
61+
62+
//! return quoted column reference (in double quotes)
63+
static QString quotedColumnRef( QString name );
64+
};

python/core/symbology-ng-core.sip

+2-1
Original file line numberDiff line numberDiff line change
@@ -407,14 +407,15 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
407407
~Rule();
408408
QString dump() const;
409409
QStringList needsFields() const;
410-
bool isFilterOK( const QgsFieldMap& fields, QgsFeature& f ) const;
410+
bool isFilterOK( QgsFeature& f ) const;
411411
bool isScaleOK( double scale ) const;
412412

413413
QgsSymbolV2* symbol();
414414
bool dependsOnScale() const;
415415
int scaleMinDenom() const;
416416
int scaleMaxDenom() const;
417417
QString filterExpression() const;
418+
QgsExpression* filter() const;
418419

419420
void setScaleMinDenom( int scaleMinDenom );
420421
void setScaleMaxDenom( int scaleMaxDenom );

src/app/attributetable/qgsattributetabledialog.cpp

100755100644
+18-20
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
#include <qgsapplication.h>
2525
#include <qgsvectordataprovider.h>
2626
#include <qgsvectorlayer.h>
27-
#include <qgssearchstring.h>
28-
#include <qgssearchtreenode.h>
27+
#include <qgsexpression.h>
2928

3029
#include "qgisapp.h"
3130
#include "qgsaddattrdialog.h"
@@ -532,23 +531,21 @@ void QgsAttributeTableDialog::updateSelectionFromLayer()
532531
void QgsAttributeTableDialog::doSearch( QString searchString )
533532
{
534533
// parse search string and build parsed tree
535-
QgsSearchString search;
536-
if ( !search.setString( searchString ) )
534+
QgsExpression search( searchString );
535+
if ( search.hasParserError() )
537536
{
538-
QMessageBox::critical( this, tr( "Search string parsing error" ), search.parserErrorMsg() );
537+
QMessageBox::critical( this, tr( "Parsing error" ), search.parserErrorString() );
539538
return;
540539
}
541540

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

549546
// TODO: fetch only necessary columns
550-
// QStringList columns = searchTree->referencedColumns();
551-
bool fetchGeom = searchTree->needsGeometry();
547+
//QStringList columns = search.referencedColumns();
548+
bool fetchGeom = search.needsGeometry();
552549

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

564562
// check if there were errors during evaluating
565-
if ( searchTree->hasError() )
563+
if ( search.hasEvalError() )
566564
break;
567565
}
568566
}
@@ -573,20 +571,20 @@ void QgsAttributeTableDialog::doSearch( QString searchString )
573571

574572
while ( mLayer->nextFeature( f ) )
575573
{
576-
if ( searchTree->checkAgainst( mLayer->pendingFields(), f ) )
574+
if ( search.evaluate( &f ).toInt() != 0 )
577575
mSelectedFeatures << f.id();
578576

579577
// check if there were errors during evaluating
580-
if ( searchTree->hasError() )
578+
if ( search.hasEvalError() )
581579
break;
582580
}
583581
}
584582

585583
QApplication::restoreOverrideCursor();
586584

587-
if ( searchTree->hasError() )
585+
if ( search.hasEvalError() )
588586
{
589-
QMessageBox::critical( this, tr( "Error during search" ), searchTree->errorMsg() );
587+
QMessageBox::critical( this, tr( "Error during search" ), search.evalErrorString() );
590588
return;
591589
}
592590

@@ -625,12 +623,12 @@ void QgsAttributeTableDialog::search()
625623
QString str;
626624
if ( mQuery->displayText() == nullValue )
627625
{
628-
str = QString( "%1 IS NULL" ).arg( QgsSearchTreeNode::quotedColumnRef( fieldName ) );
626+
str = QString( "%1 IS NULL" ).arg( QgsExpression::quotedColumnRef( fieldName ) );
629627
}
630628
else
631629
{
632630
str = QString( "%1 %2 '%3'" )
633-
.arg( QgsSearchTreeNode::quotedColumnRef( fieldName ) )
631+
.arg( QgsExpression::quotedColumnRef( fieldName ) )
634632
.arg( numeric ? "=" : sensString )
635633
.arg( numeric
636634
? mQuery->displayText().replace( "'", "''" )

src/app/qgsattributedialog.cpp

+17-16
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
#include "qgssymbol.h"
2525
#include "qgsattributeeditor.h"
2626
#include "qgshighlight.h"
27-
#include "qgssearchstring.h"
28-
#include "qgssearchtreenode.h"
27+
#include "qgsexpression.h"
2928
#include "qgspythonrunner.h"
3029

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

211-
QgsSearchString ss;
212-
if ( !ss.setString( expr ) )
210+
QgsExpression exp( expr );
211+
if ( exp.hasParserError() )
213212
continue;
214213

215-
QgsSearchTreeNode *st = ss.tree();
216-
if ( !st )
217-
continue;
218214

219-
if ( !mFeature->geometry() && st->needsGeometry() )
215+
if ( !mFeature->geometry() && exp.needsGeometry() )
220216
{
221217
QgsFeature f;
222218
if ( vl->featureAtId( mFeature->id(), f, true, false ) && f.geometry() )
@@ -225,19 +221,24 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
225221
}
226222
}
227223

228-
QgsSearchTreeValue value;
229-
st->getValue( value, st, vl->pendingFields(), *mFeature );
224+
QVariant value = exp.evaluate( mFeature, vl->pendingFields() );
230225

231-
if ( !value.isError() )
226+
if ( !exp.hasEvalError() )
232227
{
233-
if ( value.isNumeric() )
234-
le->setText( QString::number( value.number() ) );
235-
else
236-
le->setText( value.string() );
228+
QString text;
229+
switch ( value.type() )
230+
{
231+
case QVariant::Invalid: text = "NULL"; break;
232+
case QVariant::Int: text = QString::number( value.toInt() ); break;
233+
case QVariant::Double: text = QString::number( value.toDouble() ); break;
234+
case QVariant::String:
235+
default: text = value.toString();
236+
}
237+
le->setText( text );
237238
}
238239
else
239240
{
240-
le->setText( tr( "Error: %1" ).arg( st->errorMsg() ) );
241+
le->setText( tr( "Error: %1" ).arg( exp.evalErrorString() ) );
241242
}
242243
}
243244
}

src/app/qgsfieldcalculator.cpp

+18-54
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
***************************************************************************/
1515

1616
#include "qgsfieldcalculator.h"
17-
#include "qgssearchtreenode.h"
18-
#include "qgssearchstring.h"
17+
#include "qgsexpression.h"
1918
#include "qgsvectordataprovider.h"
2019
#include "qgsvectorlayer.h"
2120

@@ -81,19 +80,18 @@ void QgsFieldCalculator::accept()
8180
{
8281
QString calcString = mExpressionTextEdit->toPlainText();
8382

84-
//create QgsSearchString
85-
QgsSearchString searchString;
86-
if ( !searchString.setString( calcString ) )
83+
//create QgsExpression
84+
QgsExpression exp( calcString );
85+
if ( exp.hasParserError() )
8786
{
8887
//expression not valid
89-
QMessageBox::critical( 0, tr( "Syntax error" ), tr( QString( "Invalid expression syntax. The error message of the parser is: '" + searchString.parserErrorMsg() + "'" ).toLocal8Bit().data() ) );
88+
QMessageBox::critical( 0, tr( "Syntax error" ), tr( QString( "Invalid expression syntax. The error message of the parser is: '" + exp.parserErrorString() + "'" ).toLocal8Bit().data() ) );
9089
return;
9190
}
9291

93-
//get QgsSearchTreeNode
94-
QgsSearchTreeNode* searchTree = searchString.tree();
95-
if ( !searchTree )
92+
if ( ! exp.prepare( mVectorLayer->pendingFields() ) )
9693
{
94+
QMessageBox::critical( 0, tr( "Evaluation error" ), exp.evalErrorString() );
9795
return;
9896
}
9997

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

159-
bool useGeometry = searchTree->needsGeometry();
157+
bool useGeometry = exp.needsGeometry();
160158
int rownum = 1;
161159

162160
mVectorLayer->select( mVectorLayer->pendingAllAttributesList(), QgsRectangle(), useGeometry, false );
@@ -170,52 +168,18 @@ void QgsFieldCalculator::accept()
170168
}
171169
}
172170

173-
searchTree->setCurrentRowNumber( rownum );
171+
exp.setCurrentRowNumber( rownum );
174172

175-
QgsSearchTreeValue value;
176-
searchTree->getValue( value, searchTree, mVectorLayer->pendingFields(), feature );
177-
if ( value.isError() )
173+
QVariant value = exp.evaluate( &feature );
174+
if ( exp.hasEvalError() )
178175
{
179-
//insert NULL value for this feature and continue the calculation
180-
if ( searchTree->errorMsg() == QObject::tr( "Division by zero." ) )
181-
{
182-
mVectorLayer->changeAttributeValue( feature.id(), mAttributeId, QVariant(), false );
183-
}
184-
else
185-
{
186-
calculationSuccess = false;
187-
error = searchTree->errorMsg();
188-
break;
189-
}
190-
}
191-
else if ( value.isNumeric() )
192-
{
193-
const QgsField &f = mVectorLayer->pendingFields()[ mAttributeId ];
194-
QVariant v;
195-
196-
if ( f.type() == QVariant::Double && f.precision() > 0 )
197-
{
198-
v = QString::number( value.number(), 'f', f.precision() );
199-
}
200-
else if ( f.type() == QVariant::Double && f.precision() == 0 )
201-
{
202-
v = QString::number( qRound( value.number() ) );
203-
}
204-
else
205-
{
206-
v = value.number();
207-
}
208-
209-
v.convert( f.type() );
210-
mVectorLayer->changeAttributeValue( feature.id(), mAttributeId, v, false );
211-
}
212-
else if ( value.isNull() )
213-
{
214-
mVectorLayer->changeAttributeValue( feature.id(), mAttributeId, QVariant(), false );
176+
calculationSuccess = false;
177+
error = exp.evalErrorString();
178+
break;
215179
}
216180
else
217181
{
218-
mVectorLayer->changeAttributeValue( feature.id(), mAttributeId, value.string(), false );
182+
mVectorLayer->changeAttributeValue( feature.id(), mAttributeId, value, false );
219183
}
220184

221185
rownum++;
@@ -385,17 +349,17 @@ void QgsFieldCalculator::on_mCloseBracketPushButton_clicked()
385349

386350
void QgsFieldCalculator::on_mToRealButton_clicked()
387351
{
388-
mExpressionTextEdit->insertPlainText( " to real ( " );
352+
mExpressionTextEdit->insertPlainText( " toreal ( " );
389353
}
390354

391355
void QgsFieldCalculator::on_mToIntButton_clicked()
392356
{
393-
mExpressionTextEdit->insertPlainText( " to int ( " );
357+
mExpressionTextEdit->insertPlainText( " toint ( " );
394358
}
395359

396360
void QgsFieldCalculator::on_mToStringButton_clicked()
397361
{
398-
mExpressionTextEdit->insertPlainText( " to string ( " );
362+
mExpressionTextEdit->insertPlainText( " tostring ( " );
399363
}
400364

401365
void QgsFieldCalculator::on_mLengthButton_clicked()

0 commit comments

Comments
 (0)