QGIS API Documentation  2.11.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules 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 #include "qgsexpressioncontext.h"
39 #include "qgsproject.h"
40 #include "qgsstringutils.h"
41 
42 // from parser
43 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
44 
46 
48 {
50  inter.setValid( false );
51  return inter;
52 }
53 
55 {
56  int seconds = 0;
57  QRegExp rx( "([-+]?\\d?\\.?\\d+\\s+\\S+)", Qt::CaseInsensitive );
58  QStringList list;
59  int pos = 0;
60 
61  while (( pos = rx.indexIn( string, pos ) ) != -1 )
62  {
63  list << rx.cap( 1 );
64  pos += rx.matchedLength();
65  }
66 
68  map.insert( 1, QStringList() << "second" << "seconds" << QObject::tr( "second|seconds", "list of words separated by | which reference years" ).split( "|" ) );
69  map.insert( 0 + MINUTE, QStringList() << "minute" << "minutes" << QObject::tr( "minute|minutes", "list of words separated by | which reference minutes" ).split( "|" ) );
70  map.insert( 0 + HOUR, QStringList() << "hour" << "hours" << QObject::tr( "hour|hours", "list of words separated by | which reference minutes hours" ).split( "|" ) );
71  map.insert( 0 + DAY, QStringList() << "day" << "days" << QObject::tr( "day|days", "list of words separated by | which reference days" ).split( "|" ) );
72  map.insert( 0 + WEEKS, QStringList() << "week" << "weeks" << QObject::tr( "week|weeks", "wordlist separated by | which reference weeks" ).split( "|" ) );
73  map.insert( 0 + MONTHS, QStringList() << "month" << "months" << QObject::tr( "month|months", "list of words separated by | which reference months" ).split( "|" ) );
74  map.insert( 0 + YEARS, QStringList() << "year" << "years" << QObject::tr( "year|years", "list of words separated by | which reference years" ).split( "|" ) );
75 
76  foreach ( QString match, list )
77  {
78  QStringList split = match.split( QRegExp( "\\s+" ) );
79  bool ok;
80  double value = split.at( 0 ).toDouble( &ok );
81  if ( !ok )
82  {
83  continue;
84  }
85 
86  bool matched = false;
87  foreach ( int duration, map.keys() )
88  {
89  foreach ( QString name, map[duration] )
90  {
91  if ( match.contains( name, Qt::CaseInsensitive ) )
92  {
93  matched = true;
94  break;
95  }
96  }
97 
98  if ( matched )
99  {
100  seconds += value * duration;
101  break;
102  }
103  }
104  }
105 
106  // If we can't parse the string at all then we just return invalid
107  if ( seconds == 0 )
109 
110  return QgsExpression::Interval( seconds );
111 }
112 
114 {
115  return ( mSeconds == other.mSeconds );
116 }
117 
119 // three-value logic
120 
121 enum TVL
122 {
126 };
127 
128 static TVL AND[3][3] =
129 {
130  // false true unknown
131  { False, False, False }, // false
132  { False, True, Unknown }, // true
133  { False, Unknown, Unknown } // unknown
134 };
135 
136 static TVL OR[3][3] =
137 {
138  { False, True, Unknown }, // false
139  { True, True, True }, // true
140  { Unknown, True, Unknown } // unknown
141 };
142 
143 static TVL NOT[3] = { True, False, Unknown };
144 
146 {
147  switch ( v )
148  {
149  case False: return 0;
150  case True: return 1;
151  case Unknown:
152  default:
153  return QVariant();
154  }
155 }
156 
157 #define TVL_True QVariant(1)
158 #define TVL_False QVariant(0)
159 #define TVL_Unknown QVariant()
160 
162 // QVariant checks and conversions
163 
164 inline bool isIntSafe( const QVariant& v )
165 {
166  if ( v.type() == QVariant::Int ) return true;
167  if ( v.type() == QVariant::UInt ) return true;
168  if ( v.type() == QVariant::LongLong ) return true;
169  if ( v.type() == QVariant::ULongLong ) return true;
170  if ( v.type() == QVariant::Double ) return false;
171  if ( v.type() == QVariant::String ) { bool ok; v.toString().toInt( &ok ); return ok; }
172  return false;
173 }
174 inline bool isDoubleSafe( const QVariant& v )
175 {
176  if ( v.type() == QVariant::Double ) return true;
177  if ( v.type() == QVariant::Int ) return true;
178  if ( v.type() == QVariant::UInt ) return true;
179  if ( v.type() == QVariant::LongLong ) return true;
180  if ( v.type() == QVariant::ULongLong ) return true;
181  if ( v.type() == QVariant::String )
182  {
183  bool ok;
184  double val = v.toString().toDouble( &ok );
185  ok = ok && qIsFinite( val ) && !qIsNaN( val );
186  return ok;
187  }
188  return false;
189 }
190 
191 inline bool isDateTimeSafe( const QVariant& v )
192 {
193  return v.type() == QVariant::DateTime || v.type() == QVariant::Date ||
194  v.type() == QVariant::Time;
195 }
196 
197 inline bool isIntervalSafe( const QVariant& v )
198 {
200  {
201  return true;
202  }
203 
204  if ( v.type() == QVariant::String )
205  {
207  }
208  return false;
209 }
210 
211 inline bool isNull( const QVariant& v ) { return v.isNull(); }
212 
214 // evaluation error macros
215 
216 #define ENSURE_NO_EVAL_ERROR { if (parent->hasEvalError()) return QVariant(); }
217 #define SET_EVAL_ERROR(x) { parent->setEvalErrorString(x); return QVariant(); }
218 
220 // operators
221 
222 const char* QgsExpression::BinaryOperatorText[] =
223 {
224  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
225  "OR", "AND",
226  "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
227  "+", "-", "*", "/", "//", "%", "^",
228  "||"
229 };
230 
231 const char* QgsExpression::UnaryOperatorText[] =
232 {
233  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
234  "NOT", "-"
235 };
236 
238 // functions
239 
240 // implicit conversion to string
242 {
243  return value.toString();
244 }
245 
246 static double getDoubleValue( const QVariant& value, QgsExpression* parent )
247 {
248  bool ok;
249  double x = value.toDouble( &ok );
250  if ( !ok || qIsNaN( x ) || !qIsFinite( x ) )
251  {
252  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
253  return 0;
254  }
255  return x;
256 }
257 
258 static int getIntValue( const QVariant& value, QgsExpression* parent )
259 {
260  bool ok;
261  qint64 x = value.toLongLong( &ok );
263  {
264  return x;
265  }
266  else
267  {
268  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
269  return 0;
270  }
271 }
272 
273 static QDateTime getDateTimeValue( const QVariant& value, QgsExpression* parent )
274 {
275  QDateTime d = value.toDateTime();
276  if ( d.isValid() )
277  {
278  return d;
279  }
280  else
281  {
282  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
283  return QDateTime();
284  }
285 }
286 
287 static QDate getDateValue( const QVariant& value, QgsExpression* parent )
288 {
289  QDate d = value.toDate();
290  if ( d.isValid() )
291  {
292  return d;
293  }
294  else
295  {
296  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
297  return QDate();
298  }
299 }
300 
301 static QTime getTimeValue( const QVariant& value, QgsExpression* parent )
302 {
303  QTime t = value.toTime();
304  if ( t.isValid() )
305  {
306  return t;
307  }
308  else
309  {
310  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
311  return QTime();
312  }
313 }
314 
315 static QgsExpression::Interval getInterval( const QVariant& value, QgsExpression* parent, bool report_error = false )
316 {
317  if ( value.canConvert<QgsExpression::Interval>() )
318  return value.value<QgsExpression::Interval>();
319 
321  if ( inter.isValid() )
322  {
323  return inter;
324  }
325  // If we get here then we can't convert so we just error and return invalid.
326  if ( report_error )
327  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Interval" ).arg( value.toString() ) );
328 
330 }
331 
332 static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent )
333 {
334  if ( value.canConvert<QgsGeometry>() )
335  return value.value<QgsGeometry>();
336 
337  parent->setEvalErrorString( "Cannot convert to QgsGeometry" );
338  return QgsGeometry();
339 }
340 
341 static QgsFeature getFeature( const QVariant& value, QgsExpression* parent )
342 {
343  if ( value.canConvert<QgsFeature>() )
344  return value.value<QgsFeature>();
345 
346  parent->setEvalErrorString( "Cannot convert to QgsFeature" );
347  return 0;
348 }
349 
350 static QgsExpression::Node* getNode( const QVariant& value, QgsExpression* parent )
351 {
352  if ( value.canConvert<QgsExpression::Node*>() )
353  return value.value<QgsExpression::Node*>();
354 
355  parent->setEvalErrorString( "Cannot convert to Node" );
356  return 0;
357 }
358 
359 // this handles also NULL values
360 static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
361 {
362  // we need to convert to TVL
363  if ( value.isNull() )
364  return Unknown;
365 
366  if ( value.type() == QVariant::Int )
367  return value.toInt() != 0 ? True : False;
368 
369  bool ok;
370  double x = value.toDouble( &ok );
371  if ( !ok )
372  {
373  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
374  return Unknown;
375  }
376  return x != 0 ? True : False;
377 }
378 
380 
381 static QVariant fcnGetVariable( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
382 {
383  if ( !context )
384  return QVariant();
385 
386  QString name = getStringValue( values.at( 0 ), parent );
387  return context->variable( name );
388 }
389 
390 static QVariant fcnSqrt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
391 {
392  double x = getDoubleValue( values.at( 0 ), parent );
393  return QVariant( sqrt( x ) );
394 }
395 
396 static QVariant fcnAbs( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
397 {
398  double val = getDoubleValue( values.at( 0 ), parent );
399  return QVariant( fabs( val ) );
400 }
401 
402 static QVariant fcnSin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
403 {
404  double x = getDoubleValue( values.at( 0 ), parent );
405  return QVariant( sin( x ) );
406 }
407 static QVariant fcnCos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
408 {
409  double x = getDoubleValue( values.at( 0 ), parent );
410  return QVariant( cos( x ) );
411 }
412 static QVariant fcnTan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
413 {
414  double x = getDoubleValue( values.at( 0 ), parent );
415  return QVariant( tan( x ) );
416 }
417 static QVariant fcnAsin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
418 {
419  double x = getDoubleValue( values.at( 0 ), parent );
420  return QVariant( asin( x ) );
421 }
422 static QVariant fcnAcos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
423 {
424  double x = getDoubleValue( values.at( 0 ), parent );
425  return QVariant( acos( x ) );
426 }
427 static QVariant fcnAtan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
428 {
429  double x = getDoubleValue( values.at( 0 ), parent );
430  return QVariant( atan( x ) );
431 }
432 static QVariant fcnAtan2( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
433 {
434  double y = getDoubleValue( values.at( 0 ), parent );
435  double x = getDoubleValue( values.at( 1 ), parent );
436  return QVariant( atan2( y, x ) );
437 }
438 static QVariant fcnExp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
439 {
440  double x = getDoubleValue( values.at( 0 ), parent );
441  return QVariant( exp( x ) );
442 }
443 static QVariant fcnLn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
444 {
445  double x = getDoubleValue( values.at( 0 ), parent );
446  if ( x <= 0 )
447  return QVariant();
448  return QVariant( log( x ) );
449 }
450 static QVariant fcnLog10( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
451 {
452  double x = getDoubleValue( values.at( 0 ), parent );
453  if ( x <= 0 )
454  return QVariant();
455  return QVariant( log10( x ) );
456 }
457 static QVariant fcnLog( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
458 {
459  double b = getDoubleValue( values.at( 0 ), parent );
460  double x = getDoubleValue( values.at( 1 ), parent );
461  if ( x <= 0 || b <= 0 )
462  return QVariant();
463  return QVariant( log( x ) / log( b ) );
464 }
465 static QVariant fcnRndF( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
466 {
467  double min = getDoubleValue( values.at( 0 ), parent );
468  double max = getDoubleValue( values.at( 1 ), parent );
469  if ( max < min )
470  return QVariant();
471 
472  // Return a random double in the range [min, max] (inclusive)
473  double f = ( double )qrand() / RAND_MAX;
474  return QVariant( min + f * ( max - min ) );
475 }
476 static QVariant fcnRnd( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
477 {
478  int min = getIntValue( values.at( 0 ), parent );
479  int max = getIntValue( values.at( 1 ), parent );
480  if ( max < min )
481  return QVariant();
482 
483  // Return a random integer in the range [min, max] (inclusive)
484  return QVariant( min + ( qrand() % ( int )( max - min + 1 ) ) );
485 }
486 
487 static QVariant fcnLinearScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
488 {
489  double val = getDoubleValue( values.at( 0 ), parent );
490  double domainMin = getDoubleValue( values.at( 1 ), parent );
491  double domainMax = getDoubleValue( values.at( 2 ), parent );
492  double rangeMin = getDoubleValue( values.at( 3 ), parent );
493  double rangeMax = getDoubleValue( values.at( 4 ), parent );
494 
495  if ( domainMin >= domainMax )
496  {
497  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
498  return QVariant();
499  }
500 
501  // outside of domain?
502  if ( val >= domainMax )
503  {
504  return rangeMax;
505  }
506  else if ( val <= domainMin )
507  {
508  return rangeMin;
509  }
510 
511  // calculate linear scale
512  double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
513  double c = rangeMin - ( domainMin * m );
514 
515  // Return linearly scaled value
516  return QVariant( m * val + c );
517 }
518 
519 static QVariant fcnExpScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
520 {
521  double val = getDoubleValue( values.at( 0 ), parent );
522  double domainMin = getDoubleValue( values.at( 1 ), parent );
523  double domainMax = getDoubleValue( values.at( 2 ), parent );
524  double rangeMin = getDoubleValue( values.at( 3 ), parent );
525  double rangeMax = getDoubleValue( values.at( 4 ), parent );
526  double exponent = getDoubleValue( values.at( 5 ), parent );
527 
528  if ( domainMin >= domainMax )
529  {
530  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
531  return QVariant();
532  }
533  if ( exponent <= 0 )
534  {
535  parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
536  return QVariant();
537  }
538 
539  // outside of domain?
540  if ( val >= domainMax )
541  {
542  return rangeMax;
543  }
544  else if ( val <= domainMin )
545  {
546  return rangeMin;
547  }
548 
549  // Return exponentially scaled value
550  return QVariant((( rangeMax - rangeMin ) / pow( domainMax - domainMin, exponent ) ) * pow( val - domainMin, exponent ) + rangeMin );
551 }
552 
553 static QVariant fcnMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
554 {
555  //initially set max as first value
556  double maxVal = getDoubleValue( values.at( 0 ), parent );
557 
558  //check against all other values
559  for ( int i = 1; i < values.length(); ++i )
560  {
561  double testVal = getDoubleValue( values[i], parent );
562  if ( testVal > maxVal )
563  {
564  maxVal = testVal;
565  }
566  }
567 
568  return QVariant( maxVal );
569 }
570 
571 static QVariant fcnMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
572 {
573  //initially set min as first value
574  double minVal = getDoubleValue( values.at( 0 ), parent );
575 
576  //check against all other values
577  for ( int i = 1; i < values.length(); ++i )
578  {
579  double testVal = getDoubleValue( values[i], parent );
580  if ( testVal < minVal )
581  {
582  minVal = testVal;
583  }
584  }
585 
586  return QVariant( minVal );
587 }
588 
589 static QVariant fcnClamp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
590 {
591  double minValue = getDoubleValue( values.at( 0 ), parent );
592  double testValue = getDoubleValue( values.at( 1 ), parent );
593  double maxValue = getDoubleValue( values.at( 2 ), parent );
594 
595  // force testValue to sit inside the range specified by the min and max value
596  if ( testValue <= minValue )
597  {
598  return QVariant( minValue );
599  }
600  else if ( testValue >= maxValue )
601  {
602  return QVariant( maxValue );
603  }
604  else
605  {
606  return QVariant( testValue );
607  }
608 }
609 
610 static QVariant fcnFloor( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
611 {
612  double x = getDoubleValue( values.at( 0 ), parent );
613  return QVariant( floor( x ) );
614 }
615 
616 static QVariant fcnCeil( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
617 {
618  double x = getDoubleValue( values.at( 0 ), parent );
619  return QVariant( ceil( x ) );
620 }
621 
622 static QVariant fcnToInt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
623 {
624  return QVariant( getIntValue( values.at( 0 ), parent ) );
625 }
626 static QVariant fcnToReal( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
627 {
628  return QVariant( getDoubleValue( values.at( 0 ), parent ) );
629 }
630 static QVariant fcnToString( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
631 {
632  return QVariant( getStringValue( values.at( 0 ), parent ) );
633 }
634 
635 static QVariant fcnToDateTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
636 {
637  return QVariant( getDateTimeValue( values.at( 0 ), parent ) );
638 }
639 
640 static QVariant fcnCoalesce( const QVariantList& values, const QgsExpressionContext*, QgsExpression* )
641 {
642  foreach ( const QVariant &value, values )
643  {
644  if ( value.isNull() )
645  continue;
646  return value;
647  }
648  return QVariant();
649 }
650 static QVariant fcnLower( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
651 {
652  QString str = getStringValue( values.at( 0 ), parent );
653  return QVariant( str.toLower() );
654 }
655 static QVariant fcnUpper( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
656 {
657  QString str = getStringValue( values.at( 0 ), parent );
658  return QVariant( str.toUpper() );
659 }
660 static QVariant fcnTitle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
661 {
662  QString str = getStringValue( values.at( 0 ), parent );
663  QStringList elems = str.split( " " );
664  for ( int i = 0; i < elems.size(); i++ )
665  {
666  if ( elems[i].size() > 1 )
667  elems[i] = elems[i].left( 1 ).toUpper() + elems[i].mid( 1 ).toLower();
668  }
669  return QVariant( elems.join( " " ) );
670 }
671 
672 static QVariant fcnTrim( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
673 {
674  QString str = getStringValue( values.at( 0 ), parent );
675  return QVariant( str.trimmed() );
676 }
677 
678 static QVariant fcnLevenshtein( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
679 {
680  QString string1 = getStringValue( values.at( 0 ), parent );
681  QString string2 = getStringValue( values.at( 1 ), parent );
682  return QVariant( QgsStringUtils::levenshteinDistance( string1, string2, true ) );
683 }
684 
685 static QVariant fcnLCS( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
686 {
687  QString string1 = getStringValue( values.at( 0 ), parent );
688  QString string2 = getStringValue( values.at( 1 ), parent );
689  return QVariant( QgsStringUtils::longestCommonSubstring( string1, string2, true ) );
690 }
691 
692 static QVariant fcnHamming( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
693 {
694  QString string1 = getStringValue( values.at( 0 ), parent );
695  QString string2 = getStringValue( values.at( 1 ), parent );
696  int dist = QgsStringUtils::hammingDistance( string1, string2 );
697  return ( dist < 0 ? QVariant() : QVariant( QgsStringUtils::hammingDistance( string1, string2, true ) ) );
698 }
699 
700 static QVariant fcnSoundex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
701 {
702  QString string = getStringValue( values.at( 0 ), parent );
703  return QVariant( QgsStringUtils::soundex( string ) );
704 }
705 
706 static QVariant fcnWordwrap( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
707 {
708  if ( values.length() == 2 || values.length() == 3 )
709  {
710  QString str = getStringValue( values.at( 0 ), parent );
711  int wrap = getIntValue( values.at( 1 ), parent );
712 
713  if ( !str.isEmpty() && wrap != 0 )
714  {
715  QString newstr;
716  QString delimiterstr;
717  if ( values.length() == 3 ) delimiterstr = getStringValue( values.at( 2 ), parent );
718  if ( delimiterstr.isEmpty() ) delimiterstr = " ";
719  int delimiterlength = delimiterstr.length();
720 
721  QStringList lines = str.split( "\n" );
722  int strlength, strcurrent, strhit, lasthit;
723 
724  for ( int i = 0; i < lines.size(); i++ )
725  {
726  strlength = lines[i].length();
727  strcurrent = 0;
728  strhit = 0;
729  lasthit = 0;
730 
731  while ( strcurrent < strlength )
732  {
733  // positive wrap value = desired maximum line width to wrap
734  // negative wrap value = desired minimum line width before wrap
735  if ( wrap > 0 )
736  {
737  //first try to locate delimiter backwards
738  strhit = lines[i].lastIndexOf( delimiterstr, strcurrent + wrap );
739  if ( strhit == lasthit || strhit == -1 )
740  {
741  //if no new backward delimiter found, try to locate forward
742  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
743  }
744  lasthit = strhit;
745  }
746  else
747  {
748  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
749  }
750  if ( strhit > -1 )
751  {
752  newstr.append( lines[i].midRef( strcurrent, strhit - strcurrent ) );
753  newstr.append( "\n" );
754  strcurrent = strhit + delimiterlength;
755  }
756  else
757  {
758  newstr.append( lines[i].midRef( strcurrent ) );
759  strcurrent = strlength;
760  }
761  }
762  if ( i < lines.size() - 1 ) newstr.append( "\n" );
763  }
764 
765  return QVariant( newstr );
766  }
767  }
768 
769  return QVariant();
770 }
771 
772 static QVariant fcnLength( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
773 {
774  QString str = getStringValue( values.at( 0 ), parent );
775  return QVariant( str.length() );
776 }
777 static QVariant fcnReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
778 {
779  QString str = getStringValue( values.at( 0 ), parent );
780  QString before = getStringValue( values.at( 1 ), parent );
781  QString after = getStringValue( values.at( 2 ), parent );
782  return QVariant( str.replace( before, after ) );
783 }
784 static QVariant fcnRegexpReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
785 {
786  QString str = getStringValue( values.at( 0 ), parent );
787  QString regexp = getStringValue( values.at( 1 ), parent );
788  QString after = getStringValue( values.at( 2 ), parent );
789 
790  QRegExp re( regexp );
791  if ( !re.isValid() )
792  {
793  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp ).arg( re.errorString() ) );
794  return QVariant();
795  }
796  return QVariant( str.replace( re, after ) );
797 }
798 
799 static QVariant fcnRegexpMatch( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
800 {
801  QString str = getStringValue( values.at( 0 ), parent );
802  QString regexp = getStringValue( values.at( 1 ), parent );
803 
804  QRegExp re( regexp );
805  if ( !re.isValid() )
806  {
807  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp ).arg( re.errorString() ) );
808  return QVariant();
809  }
810  return QVariant( str.contains( re ) ? 1 : 0 );
811 }
812 
813 static QVariant fcnRegexpSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
814 {
815  QString str = getStringValue( values.at( 0 ), parent );
816  QString regexp = getStringValue( values.at( 1 ), parent );
817 
818  QRegExp re( regexp );
819  if ( !re.isValid() )
820  {
821  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp ).arg( re.errorString() ) );
822  return QVariant();
823  }
824 
825  // extract substring
826  ( void )re.indexIn( str );
827  if ( re.captureCount() > 0 )
828  {
829  // return first capture
830  return QVariant( re.capturedTexts()[1] );
831  }
832  else
833  {
834  return QVariant( "" );
835  }
836 }
837 
838 static QVariant fcnUuid( const QVariantList&, const QgsExpressionContext*, QgsExpression* )
839 {
840  return QUuid::createUuid().toString();
841 }
842 
843 static QVariant fcnSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
844 {
845  QString str = getStringValue( values.at( 0 ), parent );
846  int from = getIntValue( values.at( 1 ), parent );
847  int len = getIntValue( values.at( 2 ), parent );
848  return QVariant( str.mid( from -1, len ) );
849 }
850 
851 static QVariant fcnRowNumber( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
852 {
853  if ( context && context->hasVariable( "_rownum_" ) )
854  return context->variable( "_rownum_" );
855 
857  return QVariant( parent->currentRowNumber() );
859  //when above is removed - return QVariant()
860 }
861 
862 #define FEAT_FROM_CONTEXT(c, f) if (!c || !c->hasVariable(QgsExpressionContext::EXPR_FEATURE)) return QVariant(); \
863  QgsFeature f = qvariant_cast<QgsFeature>( c->variable( QgsExpressionContext::EXPR_FEATURE ) );
864 
865 static QVariant fcnFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
866 {
867  FEAT_FROM_CONTEXT( context, f );
868  // TODO: handling of 64-bit feature ids?
869  return QVariant(( int )f.id() );
870 }
871 
872 static QVariant fcnFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
873 {
874  if ( !context )
875  return QVariant();
876 
877  return context->variable( QgsExpressionContext::EXPR_FEATURE );
878 }
879 static QVariant fcnAttribute( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
880 {
881  QgsFeature feat = getFeature( values.at( 0 ), parent );
882  QString attr = getStringValue( values.at( 1 ), parent );
883 
884  return feat.attribute( attr );
885 }
886 static QVariant fcnConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
887 {
888  QString concat;
889  foreach ( const QVariant &value, values )
890  {
891  concat += getStringValue( value, parent );
892  }
893  return concat;
894 }
895 
896 static QVariant fcnStrpos( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
897 {
898  QString string = getStringValue( values.at( 0 ), parent );
899  return string.indexOf( QRegExp( getStringValue( values.at( 1 ), parent ) ) );
900 }
901 
902 static QVariant fcnRight( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
903 {
904  QString string = getStringValue( values.at( 0 ), parent );
905  int pos = getIntValue( values.at( 1 ), parent );
906  return string.right( pos );
907 }
908 
909 static QVariant fcnLeft( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
910 {
911  QString string = getStringValue( values.at( 0 ), parent );
912  int pos = getIntValue( values.at( 1 ), parent );
913  return string.left( pos );
914 }
915 
916 static QVariant fcnRPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
917 {
918  QString string = getStringValue( values.at( 0 ), parent );
919  int length = getIntValue( values.at( 1 ), parent );
920  QString fill = getStringValue( values.at( 2 ), parent );
921  return string.leftJustified( length, fill.at( 0 ), true );
922 }
923 
924 static QVariant fcnLPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
925 {
926  QString string = getStringValue( values.at( 0 ), parent );
927  int length = getIntValue( values.at( 1 ), parent );
928  QString fill = getStringValue( values.at( 2 ), parent );
929  return string.rightJustified( length, fill.at( 0 ), true );
930 }
931 
932 static QVariant fcnFormatString( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
933 {
934  QString string = getStringValue( values.at( 0 ), parent );
935  for ( int n = 1; n < values.length(); n++ )
936  {
937  string = string.arg( getStringValue( values.at( n ), parent ) );
938  }
939  return string;
940 }
941 
942 
943 static QVariant fcnNow( const QVariantList&, const QgsExpressionContext*, QgsExpression * )
944 {
946 }
947 
948 static QVariant fcnToDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
949 {
950  return QVariant( getDateValue( values.at( 0 ), parent ) );
951 }
952 
953 static QVariant fcnToTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
954 {
955  return QVariant( getTimeValue( values.at( 0 ), parent ) );
956 }
957 
958 static QVariant fcnToInterval( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
959 {
960  return QVariant::fromValue( getInterval( values.at( 0 ), parent ) );
961 }
962 
963 static QVariant fcnAge( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
964 {
965  QDateTime d1 = getDateTimeValue( values.at( 0 ), parent );
966  QDateTime d2 = getDateTimeValue( values.at( 1 ), parent );
967  int seconds = d2.secsTo( d1 );
968  return QVariant::fromValue( QgsExpression::Interval( seconds ) );
969 }
970 
971 static QVariant fcnDay( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
972 {
973  QVariant value = values.at( 0 );
974  QgsExpression::Interval inter = getInterval( value, parent, false );
975  if ( inter.isValid() )
976  {
977  return QVariant( inter.days() );
978  }
979  else
980  {
981  QDateTime d1 = getDateTimeValue( value, parent );
982  return QVariant( d1.date().day() );
983  }
984 }
985 
986 static QVariant fcnYear( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
987 {
988  QVariant value = values.at( 0 );
989  QgsExpression::Interval inter = getInterval( value, parent, false );
990  if ( inter.isValid() )
991  {
992  return QVariant( inter.years() );
993  }
994  else
995  {
996  QDateTime d1 = getDateTimeValue( value, parent );
997  return QVariant( d1.date().year() );
998  }
999 }
1000 
1001 static QVariant fcnMonth( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1002 {
1003  QVariant value = values.at( 0 );
1004  QgsExpression::Interval inter = getInterval( value, parent, false );
1005  if ( inter.isValid() )
1006  {
1007  return QVariant( inter.months() );
1008  }
1009  else
1010  {
1011  QDateTime d1 = getDateTimeValue( value, parent );
1012  return QVariant( d1.date().month() );
1013  }
1014 }
1015 
1016 static QVariant fcnWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1017 {
1018  QVariant value = values.at( 0 );
1019  QgsExpression::Interval inter = getInterval( value, parent, false );
1020  if ( inter.isValid() )
1021  {
1022  return QVariant( inter.weeks() );
1023  }
1024  else
1025  {
1026  QDateTime d1 = getDateTimeValue( value, parent );
1027  return QVariant( d1.date().weekNumber() );
1028  }
1029 }
1030 
1031 static QVariant fcnHour( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1032 {
1033  QVariant value = values.at( 0 );
1034  QgsExpression::Interval inter = getInterval( value, parent, false );
1035  if ( inter.isValid() )
1036  {
1037  return QVariant( inter.hours() );
1038  }
1039  else
1040  {
1041  QDateTime d1 = getDateTimeValue( value, parent );
1042  return QVariant( d1.time().hour() );
1043  }
1044 }
1045 
1046 static QVariant fcnMinute( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1047 {
1048  QVariant value = values.at( 0 );
1049  QgsExpression::Interval inter = getInterval( value, parent, false );
1050  if ( inter.isValid() )
1051  {
1052  return QVariant( inter.minutes() );
1053  }
1054  else
1055  {
1056  QDateTime d1 = getDateTimeValue( value, parent );
1057  return QVariant( d1.time().minute() );
1058  }
1059 }
1060 
1061 static QVariant fcnSeconds( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1062 {
1063  QVariant value = values.at( 0 );
1064  QgsExpression::Interval inter = getInterval( value, parent, false );
1065  if ( inter.isValid() )
1066  {
1067  return QVariant( inter.seconds() );
1068  }
1069  else
1070  {
1071  QDateTime d1 = getDateTimeValue( value, parent );
1072  return QVariant( d1.time().second() );
1073  }
1074 }
1075 
1076 
1077 #define ENSURE_GEOM_TYPE(f, g, geomtype) const QgsGeometry* g = f.constGeometry(); \
1078  if (!g || g->type() != geomtype) return QVariant();
1079 
1080 static QVariant fcnX( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1081 {
1082  FEAT_FROM_CONTEXT( context, f );
1083  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1084  if ( g->isMultipart() )
1085  {
1086  return g->asMultiPoint()[ 0 ].x();
1087  }
1088  else
1089  {
1090  return g->asPoint().x();
1091  }
1092 }
1093 static QVariant fcnY( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1094 {
1095  FEAT_FROM_CONTEXT( context, f );
1096  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1097  if ( g->isMultipart() )
1098  {
1099  return g->asMultiPoint()[ 0 ].y();
1100  }
1101  else
1102  {
1103  return g->asPoint().y();
1104  }
1105 }
1106 
1107 static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
1108 {
1109  FEAT_FROM_CONTEXT( context, f );
1110  int idx = getIntValue( values.at( 0 ), parent );
1111  ENSURE_GEOM_TYPE( f, g, QGis::Line );
1112  QgsPolyline polyline = g->asPolyline();
1113  if ( idx < 0 )
1114  idx += polyline.count();
1115 
1116  if ( idx < 0 || idx >= polyline.count() )
1117  {
1118  parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
1119  return QVariant();
1120  }
1121  return QVariant( QPointF( polyline[idx].x(), polyline[idx].y() ) );
1122 }
1123 
1124 static QVariant fcnXat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1125 {
1126  QVariant v = pointAt( values, f, parent );
1127  if ( v.type() == QVariant::PointF )
1128  return QVariant( v.toPointF().x() );
1129  else
1130  return QVariant();
1131 }
1132 static QVariant fcnYat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1133 {
1134  QVariant v = pointAt( values, f, parent );
1135  if ( v.type() == QVariant::PointF )
1136  return QVariant( v.toPointF().y() );
1137  else
1138  return QVariant();
1139 }
1140 static QVariant fcnGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1141 {
1142  FEAT_FROM_CONTEXT( context, f );
1143  const QgsGeometry* geom = f.constGeometry();
1144  if ( geom )
1145  return QVariant::fromValue( *geom );
1146  else
1147  return QVariant();
1148 }
1149 static QVariant fcnGeomFromWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1150 {
1151  QString wkt = getStringValue( values.at( 0 ), parent );
1152  QgsGeometry* geom = QgsGeometry::fromWkt( wkt );
1153  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1154  delete geom;
1155  return result;
1156 }
1157 static QVariant fcnGeomFromGML( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1158 {
1159  QString gml = getStringValue( values.at( 0 ), parent );
1161  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1162  delete geom;
1163  return result;
1164 }
1165 
1166 static QVariant fcnGeomArea( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1167 {
1168  FEAT_FROM_CONTEXT( context, f );
1170  QgsDistanceArea* calc = parent->geomCalculator();
1171  return QVariant( calc->measure( f.constGeometry() ) );
1172 }
1173 static QVariant fcnGeomLength( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1174 {
1175  FEAT_FROM_CONTEXT( context, f );
1176  ENSURE_GEOM_TYPE( f, g, QGis::Line );
1177  QgsDistanceArea* calc = parent->geomCalculator();
1178  return QVariant( calc->measure( f.constGeometry() ) );
1179 }
1180 static QVariant fcnGeomPerimeter( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1181 {
1182  FEAT_FROM_CONTEXT( context, f );
1184  QgsDistanceArea* calc = parent->geomCalculator();
1185  return QVariant( calc->measurePerimeter( f.constGeometry() ) );
1186 }
1187 
1188 static QVariant fcnBounds( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1189 {
1190  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1191  QgsGeometry* geomBounds = QgsGeometry::fromRect( geom.boundingBox() );
1192  QVariant result = geomBounds ? QVariant::fromValue( *geomBounds ) : QVariant();
1193  delete geomBounds;
1194  return result;
1195 }
1196 
1197 static QVariant fcnBoundsWidth( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1198 {
1199  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1200  return QVariant::fromValue( geom.boundingBox().width() );
1201 }
1202 
1203 static QVariant fcnBoundsHeight( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1204 {
1205  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1206  return QVariant::fromValue( geom.boundingBox().height() );
1207 }
1208 
1209 static QVariant fcnXMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1210 {
1211  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1212  return QVariant::fromValue( geom.boundingBox().xMinimum() );
1213 }
1214 
1215 static QVariant fcnXMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1216 {
1217  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1218  return QVariant::fromValue( geom.boundingBox().xMaximum() );
1219 }
1220 
1221 static QVariant fcnYMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1222 {
1223  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1224  return QVariant::fromValue( geom.boundingBox().yMinimum() );
1225 }
1226 
1227 static QVariant fcnYMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1228 {
1229  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1230  return QVariant::fromValue( geom.boundingBox().yMaximum() );
1231 }
1232 
1233 static QVariant fcnBbox( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1234 {
1235  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1236  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1237  return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
1238 }
1239 static QVariant fcnDisjoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1240 {
1241  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1242  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1243  return fGeom.disjoint( &sGeom ) ? TVL_True : TVL_False;
1244 }
1245 static QVariant fcnIntersects( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1246 {
1247  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1248  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1249  return fGeom.intersects( &sGeom ) ? TVL_True : TVL_False;
1250 }
1251 static QVariant fcnTouches( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1252 {
1253  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1254  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1255  return fGeom.touches( &sGeom ) ? TVL_True : TVL_False;
1256 }
1257 static QVariant fcnCrosses( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1258 {
1259  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1260  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1261  return fGeom.crosses( &sGeom ) ? TVL_True : TVL_False;
1262 }
1263 static QVariant fcnContains( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1264 {
1265  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1266  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1267  return fGeom.contains( &sGeom ) ? TVL_True : TVL_False;
1268 }
1269 static QVariant fcnOverlaps( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1270 {
1271  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1272  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1273  return fGeom.overlaps( &sGeom ) ? TVL_True : TVL_False;
1274 }
1275 static QVariant fcnWithin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1276 {
1277  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1278  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1279  return fGeom.within( &sGeom ) ? TVL_True : TVL_False;
1280 }
1281 static QVariant fcnBuffer( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1282 {
1283  if ( values.length() < 2 || values.length() > 3 )
1284  return QVariant();
1285 
1286  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1287  double dist = getDoubleValue( values.at( 1 ), parent );
1288  int seg = 8;
1289  if ( values.length() == 3 )
1290  seg = getIntValue( values.at( 2 ), parent );
1291 
1292  QgsGeometry* geom = fGeom.buffer( dist, seg );
1293  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1294  delete geom;
1295  return result;
1296 }
1297 static QVariant fcnCentroid( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1298 {
1299  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1300  QgsGeometry* geom = fGeom.centroid();
1301  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1302  delete geom;
1303  return result;
1304 }
1305 static QVariant fcnConvexHull( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1306 {
1307  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1308  QgsGeometry* geom = fGeom.convexHull();
1309  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1310  delete geom;
1311  return result;
1312 }
1313 static QVariant fcnDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1314 {
1315  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1316  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1317  QgsGeometry* geom = fGeom.difference( &sGeom );
1318  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1319  delete geom;
1320  return result;
1321 }
1322 static QVariant fcnDistance( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1323 {
1324  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1325  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1326  return QVariant( fGeom.distance( sGeom ) );
1327 }
1328 static QVariant fcnIntersection( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1329 {
1330  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1331  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1332  QgsGeometry* geom = fGeom.intersection( &sGeom );
1333  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1334  delete geom;
1335  return result;
1336 }
1337 static QVariant fcnSymDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1338 {
1339  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1340  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1341  QgsGeometry* geom = fGeom.symDifference( &sGeom );
1342  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1343  delete geom;
1344  return result;
1345 }
1346 static QVariant fcnCombine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1347 {
1348  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1349  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1350  QgsGeometry* geom = fGeom.combine( &sGeom );
1351  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1352  delete geom;
1353  return result;
1354 }
1355 static QVariant fcnGeomToWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1356 {
1357  if ( values.length() < 1 || values.length() > 2 )
1358  return QVariant();
1359 
1360  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1361  int prec = 8;
1362  if ( values.length() == 2 )
1363  prec = getIntValue( values.at( 1 ), parent );
1364  QString wkt = fGeom.exportToWkt( prec );
1365  return QVariant( wkt );
1366 }
1367 
1368 static QVariant fcnRound( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
1369 {
1370  if ( values.length() == 2 )
1371  {
1372  double number = getDoubleValue( values.at( 0 ), parent );
1373  double scaler = pow( 10.0, getIntValue( values.at( 1 ), parent ) );
1374  return QVariant( qRound( number * scaler ) / scaler );
1375  }
1376 
1377  if ( values.length() == 1 )
1378  {
1379  double number = getIntValue( values.at( 0 ), parent );
1380  return QVariant( qRound( number ) ).toInt();
1381  }
1382 
1383  return QVariant();
1384 }
1385 
1386 static QVariant fcnPi( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
1387 {
1388  Q_UNUSED( values );
1389  Q_UNUSED( parent );
1390  return M_PI;
1391 }
1392 
1393 static QVariant fcnScale( const QVariantList&, const QgsExpressionContext*, QgsExpression* parent )
1394 {
1395  return QVariant( parent->scale() );
1396 }
1397 
1398 static QVariant fcnFormatNumber( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1399 {
1400  double value = getDoubleValue( values.at( 0 ), parent );
1401  int places = getIntValue( values.at( 1 ), parent );
1402  if ( places < 0 )
1403  {
1404  parent->setEvalErrorString( QObject::tr( "Number of places must be positive" ) );
1405  return QVariant();
1406  }
1407  return QString( "%L1" ).arg( value, 0, 'f', places );
1408 }
1409 
1410 static QVariant fcnFormatDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1411 {
1412  QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
1413  QString format = getStringValue( values.at( 1 ), parent );
1414  return dt.toString( format );
1415 }
1416 
1417 static QVariant fcnColorRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
1418 {
1419  int red = getIntValue( values.at( 0 ), parent );
1420  int green = getIntValue( values.at( 1 ), parent );
1421  int blue = getIntValue( values.at( 2 ), parent );
1422  QColor color = QColor( red, green, blue );
1423  if ( ! color.isValid() )
1424  {
1425  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
1426  color = QColor( 0, 0, 0 );
1427  }
1428 
1429  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
1430 }
1431 
1432 static QVariant fcnIf( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
1433 {
1434  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
1436  QVariant value = node->eval( parent, context );
1438  if ( value.toBool() )
1439  {
1440  node = getNode( values.at( 1 ), parent );
1442  value = node->eval( parent, context );
1444  }
1445  else
1446  {
1447  node = getNode( values.at( 2 ), parent );
1449  value = node->eval( parent, context );
1451  }
1452  return value;
1453 }
1454 
1455 static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
1456 {
1457  int red = getIntValue( values.at( 0 ), parent );
1458  int green = getIntValue( values.at( 1 ), parent );
1459  int blue = getIntValue( values.at( 2 ), parent );
1460  int alpha = getIntValue( values.at( 3 ), parent );
1461  QColor color = QColor( red, green, blue, alpha );
1462  if ( ! color.isValid() )
1463  {
1464  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
1465  color = QColor( 0, 0, 0 );
1466  }
1467  return QgsSymbolLayerV2Utils::encodeColor( color );
1468 }
1469 
1470 QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
1471 {
1472  QString rampName = getStringValue( values.at( 0 ), parent );
1473  const QgsVectorColorRampV2 *mRamp = QgsStyleV2::defaultStyle()->colorRampRef( rampName );
1474  if ( ! mRamp )
1475  {
1476  parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
1477  return QColor( 0, 0, 0 ).name();
1478  }
1479  double value = getDoubleValue( values.at( 1 ), parent );
1480  QColor color = mRamp->color( value );
1481  return QgsSymbolLayerV2Utils::encodeColor( color );
1482 }
1483 
1484 static QVariant fcnColorHsl( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
1485 {
1486  // Hue ranges from 0 - 360
1487  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
1488  // Saturation ranges from 0 - 100
1489  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
1490  // Lightness ranges from 0 - 100
1491  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
1492 
1493  QColor color = QColor::fromHslF( hue, saturation, lightness );
1494 
1495  if ( ! color.isValid() )
1496  {
1497  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
1498  color = QColor( 0, 0, 0 );
1499  }
1500 
1501  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
1502 }
1503 
1504 static QVariant fncColorHsla( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
1505 {
1506  // Hue ranges from 0 - 360
1507  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
1508  // Saturation ranges from 0 - 100
1509  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
1510  // Lightness ranges from 0 - 100
1511  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
1512  // Alpha ranges from 0 - 255
1513  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
1514 
1515  QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
1516  if ( ! color.isValid() )
1517  {
1518  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
1519  color = QColor( 0, 0, 0 );
1520  }
1521  return QgsSymbolLayerV2Utils::encodeColor( color );
1522 }
1523 
1524 static QVariant fcnColorHsv( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
1525 {
1526  // Hue ranges from 0 - 360
1527  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
1528  // Saturation ranges from 0 - 100
1529  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
1530  // Value ranges from 0 - 100
1531  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
1532 
1533  QColor color = QColor::fromHsvF( hue, saturation, value );
1534 
1535  if ( ! color.isValid() )
1536  {
1537  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
1538  color = QColor( 0, 0, 0 );
1539  }
1540 
1541  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
1542 }
1543 
1544 static QVariant fncColorHsva( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
1545 {
1546  // Hue ranges from 0 - 360
1547  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
1548  // Saturation ranges from 0 - 100
1549  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
1550  // Value ranges from 0 - 100
1551  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
1552  // Alpha ranges from 0 - 255
1553  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
1554 
1555  QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
1556  if ( ! color.isValid() )
1557  {
1558  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
1559  color = QColor( 0, 0, 0 );
1560  }
1561  return QgsSymbolLayerV2Utils::encodeColor( color );
1562 }
1563 
1564 static QVariant fcnColorCmyk( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
1565 {
1566  // Cyan ranges from 0 - 100
1567  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
1568  // Magenta ranges from 0 - 100
1569  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
1570  // Yellow ranges from 0 - 100
1571  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
1572  // Black ranges from 0 - 100
1573  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
1574 
1575  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
1576 
1577  if ( ! color.isValid() )
1578  {
1579  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
1580  color = QColor( 0, 0, 0 );
1581  }
1582 
1583  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
1584 }
1585 
1586 static QVariant fncColorCmyka( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
1587 {
1588  // Cyan ranges from 0 - 100
1589  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
1590  // Magenta ranges from 0 - 100
1591  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
1592  // Yellow ranges from 0 - 100
1593  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
1594  // Black ranges from 0 - 100
1595  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
1596  // Alpha ranges from 0 - 255
1597  double alpha = getIntValue( values.at( 4 ), parent ) / 255.0;
1598 
1599  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
1600  if ( ! color.isValid() )
1601  {
1602  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
1603  color = QColor( 0, 0, 0 );
1604  }
1605  return QgsSymbolLayerV2Utils::encodeColor( color );
1606 }
1607 
1608 static QVariant fcnSpecialColumn( const QVariantList& values, const QgsExpressionContext* /*f*/, QgsExpression* parent )
1609 {
1610  QString varName = getStringValue( values.at( 0 ), parent );
1611  return QgsExpression::specialColumn( varName );
1612 }
1613 
1614 static QVariant fcnGetGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1615 {
1616  QgsFeature feat = getFeature( values.at( 0 ), parent );
1617  const QgsGeometry* geom = feat.constGeometry();
1618  if ( geom )
1619  return QVariant::fromValue( *geom );
1620  return QVariant();
1621 }
1622 
1623 static QVariant fcnTransformGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1624 {
1625  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1626  QString sAuthId = getStringValue( values.at( 1 ), parent );
1627  QString dAuthId = getStringValue( values.at( 2 ), parent );
1628 
1630  if ( ! s.createFromOgcWmsCrs( sAuthId ) )
1631  return QVariant::fromValue( fGeom );
1633  if ( ! d.createFromOgcWmsCrs( dAuthId ) )
1634  return QVariant::fromValue( fGeom );
1635 
1636  QgsCoordinateTransform t( s, d );
1637  if ( fGeom.transform( t ) == 0 )
1638  return QVariant::fromValue( fGeom );
1639  return QVariant();
1640 }
1641 
1642 static QVariant fcnGetFeature( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1643 {
1644  //arguments: 1. layer id / name, 2. key attribute, 3. eq value
1645  QString layerString = getStringValue( values.at( 0 ), parent );
1646  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerString ) ); //search by id first
1647  if ( !vl )
1648  {
1649  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerString );
1650  if ( layersByName.size() > 0 )
1651  {
1652  vl = qobject_cast<QgsVectorLayer*>( layersByName.at( 0 ) );
1653  }
1654  }
1655 
1656  //no layer found
1657  if ( !vl )
1658  {
1659  return QVariant();
1660  }
1661 
1662  QString attribute = getStringValue( values.at( 1 ), parent );
1663  int attributeId = vl->fieldNameIndex( attribute );
1664  if ( attributeId == -1 )
1665  {
1666  return QVariant();
1667  }
1668 
1669  const QVariant& attVal = values.at( 2 );
1670  QgsFeatureRequest req;
1671  if ( !parent->needsGeometry() )
1672  {
1674  }
1675  QgsFeatureIterator fIt = vl->getFeatures( req );
1676 
1677  QgsFeature fet;
1678  while ( fIt.nextFeature( fet ) )
1679  {
1680  if ( fet.attribute( attributeId ) == attVal )
1681  {
1682  return QVariant::fromValue( fet );
1683  }
1684  }
1685  return QVariant();
1686 }
1687 
1688 static QVariant fcnGetLayerProperty( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1689 {
1690  QString layerIdOrName = getStringValue( values.at( 0 ), parent );
1691 
1692  //try to find a matching layer by name
1693  QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerIdOrName ); //search by id first
1694  if ( !layer )
1695  {
1696  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerIdOrName );
1697  if ( layersByName.size() > 0 )
1698  {
1699  layer = layersByName.at( 0 );
1700  }
1701  }
1702 
1703  if ( !layer )
1704  return QVariant();
1705 
1706  QString layerProperty = getStringValue( values.at( 1 ), parent );
1707  if ( QString::compare( layerProperty, QString( "name" ), Qt::CaseInsensitive ) == 0 )
1708  return layer->name();
1709  else if ( QString::compare( layerProperty, QString( "id" ), Qt::CaseInsensitive ) == 0 )
1710  return layer->id();
1711  else if ( QString::compare( layerProperty, QString( "title" ), Qt::CaseInsensitive ) == 0 )
1712  return layer->title();
1713  else if ( QString::compare( layerProperty, QString( "abstract" ), Qt::CaseInsensitive ) == 0 )
1714  return layer->abstract();
1715  else if ( QString::compare( layerProperty, QString( "keywords" ), Qt::CaseInsensitive ) == 0 )
1716  return layer->keywordList();
1717  else if ( QString::compare( layerProperty, QString( "data_url" ), Qt::CaseInsensitive ) == 0 )
1718  return layer->dataUrl();
1719  else if ( QString::compare( layerProperty, QString( "attribution" ), Qt::CaseInsensitive ) == 0 )
1720  return layer->attribution();
1721  else if ( QString::compare( layerProperty, QString( "attribution_url" ), Qt::CaseInsensitive ) == 0 )
1722  return layer->attributionUrl();
1723  else if ( QString::compare( layerProperty, QString( "source" ), Qt::CaseInsensitive ) == 0 )
1724  return layer->publicSource();
1725  else if ( QString::compare( layerProperty, QString( "min_scale" ), Qt::CaseInsensitive ) == 0 )
1726  return ( double )layer->minimumScale();
1727  else if ( QString::compare( layerProperty, QString( "max_scale" ), Qt::CaseInsensitive ) == 0 )
1728  return ( double )layer->maximumScale();
1729  else if ( QString::compare( layerProperty, QString( "crs" ), Qt::CaseInsensitive ) == 0 )
1730  return layer->crs().authid();
1731  else if ( QString::compare( layerProperty, QString( "crs_definition" ), Qt::CaseInsensitive ) == 0 )
1732  return layer->crs().toProj4();
1733  else if ( QString::compare( layerProperty, QString( "extent" ), Qt::CaseInsensitive ) == 0 )
1734  {
1735  QgsGeometry* extentGeom = QgsGeometry::fromRect( layer->extent() );
1736  QVariant result = QVariant::fromValue( *extentGeom );
1737  delete extentGeom;
1738  return result;
1739  }
1740  else if ( QString::compare( layerProperty, QString( "type" ), Qt::CaseInsensitive ) == 0 )
1741  {
1742  switch ( layer->type() )
1743  {
1745  return QCoreApplication::translate( "expressions", "Vector" );
1747  return QCoreApplication::translate( "expressions", "Raster" );
1749  return QCoreApplication::translate( "expressions", "Plugin" );
1750  }
1751  }
1752  else
1753  {
1754  //vector layer methods
1755  QgsVectorLayer* vLayer = dynamic_cast< QgsVectorLayer* >( layer );
1756  if ( vLayer )
1757  {
1758  if ( QString::compare( layerProperty, QString( "storage_type" ), Qt::CaseInsensitive ) == 0 )
1759  return vLayer->storageType();
1760  else if ( QString::compare( layerProperty, QString( "geometry_type" ), Qt::CaseInsensitive ) == 0 )
1761  return QGis::vectorGeometryType( vLayer->geometryType() );
1762  else if ( QString::compare( layerProperty, QString( "feature_count" ), Qt::CaseInsensitive ) == 0 )
1763  return QVariant::fromValue( vLayer->featureCount() );
1764  }
1765  }
1766 
1767  return QVariant();
1768 }
1769 
1770 bool QgsExpression::registerFunction( QgsExpression::Function* function, bool transferOwnership )
1771 {
1772  int fnIdx = functionIndex( function->name() );
1773  if ( fnIdx != -1 )
1774  {
1775  return false;
1776  }
1777  QgsExpression::gmFunctions.append( function );
1778  if ( transferOwnership )
1779  QgsExpression::gmOwnedFunctions.append( function );
1780  return true;
1781 }
1782 
1784 {
1785  // You can never override the built in functions.
1786  if ( QgsExpression::BuiltinFunctions().contains( name ) )
1787  {
1788  return false;
1789  }
1790  int fnIdx = functionIndex( name );
1791  if ( fnIdx != -1 )
1792  {
1793  QgsExpression::gmFunctions.removeAt( fnIdx );
1794  return true;
1795  }
1796  return false;
1797 }
1798 
1800 {
1801  qDeleteAll( QgsExpression::gmOwnedFunctions );
1803 }
1804 
1806 
1808 {
1809  if ( gmBuiltinFunctions.isEmpty() )
1810  {
1812  << "abs" << "sqrt" << "cos" << "sin" << "tan"
1813  << "asin" << "acos" << "atan" << "atan2"
1814  << "exp" << "ln" << "log10" << "log"
1815  << "round" << "rand" << "randf" << "max" << "min" << "clamp"
1816  << "scale_linear" << "scale_exp" << "floor" << "ceil" << "$pi"
1817  << "toint" << "to_int" << "toreal" << "to_real" << "tostring" << "to_string"
1818  << "todatetime" << "to_datetime" << "todate" << "to_date"
1819  << "totime" << "to_time" << "tointerval" << "to_interval"
1820  << "coalesce" << "if" << "regexp_match" << "age" << "year"
1821  << "month" << "week" << "day" << "hour"
1822  << "minute" << "second" << "lower" << "upper"
1823  << "title" << "length" << "replace" << "trim" << "wordwrap"
1824  << "regexp_replace" << "regexp_substr"
1825  << "substr" << "concat" << "strpos" << "left"
1826  << "right" << "rpad" << "lpad" << "format"
1827  << "format_number" << "format_date"
1828  << "color_rgb" << "color_rgba" << "ramp_color"
1829  << "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
1830  << "color_cymk" << "color_cymka"
1831  << "xat" << "yat" << "$area"
1832  << "$length" << "$perimeter" << "$x" << "$y"
1833  << "x_at" << "xat" << "y_at" << "yat" << "x_min" << "xmin" << "x_max" << "xmax"
1834  << "y_min" << "ymin" << "y_max" << "ymax" << "geom_from_wkt" << "geomFromWKT"
1835  << "geom_from_gml" << "geomFromGML" << "intersects_bbox" << "bbox"
1836  << "disjoint" << "intersects" << "touches" << "crosses" << "contains"
1837  << "overlaps" << "within" << "buffer" << "centroid" << "bounds"
1838  << "bounds_width" << "bounds_height" << "convex_hull" << "difference"
1839  << "distance" << "intersection" << "sym_difference" << "combine"
1840  << "union" << "geom_to_wkt" << "geomToWKT" << "geometry"
1841  << "transform" << "get_feature" << "getFeature"
1842  << "levenshtein" << "longest_common_substring" << "hamming_distance"
1843  << "soundex"
1844  << "attribute" << "var" << "layer_property"
1845  << "$rownum" << "$id" << "$scale" << "_specialcol_";
1846  }
1847  return gmBuiltinFunctions;
1848 }
1849 
1852 
1854 {
1855  if ( gmFunctions.isEmpty() )
1856  {
1857  gmFunctions
1858  << new StaticFunction( "sqrt", 1, fcnSqrt, "Math" )
1859  << new StaticFunction( "abs", 1, fcnAbs, "Math" )
1860  << new StaticFunction( "cos", 1, fcnCos, "Math" )
1861  << new StaticFunction( "sin", 1, fcnSin, "Math" )
1862  << new StaticFunction( "tan", 1, fcnTan, "Math" )
1863  << new StaticFunction( "asin", 1, fcnAsin, "Math" )
1864  << new StaticFunction( "acos", 1, fcnAcos, "Math" )
1865  << new StaticFunction( "atan", 1, fcnAtan, "Math" )
1866  << new StaticFunction( "atan2", 2, fcnAtan2, "Math" )
1867  << new StaticFunction( "exp", 1, fcnExp, "Math" )
1868  << new StaticFunction( "ln", 1, fcnLn, "Math" )
1869  << new StaticFunction( "log10", 1, fcnLog10, "Math" )
1870  << new StaticFunction( "log", 2, fcnLog, "Math" )
1871  << new StaticFunction( "round", -1, fcnRound, "Math" )
1872  << new StaticFunction( "rand", 2, fcnRnd, "Math" )
1873  << new StaticFunction( "randf", 2, fcnRndF, "Math" )
1874  << new StaticFunction( "max", -1, fcnMax, "Math" )
1875  << new StaticFunction( "min", -1, fcnMin, "Math" )
1876  << new StaticFunction( "clamp", 3, fcnClamp, "Math" )
1877  << new StaticFunction( "scale_linear", 5, fcnLinearScale, "Math" )
1878  << new StaticFunction( "scale_exp", 6, fcnExpScale, "Math" )
1879  << new StaticFunction( "floor", 1, fcnFloor, "Math" )
1880  << new StaticFunction( "ceil", 1, fcnCeil, "Math" )
1881  << new StaticFunction( "pi", 0, fcnPi, "Math", QString(), false, QStringList(), false, QStringList() << "$pi" )
1882  << new StaticFunction( "to_int", 1, fcnToInt, "Conversions", QString(), false, QStringList(), false, QStringList() << "toint" )
1883  << new StaticFunction( "to_real", 1, fcnToReal, "Conversions", QString(), false, QStringList(), false, QStringList() << "toreal" )
1884  << new StaticFunction( "to_string", 1, fcnToString, "Conversions", QString(), false, QStringList(), false, QStringList() << "tostring" )
1885  << new StaticFunction( "to_datetime", 1, fcnToDateTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "todatetime" )
1886  << new StaticFunction( "to_date", 1, fcnToDate, "Conversions", QString(), false, QStringList(), false, QStringList() << "todate" )
1887  << new StaticFunction( "to_time", 1, fcnToTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "totime" )
1888  << new StaticFunction( "to_interval", 1, fcnToInterval, "Conversions", QString(), false, QStringList(), false, QStringList() << "tointerval" )
1889  << new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals", QString(), false, QStringList(), false, QStringList(), true )
1890  << new StaticFunction( "if", 3, fcnIf, "Conditionals", "", False, QStringList(), true )
1891  << new StaticFunction( "regexp_match", 2, fcnRegexpMatch, "Conditionals" )
1892  << new StaticFunction( "now", 0, fcnNow, "Date and Time", QString(), false, QStringList(), false, QStringList() << "$now" )
1893  << new StaticFunction( "age", 2, fcnAge, "Date and Time" )
1894  << new StaticFunction( "year", 1, fcnYear, "Date and Time" )
1895  << new StaticFunction( "month", 1, fcnMonth, "Date and Time" )
1896  << new StaticFunction( "week", 1, fcnWeek, "Date and Time" )
1897  << new StaticFunction( "day", 1, fcnDay, "Date and Time" )
1898  << new StaticFunction( "hour", 1, fcnHour, "Date and Time" )
1899  << new StaticFunction( "minute", 1, fcnMinute, "Date and Time" )
1900  << new StaticFunction( "second", 1, fcnSeconds, "Date and Time" )
1901  << new StaticFunction( "lower", 1, fcnLower, "String" )
1902  << new StaticFunction( "upper", 1, fcnUpper, "String" )
1903  << new StaticFunction( "title", 1, fcnTitle, "String" )
1904  << new StaticFunction( "trim", 1, fcnTrim, "String" )
1905  << new StaticFunction( "levenshtein", 2, fcnLevenshtein, "Fuzzy Matching" )
1906  << new StaticFunction( "longest_common_substring", 2, fcnLCS, "Fuzzy Matching" )
1907  << new StaticFunction( "hamming_distance", 2, fcnHamming, "Fuzzy Matching" )
1908  << new StaticFunction( "soundex", 1, fcnSoundex, "Fuzzy Matching" )
1909  << new StaticFunction( "wordwrap", -1, fcnWordwrap, "String" )
1910  << new StaticFunction( "length", 1, fcnLength, "String" )
1911  << new StaticFunction( "replace", 3, fcnReplace, "String" )
1912  << new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
1913  << new StaticFunction( "regexp_substr", 2, fcnRegexpSubstr, "String" )
1914  << new StaticFunction( "substr", 3, fcnSubstr, "String" )
1915  << new StaticFunction( "concat", -1, fcnConcat, "String", QString(), false, QStringList(), false, QStringList(), true )
1916  << new StaticFunction( "strpos", 2, fcnStrpos, "String" )
1917  << new StaticFunction( "left", 2, fcnLeft, "String" )
1918  << new StaticFunction( "right", 2, fcnRight, "String" )
1919  << new StaticFunction( "rpad", 3, fcnRPad, "String" )
1920  << new StaticFunction( "lpad", 3, fcnLPad, "String" )
1921  << new StaticFunction( "format", -1, fcnFormatString, "String" )
1922  << new StaticFunction( "format_number", 2, fcnFormatNumber, "String" )
1923  << new StaticFunction( "format_date", 2, fcnFormatDate, "String" )
1924  << new StaticFunction( "color_rgb", 3, fcnColorRgb, "Color" )
1925  << new StaticFunction( "color_rgba", 4, fncColorRgba, "Color" )
1926  << new StaticFunction( "ramp_color", 2, fcnRampColor, "Color" )
1927  << new StaticFunction( "color_hsl", 3, fcnColorHsl, "Color" )
1928  << new StaticFunction( "color_hsla", 4, fncColorHsla, "Color" )
1929  << new StaticFunction( "color_hsv", 3, fcnColorHsv, "Color" )
1930  << new StaticFunction( "color_hsva", 4, fncColorHsva, "Color" )
1931  << new StaticFunction( "color_cmyk", 4, fcnColorCmyk, "Color" )
1932  << new StaticFunction( "color_cmyka", 5, fncColorCmyka, "Color" )
1933  << new StaticFunction( "$geometry", 0, fcnGeometry, "GeometryGroup", "", true )
1934  << new StaticFunction( "$area", 0, fcnGeomArea, "GeometryGroup", "", true )
1935  << new StaticFunction( "$length", 0, fcnGeomLength, "GeometryGroup", "", true )
1936  << new StaticFunction( "$perimeter", 0, fcnGeomPerimeter, "GeometryGroup", "", true )
1937  << new StaticFunction( "$x", 0, fcnX, "GeometryGroup", "", true )
1938  << new StaticFunction( "$y", 0, fcnY, "GeometryGroup", "", true )
1939  << new StaticFunction( "x_at", 1, fcnXat, "GeometryGroup", "", true, QStringList(), false, QStringList() << "xat" )
1940  << new StaticFunction( "y_at", 1, fcnYat, "GeometryGroup", "", true, QStringList(), false, QStringList() << "yat" )
1941  << new StaticFunction( "x_min", 1, fcnXMin, "GeometryGroup", "", true, QStringList(), false, QStringList() << "xmin" )
1942  << new StaticFunction( "x_max", 1, fcnXMax, "GeometryGroup", "", true, QStringList(), false, QStringList() << "xmax" )
1943  << new StaticFunction( "y_min", 1, fcnYMin, "GeometryGroup", "", true, QStringList(), false, QStringList() << "ymin" )
1944  << new StaticFunction( "y_max", 1, fcnYMax, "GeometryGroup", "", true, QStringList(), false, QStringList() << "ymax" )
1945  << new StaticFunction( "geom_from_wkt", 1, fcnGeomFromWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromWKT" )
1946  << new StaticFunction( "geom_from_gml", 1, fcnGeomFromGML, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromGML" )
1947  << new StaticFunction( "intersects_bbox", 2, fcnBbox, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "bbox" )
1948  << new StaticFunction( "disjoint", 2, fcnDisjoint, "GeometryGroup" )
1949  << new StaticFunction( "intersects", 2, fcnIntersects, "GeometryGroup" )
1950  << new StaticFunction( "touches", 2, fcnTouches, "GeometryGroup" )
1951  << new StaticFunction( "crosses", 2, fcnCrosses, "GeometryGroup" )
1952  << new StaticFunction( "contains", 2, fcnContains, "GeometryGroup" )
1953  << new StaticFunction( "overlaps", 2, fcnOverlaps, "GeometryGroup" )
1954  << new StaticFunction( "within", 2, fcnWithin, "GeometryGroup" )
1955  << new StaticFunction( "buffer", -1, fcnBuffer, "GeometryGroup" )
1956  << new StaticFunction( "centroid", 1, fcnCentroid, "GeometryGroup" )
1957  << new StaticFunction( "bounds", 1, fcnBounds, "GeometryGroup", "", true )
1958  << new StaticFunction( "bounds_width", 1, fcnBoundsWidth, "GeometryGroup", "", true )
1959  << new StaticFunction( "bounds_height", 1, fcnBoundsHeight, "GeometryGroup", "", true )
1960  << new StaticFunction( "convex_hull", 1, fcnConvexHull, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "convexHull" )
1961  << new StaticFunction( "difference", 2, fcnDifference, "GeometryGroup" )
1962  << new StaticFunction( "distance", 2, fcnDistance, "GeometryGroup" )
1963  << new StaticFunction( "intersection", 2, fcnIntersection, "GeometryGroup" )
1964  << new StaticFunction( "sym_difference", 2, fcnSymDifference, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "symDifference" )
1965  << new StaticFunction( "combine", 2, fcnCombine, "GeometryGroup" )
1966  << new StaticFunction( "union", 2, fcnCombine, "GeometryGroup" )
1967  << new StaticFunction( "geom_to_wkt", -1, fcnGeomToWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomToWKT" )
1968  << new StaticFunction( "geometry", 1, fcnGetGeometry, "GeometryGroup" )
1969  << new StaticFunction( "transform", 3, fcnTransformGeometry, "GeometryGroup" )
1970  << new StaticFunction( "$rownum", 0, fcnRowNumber, "Record" )
1971  << new StaticFunction( "$id", 0, fcnFeatureId, "Record" )
1972  << new StaticFunction( "$currentfeature", 0, fcnFeature, "Record" )
1973  << new StaticFunction( "$scale", 0, fcnScale, "Record" )
1974  << new StaticFunction( "uuid", 0, fcnUuid, "Record", QString(), false, QStringList(), false, QStringList() << "$uuid" )
1975  << new StaticFunction( "get_feature", 3, fcnGetFeature, "Record", QString(), false, QStringList(), false, QStringList() << "getFeature" )
1976  << new StaticFunction( "layer_property", 2, fcnGetLayerProperty, "General" )
1977  << new StaticFunction( "var", 1, fcnGetVariable, "General" )
1978 
1979  //return all attributes string for referencedColumns - this is caught by
1980  // QgsFeatureRequest::setSubsetOfAttributes and causes all attributes to be fetched by the
1981  // feature request
1982  << new StaticFunction( "attribute", 2, fcnAttribute, "Record", QString(), false, QStringList( QgsFeatureRequest::AllAttributes ) )
1983 
1984  << new StaticFunction( "_specialcol_", 1, fcnSpecialColumn, "Special" )
1985  ;
1986 
1988 
1989  //QgsExpression has ownership of all built-in functions
1990  Q_FOREACH ( QgsExpression::Function* func, gmFunctions )
1991  {
1992  gmOwnedFunctions << func;
1993  }
1994  }
1995  return gmFunctions;
1996 }
1997 
2000 
2002 {
2003  int fnIdx = functionIndex( name );
2004  if ( fnIdx != -1 )
2005  {
2006  // function of the same name already exists
2007  return;
2008  }
2009  gmSpecialColumns[ name ] = variant;
2010 }
2011 
2013 {
2015  if ( fit != gmSpecialColumns.end() )
2016  {
2017  gmSpecialColumns.erase( fit );
2018  }
2019 }
2020 
2022 {
2023  int fnIdx = functionIndex( name );
2024  if ( fnIdx != -1 )
2025  {
2026  // function of the same name already exists
2027  return QVariant();
2028  }
2030  if ( it == gmSpecialColumns.end() )
2031  {
2032  return QVariant();
2033  }
2034  return it.value();
2035 }
2036 
2038 {
2039  static bool initialized = false;
2040  if ( !initialized )
2041  {
2042  // Pre-register special columns that will exist within QGIS so that expressions that may use them are parsed correctly.
2043  // This is really sub-optimal, we should get rid of the special columns and instead have contexts in which some values
2044  // are defined and some are not ($rownum makes sense only in field calculator, $scale only when rendering, $page only for composer etc.)
2045 
2046  //pairs of column name to group name
2048  lst << qMakePair( QString( "$page" ), QString( "Composer" ) );
2049  lst << qMakePair( QString( "$feature" ), QString( "Atlas" ) );
2050  lst << qMakePair( QString( "$numpages" ), QString( "Composer" ) );
2051  lst << qMakePair( QString( "$numfeatures" ), QString( "Atlas" ) );
2052  lst << qMakePair( QString( "$atlasfeatureid" ), QString( "Atlas" ) );
2053  lst << qMakePair( QString( "$atlasgeometry" ), QString( "Atlas" ) );
2054  lst << qMakePair( QString( "$atlasfeature" ), QString( "Atlas" ) );
2055  lst << qMakePair( QString( "$map" ), QString( "Composer" ) );
2056 
2057  QList< QPair<QString, QString> >::const_iterator it = lst.constBegin();
2058  for ( ; it != lst.constEnd(); ++it )
2059  {
2060  setSpecialColumn(( *it ).first, QVariant() );
2061  gmSpecialColumnGroups[( *it ).first ] = ( *it ).second;
2062  }
2063 
2064  initialized = true;
2065  }
2066 
2067  if ( functionIndex( name ) != -1 )
2068  return false;
2069  return gmSpecialColumns.contains( name );
2070 }
2071 
2072 bool QgsExpression::isValid( const QString &text, const QgsFields &fields, QString &errorMessage )
2073 {
2075  return isValid( text, &context, errorMessage );
2076 }
2077 
2078 bool QgsExpression::isValid( const QString &text, const QgsExpressionContext *context, QString &errorMessage )
2079 {
2080  QgsExpression exp( text );
2081  exp.prepare( context );
2082  errorMessage = exp.parserErrorString();
2083  return !exp.hasParserError();
2084 }
2085 
2087 {
2088  QList<Function*> defs;
2090  {
2091  //check for special column group name
2092  QString group = gmSpecialColumnGroups.value( it.key(), "Record" );
2093  defs << new StaticFunction( it.key(), 0, ( FcnEvalContext )0, group );
2094  }
2095  return defs;
2096 }
2097 
2099 {
2100  return QString( "\"%1\"" ).arg( name.replace( "\"", "\"\"" ) );
2101 }
2102 
2104 {
2105  text.replace( "'", "''" );
2106  text.replace( '\\', "\\\\" );
2107  text.replace( '\n', "\\n" );
2108  text.replace( '\t', "\\t" );
2109  return QString( "'%1'" ).arg( text );
2110 }
2111 
2113 {
2114  return functionIndex( name ) != -1;
2115 }
2116 
2118 {
2119  int count = functionCount();
2120  for ( int i = 0; i < count; i++ )
2121  {
2122  if ( QString::compare( name, Functions()[i]->name(), Qt::CaseInsensitive ) == 0 )
2123  return i;
2124  foreach ( QString alias, Functions()[i]->aliases() )
2125  {
2126  if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
2127  return i;
2128  }
2129  }
2130  return -1;
2131 }
2132 
2134 {
2135  return Functions().size();
2136 }
2137 
2138 
2140  : mRowNumber( 0 )
2141  , mScale( 0 )
2142  , mExp( expr )
2143  , mCalc( 0 )
2144 {
2146 
2147  if ( mParserErrorString.isNull() )
2148  Q_ASSERT( mRootNode );
2149 }
2150 
2152 {
2153  delete mCalc;
2154  delete mRootNode;
2155 }
2156 
2158 {
2159  if ( !mRootNode )
2160  return QStringList();
2161 
2163 
2164  // filter out duplicates
2165  for ( int i = 0; i < columns.count(); i++ )
2166  {
2167  QString col = columns.at( i );
2168  for ( int j = i + 1; j < columns.count(); j++ )
2169  {
2170  if ( QString::compare( col, columns[j], Qt::CaseInsensitive ) == 0 )
2171  {
2172  // this column is repeated: remove it!
2173  columns.removeAt( j-- );
2174  }
2175  }
2176  }
2177 
2178  return columns;
2179 }
2180 
2182 {
2183  if ( !mRootNode )
2184  return false;
2185  return mRootNode->needsGeometry();
2186 }
2187 
2189 {
2190  if ( mCalc )
2191  return;
2192 
2193  // Use planimetric as default
2194  mCalc = new QgsDistanceArea();
2195  mCalc->setEllipsoidalMode( false );
2196 }
2197 
2199 {
2200  delete mCalc;
2201  mCalc = new QgsDistanceArea( calc );
2202 }
2203 
2204 bool QgsExpression::prepare( const QgsFields& fields )
2205 {
2207  return prepare( &fc );
2208 }
2209 
2211 {
2213  if ( !mRootNode )
2214  {
2215  //re-parse expression. Creation of QgsExpressionContexts may have added extra
2216  //known functions since this expression was created, so we have another try
2217  //at re-parsing it now that the context must have been created
2219  }
2220 
2221  if ( !mRootNode )
2222  {
2223  mEvalErrorString = QObject::tr( "No root node! Parsing failed?" );
2224  return false;
2225  }
2226 
2227  return mRootNode->prepare( this, context );
2228 }
2229 
2231 {
2233  if ( !mRootNode )
2234  {
2235  mEvalErrorString = QObject::tr( "No root node! Parsing failed?" );
2236  return QVariant();
2237  }
2238 
2240  return mRootNode->eval( this, &context );
2241 }
2242 
2244 {
2246  return evaluate( &f );
2248 }
2249 
2251 {
2252  // first prepare
2254  bool res = prepare( &context );
2255  if ( !res )
2256  return QVariant();
2257 
2258  // then evaluate
2259  return evaluate( &context );
2260 }
2261 
2262 inline QVariant QgsExpression::evaluate( const QgsFeature& f, const QgsFields& fields )
2263 {
2265  return evaluate( &f, fields );
2267 }
2268 
2270 {
2272  if ( !mRootNode )
2273  {
2274  mEvalErrorString = QObject::tr( "No root node! Parsing failed?" );
2275  return QVariant();
2276  }
2277 
2278  return mRootNode->eval( this, ( QgsExpressionContext* )0 );
2279 }
2280 
2282 {
2284  if ( !mRootNode )
2285  {
2286  mEvalErrorString = QObject::tr( "No root node! Parsing failed?" );
2287  return QVariant();
2288  }
2289 
2290  return mRootNode->eval( this, context );
2291 }
2292 
2294 {
2295  if ( !mRootNode )
2296  return QObject::tr( "(no root)" );
2297 
2298  return mRootNode->dump();
2299 }
2300 
2302 {
2303  if ( mRootNode )
2304  mRootNode->accept( v );
2305 }
2306 
2308  QgsVectorLayer *layer,
2309  const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
2310 {
2312  return replaceExpressionText( action, &context, substitutionMap, distanceArea );
2313 }
2314 
2315 QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
2316 {
2317  QString expr_action;
2318 
2319  QMap<QString, QVariant> savedValues;
2320  if ( substitutionMap )
2321  {
2322  // variables with a local scope (must be restored after evaluation)
2323  for ( QMap<QString, QVariant>::const_iterator sit = substitutionMap->begin(); sit != substitutionMap->end(); ++sit )
2324  {
2325  QVariant oldValue = QgsExpression::specialColumn( sit.key() );
2326  if ( !oldValue.isNull() )
2327  savedValues.insert( sit.key(), oldValue );
2328 
2329  // set the new value
2330  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
2331  }
2332  }
2333 
2334  int index = 0;
2335  while ( index < action.size() )
2336  {
2337  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
2338 
2339  int pos = rx.indexIn( action, index );
2340  if ( pos < 0 )
2341  break;
2342 
2343  int start = index;
2344  index = pos + rx.matchedLength();
2345  QString to_replace = rx.cap( 1 ).trimmed();
2346  QgsDebugMsg( "Found expression: " + to_replace );
2347 
2348  QgsExpression exp( to_replace );
2349  if ( exp.hasParserError() )
2350  {
2351  QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
2352  expr_action += action.mid( start, index - start );
2353  continue;
2354  }
2355 
2356  if ( distanceArea )
2357  {
2358  //if QgsDistanceArea specified for area/distance conversion, use it
2359  exp.setGeomCalculator( *distanceArea );
2360  }
2361 
2362  QVariant result = exp.evaluate( context );
2363 
2364  if ( exp.hasEvalError() )
2365  {
2366  QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
2367  expr_action += action.mid( start, index - start );
2368  continue;
2369  }
2370 
2371  QgsDebugMsg( "Expression result is: " + result.toString() );
2372  expr_action += action.mid( start, pos - start ) + result.toString();
2373  }
2374 
2375  expr_action += action.mid( index );
2376 
2377  // restore overwritten local values
2378  for ( QMap<QString, QVariant>::const_iterator sit = savedValues.begin(); sit != savedValues.end(); ++sit )
2379  {
2380  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
2381  }
2382 
2383  return expr_action;
2384 }
2385 
2386 double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
2387 {
2388  bool ok;
2389  //first test if text is directly convertible to double
2390  double convertedValue = text.toDouble( &ok );
2391  if ( ok )
2392  {
2393  return convertedValue;
2394  }
2395 
2396  //otherwise try to evalute as expression
2397  QgsExpression expr( text );
2398 
2399  QgsExpressionContext context;
2402 
2403  QVariant result = expr.evaluate( &context );
2404  convertedValue = result.toDouble( &ok );
2405  if ( expr.hasEvalError() || !ok )
2406  {
2407  return fallbackValue;
2408  }
2409  return convertedValue;
2410 }
2411 
2412 
2414 // nodes
2415 
2417 {
2418  QString msg; bool first = true;
2419  foreach ( Node* n, mList )
2420  {
2421  if ( !first ) msg += ", "; else first = false;
2422  msg += n->dump();
2423  }
2424  return msg;
2425 }
2426 
2427 
2428 //
2429 
2431 {
2432  QVariant val = mOperand->eval( parent, context );
2434 
2435  switch ( mOp )
2436  {
2437  case uoNot:
2438  {
2439  TVL tvl = getTVLValue( val, parent );
2441  return tvl2variant( NOT[tvl] );
2442  }
2443 
2444  case uoMinus:
2445  if ( isIntSafe( val ) )
2446  return QVariant( - getIntValue( val, parent ) );
2447  else if ( isDoubleSafe( val ) )
2448  return QVariant( - getDoubleValue( val, parent ) );
2449  else
2450  SET_EVAL_ERROR( QObject::tr( "Unary minus only for numeric values." ) );
2451  break;
2452  default:
2453  Q_ASSERT( 0 && "unknown unary operation" );
2454  }
2455  return QVariant();
2456 }
2457 
2459 {
2460  return mOperand->prepare( parent, context );
2461 }
2462 
2464 {
2465  return QString( "%1 %2" ).arg( UnaryOperatorText[mOp] ).arg( mOperand->dump() );
2466 }
2467 
2468 //
2469 
2471 {
2472  QVariant vL = mOpLeft->eval( parent, context );
2474  QVariant vR = mOpRight->eval( parent, context );
2476 
2477  switch ( mOp )
2478  {
2479  case boPlus:
2480  if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
2481  {
2482  QString sL = isNull( vL ) ? QString() : getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2483  QString sR = isNull( vR ) ? QString() : getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2484  return QVariant( sL + sR );
2485  }
2486  //intentional fall-through
2487  case boMinus:
2488  case boMul:
2489  case boDiv:
2490  case boMod:
2491  {
2492  if ( isNull( vL ) || isNull( vR ) )
2493  return QVariant();
2494  else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
2495  {
2496  // both are integers - let's use integer arithmetics
2497  int iL = getIntValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2498  int iR = getIntValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2499 
2500  if ( mOp == boMod && iR == 0 )
2501  return QVariant();
2502 
2503  return QVariant( computeInt( iL, iR ) );
2504  }
2505  else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
2506  {
2507  QDateTime dL = getDateTimeValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2509  if ( mOp == boDiv || mOp == boMul || mOp == boMod )
2510  {
2511  parent->setEvalErrorString( QObject::tr( "Can't preform /, *, or % on DateTime and Interval" ) );
2512  return QVariant();
2513  }
2514  return QVariant( computeDateTimeFromInterval( dL, &iL ) );
2515  }
2516  else
2517  {
2518  // general floating point arithmetic
2519  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2520  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2521  if (( mOp == boDiv || mOp == boMod ) && fR == 0. )
2522  return QVariant(); // silently handle division by zero and return NULL
2523  return QVariant( computeDouble( fL, fR ) );
2524  }
2525  }
2526  case boIntDiv:
2527  {
2528  //integer division
2529  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2530  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2531  if ( fR == 0. )
2532  return QVariant(); // silently handle division by zero and return NULL
2533  return QVariant( qFloor( fL / fR ) );
2534  }
2535  case boPow:
2536  if ( isNull( vL ) || isNull( vR ) )
2537  return QVariant();
2538  else
2539  {
2540  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2541  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2542  return QVariant( pow( fL, fR ) );
2543  }
2544 
2545  case boAnd:
2546  {
2547  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
2549  return tvl2variant( AND[tvlL][tvlR] );
2550  }
2551 
2552  case boOr:
2553  {
2554  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
2556  return tvl2variant( OR[tvlL][tvlR] );
2557  }
2558 
2559  case boEQ:
2560  case boNE:
2561  case boLT:
2562  case boGT:
2563  case boLE:
2564  case boGE:
2565  if ( isNull( vL ) || isNull( vR ) )
2566  {
2567  return TVL_Unknown;
2568  }
2569  else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) )
2570  {
2571  // do numeric comparison if both operators can be converted to numbers
2572  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2573  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2574  return compare( fL - fR ) ? TVL_True : TVL_False;
2575  }
2576  else
2577  {
2578  // do string comparison otherwise
2579  QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2580  QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2581  int diff = QString::compare( sL, sR );
2582  return compare( diff ) ? TVL_True : TVL_False;
2583  }
2584 
2585  case boIs:
2586  case boIsNot:
2587  if ( isNull( vL ) && isNull( vR ) ) // both operators null
2588  return ( mOp == boIs ? TVL_True : TVL_False );
2589  else if ( isNull( vL ) || isNull( vR ) ) // one operator null
2590  return ( mOp == boIs ? TVL_False : TVL_True );
2591  else // both operators non-null
2592  {
2593  bool equal = false;
2594  if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) )
2595  {
2596  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2597  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2598  equal = fL == fR;
2599  }
2600  else
2601  {
2602  QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2603  QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2604  equal = QString::compare( sL, sR ) == 0;
2605  }
2606  if ( equal )
2607  return mOp == boIs ? TVL_True : TVL_False;
2608  else
2609  return mOp == boIs ? TVL_False : TVL_True;
2610  }
2611 
2612  case boRegexp:
2613  case boLike:
2614  case boNotLike:
2615  case boILike:
2616  case boNotILike:
2617  if ( isNull( vL ) || isNull( vR ) )
2618  return TVL_Unknown;
2619  else
2620  {
2621  QString str = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2622  QString regexp = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2623  // TODO: cache QRegExp in case that regexp is a literal string (i.e. it will stay constant)
2624  bool matches;
2625  if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
2626  {
2627  QString esc_regexp = QRegExp::escape( regexp );
2628  // XXX escape % and _ ???
2629  esc_regexp.replace( "%", ".*" );
2630  esc_regexp.replace( "_", "." );
2631  matches = QRegExp( esc_regexp, mOp == boLike || mOp == boNotLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( str );
2632  }
2633  else
2634  {
2635  matches = QRegExp( regexp ).indexIn( str ) != -1;
2636  }
2637 
2638  if ( mOp == boNotLike || mOp == boNotILike )
2639  {
2640  matches = !matches;
2641  }
2642 
2643  return matches ? TVL_True : TVL_False;
2644  }
2645 
2646  case boConcat:
2647  if ( isNull( vL ) || isNull( vR ) )
2648  return QVariant();
2649  else
2650  {
2651  QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2652  QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2653  return QVariant( sL + sR );
2654  }
2655 
2656  default: break;
2657  }
2658  Q_ASSERT( false );
2659  return QVariant();
2660 }
2661 
2663 {
2664  switch ( mOp )
2665  {
2666  case boEQ: return diff == 0;
2667  case boNE: return diff != 0;
2668  case boLT: return diff < 0;
2669  case boGT: return diff > 0;
2670  case boLE: return diff <= 0;
2671  case boGE: return diff >= 0;
2672  default: Q_ASSERT( false ); return false;
2673  }
2674 }
2675 
2677 {
2678  switch ( mOp )
2679  {
2680  case boPlus: return x+y;
2681  case boMinus: return x-y;
2682  case boMul: return x*y;
2683  case boDiv: return x/y;
2684  case boMod: return x%y;
2685  default: Q_ASSERT( false ); return 0;
2686  }
2687 }
2688 
2690 {
2691  switch ( mOp )
2692  {
2693  case boPlus: return d.addSecs( i->seconds() );
2694  case boMinus: return d.addSecs( -i->seconds() );
2695  default: Q_ASSERT( false ); return QDateTime();
2696  }
2697 }
2698 
2700 {
2701  switch ( mOp )
2702  {
2703  case boPlus: return x+y;
2704  case boMinus: return x-y;
2705  case boMul: return x*y;
2706  case boDiv: return x/y;
2707  case boMod: return fmod( x,y );
2708  default: Q_ASSERT( false ); return 0;
2709  }
2710 }
2711 
2713 {
2714  bool resL = mOpLeft->prepare( parent, context );
2715  bool resR = mOpRight->prepare( parent, context );
2716  return resL && resR;
2717 }
2718 
2720 {
2721  // see left/right in qgsexpressionparser.yy
2722  switch ( mOp )
2723  {
2724  case boOr:
2725  return 1;
2726 
2727  case boAnd:
2728  return 2;
2729 
2730  case boEQ:
2731  case boNE:
2732  case boLE:
2733  case boGE:
2734  case boLT:
2735  case boGT:
2736  case boRegexp:
2737  case boLike:
2738  case boILike:
2739  case boNotLike:
2740  case boNotILike:
2741  case boIs:
2742  case boIsNot:
2743  return 3;
2744 
2745  case boPlus:
2746  case boMinus:
2747  return 4;
2748 
2749  case boMul:
2750  case boDiv:
2751  case boIntDiv:
2752  case boMod:
2753  return 5;
2754 
2755  case boPow:
2756  return 6;
2757 
2758  case boConcat:
2759  return 7;
2760  }
2761  Q_ASSERT( 0 && "unexpected binary operator" );
2762  return -1;
2763 }
2764 
2766 {
2767  // see left/right in qgsexpressionparser.yy
2768  switch ( mOp )
2769  {
2770  case boOr:
2771  case boAnd:
2772  case boEQ:
2773  case boNE:
2774  case boLE:
2775  case boGE:
2776  case boLT:
2777  case boGT:
2778  case boRegexp:
2779  case boLike:
2780  case boILike:
2781  case boNotLike:
2782  case boNotILike:
2783  case boIs:
2784  case boIsNot:
2785  case boPlus:
2786  case boMinus:
2787  case boMul:
2788  case boDiv:
2789  case boIntDiv:
2790  case boMod:
2791  case boConcat:
2792  return true;
2793 
2794  case boPow:
2795  return false;
2796  }
2797  Q_ASSERT( 0 && "unexpected binary operator" );
2798  return false;
2799 }
2800 
2802 {
2803  QgsExpression::NodeBinaryOperator *lOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpLeft );
2804  QgsExpression::NodeBinaryOperator *rOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpRight );
2805 
2806  QString fmt;
2807  if ( leftAssociative() )
2808  {
2809  fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";
2810  fmt += " %2 ";
2811  fmt += rOp && ( rOp->precedence() <= precedence() ) ? "(%3)" : "%3";
2812  }
2813  else
2814  {
2815  fmt += lOp && ( lOp->precedence() <= precedence() ) ? "(%1)" : "%1";
2816  fmt += " %2 ";
2817  fmt += rOp && ( rOp->precedence() < precedence() ) ? "(%3)" : "%3";
2818  }
2819 
2820  return fmt.arg( mOpLeft->dump() ).arg( BinaryOperatorText[mOp] ).arg( mOpRight->dump() );
2821 }
2822 
2823 //
2824 
2826 {
2827  if ( mList->count() == 0 )
2828  return mNotIn ? TVL_True : TVL_False;
2829  QVariant v1 = mNode->eval( parent, context );
2831  if ( isNull( v1 ) )
2832  return TVL_Unknown;
2833 
2834  bool listHasNull = false;
2835 
2836  foreach ( Node* n, mList->list() )
2837  {
2838  QVariant v2 = n->eval( parent, context );
2840  if ( isNull( v2 ) )
2841  listHasNull = true;
2842  else
2843  {
2844  bool equal = false;
2845  // check whether they are equal
2846  if ( isDoubleSafe( v1 ) && isDoubleSafe( v2 ) )
2847  {
2848  double f1 = getDoubleValue( v1, parent ); ENSURE_NO_EVAL_ERROR;
2849  double f2 = getDoubleValue( v2, parent ); ENSURE_NO_EVAL_ERROR;
2850  equal = f1 == f2;
2851  }
2852  else
2853  {
2854  QString s1 = getStringValue( v1, parent ); ENSURE_NO_EVAL_ERROR;
2855  QString s2 = getStringValue( v2, parent ); ENSURE_NO_EVAL_ERROR;
2856  equal = QString::compare( s1, s2 ) == 0;
2857  }
2858 
2859  if ( equal ) // we know the result
2860  return mNotIn ? TVL_False : TVL_True;
2861  }
2862  }
2863 
2864  // item not found
2865  if ( listHasNull )
2866  return TVL_Unknown;
2867  else
2868  return mNotIn ? TVL_True : TVL_False;
2869 }
2870 
2872 {
2873  bool res = mNode->prepare( parent, context );
2874  foreach ( Node* n, mList->list() )
2875  {
2876  res = res && n->prepare( parent, context );
2877  }
2878  return res;
2879 }
2880 
2882 {
2883  return QString( "%1 %2 IN (%3)" ).arg( mNode->dump() ).arg( mNotIn ? "NOT" : "" ).arg( mList->dump() );
2884 }
2885 
2886 //
2887 
2889 {
2890  QString name = Functions()[mFnIndex]->name();
2891  Function* fd = context && context->hasFunction( name ) ? context->function( name ) : Functions()[mFnIndex];
2892 
2893  // evaluate arguments
2894  QVariantList argValues;
2895  if ( mArgs )
2896  {
2897  foreach ( Node* n, mArgs->list() )
2898  {
2899  QVariant v;
2900  if ( fd->lazyEval() )
2901  {
2902  // Pass in the node for the function to eval as it needs.
2903  v = QVariant::fromValue( n );
2904  }
2905  else
2906  {
2907  v = n->eval( parent, context );
2909  if ( isNull( v ) && !fd->handlesNull() )
2910  return QVariant(); // all "normal" functions return NULL, when any parameter is NULL (so coalesce is abnormal)
2911  }
2912  argValues.append( v );
2913  }
2914  }
2915 
2916  // run the function
2917  QVariant res = fd->func( argValues, context, parent );
2919 
2920  // everything went fine
2921  return res;
2922 }
2923 
2925 {
2926  bool res = true;
2927  if ( mArgs )
2928  {
2929  foreach ( Node* n, mArgs->list() )
2930  {
2931  res = res && n->prepare( parent, context );
2932  }
2933  }
2934  return res;
2935 }
2936 
2938 {
2939  Function* fd = Functions()[mFnIndex];
2940  if ( fd->params() == 0 )
2941  return QString( "%1%2" ).arg( fd->name() ).arg( fd->name().startsWith( '$' ) ? "" : "()" ); // special column
2942  else
2943  return QString( "%1(%2)" ).arg( fd->name() ).arg( mArgs ? mArgs->dump() : QString() ); // function
2944 }
2945 
2947 {
2948  Function* fd = Functions()[mFnIndex];
2949  QStringList functionColumns = fd->referencedColumns();
2950 
2951  if ( !mArgs )
2952  {
2953  //no referenced columns in arguments, just return function's referenced columns
2954  return functionColumns;
2955  }
2956 
2957  foreach ( Node* n, mArgs->list() )
2958  {
2959  functionColumns.append( n->referencedColumns() );
2960  }
2961 
2962  //remove duplicates and return
2963  return functionColumns.toSet().toList();
2964 }
2965 
2966 //
2967 
2969 {
2970  Q_UNUSED( context );
2971  Q_UNUSED( parent );
2972  return mValue;
2973 }
2974 
2976 {
2977  Q_UNUSED( parent );
2978  Q_UNUSED( context );
2979  return true;
2980 }
2981 
2982 
2984 {
2985  if ( mValue.isNull() )
2986  return "NULL";
2987 
2988  switch ( mValue.type() )
2989  {
2990  case QVariant::Int: return QString::number( mValue.toInt() );
2991  case QVariant::Double: return QString::number( mValue.toDouble() );
2992  case QVariant::String: return quotedString( mValue.toString() );
2993  case QVariant::Bool: return mValue.toBool() ? "TRUE" : "FALSE";
2994  default: return QObject::tr( "[unsupported type;%1; value:%2]" ).arg( mValue.typeName() ).arg( mValue.toString() );
2995  }
2996 }
2997 
2998 //
2999 
3001 {
3002  Q_UNUSED( parent );
3003  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) )
3004  {
3005  QgsFeature feature = qvariant_cast<QgsFeature>( context->variable( QgsExpressionContext::EXPR_FEATURE ) );
3006  if ( mIndex >= 0 )
3007  return feature.attribute( mIndex );
3008  else
3009  return feature.attribute( mName );
3010  }
3011  return QVariant( "[" + mName + "]" );
3012 }
3013 
3015 {
3016  if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
3017  return false;
3018 
3019  QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
3020 
3021  for ( int i = 0; i < fields.count(); ++i )
3022  {
3023  if ( QString::compare( fields[i].name(), mName, Qt::CaseInsensitive ) == 0 )
3024  {
3025  mIndex = i;
3026  return true;
3027  }
3028  }
3029  parent->mEvalErrorString = QObject::tr( "Column '%1' not found" ).arg( mName );
3030  mIndex = -1;
3031  return false;
3032 }
3033 
3035 {
3036  return QRegExp( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ).exactMatch( mName ) ? mName : quotedColumnRef( mName );
3037 }
3038 
3039 //
3040 
3042 {
3043  foreach ( WhenThen* cond, mConditions )
3044  {
3045  QVariant vWhen = cond->mWhenExp->eval( parent, context );
3046  TVL tvl = getTVLValue( vWhen, parent );
3048  if ( tvl == True )
3049  {
3050  QVariant vRes = cond->mThenExp->eval( parent, context );
3052  return vRes;
3053  }
3054  }
3055 
3056  if ( mElseExp )
3057  {
3058  QVariant vElse = mElseExp->eval( parent, context );
3060  return vElse;
3061  }
3062 
3063  // return NULL if no condition is matching
3064  return QVariant();
3065 }
3066 
3068 {
3069  bool res;
3070  foreach ( WhenThen* cond, mConditions )
3071  {
3072  res = cond->mWhenExp->prepare( parent, context )
3073  & cond->mThenExp->prepare( parent, context );
3074  if ( !res ) return false;
3075  }
3076 
3077  if ( mElseExp )
3078  return mElseExp->prepare( parent, context );
3079 
3080  return true;
3081 }
3082 
3084 {
3085  QString msg = QString( "CASE" );
3086  foreach ( WhenThen* cond, mConditions )
3087  {
3088  msg += QString( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump() ).arg( cond->mThenExp->dump() );
3089  }
3090  if ( mElseExp )
3091  msg += QString( " ELSE %1" ).arg( mElseExp->dump() );
3092  msg += QString( " END" );
3093  return msg;
3094 }
3095 
3097 {
3098  QStringList lst;
3099  foreach ( WhenThen* cond, mConditions )
3100  {
3101  lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
3102  }
3103 
3104  if ( mElseExp )
3105  lst += mElseExp->referencedColumns();
3106 
3107  return lst;
3108 }
3109 
3111 {
3112  foreach ( WhenThen* cond, mConditions )
3113  {
3114  if ( cond->mWhenExp->needsGeometry() ||
3115  cond->mThenExp->needsGeometry() )
3116  return true;
3117  }
3118 
3119  if ( mElseExp && mElseExp->needsGeometry() )
3120  return true;
3121 
3122  return false;
3123 }
3124 
3126 {
3128  return gFunctionHelpTexts.value( name, QObject::tr( "function help for %1 missing" ).arg( name ) );
3129 }
3130 
3132 
3134 {
3135  if ( !gVariableHelpTexts.isEmpty() )
3136  return;
3137 
3138  //global variables
3139  gVariableHelpTexts.insert( "qgis_version", QCoreApplication::translate( "variable_help", "Current QGIS version string." ) );
3140  gVariableHelpTexts.insert( "qgis_version_no", QCoreApplication::translate( "variable_help", "Current QGIS version number." ) );
3141  gVariableHelpTexts.insert( "qgis_release_name", QCoreApplication::translate( "variable_help", "Current QGIS release name." ) );
3142 
3143  //project variables
3144  gVariableHelpTexts.insert( "project_title", QCoreApplication::translate( "variable_help", "Title of current project." ) );
3145  gVariableHelpTexts.insert( "project_path", QCoreApplication::translate( "variable_help", "Full path (including file name) of current project." ) );
3146  gVariableHelpTexts.insert( "project_folder", QCoreApplication::translate( "variable_help", "Folder for current project." ) );
3147  gVariableHelpTexts.insert( "project_filename", QCoreApplication::translate( "variable_help", "Filename of current project." ) );
3148 
3149  //layer variables
3150  gVariableHelpTexts.insert( "layer_name", QCoreApplication::translate( "variable_help", "Name of current layer." ) );
3151  gVariableHelpTexts.insert( "layer_id", QCoreApplication::translate( "variable_help", "ID of current project." ) );
3152 
3153  //composition variables
3154  gVariableHelpTexts.insert( "layout_numpages", QCoreApplication::translate( "variable_help", "Number of pages in composition." ) );
3155  gVariableHelpTexts.insert( "layout_pageheight", QCoreApplication::translate( "variable_help", "Composition page height in mm." ) );
3156  gVariableHelpTexts.insert( "layout_pagewidth", QCoreApplication::translate( "variable_help", "Composition page width in mm." ) );
3157  gVariableHelpTexts.insert( "layout_dpi", QCoreApplication::translate( "variable_help", "Composition resolution (DPI)." ) );
3158 
3159  //atlas variables
3160  gVariableHelpTexts.insert( "atlas_totalfeatures", QCoreApplication::translate( "variable_help", "Total number of features in atlas." ) );
3161  gVariableHelpTexts.insert( "atlas_featurenumber", QCoreApplication::translate( "variable_help", "Current atlas feature number." ) );
3162  gVariableHelpTexts.insert( "atlas_filename", QCoreApplication::translate( "variable_help", "Current atlas file name." ) );
3163  gVariableHelpTexts.insert( "atlas_pagename", QCoreApplication::translate( "variable_help", "Current atlas page name." ) );
3164  gVariableHelpTexts.insert( "atlas_feature", QCoreApplication::translate( "variable_help", "Current atlas feature (as feature object)." ) );
3165  gVariableHelpTexts.insert( "atlas_featureid", QCoreApplication::translate( "variable_help", "Current atlas feature ID." ) );
3166 
3167  //composer item variables
3168  gVariableHelpTexts.insert( "item_id", QCoreApplication::translate( "variable_help", "Composer item user ID (not necessarily unique)." ) );
3169  gVariableHelpTexts.insert( "item_uuid", QCoreApplication::translate( "variable_help", "Composer item unique ID." ) );
3170  gVariableHelpTexts.insert( "item_left", QCoreApplication::translate( "variable_help", "Left position of composer item (in mm)." ) );
3171  gVariableHelpTexts.insert( "item_top", QCoreApplication::translate( "variable_help", "Top position of composer item (in mm)." ) );
3172  gVariableHelpTexts.insert( "item_width", QCoreApplication::translate( "variable_help", "Width of composer item (in mm)." ) );
3173  gVariableHelpTexts.insert( "item_height", QCoreApplication::translate( "variable_help", "Height of composer item (in mm)." ) );
3174 }
3175 
3176 QString QgsExpression::variableHelpText( const QString &variableName, bool showValue, const QVariant &value )
3177 {
3179  QString text = gVariableHelpTexts.contains( variableName ) ? QString( "<p>%1</p>" ).arg( gVariableHelpTexts.value( variableName ) ) : QString();
3180  if ( showValue )
3181  {
3182  QString valueString;
3183  if ( !value.isValid() )
3184  {
3185  valueString = QCoreApplication::translate( "variable_help", "not set" );
3186  }
3187  else if ( value.type() == QVariant::String )
3188  {
3189  valueString = QString( "'<b>%1</b>'" ).arg( value.toString() );
3190  }
3191  else
3192  {
3193  valueString = QString( "<b>%1</b>" ).arg( value.toString() );
3194  }
3195  text.append( QCoreApplication::translate( "variable_help", "<p>Current value: %1</p>" ).arg( valueString ) );
3196  }
3197  return text;
3198 }
3199 
3201 
3203 {
3204  if ( gGroups.isEmpty() )
3205  {
3206  gGroups.insert( "General", QObject::tr( "General" ) );
3207  gGroups.insert( "Operators", QObject::tr( "Operators" ) );
3208  gGroups.insert( "Conditionals", QObject::tr( "Conditionals" ) );
3209  gGroups.insert( "Fields and Values", QObject::tr( "Fields and Values" ) );
3210  gGroups.insert( "Math", QObject::tr( "Math" ) );
3211  gGroups.insert( "Conversions", QObject::tr( "Conversions" ) );
3212  gGroups.insert( "Date and Time", QObject::tr( "Date and Time" ) );
3213  gGroups.insert( "String", QObject::tr( "String" ) );
3214  gGroups.insert( "Color", QObject::tr( "Color" ) );
3215  gGroups.insert( "GeometryGroup", QObject::tr( "Geometry" ) );
3216  gGroups.insert( "Record", QObject::tr( "Record" ) );
3217  gGroups.insert( "Variables", QObject::tr( "Variables" ) );
3218  }
3219 
3220  //return the translated name for this group. If group does not
3221  //have a translated name in the gGroups hash, return the name
3222  //unchanged
3223  return gGroups.value( name, name );
3224 }
3225 
3226 
3227 QVariant QgsExpression::Function::func( const QVariantList& values, const QgsFeature* feature, QgsExpression* parent )
3228 {
3229  //default implementation creates a QgsFeatureBasedExpressionContext
3231  return func( values, &c, parent );
3232 }
3233 
3234 QVariant QgsExpression::Function::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
3235 {
3236  //base implementation calls deprecated func to avoid API breakage
3237  QgsFeature f;
3238  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) )
3239  f = qvariant_cast<QgsFeature>( context->variable( QgsExpressionContext::EXPR_FEATURE ) );
3240 
3242  return func( values, &f, parent );
3244 }
3245 
3247 {
3248  //default implementation creates a QgsFeatureBasedExpressionContext
3250  return eval( parent, &c );
3251 }
3252 
3254 {
3255  //base implementation calls deprecated eval to avoid API breakage
3256  QgsFeature f;
3257  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) )
3258  f = qvariant_cast<QgsFeature>( context->variable( QgsExpressionContext::EXPR_FEATURE ) );
3259 
3261  return eval( parent, &f );
3263 }
3264 
3266 {
3268  return prepare( parent, &c );
3269 }
3270 
3272 {
3273  //base implementation calls deprecated prepare to avoid API breakage
3274  QgsFields f;
3275  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
3276  f = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
3277 
3279  return prepare( parent, f );
3281 }
3282 
3283 QVariant QgsExpression::StaticFunction::func( const QVariantList &values, const QgsFeature* f, QgsExpression* parent )
3284 {
3286  return mFnc ? mFnc( values, f, parent ) : QVariant();
3288 }
static bool isFunctionName(const QString &name)
static QVariant fcnDisjoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnConvexHull(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QString longestCommonSubstring(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the longest common substring between two strings.
bool canConvert(Type t) const
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:88
qlonglong toLongLong(bool *ok) const
virtual QStringList referencedColumns() const =0
Abstract virtual method which returns a list of columns required to evaluate this node...
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.
QString toString(Qt::DateFormat format) const
static QVariant fcnGeomLength(const QVariantList &, const QgsExpressionContext *context, 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 QVariant fcnSin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static unsigned index
virtual Q_DECL_DEPRECATED QVariant eval(QgsExpression *parent, const QgsFeature *f)
Abstract virtual eval method Errors are reported to the parent.
bool hasFunction(const QString &name) const
Checks whether a specified function is contained in the context.
Base class for all map layer types.
Definition: qgsmaplayer.h:49
static QVariant fcnBoundsWidth(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnY(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
QString cap(int nth) const
static QVariant fcnGeomPerimeter(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
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:95
virtual QString dump() const override
Abstract virtual dump method.
static QVariant fcnGeomFromWKT(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
virtual Q_DECL_DEPRECATED QVariant func(const QVariantList &values, const QgsFeature *f, QgsExpression *parent) override
static QVariant fcnFormatDate(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
iterator erase(iterator pos)
QStringList referencedColumns() const
Get list of columns referenced by the expression.
QPointF toPointF() const
static QVariant fcnFormatString(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsGeometry * convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry. ...
static bool unregisterFunction(QString name)
Unregisters a function from the expression engine.
bool contains(const Key &key) const
static QString quotedColumnRef(QString name)
return quoted column reference (in double quotes)
Q_DECL_DEPRECATED QVariant evaluate(const QgsFeature *f)
Evaluate the feature and return the result.
virtual bool handlesNull() const
static QVariant fcnBuffer(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsGeometry * symDifference(const QgsGeometry *geometry) const
Returns a Geometry representing the points making up this Geometry that do not make up other...
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
static QVariant fcnClamp(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool hasVariable(const QString &name) const
Check whether a variable is specified by any scope within the context.
static QVariant fcnGetGeometry(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool lazyEval()
True if this function should use lazy evaluation.
static QVariant fcnStrpos(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static void initVariableHelp()
QString name() const
static QVariant fcnXat(const QVariantList &values, const QgsExpressionContext *f, QgsExpression *parent)
QgsGeometry * difference(const QgsGeometry *geometry) const
Returns a geometry representing the points making up this geometry that do not make up other...
double distance(const QgsGeometry &geom) const
Returns the minimum distanace between this geometry and another geometry, using GEOS.
void initGeomCalculator()
static QVariant fcnWordwrap(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int length() const
A abstract base class for defining QgsExpression functions.
Q_DECL_DEPRECATED bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
static QVariant fcnCentroid(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:192
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
double computeDouble(double x, double y)
static QVariant fcnIf(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QDateTime toDateTime() const
static QgsExpressionContext createFeatureBasedContext(const QgsFeature &feature, const QgsFields &fields)
Helper function for creating an expression context which contains just a feature and fields collectio...
virtual QString dump() const =0
Abstract virtual dump method.
static QVariant fcnPi(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QDate getDateValue(const QVariant &value, QgsExpression *parent)
static QVariant pointAt(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
QString escape(const QString &str)
static QVariant fcnAtan2(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QString helptext(QString name)
Returns the help text for a specified function.
#define FEAT_FROM_CONTEXT(c, f)
static QVariant fcnRegexpMatch(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
const T & at(int i) const
static QVariant fcnFloor(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QTime toTime() const
QVariant evaluate()
Evaluate the feature and return the result.
int size() const
static QVariant fncColorCmyka(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAcos(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAbs(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void removeAt(int i)
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:464
QgsExpression()
Used by QgsOgcUtils to create an empty.
QgsRectangle boundingBox() const
Returns the bounding box of this feature.
bool isValid() const
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
static const char * vectorGeometryType(GeometryType type)
description strings for geometry types
Definition: qgis.h:165
bool crosses(const QgsGeometry *geometry) const
Test for if geometry crosses another (uses GEOS)
T value() const
static QVariant fncColorHsva(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Container of fields for a vector layer.
Definition: qgsfield.h:177
static QVariant fcnAge(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnToTime(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QTime time() const
virtual Q_DECL_DEPRECATED bool prepare(QgsExpression *parent, const QgsFields &fields)
Abstract virtual preparation method Errors are reported to the parent.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:75
Q_DECL_DEPRECATED int currentRowNumber()
Return the number used for $rownum special column.
QgsExpression::Node * parseExpression(const QString &str, QString &parserErrorMsg)
QSet< T > toSet() const
static QVariant fcnTouches(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QString group(QString group)
Returns the translated name for a function 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)
static QVariant fcnWithin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnExpScale(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:162
static QVariant fcnMax(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnLCS(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnXMin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static TVL getTVLValue(const QVariant &value, QgsExpression *parent)
static QVariant fcnFormatNumber(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int month() const
double toDouble(bool *ok) const
static QVariant fcnToDateTime(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static Q_DECL_DEPRECATED bool isValid(const QString &text, const QgsFields &fields, QString &errorMessage)
static QVariant fncColorHsla(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int weekNumber(int *yearNumber) const
QString tr(const char *sourceText, const char *disambiguation, int n)
static QString soundex(const QString &string)
Returns the Soundex representation of a string.
QString mEvalErrorString
int second() const
virtual QString dump() const override
Abstract virtual dump method.
static QVariant fcnGeomArea(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
static QVariant fcnLevenshtein(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
int size() const
bool isNull() const
void setEvalErrorString(const QString &str)
Set evaluation error (used internally by evaluation functions)
static QgsGeometry getGeometry(const QVariant &value, QgsExpression *parent)
#define ENSURE_NO_EVAL_ERROR
static QVariant fcnToReal(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QString mParserErrorString
static QVariant fcnYat(const QVariantList &values, const QgsExpressionContext *f, QgsExpression *parent)
virtual QString dump() const override
Abstract virtual dump method.
static QString encodeColor(QColor color)
static QVariant fcnCos(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QVariant(* FcnEvalContext)(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
Function definition for evaluation against an expression context.
static const QStringList & BuiltinFunctions()
static QVariant fcnSymDifference(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
static const QList< Function * > & Functions()
long featureCount(QgsSymbolV2 *symbol)
Number of features rendered with specified symbol.
int matchedLength() const
QList< Key > keys() const
static QVariant fcnGetLayerProperty(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnColorHsl(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int indexIn(const QString &str, int offset, CaretMode caretMode) const
static QVariant fcnMin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool createFromOgcWmsCrs(QString theCrs)
Set up this CRS from the given OGC CRS.
static QHash< QString, QString > gFunctionHelpTexts
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
static int functionCount()
Returns the number of functions defined in the parser.
static QVariant fcnRndF(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression...
QgsFields pendingFields() const
Returns the list of fields of this layer.
static QVariant fcnMinute(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double measure(const QgsGeometry *geometry) const
general measurement (line distance or polygon area)
void acceptVisitor(Visitor &v) const
Entry function for the visitor pattern.
static QVariant fcnTrim(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool contains(const QgsPoint *p) const
Test for containment of a point (uses GEOS)
QString number(int n, int base)
int count(const T &value) const
static QVariant fcnMonth(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
qreal x() const
qreal y() const
void append(const T &value)
static QVariant fcnLn(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QgsDistanceArea * geomCalculator()
Return calculator used for distance and area calculations (used by internal functions) ...
#define TVL_Unknown
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the 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 fcnIntersects(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnColorHsv(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnCoalesce(const QVariantList &values, const QgsExpressionContext *, QgsExpression *)
static int functionIndex(const QString &name)
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:182
static QVariant fcnWeek(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QString rightJustified(int width, QChar fill, bool truncate) const
virtual Q_DECL_DEPRECATED QVariant func(const QVariantList &, const QgsFeature *, QgsExpression *)
virtual QString dump() const override
Abstract virtual dump method.
static QVariant fcnScale(const QVariantList &, const QgsExpressionContext *, QgsExpression *parent)
QgsDistanceArea * mCalc
static QVariant fcnRowNumber(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
static QVariant fcnConcat(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
static QVariant fcnHamming(const QVariantList &values, const QgsExpressionContext *, 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
static void cleanRegisteredFunctions()
Deletes all registered functions whose ownership have been transferred to the expression engine...
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
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static bool registerFunction(Function *function, bool transferOwnership=false)
Registers a function to the expression engine.
static QgsStyleV2 * defaultStyle()
return default application-wide style
Definition: qgsstylev2.cpp:51
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 fcnIntersection(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int day() const
virtual QString dump() const override
Abstract virtual dump method.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
static QVariant fcnUpper(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
#define M_PI
static QVariant fcnToInt(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnToDate(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
bool isValid() const
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
static const QString AllAttributes
QDateTime computeDateTimeFromInterval(QDateTime d, QgsExpression::Interval *i)
static QVariant fcnExp(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double measurePerimeter(const QgsGeometry *geometry) const
measures perimeter of polygon
static QHash< QString, QString > gVariableHelpTexts
static QVariant fcnContains(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnToInterval(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double scale()
int count() const
Return number of items.
Definition: qgsfield.cpp:285
#define TVL_False
QGis::GeometryType geometryType() const
Returns point, line or polygon.
int year() const
static QVariant fcnLog10(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnBoundsHeight(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnRight(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QList< Function * > gmFunctions
static QVariant fcnDifference(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsGeometry * centroid() const
Returns the center of mass of a geometry.
iterator end()
static QVariant fcnCrosses(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static const QString EXPR_FIELDS
virtual QString dump() const
QString name()
The name of the function.
static QVariant tvl2variant(TVL v)
#define ENSURE_GEOM_TYPE(f, g, geomtype)
static int levenshteinDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Levenshtein edit distance between two strings.
static QVariant fcnAsin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnYMax(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnGetFeature(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnToString(const QVariantList &values, const QgsExpressionContext *, 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...
static QVariant fcnNow(const QVariantList &, const QgsExpressionContext *, QgsExpression *)
iterator begin()
static QVariant fcnFeatureId(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static QVariant fcnDistance(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static int getIntValue(const QVariant &value, QgsExpression *parent)
static QVariant fcnBbox(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnRound(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int hour() const
QString toLower() const
const T value(const Key &key) const
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
static QVariant fcnGeomFromGML(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool contains(QChar ch, Qt::CaseSensitivity cs) const
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
static QVariant fcnSeconds(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QList< QgsMapLayer * > mapLayersByName(QString layerName)
Retrieve a pointer to a loaded layer by name.
static QVariant fcnCeil(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnHour(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnLeft(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QVariant fromValue(const T &value)
static QString getStringValue(const QVariant &value, QgsExpression *)
static QVariant fcnSoundex(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QgsFeature getFeature(const QVariant &value, QgsExpression *parent)
virtual QStringList referencedColumns() const
static QVariant fcnRPad(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnLog(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool isValid() const
static double getDoubleValue(const QVariant &value, QgsExpression *parent)
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:465
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...
static QVariant fcnX(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
QDate toDate() const
QString & replace(int position, int n, QChar after)
static QMap< QString, QString > gmSpecialColumnGroups
virtual QString dump() const override
Abstract virtual dump method.
static void registerContextFunctions()
Registers all known core functions provided by QgsExpressionContextScope objects. ...
static QVariant fcnBounds(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnFeature(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static QVariant fcnGetVariable(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
static QVariant fcnOverlaps(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QDateTime currentDateTime()
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
QDate date() const
bool isDateTimeSafe(const QVariant &v)
static const char * UnaryOperatorText[]
static QVariant fcnDay(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QgsExpression::Interval invalidInterVal()
static const QString EXPR_FEATURE
static QVariant fcnTransformGeometry(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int secsTo(const QDateTime &other) const
static QVariant fcnLPad(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool isEmpty() const
static QgsExpression::Node * getNode(const QVariant &value, QgsExpression *parent)
static QVariant fcnReplace(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QList< Function * > specialColumns()
Returns a list of special Column definitions.
static TVL OR[3][3]
int params()
The number of parameters this function takes.
static TVL NOT[3]
static QVariant fcnAtan(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Class for storing a coordinate reference system (CRS)
QString translate(const char *context, const char *sourceText, const char *disambiguation, Encoding encoding)
static QVariant fcnAttribute(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int count(const T &value) const
virtual QStringList referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node...
bool within(const QgsGeometry *geometry) const
Test for if geometry is within another (uses GEOS)
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
static QVariant fcnXMax(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Class for doing transforms between two map coordinate systems.
#define TVL_True
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.
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
bool toBool() const
QString leftJustified(int width, QChar fill, bool truncate) const
int lastIndexOf(const QRegExp &rx, int from) const
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTransform ct.
virtual bool needsGeometry() const =0
Abstract virtual method which returns if the geometry is required to evaluate this expression...
static QVariant fcnGeomToWKT(const QVariantList &values, const QgsExpressionContext *, 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 QVariant fcnColorCmyk(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnSqrt(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool isValid() const
static QVariant fcnTitle(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QStringList gmBuiltinFunctions
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
int indexOf(const QRegExp &rx, int from) const
static QVariant fcnRnd(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double toDouble(bool *ok) const
static QString variableHelpText(const QString &variableName, bool showValue=true, const QVariant &value=QVariant())
Returns the help text for a specified variable.
bool disjoint(const QgsGeometry *geometry) const
Test for if geometry is disjoint of another (uses GEOS)
iterator insert(const Key &key, const T &value)
bool contains(const Key &key) const
static QVariant fcnYMin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnGeometry(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static QVariant fcnUuid(const QVariantList &, const QgsExpressionContext *, QgsExpression *)
bool touches(const QgsGeometry *geometry) const
Test for if geometry touch another (uses GEOS)
static QVariant specialColumn(const QString &name)
Return the value of the given special column or a null QVariant if undefined.
static void initFunctionHelp()
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
QgsExpression::Function * function(const QString &name) const
Fetches a matching function from the context.
void setValid(bool valid)
static void setSpecialColumn(const QString &name, QVariant value)
Assign a special column.
double ANALYSIS_EXPORT min(double x, double y)
Returns the minimum of two doubles or the first argument if both are equal.
const_iterator constEnd() const
bool nextFeature(QgsFeature &f)
static QList< Function * > gmOwnedFunctions
List of functions owned by the expression engine.
const_iterator constBegin() const
static QVariant fcnTan(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QDateTime addSecs(int s) const
Type type() const
Geometry is not required. It may still be returned if e.g. required for a filter condition.
static TVL AND[3][3]
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:202
static QVariant fcnRegexpReplace(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
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
QString parserErrorString() const
Returns parser error.
Definition: qgsexpression.h:97
QgsFeatureRequest & setFlags(Flags flags)
Set flags that affect how features will be fetched.
static QVariant fcnLinearScale(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
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
virtual QStringList referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node...
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
Support the visitor pattern.
iterator find(const Key &key)
bool isNull(const QVariant &v)
virtual QString dump() const override
Abstract virtual dump method.
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
static QVariant fcnSubstr(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QUuid createUuid()
QColor fromHsvF(qreal h, qreal s, qreal v, qreal a)
void setEllipsoidalMode(bool flag)
sets whether coordinates must be projected to ellipsoid before measuring
static QVariant fcnYear(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static int hammingDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Hamming distance between two strings.
static QVariant fcnRegexpSubstr(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:207
QColor fromHslF(qreal h, qreal s, qreal l, qreal a)
static QVariant fcnColorRgb(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fncColorRgba(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
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 fcnCombine(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QVariant fcnRampColor(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static void unsetSpecialColumn(const QString &name)
Unset a special column.
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
static QVariant fcnSpecialColumn(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnLength(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnLower(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static const char * BinaryOperatorText[]
static Q_DECL_DEPRECATED 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