QGIS API Documentation  2.8.6-Wien
qgsexpression.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsexpression.cpp
3  -------------------
4  begin : August 2011
5  copyright : (C) 2011 Martin Dobias
6  email : wonder.sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsexpression.h"
17 
18 #include <QtDebug>
19 #include <QDomDocument>
20 #include <QDate>
21 #include <QRegExp>
22 #include <QColor>
23 #include <QUuid>
24 
25 #include <math.h>
26 #include <limits>
27 
28 #include "qgsdistancearea.h"
29 #include "qgsfeature.h"
30 #include "qgsgeometry.h"
31 #include "qgslogger.h"
32 #include "qgsmaplayerregistry.h"
33 #include "qgsogcutils.h"
34 #include "qgsvectorlayer.h"
35 #include "qgssymbollayerv2utils.h"
36 #include "qgsvectorcolorrampv2.h"
37 #include "qgsstylev2.h"
38 
39 // from parser
40 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
41 
43 
45 {
47  inter.setValid( false );
48  return inter;
49 }
50 
52 {
53  int seconds = 0;
54  QRegExp rx( "([-+]?\\d?\\.?\\d+\\s+\\S+)", Qt::CaseInsensitive );
55  QStringList list;
56  int pos = 0;
57 
58  while (( pos = rx.indexIn( string, pos ) ) != -1 )
59  {
60  list << rx.cap( 1 );
61  pos += rx.matchedLength();
62  }
63 
64  QMap<int, QStringList> map;
65  map.insert( 1, QStringList() << "second" << "seconds" << QObject::tr( "second|seconds", "list of words separated by | which reference years" ).split( "|" ) );
66  map.insert( 0 + MINUTE, QStringList() << "minute" << "minutes" << QObject::tr( "minute|minutes", "list of words separated by | which reference minutes" ).split( "|" ) );
67  map.insert( 0 + HOUR, QStringList() << "hour" << "hours" << QObject::tr( "hour|hours", "list of words separated by | which reference minutes hours" ).split( "|" ) );
68  map.insert( 0 + DAY, QStringList() << "day" << "days" << QObject::tr( "day|days", "list of words separated by | which reference days" ).split( "|" ) );
69  map.insert( 0 + WEEKS, QStringList() << "week" << "weeks" << QObject::tr( "week|weeks", "wordlist separated by | which reference weeks" ).split( "|" ) );
70  map.insert( 0 + MONTHS, QStringList() << "month" << "months" << QObject::tr( "month|months", "list of words separated by | which reference months" ).split( "|" ) );
71  map.insert( 0 + YEARS, QStringList() << "year" << "years" << QObject::tr( "year|years", "list of words separated by | which reference years" ).split( "|" ) );
72 
73  foreach ( QString match, list )
74  {
75  QStringList split = match.split( QRegExp( "\\s+" ) );
76  bool ok;
77  double value = split.at( 0 ).toDouble( &ok );
78  if ( !ok )
79  {
80  continue;
81  }
82 
83  bool matched = false;
84  foreach ( int duration, map.keys() )
85  {
86  foreach ( QString name, map[duration] )
87  {
88  if ( match.contains( name, Qt::CaseInsensitive ) )
89  {
90  matched = true;
91  break;
92  }
93  }
94 
95  if ( matched )
96  {
97  seconds += value * duration;
98  break;
99  }
100  }
101  }
102 
103  // If we can't parse the string at all then we just return invalid
104  if ( seconds == 0 )
106 
107  return QgsExpression::Interval( seconds );
108 }
109 
111 {
112  return ( mSeconds == other.mSeconds );
113 }
114 
116 // three-value logic
117 
118 enum TVL
119 {
123 };
124 
125 static TVL AND[3][3] =
126 {
127  // false true unknown
128  { False, False, False }, // false
129  { False, True, Unknown }, // true
130  { False, Unknown, Unknown } // unknown
131 };
132 
133 static TVL OR[3][3] =
134 {
135  { False, True, Unknown }, // false
136  { True, True, True }, // true
137  { Unknown, True, Unknown } // unknown
138 };
139 
140 static TVL NOT[3] = { True, False, Unknown };
141 
142 static QVariant tvl2variant( TVL v )
143 {
144  switch ( v )
145  {
146  case False: return 0;
147  case True: return 1;
148  case Unknown:
149  default:
150  return QVariant();
151  }
152 }
153 
154 #define TVL_True QVariant(1)
155 #define TVL_False QVariant(0)
156 #define TVL_Unknown QVariant()
157 
159 // QVariant checks and conversions
160 
161 inline bool isIntSafe( const QVariant& v )
162 {
163  if ( v.type() == QVariant::Int ) return true;
164  if ( v.type() == QVariant::UInt ) return true;
165  if ( v.type() == QVariant::LongLong ) return true;
166  if ( v.type() == QVariant::ULongLong ) return true;
167  if ( v.type() == QVariant::Double ) return false;
168  if ( v.type() == QVariant::String ) { bool ok; v.toString().toInt( &ok ); return ok; }
169  return false;
170 }
171 inline bool isDoubleSafe( const QVariant& v )
172 {
173  if ( v.type() == QVariant::Double ) return true;
174  if ( v.type() == QVariant::Int ) return true;
175  if ( v.type() == QVariant::UInt ) return true;
176  if ( v.type() == QVariant::LongLong ) return true;
177  if ( v.type() == QVariant::ULongLong ) return true;
178  if ( v.type() == QVariant::String )
179  {
180  bool ok;
181  double val = v.toString().toDouble( &ok );
182  ok = ok && qIsFinite( val ) && !qIsNaN( val );
183  return ok;
184  }
185  return false;
186 }
187 
188 inline bool isDateTimeSafe( const QVariant& v )
189 {
190  return v.type() == QVariant::DateTime || v.type() == QVariant::Date ||
191  v.type() == QVariant::Time;
192 }
193 
194 inline bool isIntervalSafe( const QVariant& v )
195 {
196  if ( v.canConvert<QgsExpression::Interval>() )
197  {
198  return true;
199  }
200 
201  if ( v.type() == QVariant::String )
202  {
203  return QgsExpression::Interval::fromString( v.toString() ).isValid();
204  }
205  return false;
206 }
207 
208 inline bool isNull( const QVariant& v ) { return v.isNull(); }
209 
211 // evaluation error macros
212 
213 #define ENSURE_NO_EVAL_ERROR { if (parent->hasEvalError()) return QVariant(); }
214 #define SET_EVAL_ERROR(x) { parent->setEvalErrorString(x); return QVariant(); }
215 
217 // operators
218 
219 const char* QgsExpression::BinaryOperatorText[] =
220 {
221  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
222  "OR", "AND",
223  "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
224  "+", "-", "*", "/", "//", "%", "^",
225  "||"
226 };
227 
228 const char* QgsExpression::UnaryOperatorText[] =
229 {
230  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
231  "NOT", "-"
232 };
233 
235 // functions
236 
237 // implicit conversion to string
238 static QString getStringValue( const QVariant& value, QgsExpression* )
239 {
240  return value.toString();
241 }
242 
243 static double getDoubleValue( const QVariant& value, QgsExpression* parent )
244 {
245  bool ok;
246  double x = value.toDouble( &ok );
247  if ( !ok || qIsNaN( x ) || !qIsFinite( x ) )
248  {
249  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
250  return 0;
251  }
252  return x;
253 }
254 
255 static int getIntValue( const QVariant& value, QgsExpression* parent )
256 {
257  bool ok;
258  qint64 x = value.toLongLong( &ok );
260  {
261  return x;
262  }
263  else
264  {
265  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
266  return 0;
267  }
268 }
269 
270 static QDateTime getDateTimeValue( const QVariant& value, QgsExpression* parent )
271 {
272  QDateTime d = value.toDateTime();
273  if ( d.isValid() )
274  {
275  return d;
276  }
277  else
278  {
279  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
280  return QDateTime();
281  }
282 }
283 
284 static QDate getDateValue( const QVariant& value, QgsExpression* parent )
285 {
286  QDate d = value.toDate();
287  if ( d.isValid() )
288  {
289  return d;
290  }
291  else
292  {
293  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
294  return QDate();
295  }
296 }
297 
298 static QTime getTimeValue( const QVariant& value, QgsExpression* parent )
299 {
300  QTime t = value.toTime();
301  if ( t.isValid() )
302  {
303  return t;
304  }
305  else
306  {
307  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
308  return QTime();
309  }
310 }
311 
312 static QgsExpression::Interval getInterval( const QVariant& value, QgsExpression* parent, bool report_error = false )
313 {
314  if ( value.canConvert<QgsExpression::Interval>() )
315  return value.value<QgsExpression::Interval>();
316 
318  if ( inter.isValid() )
319  {
320  return inter;
321  }
322  // If we get here then we can't convert so we just error and return invalid.
323  if ( report_error )
324  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Interval" ).arg( value.toString() ) );
325 
327 }
328 
329 static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent )
330 {
331  if ( value.canConvert<QgsGeometry>() )
332  return value.value<QgsGeometry>();
333 
334  parent->setEvalErrorString( "Cannot convert to QgsGeometry" );
335  return QgsGeometry();
336 }
337 
338 static QgsFeature getFeature( const QVariant& value, QgsExpression* parent )
339 {
340  if ( value.canConvert<QgsFeature>() )
341  return value.value<QgsFeature>();
342 
343  parent->setEvalErrorString( "Cannot convert to QgsFeature" );
344  return 0;
345 }
346 
347 static QgsExpression::Node* getNode( const QVariant& value, QgsExpression* parent )
348 {
349  if ( value.canConvert<QgsExpression::Node*>() )
350  return value.value<QgsExpression::Node*>();
351 
352  parent->setEvalErrorString( "Cannot convert to Node" );
353  return 0;
354 }
355 
356 // this handles also NULL values
357 static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
358 {
359  // we need to convert to TVL
360  if ( value.isNull() )
361  return Unknown;
362 
363  if ( value.type() == QVariant::Int )
364  return value.toInt() != 0 ? True : False;
365 
366  bool ok;
367  double x = value.toDouble( &ok );
368  if ( !ok )
369  {
370  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
371  return Unknown;
372  }
373  return x != 0 ? True : False;
374 }
375 
377 
378 static QVariant fcnSqrt( const QVariantList& values, const QgsFeature* /*f*/, QgsExpression* parent )
379 {
380  double x = getDoubleValue( values.at( 0 ), parent );
381  return QVariant( sqrt( x ) );
382 }
383 
384 static QVariant fcnAbs( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
385 {
386  double val = getDoubleValue( values.at( 0 ), parent );
387  return QVariant( fabs( val ) );
388 }
389 
390 static QVariant fcnSin( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
391 {
392  double x = getDoubleValue( values.at( 0 ), parent );
393  return QVariant( sin( x ) );
394 }
395 static QVariant fcnCos( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
396 {
397  double x = getDoubleValue( values.at( 0 ), parent );
398  return QVariant( cos( x ) );
399 }
400 static QVariant fcnTan( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
401 {
402  double x = getDoubleValue( values.at( 0 ), parent );
403  return QVariant( tan( x ) );
404 }
405 static QVariant fcnAsin( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
406 {
407  double x = getDoubleValue( values.at( 0 ), parent );
408  return QVariant( asin( x ) );
409 }
410 static QVariant fcnAcos( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
411 {
412  double x = getDoubleValue( values.at( 0 ), parent );
413  return QVariant( acos( x ) );
414 }
415 static QVariant fcnAtan( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
416 {
417  double x = getDoubleValue( values.at( 0 ), parent );
418  return QVariant( atan( x ) );
419 }
420 static QVariant fcnAtan2( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
421 {
422  double y = getDoubleValue( values.at( 0 ), parent );
423  double x = getDoubleValue( values.at( 1 ), parent );
424  return QVariant( atan2( y, x ) );
425 }
426 static QVariant fcnExp( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
427 {
428  double x = getDoubleValue( values.at( 0 ), parent );
429  return QVariant( exp( x ) );
430 }
431 static QVariant fcnLn( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
432 {
433  double x = getDoubleValue( values.at( 0 ), parent );
434  if ( x <= 0 )
435  return QVariant();
436  return QVariant( log( x ) );
437 }
438 static QVariant fcnLog10( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
439 {
440  double x = getDoubleValue( values.at( 0 ), parent );
441  if ( x <= 0 )
442  return QVariant();
443  return QVariant( log10( x ) );
444 }
445 static QVariant fcnLog( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
446 {
447  double b = getDoubleValue( values.at( 0 ), parent );
448  double x = getDoubleValue( values.at( 1 ), parent );
449  if ( x <= 0 || b <= 0 )
450  return QVariant();
451  return QVariant( log( x ) / log( b ) );
452 }
453 static QVariant fcnRndF( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
454 {
455  double min = getDoubleValue( values.at( 0 ), parent );
456  double max = getDoubleValue( values.at( 1 ), parent );
457  if ( max < min )
458  return QVariant();
459 
460  // Return a random double in the range [min, max] (inclusive)
461  double f = ( double )qrand() / RAND_MAX;
462  return QVariant( min + f * ( max - min ) );
463 }
464 static QVariant fcnRnd( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
465 {
466  int min = getIntValue( values.at( 0 ), parent );
467  int max = getIntValue( values.at( 1 ), parent );
468  if ( max < min )
469  return QVariant();
470 
471  // Return a random integer in the range [min, max] (inclusive)
472  return QVariant( min + ( qrand() % ( int )( max - min + 1 ) ) );
473 }
474 
475 static QVariant fcnLinearScale( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
476 {
477  double val = getDoubleValue( values.at( 0 ), parent );
478  double domainMin = getDoubleValue( values.at( 1 ), parent );
479  double domainMax = getDoubleValue( values.at( 2 ), parent );
480  double rangeMin = getDoubleValue( values.at( 3 ), parent );
481  double rangeMax = getDoubleValue( values.at( 4 ), parent );
482 
483  if ( domainMin >= domainMax )
484  {
485  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
486  return QVariant();
487  }
488 
489  // outside of domain?
490  if ( val >= domainMax )
491  {
492  return rangeMax;
493  }
494  else if ( val <= domainMin )
495  {
496  return rangeMin;
497  }
498 
499  // calculate linear scale
500  double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
501  double c = rangeMin - ( domainMin * m );
502 
503  // Return linearly scaled value
504  return QVariant( m * val + c );
505 }
506 
507 static QVariant fcnExpScale( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
508 {
509  double val = getDoubleValue( values.at( 0 ), parent );
510  double domainMin = getDoubleValue( values.at( 1 ), parent );
511  double domainMax = getDoubleValue( values.at( 2 ), parent );
512  double rangeMin = getDoubleValue( values.at( 3 ), parent );
513  double rangeMax = getDoubleValue( values.at( 4 ), parent );
514  double exponent = getDoubleValue( values.at( 5 ), parent );
515 
516  if ( domainMin >= domainMax )
517  {
518  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
519  return QVariant();
520  }
521  if ( exponent <= 0 )
522  {
523  parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
524  return QVariant();
525  }
526 
527  // outside of domain?
528  if ( val >= domainMax )
529  {
530  return rangeMax;
531  }
532  else if ( val <= domainMin )
533  {
534  return rangeMin;
535  }
536 
537  // Return exponentially scaled value
538  return QVariant((( rangeMax - rangeMin ) / pow( domainMax - domainMin, exponent ) ) * pow( val - domainMin, exponent ) + rangeMin );
539 }
540 
541 static QVariant fcnMax( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
542 {
543  //initially set max as first value
544  double maxVal = getDoubleValue( values.at( 0 ), parent );
545 
546  //check against all other values
547  for ( int i = 1; i < values.length(); ++i )
548  {
549  double testVal = getDoubleValue( values[i], parent );
550  if ( testVal > maxVal )
551  {
552  maxVal = testVal;
553  }
554  }
555 
556  return QVariant( maxVal );
557 }
558 
559 static QVariant fcnMin( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
560 {
561  //initially set min as first value
562  double minVal = getDoubleValue( values.at( 0 ), parent );
563 
564  //check against all other values
565  for ( int i = 1; i < values.length(); ++i )
566  {
567  double testVal = getDoubleValue( values[i], parent );
568  if ( testVal < minVal )
569  {
570  minVal = testVal;
571  }
572  }
573 
574  return QVariant( minVal );
575 }
576 
577 static QVariant fcnClamp( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
578 {
579  double minValue = getDoubleValue( values.at( 0 ), parent );
580  double testValue = getDoubleValue( values.at( 1 ), parent );
581  double maxValue = getDoubleValue( values.at( 2 ), parent );
582 
583  // force testValue to sit inside the range specified by the min and max value
584  if ( testValue <= minValue )
585  {
586  return QVariant( minValue );
587  }
588  else if ( testValue >= maxValue )
589  {
590  return QVariant( maxValue );
591  }
592  else
593  {
594  return QVariant( testValue );
595  }
596 }
597 
598 static QVariant fcnFloor( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
599 {
600  double x = getDoubleValue( values.at( 0 ), parent );
601  return QVariant( floor( x ) );
602 }
603 
604 static QVariant fcnCeil( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
605 {
606  double x = getDoubleValue( values.at( 0 ), parent );
607  return QVariant( ceil( x ) );
608 }
609 
610 static QVariant fcnToInt( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
611 {
612  return QVariant( getIntValue( values.at( 0 ), parent ) );
613 }
614 static QVariant fcnToReal( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
615 {
616  return QVariant( getDoubleValue( values.at( 0 ), parent ) );
617 }
618 static QVariant fcnToString( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
619 {
620  return QVariant( getStringValue( values.at( 0 ), parent ) );
621 }
622 
623 static QVariant fcnToDateTime( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
624 {
625  return QVariant( getDateTimeValue( values.at( 0 ), parent ) );
626 }
627 
628 static QVariant fcnCoalesce( const QVariantList& values, const QgsFeature*, QgsExpression* )
629 {
630  foreach ( const QVariant &value, values )
631  {
632  if ( value.isNull() )
633  continue;
634  return value;
635  }
636  return QVariant();
637 }
638 static QVariant fcnLower( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
639 {
640  QString str = getStringValue( values.at( 0 ), parent );
641  return QVariant( str.toLower() );
642 }
643 static QVariant fcnUpper( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
644 {
645  QString str = getStringValue( values.at( 0 ), parent );
646  return QVariant( str.toUpper() );
647 }
648 static QVariant fcnTitle( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
649 {
650  QString str = getStringValue( values.at( 0 ), parent );
651  QStringList elems = str.split( " " );
652  for ( int i = 0; i < elems.size(); i++ )
653  {
654  if ( elems[i].size() > 1 )
655  elems[i] = elems[i].left( 1 ).toUpper() + elems[i].mid( 1 ).toLower();
656  }
657  return QVariant( elems.join( " " ) );
658 }
659 
660 static QVariant fcnTrim( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
661 {
662  QString str = getStringValue( values.at( 0 ), parent );
663  return QVariant( str.trimmed() );
664 }
665 
666 static QVariant fcnWordwrap( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
667 {
668  if ( values.length() == 2 || values.length() == 3 )
669  {
670  QString str = getStringValue( values.at( 0 ), parent );
671  int wrap = getIntValue( values.at( 1 ), parent );
672 
673  if ( !str.isEmpty() && wrap != 0 )
674  {
675  QString newstr;
676  QString delimiterstr;
677  if ( values.length() == 3 ) delimiterstr = getStringValue( values.at( 2 ), parent );
678  if ( delimiterstr.isEmpty() ) delimiterstr = " ";
679  int delimiterlength = delimiterstr.length();
680 
681  QStringList lines = str.split( "\n" );
682  int strlength, strcurrent, strhit, lasthit;
683 
684  for ( int i = 0; i < lines.size(); i++ )
685  {
686  strlength = lines[i].length();
687  strcurrent = 0;
688  strhit = 0;
689  lasthit = 0;
690 
691  while ( strcurrent < strlength )
692  {
693  // positive wrap value = desired maximum line width to wrap
694  // negative wrap value = desired minimum line width before wrap
695  if ( wrap > 0 )
696  {
697  //first try to locate delimiter backwards
698  strhit = lines[i].lastIndexOf( delimiterstr, strcurrent + wrap );
699  if ( strhit == lasthit || strhit == -1 )
700  {
701  //if no new backward delimiter found, try to locate forward
702  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
703  }
704  lasthit = strhit;
705  }
706  else
707  {
708  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
709  }
710  if ( strhit > -1 )
711  {
712  newstr.append( lines[i].midRef( strcurrent, strhit - strcurrent ) );
713  newstr.append( "\n" );
714  strcurrent = strhit + delimiterlength;
715  }
716  else
717  {
718  newstr.append( lines[i].midRef( strcurrent ) );
719  strcurrent = strlength;
720  }
721  }
722  if ( i < lines.size() - 1 ) newstr.append( "\n" );
723  }
724 
725  return QVariant( newstr );
726  }
727  }
728 
729  return QVariant();
730 }
731 
732 static QVariant fcnLength( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
733 {
734  QString str = getStringValue( values.at( 0 ), parent );
735  return QVariant( str.length() );
736 }
737 static QVariant fcnReplace( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
738 {
739  QString str = getStringValue( values.at( 0 ), parent );
740  QString before = getStringValue( values.at( 1 ), parent );
741  QString after = getStringValue( values.at( 2 ), parent );
742  return QVariant( str.replace( before, after ) );
743 }
744 static QVariant fcnRegexpReplace( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
745 {
746  QString str = getStringValue( values.at( 0 ), parent );
747  QString regexp = getStringValue( values.at( 1 ), parent );
748  QString after = getStringValue( values.at( 2 ), parent );
749 
750  QRegExp re( regexp );
751  if ( !re.isValid() )
752  {
753  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp ).arg( re.errorString() ) );
754  return QVariant();
755  }
756  return QVariant( str.replace( re, after ) );
757 }
758 
759 static QVariant fcnRegexpMatch( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
760 {
761  QString str = getStringValue( values.at( 0 ), parent );
762  QString regexp = getStringValue( values.at( 1 ), parent );
763 
764  QRegExp re( regexp );
765  if ( !re.isValid() )
766  {
767  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp ).arg( re.errorString() ) );
768  return QVariant();
769  }
770  return QVariant( str.contains( re ) ? 1 : 0 );
771 }
772 
773 static QVariant fcnRegexpSubstr( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
774 {
775  QString str = getStringValue( values.at( 0 ), parent );
776  QString regexp = getStringValue( values.at( 1 ), parent );
777 
778  QRegExp re( regexp );
779  if ( !re.isValid() )
780  {
781  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp ).arg( re.errorString() ) );
782  return QVariant();
783  }
784 
785  // extract substring
786  ( void )re.indexIn( str );
787  if ( re.captureCount() > 0 )
788  {
789  // return first capture
790  return QVariant( re.capturedTexts()[1] );
791  }
792  else
793  {
794  return QVariant( "" );
795  }
796 }
797 
798 static QVariant fcnUuid( const QVariantList&, const QgsFeature*, QgsExpression* )
799 {
800  return QUuid::createUuid().toString();
801 }
802 
803 static QVariant fcnSubstr( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
804 {
805  QString str = getStringValue( values.at( 0 ), parent );
806  int from = getIntValue( values.at( 1 ), parent );
807  int len = getIntValue( values.at( 2 ), parent );
808  return QVariant( str.mid( from -1, len ) );
809 }
810 
811 static QVariant fcnRowNumber( const QVariantList&, const QgsFeature*, QgsExpression* parent )
812 {
813  return QVariant( parent->currentRowNumber() );
814 }
815 
816 static QVariant fcnFeatureId( const QVariantList&, const QgsFeature* f, QgsExpression* )
817 {
818  // TODO: handling of 64-bit feature ids?
819  return f ? QVariant(( int )f->id() ) : QVariant();
820 }
821 
822 static QVariant fcnFeature( const QVariantList&, const QgsFeature* f, QgsExpression* )
823 {
824  return f ? QVariant::fromValue( *f ) : QVariant();
825 }
826 static QVariant fcnAttribute( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
827 {
828  QgsFeature feat = getFeature( values.at( 0 ), parent );
829  QString attr = getStringValue( values.at( 1 ), parent );
830 
831  return feat.attribute( attr );
832 }
833 static QVariant fcnConcat( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
834 {
835  QString concat;
836  foreach ( const QVariant &value, values )
837  {
838  concat += getStringValue( value, parent );
839  }
840  return concat;
841 }
842 
843 static QVariant fcnStrpos( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
844 {
845  QString string = getStringValue( values.at( 0 ), parent );
846  return string.indexOf( QRegExp( getStringValue( values.at( 1 ), parent ) ) );
847 }
848 
849 static QVariant fcnRight( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
850 {
851  QString string = getStringValue( values.at( 0 ), parent );
852  int pos = getIntValue( values.at( 1 ), parent );
853  return string.right( pos );
854 }
855 
856 static QVariant fcnLeft( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
857 {
858  QString string = getStringValue( values.at( 0 ), parent );
859  int pos = getIntValue( values.at( 1 ), parent );
860  return string.left( pos );
861 }
862 
863 static QVariant fcnRPad( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
864 {
865  QString string = getStringValue( values.at( 0 ), parent );
866  int length = getIntValue( values.at( 1 ), parent );
867  QString fill = getStringValue( values.at( 2 ), parent );
868  return string.leftJustified( length, fill.at( 0 ), true );
869 }
870 
871 static QVariant fcnLPad( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
872 {
873  QString string = getStringValue( values.at( 0 ), parent );
874  int length = getIntValue( values.at( 1 ), parent );
875  QString fill = getStringValue( values.at( 2 ), parent );
876  return string.rightJustified( length, fill.at( 0 ), true );
877 }
878 
879 static QVariant fcnFormatString( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
880 {
881  QString string = getStringValue( values.at( 0 ), parent );
882  for ( int n = 1; n < values.length(); n++ )
883  {
884  string = string.arg( getStringValue( values.at( n ), parent ) );
885  }
886  return string;
887 }
888 
889 
890 static QVariant fcnNow( const QVariantList&, const QgsFeature*, QgsExpression * )
891 {
892  return QVariant( QDateTime::currentDateTime() );
893 }
894 
895 static QVariant fcnToDate( const QVariantList& values, const QgsFeature*, QgsExpression * parent )
896 {
897  return QVariant( getDateValue( values.at( 0 ), parent ) );
898 }
899 
900 static QVariant fcnToTime( const QVariantList& values, const QgsFeature*, QgsExpression * parent )
901 {
902  return QVariant( getTimeValue( values.at( 0 ), parent ) );
903 }
904 
905 static QVariant fcnToInterval( const QVariantList& values, const QgsFeature*, QgsExpression * parent )
906 {
907  return QVariant::fromValue( getInterval( values.at( 0 ), parent ) );
908 }
909 
910 static QVariant fcnAge( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
911 {
912  QDateTime d1 = getDateTimeValue( values.at( 0 ), parent );
913  QDateTime d2 = getDateTimeValue( values.at( 1 ), parent );
914  int seconds = d2.secsTo( d1 );
915  return QVariant::fromValue( QgsExpression::Interval( seconds ) );
916 }
917 
918 static QVariant fcnDay( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
919 {
920  QVariant value = values.at( 0 );
921  QgsExpression::Interval inter = getInterval( value, parent, false );
922  if ( inter.isValid() )
923  {
924  return QVariant( inter.days() );
925  }
926  else
927  {
928  QDateTime d1 = getDateTimeValue( value, parent );
929  return QVariant( d1.date().day() );
930  }
931 }
932 
933 static QVariant fcnYear( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
934 {
935  QVariant value = values.at( 0 );
936  QgsExpression::Interval inter = getInterval( value, parent, false );
937  if ( inter.isValid() )
938  {
939  return QVariant( inter.years() );
940  }
941  else
942  {
943  QDateTime d1 = getDateTimeValue( value, parent );
944  return QVariant( d1.date().year() );
945  }
946 }
947 
948 static QVariant fcnMonth( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
949 {
950  QVariant value = values.at( 0 );
951  QgsExpression::Interval inter = getInterval( value, parent, false );
952  if ( inter.isValid() )
953  {
954  return QVariant( inter.months() );
955  }
956  else
957  {
958  QDateTime d1 = getDateTimeValue( value, parent );
959  return QVariant( d1.date().month() );
960  }
961 }
962 
963 static QVariant fcnWeek( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
964 {
965  QVariant value = values.at( 0 );
966  QgsExpression::Interval inter = getInterval( value, parent, false );
967  if ( inter.isValid() )
968  {
969  return QVariant( inter.weeks() );
970  }
971  else
972  {
973  QDateTime d1 = getDateTimeValue( value, parent );
974  return QVariant( d1.date().weekNumber() );
975  }
976 }
977 
978 static QVariant fcnHour( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
979 {
980  QVariant value = values.at( 0 );
981  QgsExpression::Interval inter = getInterval( value, parent, false );
982  if ( inter.isValid() )
983  {
984  return QVariant( inter.hours() );
985  }
986  else
987  {
988  QDateTime d1 = getDateTimeValue( value, parent );
989  return QVariant( d1.time().hour() );
990  }
991 }
992 
993 static QVariant fcnMinute( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
994 {
995  QVariant value = values.at( 0 );
996  QgsExpression::Interval inter = getInterval( value, parent, false );
997  if ( inter.isValid() )
998  {
999  return QVariant( inter.minutes() );
1000  }
1001  else
1002  {
1003  QDateTime d1 = getDateTimeValue( value, parent );
1004  return QVariant( d1.time().minute() );
1005  }
1006 }
1007 
1008 static QVariant fcnSeconds( const QVariantList& values, const QgsFeature*, QgsExpression *parent )
1009 {
1010  QVariant value = values.at( 0 );
1011  QgsExpression::Interval inter = getInterval( value, parent, false );
1012  if ( inter.isValid() )
1013  {
1014  return QVariant( inter.seconds() );
1015  }
1016  else
1017  {
1018  QDateTime d1 = getDateTimeValue( value, parent );
1019  return QVariant( d1.time().second() );
1020  }
1021 }
1022 
1023 
1024 #define ENSURE_GEOM_TYPE(f, g, geomtype) if (!f) return QVariant(); \
1025  QgsGeometry* g = f->geometry(); \
1026  if (!g || g->type() != geomtype) return QVariant();
1027 
1028 
1029 static QVariant fcnX( const QVariantList&, const QgsFeature* f, QgsExpression* )
1030 {
1031  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1032  if ( g->isMultipart() )
1033  {
1034  return g->asMultiPoint()[ 0 ].x();
1035  }
1036  else
1037  {
1038  return g->asPoint().x();
1039  }
1040 }
1041 static QVariant fcnY( const QVariantList&, const QgsFeature* f, QgsExpression* )
1042 {
1043  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1044  if ( g->isMultipart() )
1045  {
1046  return g->asMultiPoint()[ 0 ].y();
1047  }
1048  else
1049  {
1050  return g->asPoint().y();
1051  }
1052 }
1053 
1054 static QVariant pointAt( const QVariantList& values, const QgsFeature* f, QgsExpression* parent ) // helper function
1055 {
1056  int idx = getIntValue( values.at( 0 ), parent );
1057  ENSURE_GEOM_TYPE( f, g, QGis::Line );
1058  QgsPolyline polyline = g->asPolyline();
1059  if ( idx < 0 )
1060  idx += polyline.count();
1061 
1062  if ( idx < 0 || idx >= polyline.count() )
1063  {
1064  parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
1065  return QVariant();
1066  }
1067  return QVariant( QPointF( polyline[idx].x(), polyline[idx].y() ) );
1068 }
1069 
1070 static QVariant fcnXat( const QVariantList& values, const QgsFeature* f, QgsExpression* parent )
1071 {
1072  QVariant v = pointAt( values, f, parent );
1073  if ( v.type() == QVariant::PointF )
1074  return QVariant( v.toPointF().x() );
1075  else
1076  return QVariant();
1077 }
1078 static QVariant fcnYat( const QVariantList& values, const QgsFeature* f, QgsExpression* parent )
1079 {
1080  QVariant v = pointAt( values, f, parent );
1081  if ( v.type() == QVariant::PointF )
1082  return QVariant( v.toPointF().y() );
1083  else
1084  return QVariant();
1085 }
1086 static QVariant fcnGeometry( const QVariantList&, const QgsFeature* f, QgsExpression* )
1087 {
1088  QgsGeometry* geom = f ? f->geometry() : 0;
1089  if ( geom )
1090  return QVariant::fromValue( *geom );
1091  else
1092  return QVariant();
1093 }
1094 static QVariant fcnGeomFromWKT( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1095 {
1096  QString wkt = getStringValue( values.at( 0 ), parent );
1097  QgsGeometry* geom = QgsGeometry::fromWkt( wkt );
1098  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1099  delete geom;
1100  return result;
1101 }
1102 static QVariant fcnGeomFromGML( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1103 {
1104  QString gml = getStringValue( values.at( 0 ), parent );
1106  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1107  delete geom;
1108  return result;
1109 }
1110 
1111 static QVariant fcnGeomArea( const QVariantList&, const QgsFeature* f, QgsExpression* parent )
1112 {
1114  QgsDistanceArea* calc = parent->geomCalculator();
1115  return QVariant( calc->measure( f->geometry() ) );
1116 }
1117 static QVariant fcnGeomLength( const QVariantList&, const QgsFeature* f, QgsExpression* parent )
1118 {
1119  ENSURE_GEOM_TYPE( f, g, QGis::Line );
1120  QgsDistanceArea* calc = parent->geomCalculator();
1121  return QVariant( calc->measure( f->geometry() ) );
1122 }
1123 static QVariant fcnGeomPerimeter( const QVariantList&, const QgsFeature* f, QgsExpression* parent )
1124 {
1126  QgsDistanceArea* calc = parent->geomCalculator();
1127  return QVariant( calc->measurePerimeter( f->geometry() ) );
1128 }
1129 
1130 static QVariant fcnBounds( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1131 {
1132  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1133  QgsGeometry* geomBounds = QgsGeometry::fromRect( geom.boundingBox() );
1134  QVariant result = geomBounds ? QVariant::fromValue( *geomBounds ) : QVariant();
1135  delete geomBounds;
1136  return result;
1137 }
1138 
1139 static QVariant fcnBoundsWidth( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1140 {
1141  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1142  return QVariant::fromValue( geom.boundingBox().width() );
1143 }
1144 
1145 static QVariant fcnBoundsHeight( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1146 {
1147  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1148  return QVariant::fromValue( geom.boundingBox().height() );
1149 }
1150 
1151 static QVariant fcnXMin( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1152 {
1153  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1154  return QVariant::fromValue( geom.boundingBox().xMinimum() );
1155 }
1156 
1157 static QVariant fcnXMax( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1158 {
1159  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1160  return QVariant::fromValue( geom.boundingBox().xMaximum() );
1161 }
1162 
1163 static QVariant fcnYMin( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1164 {
1165  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1166  return QVariant::fromValue( geom.boundingBox().yMinimum() );
1167 }
1168 
1169 static QVariant fcnYMax( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1170 {
1171  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1172  return QVariant::fromValue( geom.boundingBox().yMaximum() );
1173 }
1174 
1175 static QVariant fcnBbox( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1176 {
1177  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1178  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1179  return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
1180 }
1181 static QVariant fcnDisjoint( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1182 {
1183  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1184  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1185  return fGeom.disjoint( &sGeom ) ? TVL_True : TVL_False;
1186 }
1187 static QVariant fcnIntersects( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1188 {
1189  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1190  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1191  return fGeom.intersects( &sGeom ) ? TVL_True : TVL_False;
1192 }
1193 static QVariant fcnTouches( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1194 {
1195  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1196  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1197  return fGeom.touches( &sGeom ) ? TVL_True : TVL_False;
1198 }
1199 static QVariant fcnCrosses( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1200 {
1201  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1202  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1203  return fGeom.crosses( &sGeom ) ? TVL_True : TVL_False;
1204 }
1205 static QVariant fcnContains( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1206 {
1207  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1208  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1209  return fGeom.contains( &sGeom ) ? TVL_True : TVL_False;
1210 }
1211 static QVariant fcnOverlaps( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1212 {
1213  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1214  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1215  return fGeom.overlaps( &sGeom ) ? TVL_True : TVL_False;
1216 }
1217 static QVariant fcnWithin( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1218 {
1219  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1220  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1221  return fGeom.within( &sGeom ) ? TVL_True : TVL_False;
1222 }
1223 static QVariant fcnBuffer( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1224 {
1225  if ( values.length() < 2 || values.length() > 3 )
1226  return QVariant();
1227 
1228  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1229  double dist = getDoubleValue( values.at( 1 ), parent );
1230  int seg = 8;
1231  if ( values.length() == 3 )
1232  seg = getIntValue( values.at( 2 ), parent );
1233 
1234  QgsGeometry* geom = fGeom.buffer( dist, seg );
1235  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1236  delete geom;
1237  return result;
1238 }
1239 static QVariant fcnCentroid( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1240 {
1241  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1242  QgsGeometry* geom = fGeom.centroid();
1243  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1244  delete geom;
1245  return result;
1246 }
1247 static QVariant fcnConvexHull( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1248 {
1249  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1250  QgsGeometry* geom = fGeom.convexHull();
1251  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1252  delete geom;
1253  return result;
1254 }
1255 static QVariant fcnDifference( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1256 {
1257  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1258  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1259  QgsGeometry* geom = fGeom.difference( &sGeom );
1260  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1261  delete geom;
1262  return result;
1263 }
1264 static QVariant fcnDistance( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1265 {
1266  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1267  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1268  return QVariant( fGeom.distance( sGeom ) );
1269 }
1270 static QVariant fcnIntersection( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1271 {
1272  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1273  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1274  QgsGeometry* geom = fGeom.intersection( &sGeom );
1275  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1276  delete geom;
1277  return result;
1278 }
1279 static QVariant fcnSymDifference( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1280 {
1281  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1282  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1283  QgsGeometry* geom = fGeom.symDifference( &sGeom );
1284  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1285  delete geom;
1286  return result;
1287 }
1288 static QVariant fcnCombine( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1289 {
1290  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1291  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1292  QgsGeometry* geom = fGeom.combine( &sGeom );
1293  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1294  delete geom;
1295  return result;
1296 }
1297 static QVariant fcnGeomToWKT( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1298 {
1299  if ( values.length() < 1 || values.length() > 2 )
1300  return QVariant();
1301 
1302  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1303  int prec = 8;
1304  if ( values.length() == 2 )
1305  prec = getIntValue( values.at( 1 ), parent );
1306  QString wkt = fGeom.exportToWkt( prec );
1307  return QVariant( wkt );
1308 }
1309 
1310 static QVariant fcnRound( const QVariantList& values, const QgsFeature *f, QgsExpression* parent )
1311 {
1312  Q_UNUSED( f );
1313  if ( values.length() == 2 )
1314  {
1315  double number = getDoubleValue( values.at( 0 ), parent );
1316  double scaler = pow( 10.0, getIntValue( values.at( 1 ), parent ) );
1317  return QVariant( qRound( number * scaler ) / scaler );
1318  }
1319 
1320  if ( values.length() == 1 )
1321  {
1322  double number = getIntValue( values.at( 0 ), parent );
1323  return QVariant( qRound( number ) ).toInt();
1324  }
1325 
1326  return QVariant();
1327 }
1328 
1329 static QVariant fcnPi( const QVariantList& values, const QgsFeature *f, QgsExpression* parent )
1330 {
1331  Q_UNUSED( values );
1332  Q_UNUSED( f );
1333  Q_UNUSED( parent );
1334  return M_PI;
1335 }
1336 
1337 static QVariant fcnScale( const QVariantList&, const QgsFeature*, QgsExpression* parent )
1338 {
1339  return QVariant( parent->scale() );
1340 }
1341 
1342 static QVariant fcnFormatNumber( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1343 {
1344  double value = getDoubleValue( values.at( 0 ), parent );
1345  int places = getIntValue( values.at( 1 ), parent );
1346  if ( places < 0 )
1347  {
1348  parent->setEvalErrorString( QObject::tr( "Number of places must be positive" ) );
1349  return QVariant();
1350  }
1351  return QString( "%L1" ).arg( value, 0, 'f', places );
1352 }
1353 
1354 static QVariant fcnFormatDate( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1355 {
1356  QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
1357  QString format = getStringValue( values.at( 1 ), parent );
1358  return dt.toString( format );
1359 }
1360 
1361 static QVariant fcnColorRgb( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
1362 {
1363  int red = getIntValue( values.at( 0 ), parent );
1364  int green = getIntValue( values.at( 1 ), parent );
1365  int blue = getIntValue( values.at( 2 ), parent );
1366  QColor color = QColor( red, green, blue );
1367  if ( ! color.isValid() )
1368  {
1369  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
1370  color = QColor( 0, 0, 0 );
1371  }
1372 
1373  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
1374 }
1375 
1376 static QVariant fcnIf( const QVariantList &values, const QgsFeature *f, QgsExpression *parent )
1377 {
1378  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
1380  QVariant value = node->eval( parent, f );
1382  if ( value.toBool() )
1383  {
1384  node = getNode( values.at( 1 ), parent );
1386  value = node->eval( parent, f );
1388  }
1389  else
1390  {
1391  node = getNode( values.at( 2 ), parent );
1393  value = node->eval( parent, f );
1395  }
1396  return value;
1397 }
1398 
1399 static QVariant fncColorRgba( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
1400 {
1401  int red = getIntValue( values.at( 0 ), parent );
1402  int green = getIntValue( values.at( 1 ), parent );
1403  int blue = getIntValue( values.at( 2 ), parent );
1404  int alpha = getIntValue( values.at( 3 ), parent );
1405  QColor color = QColor( red, green, blue, alpha );
1406  if ( ! color.isValid() )
1407  {
1408  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
1409  color = QColor( 0, 0, 0 );
1410  }
1411  return QgsSymbolLayerV2Utils::encodeColor( color );
1412 }
1413 
1414 QVariant fcnRampColor( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
1415 {
1416  QString rampName = getStringValue( values.at( 0 ), parent );
1417  const QgsVectorColorRampV2 *mRamp = QgsStyleV2::defaultStyle()->colorRampRef( rampName );
1418  if ( ! mRamp )
1419  {
1420  parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
1421  return QColor( 0, 0, 0 ).name();
1422  }
1423  double value = getDoubleValue( values.at( 1 ), parent );
1424  QColor color = mRamp->color( value );
1425  return QgsSymbolLayerV2Utils::encodeColor( color );
1426 }
1427 
1428 static QVariant fcnColorHsl( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
1429 {
1430  // Hue ranges from 0 - 360
1431  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
1432  // Saturation ranges from 0 - 100
1433  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
1434  // Lightness ranges from 0 - 100
1435  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
1436 
1437  QColor color = QColor::fromHslF( hue, saturation, lightness );
1438 
1439  if ( ! color.isValid() )
1440  {
1441  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
1442  color = QColor( 0, 0, 0 );
1443  }
1444 
1445  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
1446 }
1447 
1448 static QVariant fncColorHsla( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
1449 {
1450  // Hue ranges from 0 - 360
1451  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
1452  // Saturation ranges from 0 - 100
1453  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
1454  // Lightness ranges from 0 - 100
1455  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
1456  // Alpha ranges from 0 - 255
1457  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
1458 
1459  QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
1460  if ( ! color.isValid() )
1461  {
1462  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
1463  color = QColor( 0, 0, 0 );
1464  }
1465  return QgsSymbolLayerV2Utils::encodeColor( color );
1466 }
1467 
1468 static QVariant fcnColorHsv( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
1469 {
1470  // Hue ranges from 0 - 360
1471  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
1472  // Saturation ranges from 0 - 100
1473  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
1474  // Value ranges from 0 - 100
1475  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
1476 
1477  QColor color = QColor::fromHsvF( hue, saturation, value );
1478 
1479  if ( ! color.isValid() )
1480  {
1481  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
1482  color = QColor( 0, 0, 0 );
1483  }
1484 
1485  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
1486 }
1487 
1488 static QVariant fncColorHsva( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
1489 {
1490  // Hue ranges from 0 - 360
1491  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
1492  // Saturation ranges from 0 - 100
1493  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
1494  // Value ranges from 0 - 100
1495  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
1496  // Alpha ranges from 0 - 255
1497  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
1498 
1499  QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
1500  if ( ! color.isValid() )
1501  {
1502  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
1503  color = QColor( 0, 0, 0 );
1504  }
1505  return QgsSymbolLayerV2Utils::encodeColor( color );
1506 }
1507 
1508 static QVariant fcnColorCmyk( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
1509 {
1510  // Cyan ranges from 0 - 100
1511  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
1512  // Magenta ranges from 0 - 100
1513  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
1514  // Yellow ranges from 0 - 100
1515  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
1516  // Black ranges from 0 - 100
1517  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
1518 
1519  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
1520 
1521  if ( ! color.isValid() )
1522  {
1523  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
1524  color = QColor( 0, 0, 0 );
1525  }
1526 
1527  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
1528 }
1529 
1530 static QVariant fncColorCmyka( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
1531 {
1532  // Cyan ranges from 0 - 100
1533  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
1534  // Magenta ranges from 0 - 100
1535  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
1536  // Yellow ranges from 0 - 100
1537  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
1538  // Black ranges from 0 - 100
1539  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
1540  // Alpha ranges from 0 - 255
1541  double alpha = getIntValue( values.at( 4 ), parent ) / 255.0;
1542 
1543  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
1544  if ( ! color.isValid() )
1545  {
1546  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
1547  color = QColor( 0, 0, 0 );
1548  }
1549  return QgsSymbolLayerV2Utils::encodeColor( color );
1550 }
1551 
1552 static QVariant fcnSpecialColumn( const QVariantList& values, const QgsFeature* /*f*/, QgsExpression* parent )
1553 {
1554  QString varName = getStringValue( values.at( 0 ), parent );
1555  return QgsExpression::specialColumn( varName );
1556 }
1557 
1558 static QVariant fcnGetGeometry( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1559 {
1560  QgsFeature feat = getFeature( values.at( 0 ), parent );
1561  QgsGeometry* geom = feat.geometry();
1562  if ( geom )
1563  return QVariant::fromValue( *geom );
1564  return QVariant();
1565 }
1566 
1567 static QVariant fcnTransformGeometry( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
1568 {
1569  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1570  QString sAuthId = getStringValue( values.at( 1 ), parent );
1571  QString dAuthId = getStringValue( values.at( 2 ), parent );
1572 
1574  if ( ! s.createFromOgcWmsCrs( sAuthId ) )
1575  return QVariant::fromValue( fGeom );
1577  if ( ! d.createFromOgcWmsCrs( dAuthId ) )
1578  return QVariant::fromValue( fGeom );
1579 
1580  QgsCoordinateTransform t( s, d );
1581  if ( fGeom.transform( t ) == 0 )
1582  return QVariant::fromValue( fGeom );
1583  return QVariant();
1584 }
1585 
1586 static QVariant fcnGetFeature( const QVariantList& values, const QgsFeature *, QgsExpression* parent )
1587 {
1588  //arguments: 1. layer id / name, 2. key attribute, 3. eq value
1589  QString layerString = getStringValue( values.at( 0 ), parent );
1590  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerString ) ); //search by id first
1591  if ( !vl )
1592  {
1593  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerString );
1594  if ( layersByName.size() > 0 )
1595  {
1596  vl = qobject_cast<QgsVectorLayer*>( layersByName.at( 0 ) );
1597  }
1598  }
1599 
1600  //no layer found
1601  if ( !vl )
1602  {
1603  return QVariant();
1604  }
1605 
1606  QString attribute = getStringValue( values.at( 1 ), parent );
1607  int attributeId = vl->fieldNameIndex( attribute );
1608  if ( attributeId == -1 )
1609  {
1610  return QVariant();
1611  }
1612 
1613  const QVariant& attVal = values.at( 2 );
1614  QgsFeatureRequest req;
1615  if ( !parent->needsGeometry() )
1616  {
1618  }
1619  QgsFeatureIterator fIt = vl->getFeatures( req );
1620 
1621  QgsFeature fet;
1622  while ( fIt.nextFeature( fet ) )
1623  {
1624  if ( fet.attribute( attributeId ) == attVal )
1625  {
1626  return QVariant::fromValue( fet );
1627  }
1628  }
1629  return QVariant();
1630 }
1631 
1633 {
1634  int fnIdx = functionIndex( function->name() );
1635  if ( fnIdx != -1 )
1636  {
1637  return false;
1638  }
1639  QgsExpression::gmFunctions.append( function );
1640  return true;
1641 }
1642 
1644 {
1645  // You can never override the built in functions.
1646  if ( QgsExpression::BuiltinFunctions().contains( name ) )
1647  {
1648  return false;
1649  }
1650  int fnIdx = functionIndex( name );
1651  if ( fnIdx != -1 )
1652  {
1653  QgsExpression::gmFunctions.removeAt( fnIdx );
1654  return true;
1655  }
1656  return false;
1657 }
1658 
1659 
1660 
1662 
1664 {
1665  if ( gmBuiltinFunctions.isEmpty() )
1666  {
1668  << "abs" << "sqrt" << "cos" << "sin" << "tan"
1669  << "asin" << "acos" << "atan" << "atan2"
1670  << "exp" << "ln" << "log10" << "log"
1671  << "round" << "rand" << "randf" << "max" << "min" << "clamp"
1672  << "scale_linear" << "scale_exp" << "floor" << "ceil"
1673  << "toint" << "toreal" << "tostring"
1674  << "todatetime" << "todate" << "totime" << "tointerval"
1675  << "coalesce" << "regexp_match" << "$now" << "age" << "year"
1676  << "month" << "week" << "day" << "hour"
1677  << "minute" << "second" << "lower" << "upper"
1678  << "title" << "length" << "replace" << "trim" << "wordwrap"
1679  << "regexp_replace" << "regexp_substr"
1680  << "substr" << "concat" << "strpos" << "left"
1681  << "right" << "rpad" << "lpad"
1682  << "format_number" << "format_date"
1683  << "color_rgb" << "color_rgba" << "ramp_color"
1684  << "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
1685  << "color_cymk" << "color_cymka"
1686  << "xat" << "yat" << "$area"
1687  << "$length" << "$perimeter" << "$x" << "$y"
1688  << "$rownum" << "$id" << "$scale" << "_specialcol_";
1689  }
1690  return gmBuiltinFunctions;
1691 }
1692 
1693 QList<QgsExpression::Function*> QgsExpression::gmFunctions;
1694 
1695 const QList<QgsExpression::Function*> &QgsExpression::Functions()
1696 {
1697  if ( gmFunctions.isEmpty() )
1698  {
1699  gmFunctions
1700  << new StaticFunction( "sqrt", 1, fcnSqrt, "Math" )
1701  << new StaticFunction( "abs", 1, fcnAbs, "Math" )
1702  << new StaticFunction( "cos", 1, fcnCos, "Math" )
1703  << new StaticFunction( "sin", 1, fcnSin, "Math" )
1704  << new StaticFunction( "tan", 1, fcnTan, "Math" )
1705  << new StaticFunction( "asin", 1, fcnAsin, "Math" )
1706  << new StaticFunction( "acos", 1, fcnAcos, "Math" )
1707  << new StaticFunction( "atan", 1, fcnAtan, "Math" )
1708  << new StaticFunction( "atan2", 2, fcnAtan2, "Math" )
1709  << new StaticFunction( "exp", 1, fcnExp, "Math" )
1710  << new StaticFunction( "ln", 1, fcnLn, "Math" )
1711  << new StaticFunction( "log10", 1, fcnLog10, "Math" )
1712  << new StaticFunction( "log", 2, fcnLog, "Math" )
1713  << new StaticFunction( "round", -1, fcnRound, "Math" )
1714  << new StaticFunction( "rand", 2, fcnRnd, "Math" )
1715  << new StaticFunction( "randf", 2, fcnRndF, "Math" )
1716  << new StaticFunction( "max", -1, fcnMax, "Math" )
1717  << new StaticFunction( "min", -1, fcnMin, "Math" )
1718  << new StaticFunction( "clamp", 3, fcnClamp, "Math" )
1719  << new StaticFunction( "scale_linear", 5, fcnLinearScale, "Math" )
1720  << new StaticFunction( "scale_exp", 6, fcnExpScale, "Math" )
1721  << new StaticFunction( "floor", 1, fcnFloor, "Math" )
1722  << new StaticFunction( "ceil", 1, fcnCeil, "Math" )
1723  << new StaticFunction( "$pi", 0, fcnPi, "Math" )
1724  << new StaticFunction( "toint", 1, fcnToInt, "Conversions" )
1725  << new StaticFunction( "toreal", 1, fcnToReal, "Conversions" )
1726  << new StaticFunction( "tostring", 1, fcnToString, "Conversions" )
1727  << new StaticFunction( "todatetime", 1, fcnToDateTime, "Conversions" )
1728  << new StaticFunction( "todate", 1, fcnToDate, "Conversions" )
1729  << new StaticFunction( "totime", 1, fcnToTime, "Conversions" )
1730  << new StaticFunction( "tointerval", 1, fcnToInterval, "Conversions" )
1731  << new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals" )
1732  << new StaticFunction( "if", 3, fcnIf, "Conditionals", "", False, QStringList(), true )
1733  << new StaticFunction( "regexp_match", 2, fcnRegexpMatch, "Conditionals" )
1734  << new StaticFunction( "$now", 0, fcnNow, "Date and Time" )
1735  << new StaticFunction( "age", 2, fcnAge, "Date and Time" )
1736  << new StaticFunction( "year", 1, fcnYear, "Date and Time" )
1737  << new StaticFunction( "month", 1, fcnMonth, "Date and Time" )
1738  << new StaticFunction( "week", 1, fcnWeek, "Date and Time" )
1739  << new StaticFunction( "day", 1, fcnDay, "Date and Time" )
1740  << new StaticFunction( "hour", 1, fcnHour, "Date and Time" )
1741  << new StaticFunction( "minute", 1, fcnMinute, "Date and Time" )
1742  << new StaticFunction( "second", 1, fcnSeconds, "Date and Time" )
1743  << new StaticFunction( "lower", 1, fcnLower, "String" )
1744  << new StaticFunction( "upper", 1, fcnUpper, "String" )
1745  << new StaticFunction( "title", 1, fcnTitle, "String" )
1746  << new StaticFunction( "trim", 1, fcnTrim, "String" )
1747  << new StaticFunction( "wordwrap", -1, fcnWordwrap, "String" )
1748  << new StaticFunction( "length", 1, fcnLength, "String" )
1749  << new StaticFunction( "replace", 3, fcnReplace, "String" )
1750  << new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
1751  << new StaticFunction( "regexp_substr", 2, fcnRegexpSubstr, "String" )
1752  << new StaticFunction( "substr", 3, fcnSubstr, "String" )
1753  << new StaticFunction( "concat", -1, fcnConcat, "String" )
1754  << new StaticFunction( "strpos", 2, fcnStrpos, "String" )
1755  << new StaticFunction( "left", 2, fcnLeft, "String" )
1756  << new StaticFunction( "right", 2, fcnRight, "String" )
1757  << new StaticFunction( "rpad", 3, fcnRPad, "String" )
1758  << new StaticFunction( "lpad", 3, fcnLPad, "String" )
1759  << new StaticFunction( "format", -1, fcnFormatString, "String" )
1760  << new StaticFunction( "format_number", 2, fcnFormatNumber, "String" )
1761  << new StaticFunction( "format_date", 2, fcnFormatDate, "String" )
1762  << new StaticFunction( "color_rgb", 3, fcnColorRgb, "Color" )
1763  << new StaticFunction( "color_rgba", 4, fncColorRgba, "Color" )
1764  << new StaticFunction( "ramp_color", 2, fcnRampColor, "Color" )
1765  << new StaticFunction( "color_hsl", 3, fcnColorHsl, "Color" )
1766  << new StaticFunction( "color_hsla", 4, fncColorHsla, "Color" )
1767  << new StaticFunction( "color_hsv", 3, fcnColorHsv, "Color" )
1768  << new StaticFunction( "color_hsva", 4, fncColorHsva, "Color" )
1769  << new StaticFunction( "color_cmyk", 4, fcnColorCmyk, "Color" )
1770  << new StaticFunction( "color_cmyka", 5, fncColorCmyka, "Color" )
1771  << new StaticFunction( "$geometry", 0, fcnGeometry, "GeometryGroup", "", true )
1772  << new StaticFunction( "$area", 0, fcnGeomArea, "GeometryGroup", "", true )
1773  << new StaticFunction( "$length", 0, fcnGeomLength, "GeometryGroup", "", true )
1774  << new StaticFunction( "$perimeter", 0, fcnGeomPerimeter, "GeometryGroup", "", true )
1775  << new StaticFunction( "$x", 0, fcnX, "GeometryGroup", "", true )
1776  << new StaticFunction( "$y", 0, fcnY, "GeometryGroup", "", true )
1777  << new StaticFunction( "xat", 1, fcnXat, "GeometryGroup", "", true )
1778  << new StaticFunction( "yat", 1, fcnYat, "GeometryGroup", "", true )
1779  << new StaticFunction( "xmin", 1, fcnXMin, "GeometryGroup", "", true )
1780  << new StaticFunction( "xmax", 1, fcnXMax, "GeometryGroup", "", true )
1781  << new StaticFunction( "ymin", 1, fcnYMin, "GeometryGroup", "", true )
1782  << new StaticFunction( "ymax", 1, fcnYMax, "GeometryGroup", "", true )
1783  << new StaticFunction( "geomFromWKT", 1, fcnGeomFromWKT, "GeometryGroup" )
1784  << new StaticFunction( "geomFromGML", 1, fcnGeomFromGML, "GeometryGroup" )
1785  << new StaticFunction( "bbox", 2, fcnBbox, "GeometryGroup" )
1786  << new StaticFunction( "disjoint", 2, fcnDisjoint, "GeometryGroup" )
1787  << new StaticFunction( "intersects", 2, fcnIntersects, "GeometryGroup" )
1788  << new StaticFunction( "touches", 2, fcnTouches, "GeometryGroup" )
1789  << new StaticFunction( "crosses", 2, fcnCrosses, "GeometryGroup" )
1790  << new StaticFunction( "contains", 2, fcnContains, "GeometryGroup" )
1791  << new StaticFunction( "overlaps", 2, fcnOverlaps, "GeometryGroup" )
1792  << new StaticFunction( "within", 2, fcnWithin, "GeometryGroup" )
1793  << new StaticFunction( "buffer", -1, fcnBuffer, "GeometryGroup" )
1794  << new StaticFunction( "centroid", 1, fcnCentroid, "GeometryGroup" )
1795  << new StaticFunction( "bounds", 1, fcnBounds, "GeometryGroup", "", true )
1796  << new StaticFunction( "bounds_width", 1, fcnBoundsWidth, "GeometryGroup", "", true )
1797  << new StaticFunction( "bounds_height", 1, fcnBoundsHeight, "GeometryGroup", "", true )
1798  << new StaticFunction( "convexHull", 1, fcnConvexHull, "GeometryGroup" )
1799  << new StaticFunction( "difference", 2, fcnDifference, "GeometryGroup" )
1800  << new StaticFunction( "distance", 2, fcnDistance, "GeometryGroup" )
1801  << new StaticFunction( "intersection", 2, fcnIntersection, "GeometryGroup" )
1802  << new StaticFunction( "symDifference", 2, fcnSymDifference, "GeometryGroup" )
1803  << new StaticFunction( "combine", 2, fcnCombine, "GeometryGroup" )
1804  << new StaticFunction( "union", 2, fcnCombine, "GeometryGroup" )
1805  << new StaticFunction( "geomToWKT", -1, fcnGeomToWKT, "GeometryGroup" )
1806  << new StaticFunction( "geometry", 1, fcnGetGeometry, "GeometryGroup" )
1807  << new StaticFunction( "transform", 3, fcnTransformGeometry, "GeometryGroup" )
1808  << new StaticFunction( "$rownum", 0, fcnRowNumber, "Record" )
1809  << new StaticFunction( "$id", 0, fcnFeatureId, "Record" )
1810  << new StaticFunction( "$currentfeature", 0, fcnFeature, "Record" )
1811  << new StaticFunction( "$scale", 0, fcnScale, "Record" )
1812  << new StaticFunction( "$uuid", 0, fcnUuid, "Record" )
1813  << new StaticFunction( "getFeature", 3, fcnGetFeature, "Record" )
1814 
1815  //return all attributes string for referencedColumns - this is caught by
1816  // QgsFeatureRequest::setSubsetOfAttributes and causes all attributes to be fetched by the
1817  // feature request
1818  << new StaticFunction( "attribute", 2, fcnAttribute, "Record", QString(), false, QStringList( QgsFeatureRequest::AllAttributes ) )
1819 
1820  << new StaticFunction( "_specialcol_", 1, fcnSpecialColumn, "Special" )
1821  ;
1822  }
1823  return gmFunctions;
1824 }
1825 
1826 QMap<QString, QVariant> QgsExpression::gmSpecialColumns;
1827 QMap<QString, QString> QgsExpression::gmSpecialColumnGroups;
1828 
1829 void QgsExpression::setSpecialColumn( const QString& name, QVariant variant )
1830 {
1831  int fnIdx = functionIndex( name );
1832  if ( fnIdx != -1 )
1833  {
1834  // function of the same name already exists
1835  return;
1836  }
1837  gmSpecialColumns[ name ] = variant;
1838 }
1839 
1840 void QgsExpression::unsetSpecialColumn( const QString& name )
1841 {
1842  QMap<QString, QVariant>::iterator fit = gmSpecialColumns.find( name );
1843  if ( fit != gmSpecialColumns.end() )
1844  {
1845  gmSpecialColumns.erase( fit );
1846  }
1847 }
1848 
1849 QVariant QgsExpression::specialColumn( const QString& name )
1850 {
1851  int fnIdx = functionIndex( name );
1852  if ( fnIdx != -1 )
1853  {
1854  // function of the same name already exists
1855  return QVariant();
1856  }
1857  QMap<QString, QVariant>::iterator it = gmSpecialColumns.find( name );
1858  if ( it == gmSpecialColumns.end() )
1859  {
1860  return QVariant();
1861  }
1862  return it.value();
1863 }
1864 
1865 bool QgsExpression::hasSpecialColumn( const QString& name )
1866 {
1867  static bool initialized = false;
1868  if ( !initialized )
1869  {
1870  // Pre-register special columns that will exist within QGIS so that expressions that may use them are parsed correctly.
1871  // This is really sub-optimal, we should get rid of the special columns and instead have contexts in which some values
1872  // are defined and some are not ($rownum makes sense only in field calculator, $scale only when rendering, $page only for composer etc.)
1873 
1874  //pairs of column name to group name
1875  QList< QPair<QString, QString> > lst;
1876  lst << qMakePair( QString( "$page" ), QString( "Composer" ) );
1877  lst << qMakePair( QString( "$feature" ), QString( "Atlas" ) );
1878  lst << qMakePair( QString( "$numpages" ), QString( "Composer" ) );
1879  lst << qMakePair( QString( "$numfeatures" ), QString( "Atlas" ) );
1880  lst << qMakePair( QString( "$atlasfeatureid" ), QString( "Atlas" ) );
1881  lst << qMakePair( QString( "$atlasgeometry" ), QString( "Atlas" ) );
1882  lst << qMakePair( QString( "$atlasfeature" ), QString( "Atlas" ) );
1883  lst << qMakePair( QString( "$map" ), QString( "Composer" ) );
1884 
1885  QList< QPair<QString, QString> >::const_iterator it = lst.constBegin();
1886  for ( ; it != lst.constEnd(); ++it )
1887  {
1888  setSpecialColumn(( *it ).first, QVariant() );
1889  gmSpecialColumnGroups[( *it ).first ] = ( *it ).second;
1890  }
1891 
1892  initialized = true;
1893  }
1894 
1895  if ( functionIndex( name ) != -1 )
1896  return false;
1897  return gmSpecialColumns.contains( name );
1898 }
1899 
1900 bool QgsExpression::isValid( const QString &text, const QgsFields &fields, QString &errorMessage )
1901 {
1902  QgsExpression exp( text );
1903  exp.prepare( fields );
1904  errorMessage = exp.parserErrorString();
1905  return !exp.hasParserError();
1906 }
1907 
1908 QList<QgsExpression::Function*> QgsExpression::specialColumns()
1909 {
1910  QList<Function*> defs;
1911  for ( QMap<QString, QVariant>::const_iterator it = gmSpecialColumns.begin(); it != gmSpecialColumns.end(); ++it )
1912  {
1913  //check for special column group name
1914  QString group = gmSpecialColumnGroups.value( it.key(), "Record" );
1915  defs << new StaticFunction( it.key(), 0, 0, group );
1916  }
1917  return defs;
1918 }
1919 
1920 QString QgsExpression::quotedColumnRef( QString name )
1921 {
1922  return QString( "\"%1\"" ).arg( name.replace( "\"", "\"\"" ) );
1923 }
1924 
1925 QString QgsExpression::quotedString( QString text )
1926 {
1927  text.replace( "'", "''" );
1928  text.replace( '\\', "\\\\" );
1929  text.replace( '\n', "\\n" );
1930  text.replace( '\t', "\\t" );
1931  return QString( "'%1'" ).arg( text );
1932 }
1933 
1934 bool QgsExpression::isFunctionName( QString name )
1935 {
1936  return functionIndex( name ) != -1;
1937 }
1938 
1939 int QgsExpression::functionIndex( QString name )
1940 {
1941  int count = functionCount();
1942  for ( int i = 0; i < count; i++ )
1943  {
1944  if ( QString::compare( name, Functions()[i]->name(), Qt::CaseInsensitive ) == 0 )
1945  return i;
1946  }
1947  return -1;
1948 }
1949 
1951 {
1952  return Functions().size();
1953 }
1954 
1955 
1956 QgsExpression::QgsExpression( const QString& expr )
1957  : mRowNumber( 0 )
1958  , mScale( 0 )
1959  , mExp( expr )
1960  , mCalc( 0 )
1961 {
1963 
1964  if ( mParserErrorString.isNull() )
1965  Q_ASSERT( mRootNode );
1966 }
1967 
1969 {
1970  delete mCalc;
1971  delete mRootNode;
1972 }
1973 
1975 {
1976  if ( !mRootNode )
1977  return QStringList();
1978 
1979  QStringList columns = mRootNode->referencedColumns();
1980 
1981  // filter out duplicates
1982  for ( int i = 0; i < columns.count(); i++ )
1983  {
1984  QString col = columns.at( i );
1985  for ( int j = i + 1; j < columns.count(); j++ )
1986  {
1987  if ( QString::compare( col, columns[j], Qt::CaseInsensitive ) == 0 )
1988  {
1989  // this column is repeated: remove it!
1990  columns.removeAt( j-- );
1991  }
1992  }
1993  }
1994 
1995  return columns;
1996 }
1997 
1999 {
2000  if ( !mRootNode )
2001  return false;
2002  return mRootNode->needsGeometry();
2003 }
2004 
2006 {
2007  if ( mCalc )
2008  return;
2009 
2010  // Use planimetric as default
2011  mCalc = new QgsDistanceArea();
2012  mCalc->setEllipsoidalMode( false );
2013 }
2014 
2016 {
2017  delete mCalc;
2018  mCalc = new QgsDistanceArea( calc );
2019 }
2020 
2021 bool QgsExpression::prepare( const QgsFields& fields )
2022 {
2023  mEvalErrorString = QString();
2024  if ( !mRootNode )
2025  {
2026  mEvalErrorString = QObject::tr( "No root node! Parsing failed?" );
2027  return false;
2028  }
2029 
2030  return mRootNode->prepare( this, fields );
2031 }
2032 
2034 {
2035  mEvalErrorString = QString();
2036  if ( !mRootNode )
2037  {
2038  mEvalErrorString = QObject::tr( "No root node! Parsing failed?" );
2039  return QVariant();
2040  }
2041 
2042  return mRootNode->eval( this, f );
2043 }
2044 
2045 QVariant QgsExpression::evaluate( const QgsFeature* f, const QgsFields& fields )
2046 {
2047  // first prepare
2048  bool res = prepare( fields );
2049  if ( !res )
2050  return QVariant();
2051 
2052  // then evaluate
2053  return evaluate( f );
2054 }
2055 
2056 QString QgsExpression::dump() const
2057 {
2058  if ( !mRootNode )
2059  return QObject::tr( "(no root)" );
2060 
2061  return mRootNode->dump();
2062 }
2063 
2065 {
2066  if ( mRootNode )
2067  mRootNode->accept( v );
2068 }
2069 
2070 QString QgsExpression::replaceExpressionText( const QString &action, const QgsFeature *feat,
2071  QgsVectorLayer *layer,
2072  const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
2073 {
2074  QString expr_action;
2075 
2076  QMap<QString, QVariant> savedValues;
2077  if ( substitutionMap )
2078  {
2079  // variables with a local scope (must be restored after evaluation)
2080  for ( QMap<QString, QVariant>::const_iterator sit = substitutionMap->begin(); sit != substitutionMap->end(); ++sit )
2081  {
2082  QVariant oldValue = QgsExpression::specialColumn( sit.key() );
2083  if ( !oldValue.isNull() )
2084  savedValues.insert( sit.key(), oldValue );
2085 
2086  // set the new value
2087  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
2088  }
2089  }
2090 
2091  int index = 0;
2092  while ( index < action.size() )
2093  {
2094  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
2095 
2096  int pos = rx.indexIn( action, index );
2097  if ( pos < 0 )
2098  break;
2099 
2100  int start = index;
2101  index = pos + rx.matchedLength();
2102  QString to_replace = rx.cap( 1 ).trimmed();
2103  QgsDebugMsg( "Found expression: " + to_replace );
2104 
2105  QgsExpression exp( to_replace );
2106  if ( exp.hasParserError() )
2107  {
2108  QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
2109  expr_action += action.mid( start, index - start );
2110  continue;
2111  }
2112 
2113  if ( distanceArea )
2114  {
2115  //if QgsDistanceArea specified for area/distance conversion, use it
2116  exp.setGeomCalculator( *distanceArea );
2117  }
2118 
2119  QVariant result;
2120  if ( layer )
2121  {
2122  result = exp.evaluate( feat, layer->pendingFields() );
2123  }
2124  else
2125  {
2126  result = exp.evaluate( feat );
2127  }
2128  if ( exp.hasEvalError() )
2129  {
2130  QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
2131  expr_action += action.mid( start, index - start );
2132  continue;
2133  }
2134 
2135  QgsDebugMsg( "Expression result is: " + result.toString() );
2136  expr_action += action.mid( start, pos - start ) + result.toString();
2137  }
2138 
2139  expr_action += action.mid( index );
2140 
2141  // restore overwritten local values
2142  for ( QMap<QString, QVariant>::const_iterator sit = savedValues.begin(); sit != savedValues.end(); ++sit )
2143  {
2144  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
2145  }
2146 
2147  return expr_action;
2148 }
2149 
2150 double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
2151 {
2152  bool ok;
2153  //first test if text is directly convertible to double
2154  double convertedValue = text.toDouble( &ok );
2155  if ( ok )
2156  {
2157  return convertedValue;
2158  }
2159 
2160  //otherwise try to evalute as expression
2161  QgsExpression expr( text );
2162  QVariant result = expr.evaluate();
2163  convertedValue = result.toDouble( &ok );
2164  if ( expr.hasEvalError() || !ok )
2165  {
2166  return fallbackValue;
2167  }
2168  return convertedValue;
2169 }
2170 
2171 
2173 // nodes
2174 
2176 {
2177  QString msg; bool first = true;
2178  foreach ( Node* n, mList )
2179  {
2180  if ( !first ) msg += ", "; else first = false;
2181  msg += n->dump();
2182  }
2183  return msg;
2184 }
2185 
2186 
2187 //
2188 
2190 {
2191  QVariant val = mOperand->eval( parent, f );
2193 
2194  switch ( mOp )
2195  {
2196  case uoNot:
2197  {
2198  TVL tvl = getTVLValue( val, parent );
2200  return tvl2variant( NOT[tvl] );
2201  }
2202 
2203  case uoMinus:
2204  if ( isIntSafe( val ) )
2205  return QVariant( - getIntValue( val, parent ) );
2206  else if ( isDoubleSafe( val ) )
2207  return QVariant( - getDoubleValue( val, parent ) );
2208  else
2209  SET_EVAL_ERROR( QObject::tr( "Unary minus only for numeric values." ) );
2210  break;
2211  default:
2212  Q_ASSERT( 0 && "unknown unary operation" );
2213  }
2214  return QVariant();
2215 }
2216 
2218 {
2219  return mOperand->prepare( parent, fields );
2220 }
2221 
2223 {
2224  return QString( "%1 %2" ).arg( UnaryOperatorText[mOp] ).arg( mOperand->dump() );
2225 }
2226 
2227 //
2228 
2230 {
2231  QVariant vL = mOpLeft->eval( parent, f );
2233  QVariant vR = mOpRight->eval( parent, f );
2235 
2236  switch ( mOp )
2237  {
2238  case boPlus:
2239  if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
2240  {
2241  QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2242  QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2243  return QVariant( sL + sR );
2244  }
2245  //intentional fall-through
2246  case boMinus:
2247  case boMul:
2248  case boDiv:
2249  case boMod:
2250  {
2251  if ( isNull( vL ) || isNull( vR ) )
2252  return QVariant();
2253  else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
2254  {
2255  // both are integers - let's use integer arithmetics
2256  int iL = getIntValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2257  int iR = getIntValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2258 
2259  if ( mOp == boMod && iR == 0 )
2260  return QVariant();
2261 
2262  return QVariant( computeInt( iL, iR ) );
2263  }
2264  else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
2265  {
2266  QDateTime dL = getDateTimeValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2268  if ( mOp == boDiv || mOp == boMul || mOp == boMod )
2269  {
2270  parent->setEvalErrorString( QObject::tr( "Can't preform /, *, or % on DateTime and Interval" ) );
2271  return QVariant();
2272  }
2273  return QVariant( computeDateTimeFromInterval( dL, &iL ) );
2274  }
2275  else
2276  {
2277  // general floating point arithmetic
2278  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2279  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2280  if (( mOp == boDiv || mOp == boMod ) && fR == 0. )
2281  return QVariant(); // silently handle division by zero and return NULL
2282  return QVariant( computeDouble( fL, fR ) );
2283  }
2284  }
2285  case boIntDiv:
2286  {
2287  //integer division
2288  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2289  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2290  if ( fR == 0. )
2291  return QVariant(); // silently handle division by zero and return NULL
2292  return QVariant( qFloor( fL / fR ) );
2293  }
2294  case boPow:
2295  if ( isNull( vL ) || isNull( vR ) )
2296  return QVariant();
2297  else
2298  {
2299  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2300  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2301  return QVariant( pow( fL, fR ) );
2302  }
2303 
2304  case boAnd:
2305  {
2306  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
2308  return tvl2variant( AND[tvlL][tvlR] );
2309  }
2310 
2311  case boOr:
2312  {
2313  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
2315  return tvl2variant( OR[tvlL][tvlR] );
2316  }
2317 
2318  case boEQ:
2319  case boNE:
2320  case boLT:
2321  case boGT:
2322  case boLE:
2323  case boGE:
2324  if ( isNull( vL ) || isNull( vR ) )
2325  {
2326  return TVL_Unknown;
2327  }
2328  else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) )
2329  {
2330  // do numeric comparison if both operators can be converted to numbers
2331  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2332  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2333  return compare( fL - fR ) ? TVL_True : TVL_False;
2334  }
2335  else
2336  {
2337  // do string comparison otherwise
2338  QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2339  QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2340  int diff = QString::compare( sL, sR );
2341  return compare( diff ) ? TVL_True : TVL_False;
2342  }
2343 
2344  case boIs:
2345  case boIsNot:
2346  if ( isNull( vL ) && isNull( vR ) ) // both operators null
2347  return ( mOp == boIs ? TVL_True : TVL_False );
2348  else if ( isNull( vL ) || isNull( vR ) ) // one operator null
2349  return ( mOp == boIs ? TVL_False : TVL_True );
2350  else // both operators non-null
2351  {
2352  bool equal = false;
2353  if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) )
2354  {
2355  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2356  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2357  equal = fL == fR;
2358  }
2359  else
2360  {
2361  QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2362  QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2363  equal = QString::compare( sL, sR ) == 0;
2364  }
2365  if ( equal )
2366  return mOp == boIs ? TVL_True : TVL_False;
2367  else
2368  return mOp == boIs ? TVL_False : TVL_True;
2369  }
2370 
2371  case boRegexp:
2372  case boLike:
2373  case boNotLike:
2374  case boILike:
2375  case boNotILike:
2376  if ( isNull( vL ) || isNull( vR ) )
2377  return TVL_Unknown;
2378  else
2379  {
2380  QString str = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2381  QString regexp = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2382  // TODO: cache QRegExp in case that regexp is a literal string (i.e. it will stay constant)
2383  bool matches;
2384  if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
2385  {
2386  QString esc_regexp = QRegExp::escape( regexp );
2387  // XXX escape % and _ ???
2388  esc_regexp.replace( "%", ".*" );
2389  esc_regexp.replace( "_", "." );
2390  matches = QRegExp( esc_regexp, mOp == boLike || mOp == boNotLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( str );
2391  }
2392  else
2393  {
2394  matches = QRegExp( regexp ).indexIn( str ) != -1;
2395  }
2396 
2397  if ( mOp == boNotLike || mOp == boNotILike )
2398  {
2399  matches = !matches;
2400  }
2401 
2402  return matches ? TVL_True : TVL_False;
2403  }
2404 
2405  case boConcat:
2406  if ( isNull( vL ) || isNull( vR ) )
2407  return QVariant();
2408  else
2409  {
2410  QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2411  QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2412  return QVariant( sL + sR );
2413  }
2414 
2415  default: break;
2416  }
2417  Q_ASSERT( false );
2418  return QVariant();
2419 }
2420 
2422 {
2423  switch ( mOp )
2424  {
2425  case boEQ: return diff == 0;
2426  case boNE: return diff != 0;
2427  case boLT: return diff < 0;
2428  case boGT: return diff > 0;
2429  case boLE: return diff <= 0;
2430  case boGE: return diff >= 0;
2431  default: Q_ASSERT( false ); return false;
2432  }
2433 }
2434 
2436 {
2437  switch ( mOp )
2438  {
2439  case boPlus: return x+y;
2440  case boMinus: return x-y;
2441  case boMul: return x*y;
2442  case boDiv: return x/y;
2443  case boMod: return x%y;
2444  default: Q_ASSERT( false ); return 0;
2445  }
2446 }
2447 
2449 {
2450  switch ( mOp )
2451  {
2452  case boPlus: return d.addSecs( i->seconds() );
2453  case boMinus: return d.addSecs( -i->seconds() );
2454  default: Q_ASSERT( false ); return QDateTime();
2455  }
2456 }
2457 
2459 {
2460  switch ( mOp )
2461  {
2462  case boPlus: return x+y;
2463  case boMinus: return x-y;
2464  case boMul: return x*y;
2465  case boDiv: return x/y;
2466  case boMod: return fmod( x,y );
2467  default: Q_ASSERT( false ); return 0;
2468  }
2469 }
2470 
2471 
2473 {
2474  bool resL = mOpLeft->prepare( parent, fields );
2475  bool resR = mOpRight->prepare( parent, fields );
2476  return resL && resR;
2477 }
2478 
2480 {
2481  // see left/right in qgsexpressionparser.yy
2482  switch ( mOp )
2483  {
2484  case boOr:
2485  return 1;
2486 
2487  case boAnd:
2488  return 2;
2489 
2490  case boEQ:
2491  case boNE:
2492  case boLE:
2493  case boGE:
2494  case boLT:
2495  case boGT:
2496  case boRegexp:
2497  case boLike:
2498  case boILike:
2499  case boNotLike:
2500  case boNotILike:
2501  case boIs:
2502  case boIsNot:
2503  return 3;
2504 
2505  case boPlus:
2506  case boMinus:
2507  return 4;
2508 
2509  case boMul:
2510  case boDiv:
2511  case boIntDiv:
2512  case boMod:
2513  return 5;
2514 
2515  case boPow:
2516  return 6;
2517 
2518  case boConcat:
2519  return 7;
2520  }
2521  Q_ASSERT( 0 && "unexpected binary operator" );
2522  return -1;
2523 }
2524 
2526 {
2527  QgsExpression::NodeBinaryOperator *lOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpLeft );
2528  QgsExpression::NodeBinaryOperator *rOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpRight );
2529 
2530  QString fmt;
2531  fmt += lOp && lOp->precedence() < precedence() ? "(%1)" : "%1";
2532  fmt += " %2 ";
2533  fmt += rOp && rOp->precedence() <= precedence() ? "(%3)" : "%3";
2534 
2535  return fmt.arg( mOpLeft->dump() ).arg( BinaryOperatorText[mOp] ).arg( mOpRight->dump() );
2536 }
2537 
2538 //
2539 
2541 {
2542  if ( mList->count() == 0 )
2543  return mNotIn ? TVL_True : TVL_False;
2544  QVariant v1 = mNode->eval( parent, f );
2546  if ( isNull( v1 ) )
2547  return TVL_Unknown;
2548 
2549  bool listHasNull = false;
2550 
2551  foreach ( Node* n, mList->list() )
2552  {
2553  QVariant v2 = n->eval( parent, f );
2555  if ( isNull( v2 ) )
2556  listHasNull = true;
2557  else
2558  {
2559  bool equal = false;
2560  // check whether they are equal
2561  if ( isDoubleSafe( v1 ) && isDoubleSafe( v2 ) )
2562  {
2563  double f1 = getDoubleValue( v1, parent ); ENSURE_NO_EVAL_ERROR;
2564  double f2 = getDoubleValue( v2, parent ); ENSURE_NO_EVAL_ERROR;
2565  equal = f1 == f2;
2566  }
2567  else
2568  {
2569  QString s1 = getStringValue( v1, parent ); ENSURE_NO_EVAL_ERROR;
2570  QString s2 = getStringValue( v2, parent ); ENSURE_NO_EVAL_ERROR;
2571  equal = QString::compare( s1, s2 ) == 0;
2572  }
2573 
2574  if ( equal ) // we know the result
2575  return mNotIn ? TVL_False : TVL_True;
2576  }
2577  }
2578 
2579  // item not found
2580  if ( listHasNull )
2581  return TVL_Unknown;
2582  else
2583  return mNotIn ? TVL_True : TVL_False;
2584 }
2585 
2587 {
2588  bool res = mNode->prepare( parent, fields );
2589  foreach ( Node* n, mList->list() )
2590  {
2591  res = res && n->prepare( parent, fields );
2592  }
2593  return res;
2594 }
2595 
2597 {
2598  return QString( "%1 IN (%2)" ).arg( mNode->dump() ).arg( mList->dump() );
2599 }
2600 
2601 //
2602 
2604 {
2605  Function* fd = Functions()[mFnIndex];
2606 
2607  // evaluate arguments
2608  QVariantList argValues;
2609  if ( mArgs )
2610  {
2611  foreach ( Node* n, mArgs->list() )
2612  {
2613  QVariant v;
2614  if ( fd->lazyEval() )
2615  {
2616  // Pass in the node for the function to eval as it needs.
2617  v = QVariant::fromValue( n );
2618  }
2619  else
2620  {
2621  v = n->eval( parent, f );
2623  if ( isNull( v ) && fd->name() != "coalesce" )
2624  return QVariant(); // all "normal" functions return NULL, when any parameter is NULL (so coalesce is abnormal)
2625  }
2626  argValues.append( v );
2627  }
2628  }
2629 
2630  // run the function
2631  QVariant res = fd->func( argValues, f, parent );
2633 
2634  // everything went fine
2635  return res;
2636 }
2637 
2639 {
2640  bool res = true;
2641  if ( mArgs )
2642  {
2643  foreach ( Node* n, mArgs->list() )
2644  {
2645  res = res && n->prepare( parent, fields );
2646  }
2647  }
2648  return res;
2649 }
2650 
2652 {
2653  Function* fd = Functions()[mFnIndex];
2654  if ( fd->params() == 0 )
2655  return fd->name(); // special column
2656  else
2657  return QString( "%1(%2)" ).arg( fd->name() ).arg( mArgs ? mArgs->dump() : QString() ); // function
2658 }
2659 
2661 {
2662  Function* fd = Functions()[mFnIndex];
2663  QStringList functionColumns = fd->referencedColumns();
2664 
2665  if ( !mArgs )
2666  {
2667  //no referenced columns in arguments, just return function's referenced columns
2668  return functionColumns;
2669  }
2670 
2671  foreach ( Node* n, mArgs->list() )
2672  {
2673  functionColumns.append( n->referencedColumns() );
2674  }
2675 
2676  //remove duplicates and return
2677  return functionColumns.toSet().toList();
2678 }
2679 
2680 //
2681 
2683 {
2684  return mValue;
2685 }
2686 
2687 bool QgsExpression::NodeLiteral::prepare( QgsExpression* /*parent*/, const QgsFields& /*fields*/ )
2688 {
2689  return true;
2690 }
2691 
2692 
2694 {
2695  if ( mValue.isNull() )
2696  return "NULL";
2697 
2698  switch ( mValue.type() )
2699  {
2700  case QVariant::Int: return QString::number( mValue.toInt() );
2701  case QVariant::Double: return QString::number( mValue.toDouble() );
2702  case QVariant::String: return quotedString( mValue.toString() );
2703  default: return QObject::tr( "[unsupported type;%1; value:%2]" ).arg( mValue.typeName() ).arg( mValue.toString() );
2704  }
2705 }
2706 
2707 //
2708 
2710 {
2711  if ( f )
2712  {
2713  if ( mIndex >= 0 )
2714  return f->attribute( mIndex );
2715  else
2716  return f->attribute( mName );
2717  }
2718  return QVariant( "[" + mName + "]" );
2719 }
2720 
2722 {
2723  for ( int i = 0; i < fields.count(); ++i )
2724  {
2725  if ( QString::compare( fields[i].name(), mName, Qt::CaseInsensitive ) == 0 )
2726  {
2727  mIndex = i;
2728  return true;
2729  }
2730  }
2731  parent->mEvalErrorString = QObject::tr( "Column '%1' not found" ).arg( mName );
2732  mIndex = -1;
2733  return false;
2734 }
2735 
2737 {
2738  return QRegExp( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ).exactMatch( mName ) ? mName : quotedColumnRef( mName );
2739 }
2740 
2741 //
2742 
2744 {
2745  foreach ( WhenThen* cond, mConditions )
2746  {
2747  QVariant vWhen = cond->mWhenExp->eval( parent, f );
2748  TVL tvl = getTVLValue( vWhen, parent );
2750  if ( tvl == True )
2751  {
2752  QVariant vRes = cond->mThenExp->eval( parent, f );
2754  return vRes;
2755  }
2756  }
2757 
2758  if ( mElseExp )
2759  {
2760  QVariant vElse = mElseExp->eval( parent, f );
2762  return vElse;
2763  }
2764 
2765  // return NULL if no condition is matching
2766  return QVariant();
2767 }
2768 
2770 {
2771  bool res;
2772  foreach ( WhenThen* cond, mConditions )
2773  {
2774  res = cond->mWhenExp->prepare( parent, fields )
2775  & cond->mThenExp->prepare( parent, fields );
2776  if ( !res ) return false;
2777  }
2778 
2779  if ( mElseExp )
2780  return mElseExp->prepare( parent, fields );
2781 
2782  return true;
2783 }
2784 
2786 {
2787  QString msg = QString( "CASE" );
2788  foreach ( WhenThen* cond, mConditions )
2789  {
2790  msg += QString( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump() ).arg( cond->mThenExp->dump() );
2791  }
2792  if ( mElseExp )
2793  msg += QString( " ELSE %1" ).arg( mElseExp->dump() );
2794  msg += QString( " END" );
2795  return msg;
2796 }
2797 
2799 {
2800  QStringList lst;
2801  foreach ( WhenThen* cond, mConditions )
2802  {
2803  lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
2804  }
2805 
2806  if ( mElseExp )
2807  lst += mElseExp->referencedColumns();
2808 
2809  return lst;
2810 }
2811 
2813 {
2814  foreach ( WhenThen* cond, mConditions )
2815  {
2816  if ( cond->mWhenExp->needsGeometry() ||
2817  cond->mThenExp->needsGeometry() )
2818  return true;
2819  }
2820 
2821  if ( mElseExp && mElseExp->needsGeometry() )
2822  return true;
2823 
2824  return false;
2825 }
2826 
2827 QString QgsExpression::helptext( QString name )
2828 {
2830  return gFunctionHelpTexts.value( name, QObject::tr( "function help for %1 missing" ).arg( name ) );
2831 }
2832 
2833 QHash<QString, QString> QgsExpression::gGroups;
2834 
2835 QString QgsExpression::group( QString name )
2836 {
2837  if ( gGroups.isEmpty() )
2838  {
2839  gGroups.insert( "Operators", QObject::tr( "Operators" ) );
2840  gGroups.insert( "Conditionals", QObject::tr( "Conditionals" ) );
2841  gGroups.insert( "Fields and Values", QObject::tr( "Fields and Values" ) );
2842  gGroups.insert( "Math", QObject::tr( "Math" ) );
2843  gGroups.insert( "Conversions", QObject::tr( "Conversions" ) );
2844  gGroups.insert( "Date and Time", QObject::tr( "Date and Time" ) );
2845  gGroups.insert( "String", QObject::tr( "String" ) );
2846  gGroups.insert( "Color", QObject::tr( "Color" ) );
2847  gGroups.insert( "GeometryGroup", QObject::tr( "Geometry" ) );
2848  gGroups.insert( "Record", QObject::tr( "Record" ) );
2849  }
2850 
2851  //return the translated name for this group. If group does not
2852  //have a translated name in the gGroups hash, return the name
2853  //unchanged
2854  return gGroups.value( name, name );
2855 }
virtual QVariant eval(QgsExpression *parent, const QgsFeature *f) override
QgsFeatureId id() const
Get the feature id for this feature.
Definition: qgsfeature.cpp:100
static QVariant fcnDifference(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnCombine(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:87
static int functionIndex(QString name)
static QVariant fcnAge(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnColorHsv(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
virtual QStringList referencedColumns() const =0
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
Wrapper for iterator of features from vector data provider or vector layer.
static QVariant fcnCeil(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnLog10(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnDistance(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QgsExpression::Interval fromString(QString string)
static unsigned index
static QVariant fcnFeatureId(const QVariantList &, const QgsFeature *f, QgsExpression *)
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:94
virtual QString dump() const override
static QVariant fcnAsin(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
QStringList referencedColumns() const
Get list of columns referenced by the expression.
static QVariant fcnMin(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnTrim(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnLeft(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static bool unregisterFunction(QString name)
static QString quotedColumnRef(QString name)
return quoted column reference (in double quotes)
static QVariant fcnLog(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnYat(const QVariantList &values, const QgsFeature *f, QgsExpression *parent)
static QVariant fcnMinute(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnRight(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
bool lazyEval()
True if this function should use lazy evaluation.
virtual bool prepare(QgsExpression *parent, const QgsFields &fields) override
QgsGeometry * combine(QgsGeometry *geometry)
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
static QVariant fcnYMax(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnReplace(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
void initGeomCalculator()
static QVariant fcnTouches(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
A abstract base class for defining QgsExpression functions.
bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:188
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
static QVariant fcnGeomLength(const QVariantList &, const QgsFeature *f, QgsExpression *parent)
static QVariant fcnScale(const QVariantList &, const QgsFeature *, QgsExpression *parent)
double computeDouble(double x, double y)
virtual QString dump() const =0
static QDate getDateValue(const QVariant &value, QgsExpression *parent)
QVector< QgsPoint > QgsPolyline
polyline is represented as a vector of points
Definition: qgsgeometry.h:33
static QVariant fcnFloor(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
virtual QVariant eval(QgsExpression *parent, const QgsFeature *f) override
static QString helptext(QString name)
static QVariant fcnXMin(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
QgsGeometry * geometry() const
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:112
static QVariant fcnFormatDate(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnIf(const QVariantList &values, const QgsFeature *f, QgsExpression *parent)
virtual QVariant eval(QgsExpression *parent, const QgsFeature *f) override
static QgsMapLayerRegistry * instance()
Definition: qgssingleton.h:23
QgsExpression()
Used by QgsOgcUtils to create an empty.
static QVariant fcnToTime(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnSqrt(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnIntersects(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnNow(const QVariantList &, const QgsFeature *, QgsExpression *)
QVariant fcnRampColor(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
bool crosses(const QgsGeometry *geometry) const
Test for if geometry crosses another (uses GEOS)
Container of fields for a vector layer.
Definition: qgsfield.h:172
static QVariant fcnSin(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnContains(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnToInt(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsFields &fields)=0
QgsExpression::Node * parseExpression(const QString &str, QString &parserErrorMsg)
static QVariant fcnToDateTime(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QString group(QString group)
static QTime getTimeValue(const QVariant &value, QgsExpression *parent)
QString dump() const
Return the expression string that represents this QgsExpression.
bool isDoubleSafe(const QVariant &v)
virtual QVariant eval(QgsExpression *parent, const QgsFeature *f) override
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:156
static QVariant fcnStrpos(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnYMin(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static TVL getTVLValue(const QVariant &value, QgsExpression *parent)
int currentRowNumber()
Return the number used for $rownum special column.
static QVariant fcnBuffer(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static bool isValid(const QString &text, const QgsFields &fields, QString &errorMessage)
QgsGeometry * difference(QgsGeometry *geometry)
Returns a geometry representing the points making up this geometry that do not make up other...
QString mEvalErrorString
static QVariant fcnYear(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnFormatString(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsFields &fields) override
virtual QString dump() const override
static QVariant fcnToString(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnCrosses(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnToInterval(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
QgsGeometry * centroid()
Returns the center of mass of a geometry.
static QVariant fcnTan(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QgsGeometry getGeometry(const QVariant &value, QgsExpression *parent)
#define ENSURE_NO_EVAL_ERROR
QString mParserErrorString
virtual QString dump() const override
static QVariant fcnLower(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QString encodeColor(QColor color)
static QVariant fcnAbs(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnCos(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnCoalesce(const QVariantList &values, const QgsFeature *, QgsExpression *)
static QVariant fcnCentroid(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static const QStringList & BuiltinFunctions()
static const QList< Function * > & Functions()
static QVariant fcnToReal(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnGetGeometry(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static bool isFunctionName(QString name)
static QVariant fcnIntersection(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
bool createFromOgcWmsCrs(QString theCrs)
Set up this CRS from the given OGC CRS.
static QHash< QString, QString > gFunctionHelpTexts
static int functionCount()
Returns the number of functions defined in the parser.
virtual bool needsGeometry() const override
void acceptVisitor(Visitor &v) const
entry function for the visitor pattern
bool contains(const QgsPoint *p) const
Test for containment of a point (uses GEOS)
static QVariant fcnTransformGeometry(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
virtual QVariant eval(QgsExpression *parent, const QgsFeature *f) override
virtual QVariant eval(QgsExpression *parent, const QgsFeature *f) override
static QVariant fcnAttribute(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnLPad(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant pointAt(const QVariantList &values, const QgsFeature *f, QgsExpression *parent)
QgsDistanceArea * geomCalculator()
Return calculator used for distance and area calculations (used by internal functions) ...
#define TVL_Unknown
static QVariant fcnOverlaps(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnHour(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
const QgsVectorColorRampV2 * colorRampRef(QString name) const
return a const pointer to a symbol (doesn&#39;t create new instance)
Definition: qgsstylev2.cpp:266
QgsGeometry * buffer(double distance, int segments)
Returns a buffer region around this geometry having the given width and with a specified number of se...
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:193
static QVariant fcnFeature(const QVariantList &, const QgsFeature *f, QgsExpression *)
virtual bool prepare(QgsExpression *parent, const QgsFields &fields) override
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:178
double measurePerimeter(QgsGeometry *geometry)
measures perimeter of polygon
virtual QString dump() const override
double measure(QgsGeometry *geometry)
general measurement (line distance or polygon area)
static bool registerFunction(Function *function)
static QVariant fcnAtan2(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
QgsDistanceArea * mCalc
QgsGeometry * convexHull()
Returns the smallest convex polygon that contains all the points in the geometry. ...
static QVariant fncColorHsla(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QgsGeometry * geometryFromGML(const QString &xmlString)
static method that creates geometry from GML
Definition: qgsogcutils.cpp:81
#define SET_EVAL_ERROR(x)
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
bool overlaps(const QgsGeometry *geometry) const
Test for if geometry overlaps another (uses GEOS)
static QHash< QString, QString > gGroups
static QgsStyleV2 * defaultStyle()
return default application-wide style
Definition: qgsstylev2.cpp:51
virtual QVariant func(const QVariantList &values, const QgsFeature *f, QgsExpression *parent)=0
bool operator==(const QgsExpression::Interval &other) const
static bool hasSpecialColumn(const QString &name)
Check whether a special column exists.
static QVariant fcnGeomPerimeter(const QVariantList &, const QgsFeature *f, QgsExpression *parent)
virtual QString dump() const override
#define M_PI
This class wraps a request for features to a vector layer (or directly its vector data provider)...
static QVariant fcnY(const QVariantList &, const QgsFeature *f, QgsExpression *)
static QVariant fcnRndF(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static const QString AllAttributes
QDateTime computeDateTimeFromInterval(QDateTime d, QgsExpression::Interval *i)
double scale()
int count() const
Return number of items.
Definition: qgsfield.h:214
#define TVL_False
static QVariant fcnGeomToWKT(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnGetFeature(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnSpecialColumn(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QList< Function * > gmFunctions
virtual bool prepare(QgsExpression *parent, const QgsFields &fields) override
static QVariant fcnWordwrap(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsFields &fields) override
virtual QString dump() const
static QVariant fcnLength(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
QString name()
The name of the function.
static QVariant tvl2variant(TVL v)
#define ENSURE_GEOM_TYPE(f, g, geomtype)
static QVariant fcnMonth(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnTitle(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
bool isIntervalSafe(const QVariant &v)
QgsGeometry * intersection(QgsGeometry *geometry)
Returns a geometry representing the points shared by this geometry and other.
static QVariant fcnRPad(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static int getIntValue(const QVariant &value, QgsExpression *parent)
static QVariant fcnToDate(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fncColorRgba(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
int min(int a, int b)
Definition: util.h:93
static QVariant fcnBbox(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnBoundsWidth(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
QList< QgsMapLayer * > mapLayersByName(QString layerName)
Retrieve a pointer to a loaded layer by name.
static QVariant fcnGeomArea(const QVariantList &, const QgsFeature *f, QgsExpression *parent)
static QVariant fcnAcos(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
virtual QVariant eval(QgsExpression *parent, const QgsFeature *f)=0
static QString getStringValue(const QVariant &value, QgsExpression *)
static QVariant fcnWithin(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QgsFeature getFeature(const QVariant &value, QgsExpression *parent)
virtual QStringList referencedColumns() const
static QVariant fcnGeometry(const QVariantList &, const QgsFeature *f, QgsExpression *)
void setEvalErrorString(QString str)
Set evaluation error (used internally by evaluation functions)
static double getDoubleValue(const QVariant &value, QgsExpression *parent)
QgsGeometry * symDifference(QgsGeometry *geometry)
Returns a Geometry representing the points making up this Geometry that do not make up other...
static QVariant fcnGeomFromGML(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
General purpose distance and area calculator.
static QMap< QString, QString > gmSpecialColumnGroups
virtual QString dump() const override
QgsRectangle boundingBox()
Returns the bounding box of this feature.
static QVariant fcnBounds(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnWeek(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnRegexpReplace(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
bool isIntSafe(const QVariant &v)
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:230
static QVariant fcnConcat(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
bool isDateTimeSafe(const QVariant &v)
static const char * UnaryOperatorText[]
static QgsExpression::Interval invalidInterVal()
static QVariant fcnXat(const QVariantList &values, const QgsFeature *f, QgsExpression *parent)
static QVariant fcnUpper(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnLinearScale(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QgsExpression::Node * getNode(const QVariant &value, QgsExpression *parent)
static QVariant fncColorHsva(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsFields &fields) override
static QList< Function * > specialColumns()
Returns a list of special Column definitions.
static TVL OR[3][3]
static QVariant fcnDay(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
int params()
The number of parameters this function takes.
static QVariant fcnX(const QVariantList &, const QgsFeature *f, QgsExpression *)
static QVariant fcnClamp(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static TVL NOT[3]
Class for storing a coordinate reference system (CRS)
virtual QStringList referencedColumns() const override
bool within(const QgsGeometry *geometry) const
Test for if geometry is within another (uses GEOS)
virtual bool prepare(QgsExpression *parent, const QgsFields &fields) override
static QVariant fcnRegexpMatch(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
Class for doing transforms between two map coordinate systems.
static QVariant fcnSubstr(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnFormatNumber(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
#define TVL_True
static QVariant fcnXMax(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
support for visitor pattern - algorithms dealing with the expressions may be implemented without modi...
static QString quotedString(QString text)
return quoted string (in single quotes)
static QgsGeometry * fromRect(const QgsRectangle &rect)
construct geometry from a rectangle
static QVariant fcnExpScale(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTransform ct.
static QVariant fcnPi(const QVariantList &values, const QgsFeature *f, QgsExpression *parent)
virtual bool needsGeometry() const =0
static QVariant fcnSeconds(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QgsGeometry * fromWkt(QString wkt)
static method that creates geometry from Wkt
void setGeomCalculator(const QgsDistanceArea &calc)
Sets the geometry calculator used in evaluation of expressions,.
static QStringList gmBuiltinFunctions
static QVariant fcnColorHsl(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
virtual QVariant eval(QgsExpression *parent, const QgsFeature *f) override
bool disjoint(const QgsGeometry *geometry) const
Test for if geometry is disjoint of another (uses GEOS)
static QVariant fncColorCmyka(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnUuid(const QVariantList &, const QgsFeature *, QgsExpression *)
bool touches(const QgsGeometry *geometry) const
Test for if geometry touch another (uses GEOS)
static QVariant fcnMax(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant specialColumn(const QString &name)
Return the value of the given special column or a null QVariant if undefined.
static QVariant fcnRowNumber(const QVariantList &, const QgsFeature *, QgsExpression *parent)
static void initFunctionHelp()
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
static QVariant fcnConvexHull(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnRnd(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnColorRgb(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
void setValid(bool valid)
static void setSpecialColumn(const QString &name, QVariant value)
Assign a special column.
static QVariant fcnGeomFromWKT(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
bool nextFeature(QgsFeature &f)
static QVariant fcnColorCmyk(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnExp(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
static TVL AND[3][3]
static QVariant fcnAtan(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:198
bool intersects(const QgsRectangle &r) const
Test for intersection with a rectangle (uses GEOS)
Represents a vector layer which manages a vector based data sets.
static QVariant fcnBoundsHeight(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
QString parserErrorString() const
Returns parser error.
Definition: qgsexpression.h:96
QgsFeatureRequest & setFlags(Flags flags)
Set flags that affect how features will be fetched.
static double evaluateToDouble(const QString &text, const double fallbackValue)
Attempts to evaluate a text string as an expression to a resultant double value.
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:183
int max(int a, int b)
Definition: util.h:87
virtual QStringList referencedColumns() const override
QString evalErrorString() const
Returns evaluation error.
QString exportToWkt(const int &precision=17) const
Exports the geometry to WKT.
virtual void accept(Visitor &v) const =0
static QVariant fcnSymDifference(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
bool isNull(const QVariant &v)
virtual QString dump() const override
static QVariant fcnLn(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnRegexpSubstr(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
static QVariant fcnDisjoint(const QVariantList &values, const QgsFeature *, QgsExpression *parent)
void setEllipsoidalMode(bool flag)
sets whether coordinates must be projected to ellipsoid before measuring
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:203
static QgsExpression::Interval getInterval(const QVariant &value, QgsExpression *parent, bool report_error=false)
static QDateTime getDateTimeValue(const QVariant &value, QgsExpression *parent)
static QVariant fcnRound(const QVariantList &values, const QgsFeature *f, QgsExpression *parent)
double distance(QgsGeometry &geom)
static void unsetSpecialColumn(const QString &name)
Unset a special column.
#define tr(sourceText)
static const char * BinaryOperatorText[]
static QString replaceExpressionText(const QString &action, const QgsFeature *feat, QgsVectorLayer *layer, const QMap< QString, QVariant > *substitutionMap=0, const QgsDistanceArea *distanceArea=0)
This function currently replaces each expression between [% and %] in the string with the result of i...
static QMap< QString, QVariant > gmSpecialColumns