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