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