QGIS API Documentation  2.12.0-Lyon
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"
42 #include "qgspointv2.h"
43 
44 #if QT_VERSION < 0x050000
45 #include <qtextdocument.h>
46 #endif
47 
48 // from parser
49 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
50 
52 
54 {
56  inter.setValid( false );
57  return inter;
58 }
59 
61 {
62  int seconds = 0;
63  QRegExp rx( "([-+]?\\d?\\.?\\d+\\s+\\S+)", Qt::CaseInsensitive );
64  QStringList list;
65  int pos = 0;
66 
67  while (( pos = rx.indexIn( string, pos ) ) != -1 )
68  {
69  list << rx.cap( 1 );
70  pos += rx.matchedLength();
71  }
72 
74  map.insert( 1, QStringList() << "second" << "seconds" << tr( "second|seconds", "list of words separated by | which reference years" ).split( "|" ) );
75  map.insert( 0 + MINUTE, QStringList() << "minute" << "minutes" << tr( "minute|minutes", "list of words separated by | which reference minutes" ).split( "|" ) );
76  map.insert( 0 + HOUR, QStringList() << "hour" << "hours" << tr( "hour|hours", "list of words separated by | which reference minutes hours" ).split( "|" ) );
77  map.insert( 0 + DAY, QStringList() << "day" << "days" << tr( "day|days", "list of words separated by | which reference days" ).split( "|" ) );
78  map.insert( 0 + WEEKS, QStringList() << "week" << "weeks" << tr( "week|weeks", "wordlist separated by | which reference weeks" ).split( "|" ) );
79  map.insert( 0 + MONTHS, QStringList() << "month" << "months" << tr( "month|months", "list of words separated by | which reference months" ).split( "|" ) );
80  map.insert( 0 + YEARS, QStringList() << "year" << "years" << tr( "year|years", "list of words separated by | which reference years" ).split( "|" ) );
81 
82  Q_FOREACH ( const QString& match, list )
83  {
84  QStringList split = match.split( QRegExp( "\\s+" ) );
85  bool ok;
86  double value = split.at( 0 ).toDouble( &ok );
87  if ( !ok )
88  {
89  continue;
90  }
91 
92  bool matched = false;
93  Q_FOREACH ( int duration, map.keys() )
94  {
95  Q_FOREACH ( const QString& name, map[duration] )
96  {
97  if ( match.contains( name, Qt::CaseInsensitive ) )
98  {
99  matched = true;
100  break;
101  }
102  }
103 
104  if ( matched )
105  {
106  seconds += value * duration;
107  break;
108  }
109  }
110  }
111 
112  // If we can't parse the string at all then we just return invalid
113  if ( seconds == 0 )
115 
116  return QgsExpression::Interval( seconds );
117 }
118 
120 {
121  return ( mSeconds == other.mSeconds );
122 }
123 
125 // three-value logic
126 
127 enum TVL
128 {
132 };
133 
134 static TVL AND[3][3] =
135 {
136  // false true unknown
137  { False, False, False }, // false
138  { False, True, Unknown }, // true
139  { False, Unknown, Unknown } // unknown
140 };
141 
142 static TVL OR[3][3] =
143 {
144  { False, True, Unknown }, // false
145  { True, True, True }, // true
146  { Unknown, True, Unknown } // unknown
147 };
148 
149 static TVL NOT[3] = { True, False, Unknown };
150 
152 {
153  switch ( v )
154  {
155  case False: return 0;
156  case True: return 1;
157  case Unknown:
158  default:
159  return QVariant();
160  }
161 }
162 
163 #define TVL_True QVariant(1)
164 #define TVL_False QVariant(0)
165 #define TVL_Unknown QVariant()
166 
168 // QVariant checks and conversions
169 
170 inline bool isIntSafe( const QVariant& v )
171 {
172  if ( v.type() == QVariant::Int ) return true;
173  if ( v.type() == QVariant::UInt ) return true;
174  if ( v.type() == QVariant::LongLong ) return true;
175  if ( v.type() == QVariant::ULongLong ) return true;
176  if ( v.type() == QVariant::Double ) return false;
177  if ( v.type() == QVariant::String ) { bool ok; v.toString().toInt( &ok ); return ok; }
178  return false;
179 }
180 inline bool isDoubleSafe( const QVariant& v )
181 {
182  if ( v.type() == QVariant::Double ) return true;
183  if ( v.type() == QVariant::Int ) return true;
184  if ( v.type() == QVariant::UInt ) return true;
185  if ( v.type() == QVariant::LongLong ) return true;
186  if ( v.type() == QVariant::ULongLong ) return true;
187  if ( v.type() == QVariant::String )
188  {
189  bool ok;
190  double val = v.toString().toDouble( &ok );
191  ok = ok && qIsFinite( val ) && !qIsNaN( val );
192  return ok;
193  }
194  return false;
195 }
196 
197 inline bool isDateTimeSafe( const QVariant& v )
198 {
199  return v.type() == QVariant::DateTime || v.type() == QVariant::Date ||
200  v.type() == QVariant::Time;
201 }
202 
203 inline bool isIntervalSafe( const QVariant& v )
204 {
206  {
207  return true;
208  }
209 
210  if ( v.type() == QVariant::String )
211  {
213  }
214  return false;
215 }
216 
217 inline bool isNull( const QVariant& v ) { return v.isNull(); }
218 
220 // evaluation error macros
221 
222 #define ENSURE_NO_EVAL_ERROR { if (parent->hasEvalError()) return QVariant(); }
223 #define SET_EVAL_ERROR(x) { parent->setEvalErrorString(x); return QVariant(); }
224 
226 // operators
227 
228 const char* QgsExpression::BinaryOperatorText[] =
229 {
230  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
231  "OR", "AND",
232  "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
233  "+", "-", "*", "/", "//", "%", "^",
234  "||"
235 };
236 
237 const char* QgsExpression::UnaryOperatorText[] =
238 {
239  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
240  "NOT", "-"
241 };
242 
244 // functions
245 
246 // implicit conversion to string
248 {
249  return value.toString();
250 }
251 
252 static double getDoubleValue( const QVariant& value, QgsExpression* parent )
253 {
254  bool ok;
255  double x = value.toDouble( &ok );
256  if ( !ok || qIsNaN( x ) || !qIsFinite( x ) )
257  {
258  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
259  return 0;
260  }
261  return x;
262 }
263 
264 static int getIntValue( const QVariant& value, QgsExpression* parent )
265 {
266  bool ok;
267  qint64 x = value.toLongLong( &ok );
269  {
270  return x;
271  }
272  else
273  {
274  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
275  return 0;
276  }
277 }
278 
279 static QDateTime getDateTimeValue( const QVariant& value, QgsExpression* parent )
280 {
281  QDateTime d = value.toDateTime();
282  if ( d.isValid() )
283  {
284  return d;
285  }
286  else
287  {
288  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
289  return QDateTime();
290  }
291 }
292 
293 static QDate getDateValue( const QVariant& value, QgsExpression* parent )
294 {
295  QDate d = value.toDate();
296  if ( d.isValid() )
297  {
298  return d;
299  }
300  else
301  {
302  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
303  return QDate();
304  }
305 }
306 
307 static QTime getTimeValue( const QVariant& value, QgsExpression* parent )
308 {
309  QTime t = value.toTime();
310  if ( t.isValid() )
311  {
312  return t;
313  }
314  else
315  {
316  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
317  return QTime();
318  }
319 }
320 
321 static QgsExpression::Interval getInterval( const QVariant& value, QgsExpression* parent, bool report_error = false )
322 {
323  if ( value.canConvert<QgsExpression::Interval>() )
324  return value.value<QgsExpression::Interval>();
325 
327  if ( inter.isValid() )
328  {
329  return inter;
330  }
331  // If we get here then we can't convert so we just error and return invalid.
332  if ( report_error )
333  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Interval" ).arg( value.toString() ) );
334 
336 }
337 
338 static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent )
339 {
340  if ( value.canConvert<QgsGeometry>() )
341  return value.value<QgsGeometry>();
342 
343  parent->setEvalErrorString( "Cannot convert to QgsGeometry" );
344  return QgsGeometry();
345 }
346 
347 static QgsFeature getFeature( const QVariant& value, QgsExpression* parent )
348 {
349  if ( value.canConvert<QgsFeature>() )
350  return value.value<QgsFeature>();
351 
352  parent->setEvalErrorString( "Cannot convert to QgsFeature" );
353  return 0;
354 }
355 
356 static QgsExpression::Node* getNode( const QVariant& value, QgsExpression* parent )
357 {
358  if ( value.canConvert<QgsExpression::Node*>() )
359  return value.value<QgsExpression::Node*>();
360 
361  parent->setEvalErrorString( "Cannot convert to Node" );
362  return 0;
363 }
364 
365 // this handles also NULL values
366 static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
367 {
368  // we need to convert to TVL
369  if ( value.isNull() )
370  return Unknown;
371 
372  if ( value.type() == QVariant::Int )
373  return value.toInt() != 0 ? True : False;
374 
375  bool ok;
376  double x = value.toDouble( &ok );
377  if ( !ok )
378  {
379  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
380  return Unknown;
381  }
382  return x != 0 ? True : False;
383 }
384 
386 
387 static QVariant fcnGetVariable( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
388 {
389  if ( !context )
390  return QVariant();
391 
392  QString name = getStringValue( values.at( 0 ), parent );
393  return context->variable( name );
394 }
395 
396 static QVariant fcnSqrt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
397 {
398  double x = getDoubleValue( values.at( 0 ), parent );
399  return QVariant( sqrt( x ) );
400 }
401 
402 static QVariant fcnAbs( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
403 {
404  double val = getDoubleValue( values.at( 0 ), parent );
405  return QVariant( fabs( val ) );
406 }
407 
408 static QVariant fcnSin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
409 {
410  double x = getDoubleValue( values.at( 0 ), parent );
411  return QVariant( sin( x ) );
412 }
413 static QVariant fcnCos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
414 {
415  double x = getDoubleValue( values.at( 0 ), parent );
416  return QVariant( cos( x ) );
417 }
418 static QVariant fcnTan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
419 {
420  double x = getDoubleValue( values.at( 0 ), parent );
421  return QVariant( tan( x ) );
422 }
423 static QVariant fcnAsin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
424 {
425  double x = getDoubleValue( values.at( 0 ), parent );
426  return QVariant( asin( x ) );
427 }
428 static QVariant fcnAcos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
429 {
430  double x = getDoubleValue( values.at( 0 ), parent );
431  return QVariant( acos( x ) );
432 }
433 static QVariant fcnAtan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
434 {
435  double x = getDoubleValue( values.at( 0 ), parent );
436  return QVariant( atan( x ) );
437 }
438 static QVariant fcnAtan2( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
439 {
440  double y = getDoubleValue( values.at( 0 ), parent );
441  double x = getDoubleValue( values.at( 1 ), parent );
442  return QVariant( atan2( y, x ) );
443 }
444 static QVariant fcnExp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
445 {
446  double x = getDoubleValue( values.at( 0 ), parent );
447  return QVariant( exp( x ) );
448 }
449 static QVariant fcnLn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
450 {
451  double x = getDoubleValue( values.at( 0 ), parent );
452  if ( x <= 0 )
453  return QVariant();
454  return QVariant( log( x ) );
455 }
456 static QVariant fcnLog10( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
457 {
458  double x = getDoubleValue( values.at( 0 ), parent );
459  if ( x <= 0 )
460  return QVariant();
461  return QVariant( log10( x ) );
462 }
463 static QVariant fcnLog( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
464 {
465  double b = getDoubleValue( values.at( 0 ), parent );
466  double x = getDoubleValue( values.at( 1 ), parent );
467  if ( x <= 0 || b <= 0 )
468  return QVariant();
469  return QVariant( log( x ) / log( b ) );
470 }
471 static QVariant fcnRndF( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
472 {
473  double min = getDoubleValue( values.at( 0 ), parent );
474  double max = getDoubleValue( values.at( 1 ), parent );
475  if ( max < min )
476  return QVariant();
477 
478  // Return a random double in the range [min, max] (inclusive)
479  double f = ( double )qrand() / RAND_MAX;
480  return QVariant( min + f * ( max - min ) );
481 }
482 static QVariant fcnRnd( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
483 {
484  int min = getIntValue( values.at( 0 ), parent );
485  int max = getIntValue( values.at( 1 ), parent );
486  if ( max < min )
487  return QVariant();
488 
489  // Return a random integer in the range [min, max] (inclusive)
490  return QVariant( min + ( qrand() % ( int )( max - min + 1 ) ) );
491 }
492 
493 static QVariant fcnLinearScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
494 {
495  double val = getDoubleValue( values.at( 0 ), parent );
496  double domainMin = getDoubleValue( values.at( 1 ), parent );
497  double domainMax = getDoubleValue( values.at( 2 ), parent );
498  double rangeMin = getDoubleValue( values.at( 3 ), parent );
499  double rangeMax = getDoubleValue( values.at( 4 ), parent );
500 
501  if ( domainMin >= domainMax )
502  {
503  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
504  return QVariant();
505  }
506 
507  // outside of domain?
508  if ( val >= domainMax )
509  {
510  return rangeMax;
511  }
512  else if ( val <= domainMin )
513  {
514  return rangeMin;
515  }
516 
517  // calculate linear scale
518  double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
519  double c = rangeMin - ( domainMin * m );
520 
521  // Return linearly scaled value
522  return QVariant( m * val + c );
523 }
524 
525 static QVariant fcnExpScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
526 {
527  double val = getDoubleValue( values.at( 0 ), parent );
528  double domainMin = getDoubleValue( values.at( 1 ), parent );
529  double domainMax = getDoubleValue( values.at( 2 ), parent );
530  double rangeMin = getDoubleValue( values.at( 3 ), parent );
531  double rangeMax = getDoubleValue( values.at( 4 ), parent );
532  double exponent = getDoubleValue( values.at( 5 ), parent );
533 
534  if ( domainMin >= domainMax )
535  {
536  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
537  return QVariant();
538  }
539  if ( exponent <= 0 )
540  {
541  parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
542  return QVariant();
543  }
544 
545  // outside of domain?
546  if ( val >= domainMax )
547  {
548  return rangeMax;
549  }
550  else if ( val <= domainMin )
551  {
552  return rangeMin;
553  }
554 
555  // Return exponentially scaled value
556  return QVariant((( rangeMax - rangeMin ) / pow( domainMax - domainMin, exponent ) ) * pow( val - domainMin, exponent ) + rangeMin );
557 }
558 
559 static QVariant fcnMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
560 {
561  //initially set max as first value
562  double maxVal = getDoubleValue( values.at( 0 ), parent );
563 
564  //check against all other values
565  for ( int i = 1; i < values.length(); ++i )
566  {
567  double testVal = getDoubleValue( values[i], parent );
568  if ( testVal > maxVal )
569  {
570  maxVal = testVal;
571  }
572  }
573 
574  return QVariant( maxVal );
575 }
576 
577 static QVariant fcnMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
578 {
579  //initially set min as first value
580  double minVal = getDoubleValue( values.at( 0 ), parent );
581 
582  //check against all other values
583  for ( int i = 1; i < values.length(); ++i )
584  {
585  double testVal = getDoubleValue( values[i], parent );
586  if ( testVal < minVal )
587  {
588  minVal = testVal;
589  }
590  }
591 
592  return QVariant( minVal );
593 }
594 
595 static QVariant fcnClamp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
596 {
597  double minValue = getDoubleValue( values.at( 0 ), parent );
598  double testValue = getDoubleValue( values.at( 1 ), parent );
599  double maxValue = getDoubleValue( values.at( 2 ), parent );
600 
601  // force testValue to sit inside the range specified by the min and max value
602  if ( testValue <= minValue )
603  {
604  return QVariant( minValue );
605  }
606  else if ( testValue >= maxValue )
607  {
608  return QVariant( maxValue );
609  }
610  else
611  {
612  return QVariant( testValue );
613  }
614 }
615 
616 static QVariant fcnFloor( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
617 {
618  double x = getDoubleValue( values.at( 0 ), parent );
619  return QVariant( floor( x ) );
620 }
621 
622 static QVariant fcnCeil( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
623 {
624  double x = getDoubleValue( values.at( 0 ), parent );
625  return QVariant( ceil( x ) );
626 }
627 
628 static QVariant fcnToInt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
629 {
630  return QVariant( getIntValue( values.at( 0 ), parent ) );
631 }
632 static QVariant fcnToReal( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
633 {
634  return QVariant( getDoubleValue( values.at( 0 ), parent ) );
635 }
636 static QVariant fcnToString( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
637 {
638  return QVariant( getStringValue( values.at( 0 ), parent ) );
639 }
640 
641 static QVariant fcnToDateTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
642 {
643  return QVariant( getDateTimeValue( values.at( 0 ), parent ) );
644 }
645 
646 static QVariant fcnCoalesce( const QVariantList& values, const QgsExpressionContext*, QgsExpression* )
647 {
648  Q_FOREACH ( const QVariant &value, values )
649  {
650  if ( value.isNull() )
651  continue;
652  return value;
653  }
654  return QVariant();
655 }
656 static QVariant fcnLower( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
657 {
658  QString str = getStringValue( values.at( 0 ), parent );
659  return QVariant( str.toLower() );
660 }
661 static QVariant fcnUpper( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
662 {
663  QString str = getStringValue( values.at( 0 ), parent );
664  return QVariant( str.toUpper() );
665 }
666 static QVariant fcnTitle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
667 {
668  QString str = getStringValue( values.at( 0 ), parent );
669  QStringList elems = str.split( " " );
670  for ( int i = 0; i < elems.size(); i++ )
671  {
672  if ( elems[i].size() > 1 )
673  elems[i] = elems[i].left( 1 ).toUpper() + elems[i].mid( 1 ).toLower();
674  }
675  return QVariant( elems.join( " " ) );
676 }
677 
678 static QVariant fcnTrim( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
679 {
680  QString str = getStringValue( values.at( 0 ), parent );
681  return QVariant( str.trimmed() );
682 }
683 
684 static QVariant fcnLevenshtein( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
685 {
686  QString string1 = getStringValue( values.at( 0 ), parent );
687  QString string2 = getStringValue( values.at( 1 ), parent );
688  return QVariant( QgsStringUtils::levenshteinDistance( string1, string2, true ) );
689 }
690 
691 static QVariant fcnLCS( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
692 {
693  QString string1 = getStringValue( values.at( 0 ), parent );
694  QString string2 = getStringValue( values.at( 1 ), parent );
695  return QVariant( QgsStringUtils::longestCommonSubstring( string1, string2, true ) );
696 }
697 
698 static QVariant fcnHamming( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
699 {
700  QString string1 = getStringValue( values.at( 0 ), parent );
701  QString string2 = getStringValue( values.at( 1 ), parent );
702  int dist = QgsStringUtils::hammingDistance( string1, string2 );
703  return ( dist < 0 ? QVariant() : QVariant( QgsStringUtils::hammingDistance( string1, string2, true ) ) );
704 }
705 
706 static QVariant fcnSoundex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
707 {
708  QString string = getStringValue( values.at( 0 ), parent );
709  return QVariant( QgsStringUtils::soundex( string ) );
710 }
711 
712 static QVariant fcnWordwrap( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
713 {
714  if ( values.length() == 2 || values.length() == 3 )
715  {
716  QString str = getStringValue( values.at( 0 ), parent );
717  int wrap = getIntValue( values.at( 1 ), parent );
718 
719  if ( !str.isEmpty() && wrap != 0 )
720  {
721  QString newstr;
722  QString delimiterstr;
723  if ( values.length() == 3 ) delimiterstr = getStringValue( values.at( 2 ), parent );
724  if ( delimiterstr.isEmpty() ) delimiterstr = " ";
725  int delimiterlength = delimiterstr.length();
726 
727  QStringList lines = str.split( "\n" );
728  int strlength, strcurrent, strhit, lasthit;
729 
730  for ( int i = 0; i < lines.size(); i++ )
731  {
732  strlength = lines[i].length();
733  strcurrent = 0;
734  strhit = 0;
735  lasthit = 0;
736 
737  while ( strcurrent < strlength )
738  {
739  // positive wrap value = desired maximum line width to wrap
740  // negative wrap value = desired minimum line width before wrap
741  if ( wrap > 0 )
742  {
743  //first try to locate delimiter backwards
744  strhit = lines[i].lastIndexOf( delimiterstr, strcurrent + wrap );
745  if ( strhit == lasthit || strhit == -1 )
746  {
747  //if no new backward delimiter found, try to locate forward
748  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
749  }
750  lasthit = strhit;
751  }
752  else
753  {
754  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
755  }
756  if ( strhit > -1 )
757  {
758  newstr.append( lines[i].midRef( strcurrent, strhit - strcurrent ) );
759  newstr.append( "\n" );
760  strcurrent = strhit + delimiterlength;
761  }
762  else
763  {
764  newstr.append( lines[i].midRef( strcurrent ) );
765  strcurrent = strlength;
766  }
767  }
768  if ( i < lines.size() - 1 ) newstr.append( "\n" );
769  }
770 
771  return QVariant( newstr );
772  }
773  }
774 
775  return QVariant();
776 }
777 
778 static QVariant fcnLength( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
779 {
780  // two variants, one for geometry, one for string
781  if ( values.at( 0 ).canConvert<QgsGeometry>() )
782  {
783  //geometry variant
784  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
785  if ( geom.type() != QGis::Line )
786  return QVariant();
787 
788  return QVariant( geom.length() );
789  }
790 
791  //otherwise fall back to string variant
792  QString str = getStringValue( values.at( 0 ), parent );
793  return QVariant( str.length() );
794 }
795 
796 static QVariant fcnReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
797 {
798  QString str = getStringValue( values.at( 0 ), parent );
799  QString before = getStringValue( values.at( 1 ), parent );
800  QString after = getStringValue( values.at( 2 ), parent );
801  return QVariant( str.replace( before, after ) );
802 }
803 static QVariant fcnRegexpReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
804 {
805  QString str = getStringValue( values.at( 0 ), parent );
806  QString regexp = getStringValue( values.at( 1 ), parent );
807  QString after = getStringValue( values.at( 2 ), parent );
808 
809  QRegExp re( regexp );
810  if ( !re.isValid() )
811  {
812  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
813  return QVariant();
814  }
815  return QVariant( str.replace( re, after ) );
816 }
817 
818 static QVariant fcnRegexpMatch( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
819 {
820  QString str = getStringValue( values.at( 0 ), parent );
821  QString regexp = getStringValue( values.at( 1 ), parent );
822 
823  QRegExp re( regexp );
824  if ( !re.isValid() )
825  {
826  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
827  return QVariant();
828  }
829  return QVariant( str.contains( re ) ? 1 : 0 );
830 }
831 
832 static QVariant fcnRegexpSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
833 {
834  QString str = getStringValue( values.at( 0 ), parent );
835  QString regexp = getStringValue( values.at( 1 ), parent );
836 
837  QRegExp re( regexp );
838  if ( !re.isValid() )
839  {
840  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
841  return QVariant();
842  }
843 
844  // extract substring
845  ( void )re.indexIn( str );
846  if ( re.captureCount() > 0 )
847  {
848  // return first capture
849  return QVariant( re.capturedTexts().at( 1 ) );
850  }
851  else
852  {
853  return QVariant( "" );
854  }
855 }
856 
857 static QVariant fcnUuid( const QVariantList&, const QgsExpressionContext*, QgsExpression* )
858 {
859  return QUuid::createUuid().toString();
860 }
861 
862 static QVariant fcnSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
863 {
864  QString str = getStringValue( values.at( 0 ), parent );
865  int from = getIntValue( values.at( 1 ), parent );
866  int len = getIntValue( values.at( 2 ), parent );
867  return QVariant( str.mid( from -1, len ) );
868 }
869 
870 static QVariant fcnRowNumber( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
871 {
872  if ( context && context->hasVariable( "row_number" ) )
873  return context->variable( "row_number" );
874 
876  return QVariant( parent->currentRowNumber() );
878  //when above is removed - return QVariant()
879 }
880 
881 static QVariant fcnMapId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
882 {
883  if ( context && context->hasVariable( "map_id" ) )
884  return context->variable( "map_id" );
885 
887  return QgsExpression::specialColumn( "$map" );
889 }
890 
891 static QVariant fcnComposerNumPages( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
892 {
893  if ( context && context->hasVariable( "layout_numpages" ) )
894  return context->variable( "layout_numpages" );
895 
897  return QgsExpression::specialColumn( "$numpages" );
899 }
900 
901 static QVariant fcnComposerPage( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
902 {
903  if ( context && context->hasVariable( "layout_page" ) )
904  return context->variable( "layout_page" );
905 
907  return QgsExpression::specialColumn( "$page" );
909 }
910 
911 static QVariant fcnAtlasFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
912 {
913  if ( context && context->hasVariable( "atlas_featurenumber" ) )
914  return context->variable( "atlas_featurenumber" );
915 
917  return QgsExpression::specialColumn( "$feature" );
919 }
920 
921 static QVariant fcnAtlasFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
922 {
923  if ( context && context->hasVariable( "atlas_featureid" ) )
924  return context->variable( "atlas_featureid" );
925 
927  return QgsExpression::specialColumn( "$atlasfeatureid" );
929 }
930 
931 
932 static QVariant fcnAtlasCurrentFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
933 {
934  if ( context && context->hasVariable( "atlas_feature" ) )
935  return context->variable( "atlas_feature" );
936 
938  return QgsExpression::specialColumn( "$atlasfeature" );
940 }
941 
942 static QVariant fcnAtlasCurrentGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
943 {
944  if ( context && context->hasVariable( "atlas_geometry" ) )
945  return context->variable( "atlas_geometry" );
946 
948  return QgsExpression::specialColumn( "$atlasgeometry" );
950 }
951 
952 static QVariant fcnAtlasNumFeatures( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
953 {
954  if ( context && context->hasVariable( "atlas_totalfeatures" ) )
955  return context->variable( "atlas_totalfeatures" );
956 
958  return QgsExpression::specialColumn( "$numfeatures" );
960 }
961 
962 #define FEAT_FROM_CONTEXT(c, f) if (!c || !c->hasVariable(QgsExpressionContext::EXPR_FEATURE)) return QVariant(); \
963  QgsFeature f = qvariant_cast<QgsFeature>( c->variable( QgsExpressionContext::EXPR_FEATURE ) );
964 
965 static QVariant fcnFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
966 {
967  FEAT_FROM_CONTEXT( context, f );
968  // TODO: handling of 64-bit feature ids?
969  return QVariant(( int )f.id() );
970 }
971 
972 static QVariant fcnFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
973 {
974  if ( !context )
975  return QVariant();
976 
977  return context->variable( QgsExpressionContext::EXPR_FEATURE );
978 }
979 static QVariant fcnAttribute( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
980 {
981  QgsFeature feat = getFeature( values.at( 0 ), parent );
982  QString attr = getStringValue( values.at( 1 ), parent );
983 
984  return feat.attribute( attr );
985 }
986 static QVariant fcnConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
987 {
988  QString concat;
989  Q_FOREACH ( const QVariant &value, values )
990  {
991  concat += getStringValue( value, parent );
992  }
993  return concat;
994 }
995 
996 static QVariant fcnStrpos( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
997 {
998  QString string = getStringValue( values.at( 0 ), parent );
999  return string.indexOf( QRegExp( getStringValue( values.at( 1 ), parent ) ) );
1000 }
1001 
1002 static QVariant fcnRight( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1003 {
1004  QString string = getStringValue( values.at( 0 ), parent );
1005  int pos = getIntValue( values.at( 1 ), parent );
1006  return string.right( pos );
1007 }
1008 
1009 static QVariant fcnLeft( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1010 {
1011  QString string = getStringValue( values.at( 0 ), parent );
1012  int pos = getIntValue( values.at( 1 ), parent );
1013  return string.left( pos );
1014 }
1015 
1016 static QVariant fcnRPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1017 {
1018  QString string = getStringValue( values.at( 0 ), parent );
1019  int length = getIntValue( values.at( 1 ), parent );
1020  QString fill = getStringValue( values.at( 2 ), parent );
1021  return string.leftJustified( length, fill.at( 0 ), true );
1022 }
1023 
1024 static QVariant fcnLPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1025 {
1026  QString string = getStringValue( values.at( 0 ), parent );
1027  int length = getIntValue( values.at( 1 ), parent );
1028  QString fill = getStringValue( values.at( 2 ), parent );
1029  return string.rightJustified( length, fill.at( 0 ), true );
1030 }
1031 
1032 static QVariant fcnFormatString( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1033 {
1034  QString string = getStringValue( values.at( 0 ), parent );
1035  for ( int n = 1; n < values.length(); n++ )
1036  {
1037  string = string.arg( getStringValue( values.at( n ), parent ) );
1038  }
1039  return string;
1040 }
1041 
1042 
1043 static QVariant fcnNow( const QVariantList&, const QgsExpressionContext*, QgsExpression * )
1044 {
1046 }
1047 
1048 static QVariant fcnToDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1049 {
1050  return QVariant( getDateValue( values.at( 0 ), parent ) );
1051 }
1052 
1053 static QVariant fcnToTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1054 {
1055  return QVariant( getTimeValue( values.at( 0 ), parent ) );
1056 }
1057 
1058 static QVariant fcnToInterval( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1059 {
1060  return QVariant::fromValue( getInterval( values.at( 0 ), parent ) );
1061 }
1062 
1063 static QVariant fcnAge( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1064 {
1065  QDateTime d1 = getDateTimeValue( values.at( 0 ), parent );
1066  QDateTime d2 = getDateTimeValue( values.at( 1 ), parent );
1067  int seconds = d2.secsTo( d1 );
1068  return QVariant::fromValue( QgsExpression::Interval( seconds ) );
1069 }
1070 
1071 static QVariant fcnDayOfWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1072 {
1073  if ( !values.at( 0 ).canConvert<QDate>() )
1074  return QVariant();
1075 
1076  QDate date = getDateValue( values.at( 0 ), parent );
1077  if ( !date.isValid() )
1078  return QVariant();
1079 
1080  // return dayOfWeek() % 7 so that values range from 0 (sun) to 6 (sat)
1081  // (to match PostgreSQL behaviour)
1082  return date.dayOfWeek() % 7;
1083 }
1084 
1085 static QVariant fcnDay( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1086 {
1087  QVariant value = values.at( 0 );
1088  QgsExpression::Interval inter = getInterval( value, parent, false );
1089  if ( inter.isValid() )
1090  {
1091  return QVariant( inter.days() );
1092  }
1093  else
1094  {
1095  QDateTime d1 = getDateTimeValue( value, parent );
1096  return QVariant( d1.date().day() );
1097  }
1098 }
1099 
1100 static QVariant fcnYear( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1101 {
1102  QVariant value = values.at( 0 );
1103  QgsExpression::Interval inter = getInterval( value, parent, false );
1104  if ( inter.isValid() )
1105  {
1106  return QVariant( inter.years() );
1107  }
1108  else
1109  {
1110  QDateTime d1 = getDateTimeValue( value, parent );
1111  return QVariant( d1.date().year() );
1112  }
1113 }
1114 
1115 static QVariant fcnMonth( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1116 {
1117  QVariant value = values.at( 0 );
1118  QgsExpression::Interval inter = getInterval( value, parent, false );
1119  if ( inter.isValid() )
1120  {
1121  return QVariant( inter.months() );
1122  }
1123  else
1124  {
1125  QDateTime d1 = getDateTimeValue( value, parent );
1126  return QVariant( d1.date().month() );
1127  }
1128 }
1129 
1130 static QVariant fcnWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1131 {
1132  QVariant value = values.at( 0 );
1133  QgsExpression::Interval inter = getInterval( value, parent, false );
1134  if ( inter.isValid() )
1135  {
1136  return QVariant( inter.weeks() );
1137  }
1138  else
1139  {
1140  QDateTime d1 = getDateTimeValue( value, parent );
1141  return QVariant( d1.date().weekNumber() );
1142  }
1143 }
1144 
1145 static QVariant fcnHour( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1146 {
1147  QVariant value = values.at( 0 );
1148  QgsExpression::Interval inter = getInterval( value, parent, false );
1149  if ( inter.isValid() )
1150  {
1151  return QVariant( inter.hours() );
1152  }
1153  else
1154  {
1155  QDateTime d1 = getDateTimeValue( value, parent );
1156  return QVariant( d1.time().hour() );
1157  }
1158 }
1159 
1160 static QVariant fcnMinute( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1161 {
1162  QVariant value = values.at( 0 );
1163  QgsExpression::Interval inter = getInterval( value, parent, false );
1164  if ( inter.isValid() )
1165  {
1166  return QVariant( inter.minutes() );
1167  }
1168  else
1169  {
1170  QDateTime d1 = getDateTimeValue( value, parent );
1171  return QVariant( d1.time().minute() );
1172  }
1173 }
1174 
1175 static QVariant fcnSeconds( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1176 {
1177  QVariant value = values.at( 0 );
1178  QgsExpression::Interval inter = getInterval( value, parent, false );
1179  if ( inter.isValid() )
1180  {
1181  return QVariant( inter.seconds() );
1182  }
1183  else
1184  {
1185  QDateTime d1 = getDateTimeValue( value, parent );
1186  return QVariant( d1.time().second() );
1187  }
1188 }
1189 
1190 
1191 #define ENSURE_GEOM_TYPE(f, g, geomtype) const QgsGeometry* g = f.constGeometry(); \
1192  if (!g || g->type() != geomtype) return QVariant();
1193 
1194 static QVariant fcnX( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1195 {
1196  FEAT_FROM_CONTEXT( context, f );
1197  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1198  if ( g->isMultipart() )
1199  {
1200  return g->asMultiPoint().at( 0 ).x();
1201  }
1202  else
1203  {
1204  return g->asPoint().x();
1205  }
1206 }
1207 
1208 static QVariant fcnY( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1209 {
1210  FEAT_FROM_CONTEXT( context, f );
1211  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1212  if ( g->isMultipart() )
1213  {
1214  return g->asMultiPoint().at( 0 ).y();
1215  }
1216  else
1217  {
1218  return g->asPoint().y();
1219  }
1220 }
1221 
1222 static QVariant fcnGeomX( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1223 {
1224  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1225  if ( geom.isEmpty() )
1226  return QVariant();
1227 
1228  //if single point, return the point's x coordinate
1229  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1230  {
1231  return geom.asPoint().x();
1232  }
1233 
1234  //otherwise return centroid x
1235  QgsGeometry* centroid = geom.centroid();
1236  QVariant result( centroid->asPoint().x() );
1237  delete centroid;
1238  return result;
1239 }
1240 
1241 static QVariant fcnGeomY( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1242 {
1243  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1244  if ( geom.isEmpty() )
1245  return QVariant();
1246 
1247  //if single point, return the point's y coordinate
1248  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1249  {
1250  return geom.asPoint().y();
1251  }
1252 
1253  //otherwise return centroid y
1254  QgsGeometry* centroid = geom.centroid();
1255  QVariant result( centroid->asPoint().y() );
1256  delete centroid;
1257  return result;
1258 }
1259 
1260 static QVariant fcnPointN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1261 {
1262  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1263 
1264  if ( geom.isEmpty() )
1265  return QVariant();
1266 
1267  //idx is 1 based
1268  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1269 
1270  QgsVertexId vId;
1271  if ( idx < 0 || !geom.vertexIdFromVertexNr( idx, vId ) )
1272  {
1273  parent->setEvalErrorString( QObject::tr( "Point index is out of range" ) );
1274  return QVariant();
1275  }
1276 
1277  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1278  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1279 }
1280 
1281 static QVariant fcnStartPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1282 {
1283  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1284 
1285  if ( geom.isEmpty() )
1286  return QVariant();
1287 
1288  QgsVertexId vId;
1289  if ( !geom.vertexIdFromVertexNr( 0, vId ) )
1290  {
1291  return QVariant();
1292  }
1293 
1294  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1295  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1296 }
1297 
1298 static QVariant fcnEndPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1299 {
1300  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1301 
1302  if ( geom.isEmpty() )
1303  return QVariant();
1304 
1305  QgsVertexId vId;
1306  if ( !geom.vertexIdFromVertexNr( geom.geometry()->nCoordinates() - 1, vId ) )
1307  {
1308  return QVariant();
1309  }
1310 
1311  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1312  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1313 }
1314 
1315 static QVariant fcnMakePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1316 {
1317  double x = getDoubleValue( values.at( 0 ), parent );
1318  double y = getDoubleValue( values.at( 1 ), parent );
1319  return QVariant::fromValue( QgsGeometry( new QgsPointV2( x, y ) ) );
1320 }
1321 
1322 static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
1323 {
1324  FEAT_FROM_CONTEXT( context, f );
1325  int idx = getIntValue( values.at( 0 ), parent );
1326  ENSURE_GEOM_TYPE( f, g, QGis::Line );
1327  QgsPolyline polyline = g->asPolyline();
1328  if ( idx < 0 )
1329  idx += polyline.count();
1330 
1331  if ( idx < 0 || idx >= polyline.count() )
1332  {
1333  parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
1334  return QVariant();
1335  }
1336  return QVariant( QPointF( polyline[idx].x(), polyline[idx].y() ) );
1337 }
1338 
1339 static QVariant fcnXat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1340 {
1341  QVariant v = pointAt( values, f, parent );
1342  if ( v.type() == QVariant::PointF )
1343  return QVariant( v.toPointF().x() );
1344  else
1345  return QVariant();
1346 }
1347 static QVariant fcnYat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1348 {
1349  QVariant v = pointAt( values, f, parent );
1350  if ( v.type() == QVariant::PointF )
1351  return QVariant( v.toPointF().y() );
1352  else
1353  return QVariant();
1354 }
1355 static QVariant fcnGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1356 {
1357  FEAT_FROM_CONTEXT( context, f );
1358  const QgsGeometry* geom = f.constGeometry();
1359  if ( geom )
1360  return QVariant::fromValue( *geom );
1361  else
1362  return QVariant();
1363 }
1364 static QVariant fcnGeomFromWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1365 {
1366  QString wkt = getStringValue( values.at( 0 ), parent );
1367  QgsGeometry* geom = QgsGeometry::fromWkt( wkt );
1368  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1369  delete geom;
1370  return result;
1371 }
1372 static QVariant fcnGeomFromGML( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1373 {
1374  QString gml = getStringValue( values.at( 0 ), parent );
1376  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1377  delete geom;
1378  return result;
1379 }
1380 
1381 static QVariant fcnGeomArea( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1382 {
1383  FEAT_FROM_CONTEXT( context, f );
1385  QgsDistanceArea* calc = parent->geomCalculator();
1386  return QVariant( calc->measureArea( f.constGeometry() ) );
1387 }
1388 
1389 static QVariant fcnArea( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1390 {
1391  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1392 
1393  if ( geom.type() != QGis::Polygon )
1394  return QVariant();
1395 
1396  return QVariant( geom.area() );
1397 }
1398 
1399 static QVariant fcnGeomLength( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1400 {
1401  FEAT_FROM_CONTEXT( context, f );
1402  ENSURE_GEOM_TYPE( f, g, QGis::Line );
1403  QgsDistanceArea* calc = parent->geomCalculator();
1404  return QVariant( calc->measureLength( f.constGeometry() ) );
1405 }
1406 
1407 static QVariant fcnGeomPerimeter( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1408 {
1409  FEAT_FROM_CONTEXT( context, f );
1411  QgsDistanceArea* calc = parent->geomCalculator();
1412  return QVariant( calc->measurePerimeter( f.constGeometry() ) );
1413 }
1414 
1415 static QVariant fcnPerimeter( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1416 {
1417  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1418 
1419  if ( geom.type() != QGis::Polygon )
1420  return QVariant();
1421 
1422  //length for polygons = perimeter
1423  return QVariant( geom.length() );
1424 }
1425 
1426 static QVariant fcnGeomNumPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1427 {
1428  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1429  return QVariant( geom.isEmpty() ? 0 : geom.geometry()->nCoordinates() );
1430 }
1431 
1432 static QVariant fcnBounds( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1433 {
1434  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1435  QgsGeometry* geomBounds = QgsGeometry::fromRect( geom.boundingBox() );
1436  QVariant result = geomBounds ? QVariant::fromValue( *geomBounds ) : QVariant();
1437  delete geomBounds;
1438  return result;
1439 }
1440 
1441 static QVariant fcnBoundsWidth( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1442 {
1443  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1444  return QVariant::fromValue( geom.boundingBox().width() );
1445 }
1446 
1447 static QVariant fcnBoundsHeight( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1448 {
1449  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1450  return QVariant::fromValue( geom.boundingBox().height() );
1451 }
1452 
1453 static QVariant fcnXMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1454 {
1455  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1456  return QVariant::fromValue( geom.boundingBox().xMinimum() );
1457 }
1458 
1459 static QVariant fcnXMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1460 {
1461  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1462  return QVariant::fromValue( geom.boundingBox().xMaximum() );
1463 }
1464 
1465 static QVariant fcnYMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1466 {
1467  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1468  return QVariant::fromValue( geom.boundingBox().yMinimum() );
1469 }
1470 
1471 static QVariant fcnYMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1472 {
1473  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1474  return QVariant::fromValue( geom.boundingBox().yMaximum() );
1475 }
1476 
1477 static QVariant fcnBbox( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1478 {
1479  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1480  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1481  return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
1482 }
1483 static QVariant fcnDisjoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1484 {
1485  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1486  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1487  return fGeom.disjoint( &sGeom ) ? TVL_True : TVL_False;
1488 }
1489 static QVariant fcnIntersects( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1490 {
1491  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1492  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1493  return fGeom.intersects( &sGeom ) ? TVL_True : TVL_False;
1494 }
1495 static QVariant fcnTouches( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1496 {
1497  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1498  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1499  return fGeom.touches( &sGeom ) ? TVL_True : TVL_False;
1500 }
1501 static QVariant fcnCrosses( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1502 {
1503  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1504  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1505  return fGeom.crosses( &sGeom ) ? TVL_True : TVL_False;
1506 }
1507 static QVariant fcnContains( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1508 {
1509  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1510  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1511  return fGeom.contains( &sGeom ) ? TVL_True : TVL_False;
1512 }
1513 static QVariant fcnOverlaps( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1514 {
1515  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1516  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1517  return fGeom.overlaps( &sGeom ) ? TVL_True : TVL_False;
1518 }
1519 static QVariant fcnWithin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1520 {
1521  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1522  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1523  return fGeom.within( &sGeom ) ? TVL_True : TVL_False;
1524 }
1525 static QVariant fcnBuffer( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1526 {
1527  if ( values.length() < 2 || values.length() > 3 )
1528  return QVariant();
1529 
1530  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1531  double dist = getDoubleValue( values.at( 1 ), parent );
1532  int seg = 8;
1533  if ( values.length() == 3 )
1534  seg = getIntValue( values.at( 2 ), parent );
1535 
1536  QgsGeometry* geom = fGeom.buffer( dist, seg );
1537  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1538  delete geom;
1539  return result;
1540 }
1541 static QVariant fcnCentroid( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1542 {
1543  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1544  QgsGeometry* geom = fGeom.centroid();
1545  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1546  delete geom;
1547  return result;
1548 }
1549 static QVariant fcnConvexHull( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1550 {
1551  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1552  QgsGeometry* geom = fGeom.convexHull();
1553  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1554  delete geom;
1555  return result;
1556 }
1557 static QVariant fcnDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1558 {
1559  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1560  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1561  QgsGeometry* geom = fGeom.difference( &sGeom );
1562  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1563  delete geom;
1564  return result;
1565 }
1566 static QVariant fcnDistance( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1567 {
1568  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1569  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1570  return QVariant( fGeom.distance( sGeom ) );
1571 }
1572 static QVariant fcnIntersection( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1573 {
1574  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1575  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1576  QgsGeometry* geom = fGeom.intersection( &sGeom );
1577  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1578  delete geom;
1579  return result;
1580 }
1581 static QVariant fcnSymDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1582 {
1583  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1584  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1585  QgsGeometry* geom = fGeom.symDifference( &sGeom );
1586  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1587  delete geom;
1588  return result;
1589 }
1590 static QVariant fcnCombine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1591 {
1592  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1593  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1594  QgsGeometry* geom = fGeom.combine( &sGeom );
1595  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1596  delete geom;
1597  return result;
1598 }
1599 static QVariant fcnGeomToWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1600 {
1601  if ( values.length() < 1 || values.length() > 2 )
1602  return QVariant();
1603 
1604  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1605  int prec = 8;
1606  if ( values.length() == 2 )
1607  prec = getIntValue( values.at( 1 ), parent );
1608  QString wkt = fGeom.exportToWkt( prec );
1609  return QVariant( wkt );
1610 }
1611 
1612 static QVariant fcnRound( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
1613 {
1614  if ( values.length() == 2 )
1615  {
1616  double number = getDoubleValue( values.at( 0 ), parent );
1617  double scaler = pow( 10.0, getIntValue( values.at( 1 ), parent ) );
1618  return QVariant( qRound( number * scaler ) / scaler );
1619  }
1620 
1621  if ( values.length() == 1 )
1622  {
1623  double number = getIntValue( values.at( 0 ), parent );
1624  return QVariant( qRound( number ) ).toInt();
1625  }
1626 
1627  return QVariant();
1628 }
1629 
1630 static QVariant fcnPi( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
1631 {
1632  Q_UNUSED( values );
1633  Q_UNUSED( parent );
1634  return M_PI;
1635 }
1636 
1637 static QVariant fcnScale( const QVariantList&, const QgsExpressionContext*, QgsExpression* parent )
1638 {
1639  return QVariant( parent->scale() );
1640 }
1641 
1642 static QVariant fcnFormatNumber( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1643 {
1644  double value = getDoubleValue( values.at( 0 ), parent );
1645  int places = getIntValue( values.at( 1 ), parent );
1646  if ( places < 0 )
1647  {
1648  parent->setEvalErrorString( QObject::tr( "Number of places must be positive" ) );
1649  return QVariant();
1650  }
1651  return QString( "%L1" ).arg( value, 0, 'f', places );
1652 }
1653 
1654 static QVariant fcnFormatDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1655 {
1656  QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
1657  QString format = getStringValue( values.at( 1 ), parent );
1658  return dt.toString( format );
1659 }
1660 
1661 static QVariant fcnColorRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
1662 {
1663  int red = getIntValue( values.at( 0 ), parent );
1664  int green = getIntValue( values.at( 1 ), parent );
1665  int blue = getIntValue( values.at( 2 ), parent );
1666  QColor color = QColor( red, green, blue );
1667  if ( ! color.isValid() )
1668  {
1669  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
1670  color = QColor( 0, 0, 0 );
1671  }
1672 
1673  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
1674 }
1675 
1676 static QVariant fcnIf( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
1677 {
1678  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
1680  QVariant value = node->eval( parent, context );
1682  if ( value.toBool() )
1683  {
1684  node = getNode( values.at( 1 ), parent );
1686  value = node->eval( parent, context );
1688  }
1689  else
1690  {
1691  node = getNode( values.at( 2 ), parent );
1693  value = node->eval( parent, context );
1695  }
1696  return value;
1697 }
1698 
1699 static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
1700 {
1701  int red = getIntValue( values.at( 0 ), parent );
1702  int green = getIntValue( values.at( 1 ), parent );
1703  int blue = getIntValue( values.at( 2 ), parent );
1704  int alpha = getIntValue( values.at( 3 ), parent );
1705  QColor color = QColor( red, green, blue, alpha );
1706  if ( ! color.isValid() )
1707  {
1708  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
1709  color = QColor( 0, 0, 0 );
1710  }
1711  return QgsSymbolLayerV2Utils::encodeColor( color );
1712 }
1713 
1714 QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
1715 {
1716  QString rampName = getStringValue( values.at( 0 ), parent );
1717  const QgsVectorColorRampV2 *mRamp = QgsStyleV2::defaultStyle()->colorRampRef( rampName );
1718  if ( ! mRamp )
1719  {
1720  parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
1721  return QColor( 0, 0, 0 ).name();
1722  }
1723  double value = getDoubleValue( values.at( 1 ), parent );
1724  QColor color = mRamp->color( value );
1725  return QgsSymbolLayerV2Utils::encodeColor( color );
1726 }
1727 
1728 static QVariant fcnColorHsl( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
1729 {
1730  // Hue ranges from 0 - 360
1731  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
1732  // Saturation ranges from 0 - 100
1733  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
1734  // Lightness ranges from 0 - 100
1735  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
1736 
1737  QColor color = QColor::fromHslF( hue, saturation, lightness );
1738 
1739  if ( ! color.isValid() )
1740  {
1741  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
1742  color = QColor( 0, 0, 0 );
1743  }
1744 
1745  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
1746 }
1747 
1748 static QVariant fncColorHsla( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
1749 {
1750  // Hue ranges from 0 - 360
1751  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
1752  // Saturation ranges from 0 - 100
1753  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
1754  // Lightness ranges from 0 - 100
1755  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
1756  // Alpha ranges from 0 - 255
1757  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
1758 
1759  QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
1760  if ( ! color.isValid() )
1761  {
1762  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
1763  color = QColor( 0, 0, 0 );
1764  }
1765  return QgsSymbolLayerV2Utils::encodeColor( color );
1766 }
1767 
1768 static QVariant fcnColorHsv( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
1769 {
1770  // Hue ranges from 0 - 360
1771  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
1772  // Saturation ranges from 0 - 100
1773  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
1774  // Value ranges from 0 - 100
1775  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
1776 
1777  QColor color = QColor::fromHsvF( hue, saturation, value );
1778 
1779  if ( ! color.isValid() )
1780  {
1781  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
1782  color = QColor( 0, 0, 0 );
1783  }
1784 
1785  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
1786 }
1787 
1788 static QVariant fncColorHsva( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
1789 {
1790  // Hue ranges from 0 - 360
1791  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
1792  // Saturation ranges from 0 - 100
1793  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
1794  // Value ranges from 0 - 100
1795  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
1796  // Alpha ranges from 0 - 255
1797  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
1798 
1799  QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
1800  if ( ! color.isValid() )
1801  {
1802  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
1803  color = QColor( 0, 0, 0 );
1804  }
1805  return QgsSymbolLayerV2Utils::encodeColor( color );
1806 }
1807 
1808 static QVariant fcnColorCmyk( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
1809 {
1810  // Cyan ranges from 0 - 100
1811  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
1812  // Magenta ranges from 0 - 100
1813  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
1814  // Yellow ranges from 0 - 100
1815  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
1816  // Black ranges from 0 - 100
1817  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
1818 
1819  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
1820 
1821  if ( ! color.isValid() )
1822  {
1823  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
1824  color = QColor( 0, 0, 0 );
1825  }
1826 
1827  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
1828 }
1829 
1830 static QVariant fncColorCmyka( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
1831 {
1832  // Cyan ranges from 0 - 100
1833  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
1834  // Magenta ranges from 0 - 100
1835  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
1836  // Yellow ranges from 0 - 100
1837  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
1838  // Black ranges from 0 - 100
1839  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
1840  // Alpha ranges from 0 - 255
1841  double alpha = getIntValue( values.at( 4 ), parent ) / 255.0;
1842 
1843  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
1844  if ( ! color.isValid() )
1845  {
1846  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
1847  color = QColor( 0, 0, 0 );
1848  }
1849  return QgsSymbolLayerV2Utils::encodeColor( color );
1850 }
1851 
1852 static QVariant fncColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
1853 {
1854  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
1855  if ( ! color.isValid() )
1856  {
1857  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
1858  return QVariant();
1859  }
1860 
1861  QString part = getStringValue( values.at( 1 ), parent );
1862  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
1863  return color.red();
1864  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
1865  return color.green();
1866  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
1867  return color.blue();
1868  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
1869  return color.alpha();
1870  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
1871  return color.hsvHueF() * 360;
1872  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
1873  return color.hsvSaturationF() * 100;
1874  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
1875  return color.valueF() * 100;
1876  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
1877  return color.hslHueF() * 360;
1878  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
1879  return color.hslSaturationF() * 100;
1880  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
1881  return color.lightnessF() * 100;
1882  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
1883  return color.cyanF() * 100;
1884  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
1885  return color.magentaF() * 100;
1886  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
1887  return color.yellowF() * 100;
1888  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
1889  return color.blackF() * 100;
1890 
1891  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
1892  return QVariant();
1893 }
1894 
1895 static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
1896 {
1897  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
1898  if ( ! color.isValid() )
1899  {
1900  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
1901  return QVariant();
1902  }
1903 
1904  QString part = getStringValue( values.at( 1 ), parent );
1905  int value = getIntValue( values.at( 2 ), parent );
1906  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
1907  color.setRed( value );
1908  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
1909  color.setGreen( value );
1910  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
1911  color.setBlue( value );
1912  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
1913  color.setAlpha( value );
1914  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
1915  color.setHsv( value, color.hsvSaturation(), color.value(), color.alpha() );
1916  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
1917  color.setHsvF( color.hsvHueF(), value / 100.0, color.valueF(), color.alphaF() );
1918  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
1919  color.setHsvF( color.hsvHueF(), color.hsvSaturationF(), value / 100.0, color.alphaF() );
1920  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
1921  color.setHsl( value, color.hslSaturation(), color.lightness(), color.alpha() );
1922  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
1923  color.setHslF( color.hslHueF(), value / 100.0, color.lightnessF(), color.alphaF() );
1924  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
1925  color.setHslF( color.hslHueF(), color.hslSaturationF(), value / 100.0, color.alphaF() );
1926  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
1927  color.setCmykF( value / 100.0, color.magentaF(), color.yellowF(), color.blackF(), color.alphaF() );
1928  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
1929  color.setCmykF( color.cyanF(), value / 100.0, color.yellowF(), color.blackF(), color.alphaF() );
1930  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
1931  color.setCmykF( color.cyanF(), color.magentaF(), value / 100.0, color.blackF(), color.alphaF() );
1932  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
1933  color.setCmykF( color.cyanF(), color.magentaF(), color.yellowF(), value / 100.0, color.alphaF() );
1934  else
1935  {
1936  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
1937  return QVariant();
1938  }
1939  return QgsSymbolLayerV2Utils::encodeColor( color );
1940 }
1941 
1942 static QVariant fcnSpecialColumn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1943 {
1944  QString varName = getStringValue( values.at( 0 ), parent );
1946  return QgsExpression::specialColumn( varName );
1948 }
1949 
1950 static QVariant fcnGetGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1951 {
1952  QgsFeature feat = getFeature( values.at( 0 ), parent );
1953  const QgsGeometry* geom = feat.constGeometry();
1954  if ( geom )
1955  return QVariant::fromValue( *geom );
1956  return QVariant();
1957 }
1958 
1959 static QVariant fcnTransformGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1960 {
1961  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1962  QString sAuthId = getStringValue( values.at( 1 ), parent );
1963  QString dAuthId = getStringValue( values.at( 2 ), parent );
1964 
1966  if ( ! s.createFromOgcWmsCrs( sAuthId ) )
1967  return QVariant::fromValue( fGeom );
1969  if ( ! d.createFromOgcWmsCrs( dAuthId ) )
1970  return QVariant::fromValue( fGeom );
1971 
1972  QgsCoordinateTransform t( s, d );
1973  if ( fGeom.transform( t ) == 0 )
1974  return QVariant::fromValue( fGeom );
1975  return QVariant();
1976 }
1977 
1978 static QVariant fcnGetFeature( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1979 {
1980  //arguments: 1. layer id / name, 2. key attribute, 3. eq value
1981  QString layerString = getStringValue( values.at( 0 ), parent );
1982  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerString ) ); //search by id first
1983  if ( !vl )
1984  {
1985  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerString );
1986  if ( layersByName.size() > 0 )
1987  {
1988  vl = qobject_cast<QgsVectorLayer*>( layersByName.at( 0 ) );
1989  }
1990  }
1991 
1992  //no layer found
1993  if ( !vl )
1994  {
1995  return QVariant();
1996  }
1997 
1998  QString attribute = getStringValue( values.at( 1 ), parent );
1999  int attributeId = vl->fieldNameIndex( attribute );
2000  if ( attributeId == -1 )
2001  {
2002  return QVariant();
2003  }
2004 
2005  const QVariant& attVal = values.at( 2 );
2006  QgsFeatureRequest req;
2007  if ( !parent->needsGeometry() )
2008  {
2010  }
2011  QgsFeatureIterator fIt = vl->getFeatures( req );
2012 
2013  QgsFeature fet;
2014  while ( fIt.nextFeature( fet ) )
2015  {
2016  if ( fet.attribute( attributeId ) == attVal )
2017  {
2018  return QVariant::fromValue( fet );
2019  }
2020  }
2021  return QVariant();
2022 }
2023 
2024 static QVariant fcnGetLayerProperty( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2025 {
2026  QString layerIdOrName = getStringValue( values.at( 0 ), parent );
2027 
2028  //try to find a matching layer by name
2029  QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerIdOrName ); //search by id first
2030  if ( !layer )
2031  {
2032  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerIdOrName );
2033  if ( layersByName.size() > 0 )
2034  {
2035  layer = layersByName.at( 0 );
2036  }
2037  }
2038 
2039  if ( !layer )
2040  return QVariant();
2041 
2042  QString layerProperty = getStringValue( values.at( 1 ), parent );
2043  if ( QString::compare( layerProperty, QString( "name" ), Qt::CaseInsensitive ) == 0 )
2044  return layer->name();
2045  else if ( QString::compare( layerProperty, QString( "id" ), Qt::CaseInsensitive ) == 0 )
2046  return layer->id();
2047  else if ( QString::compare( layerProperty, QString( "title" ), Qt::CaseInsensitive ) == 0 )
2048  return layer->title();
2049  else if ( QString::compare( layerProperty, QString( "abstract" ), Qt::CaseInsensitive ) == 0 )
2050  return layer->abstract();
2051  else if ( QString::compare( layerProperty, QString( "keywords" ), Qt::CaseInsensitive ) == 0 )
2052  return layer->keywordList();
2053  else if ( QString::compare( layerProperty, QString( "data_url" ), Qt::CaseInsensitive ) == 0 )
2054  return layer->dataUrl();
2055  else if ( QString::compare( layerProperty, QString( "attribution" ), Qt::CaseInsensitive ) == 0 )
2056  return layer->attribution();
2057  else if ( QString::compare( layerProperty, QString( "attribution_url" ), Qt::CaseInsensitive ) == 0 )
2058  return layer->attributionUrl();
2059  else if ( QString::compare( layerProperty, QString( "source" ), Qt::CaseInsensitive ) == 0 )
2060  return layer->publicSource();
2061  else if ( QString::compare( layerProperty, QString( "min_scale" ), Qt::CaseInsensitive ) == 0 )
2062  return ( double )layer->minimumScale();
2063  else if ( QString::compare( layerProperty, QString( "max_scale" ), Qt::CaseInsensitive ) == 0 )
2064  return ( double )layer->maximumScale();
2065  else if ( QString::compare( layerProperty, QString( "crs" ), Qt::CaseInsensitive ) == 0 )
2066  return layer->crs().authid();
2067  else if ( QString::compare( layerProperty, QString( "crs_definition" ), Qt::CaseInsensitive ) == 0 )
2068  return layer->crs().toProj4();
2069  else if ( QString::compare( layerProperty, QString( "extent" ), Qt::CaseInsensitive ) == 0 )
2070  {
2071  QgsGeometry* extentGeom = QgsGeometry::fromRect( layer->extent() );
2072  QVariant result = QVariant::fromValue( *extentGeom );
2073  delete extentGeom;
2074  return result;
2075  }
2076  else if ( QString::compare( layerProperty, QString( "type" ), Qt::CaseInsensitive ) == 0 )
2077  {
2078  switch ( layer->type() )
2079  {
2081  return QCoreApplication::translate( "expressions", "Vector" );
2083  return QCoreApplication::translate( "expressions", "Raster" );
2085  return QCoreApplication::translate( "expressions", "Plugin" );
2086  }
2087  }
2088  else
2089  {
2090  //vector layer methods
2091  QgsVectorLayer* vLayer = dynamic_cast< QgsVectorLayer* >( layer );
2092  if ( vLayer )
2093  {
2094  if ( QString::compare( layerProperty, QString( "storage_type" ), Qt::CaseInsensitive ) == 0 )
2095  return vLayer->storageType();
2096  else if ( QString::compare( layerProperty, QString( "geometry_type" ), Qt::CaseInsensitive ) == 0 )
2097  return QGis::vectorGeometryType( vLayer->geometryType() );
2098  else if ( QString::compare( layerProperty, QString( "feature_count" ), Qt::CaseInsensitive ) == 0 )
2099  return QVariant::fromValue( vLayer->featureCount() );
2100  }
2101  }
2102 
2103  return QVariant();
2104 }
2105 
2106 bool QgsExpression::registerFunction( QgsExpression::Function* function, bool transferOwnership )
2107 {
2108  int fnIdx = functionIndex( function->name() );
2109  if ( fnIdx != -1 )
2110  {
2111  return false;
2112  }
2113  QgsExpression::gmFunctions.append( function );
2114  if ( transferOwnership )
2115  QgsExpression::gmOwnedFunctions.append( function );
2116  return true;
2117 }
2118 
2120 {
2121  // You can never override the built in functions.
2122  if ( QgsExpression::BuiltinFunctions().contains( name ) )
2123  {
2124  return false;
2125  }
2126  int fnIdx = functionIndex( name );
2127  if ( fnIdx != -1 )
2128  {
2129  QgsExpression::gmFunctions.removeAt( fnIdx );
2130  return true;
2131  }
2132  return false;
2133 }
2134 
2136 {
2137  qDeleteAll( QgsExpression::gmOwnedFunctions );
2139 }
2140 
2142 
2144 {
2145  if ( gmBuiltinFunctions.isEmpty() )
2146  {
2148  << "abs" << "sqrt" << "cos" << "sin" << "tan"
2149  << "asin" << "acos" << "atan" << "atan2"
2150  << "exp" << "ln" << "log10" << "log"
2151  << "round" << "rand" << "randf" << "max" << "min" << "clamp"
2152  << "scale_linear" << "scale_exp" << "floor" << "ceil" << "$pi"
2153  << "toint" << "to_int" << "toreal" << "to_real" << "tostring" << "to_string"
2154  << "todatetime" << "to_datetime" << "todate" << "to_date"
2155  << "totime" << "to_time" << "tointerval" << "to_interval"
2156  << "coalesce" << "if" << "regexp_match" << "age" << "year"
2157  << "month" << "week" << "day" << "hour" << "day_of_week"
2158  << "minute" << "second" << "lower" << "upper"
2159  << "title" << "length" << "replace" << "trim" << "wordwrap"
2160  << "regexp_replace" << "regexp_substr"
2161  << "substr" << "concat" << "strpos" << "left"
2162  << "right" << "rpad" << "lpad" << "format"
2163  << "format_number" << "format_date"
2164  << "color_rgb" << "color_rgba" << "ramp_color"
2165  << "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
2166  << "color_cmyk" << "color_cmyka" << "color_part" << "set_color_part"
2167  << "xat" << "yat" << "$area" << "area" << "perimeter"
2168  << "$length" << "$perimeter" << "x" << "y" << "$x" << "$y" << "num_points"
2169  << "point_n" << "start_point" << "end_point" << "make_point"
2170  << "$x_at" << "x_at" << "xat" << "$y_at" << "y_at" << "yat" << "x_min" << "xmin" << "x_max" << "xmax"
2171  << "y_min" << "ymin" << "y_max" << "ymax" << "geom_from_wkt" << "geomFromWKT"
2172  << "geom_from_gml" << "geomFromGML" << "intersects_bbox" << "bbox"
2173  << "disjoint" << "intersects" << "touches" << "crosses" << "contains"
2174  << "overlaps" << "within" << "buffer" << "centroid" << "bounds"
2175  << "bounds_width" << "bounds_height" << "convex_hull" << "difference"
2176  << "distance" << "intersection" << "sym_difference" << "combine"
2177  << "union" << "geom_to_wkt" << "geomToWKT" << "geometry"
2178  << "transform" << "get_feature" << "getFeature"
2179  << "levenshtein" << "longest_common_substring" << "hamming_distance"
2180  << "soundex"
2181  << "attribute" << "var" << "layer_property"
2182  << "$id" << "$scale" << "_specialcol_";
2183  }
2184  return gmBuiltinFunctions;
2185 }
2186 
2189 
2191 {
2192  if ( gmFunctions.isEmpty() )
2193  {
2194  gmFunctions
2195  << new StaticFunction( "sqrt", 1, fcnSqrt, "Math" )
2196  << new StaticFunction( "abs", 1, fcnAbs, "Math" )
2197  << new StaticFunction( "cos", 1, fcnCos, "Math" )
2198  << new StaticFunction( "sin", 1, fcnSin, "Math" )
2199  << new StaticFunction( "tan", 1, fcnTan, "Math" )
2200  << new StaticFunction( "asin", 1, fcnAsin, "Math" )
2201  << new StaticFunction( "acos", 1, fcnAcos, "Math" )
2202  << new StaticFunction( "atan", 1, fcnAtan, "Math" )
2203  << new StaticFunction( "atan2", 2, fcnAtan2, "Math" )
2204  << new StaticFunction( "exp", 1, fcnExp, "Math" )
2205  << new StaticFunction( "ln", 1, fcnLn, "Math" )
2206  << new StaticFunction( "log10", 1, fcnLog10, "Math" )
2207  << new StaticFunction( "log", 2, fcnLog, "Math" )
2208  << new StaticFunction( "round", -1, fcnRound, "Math" )
2209  << new StaticFunction( "rand", 2, fcnRnd, "Math" )
2210  << new StaticFunction( "randf", 2, fcnRndF, "Math" )
2211  << new StaticFunction( "max", -1, fcnMax, "Math" )
2212  << new StaticFunction( "min", -1, fcnMin, "Math" )
2213  << new StaticFunction( "clamp", 3, fcnClamp, "Math" )
2214  << new StaticFunction( "scale_linear", 5, fcnLinearScale, "Math" )
2215  << new StaticFunction( "scale_exp", 6, fcnExpScale, "Math" )
2216  << new StaticFunction( "floor", 1, fcnFloor, "Math" )
2217  << new StaticFunction( "ceil", 1, fcnCeil, "Math" )
2218  << new StaticFunction( "pi", 0, fcnPi, "Math", QString(), false, QStringList(), false, QStringList() << "$pi" )
2219  << new StaticFunction( "to_int", 1, fcnToInt, "Conversions", QString(), false, QStringList(), false, QStringList() << "toint" )
2220  << new StaticFunction( "to_real", 1, fcnToReal, "Conversions", QString(), false, QStringList(), false, QStringList() << "toreal" )
2221  << new StaticFunction( "to_string", 1, fcnToString, "Conversions", QString(), false, QStringList(), false, QStringList() << "tostring" )
2222  << new StaticFunction( "to_datetime", 1, fcnToDateTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "todatetime" )
2223  << new StaticFunction( "to_date", 1, fcnToDate, "Conversions", QString(), false, QStringList(), false, QStringList() << "todate" )
2224  << new StaticFunction( "to_time", 1, fcnToTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "totime" )
2225  << new StaticFunction( "to_interval", 1, fcnToInterval, "Conversions", QString(), false, QStringList(), false, QStringList() << "tointerval" )
2226  << new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals", QString(), false, QStringList(), false, QStringList(), true )
2227  << new StaticFunction( "if", 3, fcnIf, "Conditionals", QString(), False, QStringList(), true )
2228  << new StaticFunction( "regexp_match", 2, fcnRegexpMatch, "Conditionals" )
2229  << new StaticFunction( "now", 0, fcnNow, "Date and Time", QString(), false, QStringList(), false, QStringList() << "$now" )
2230  << new StaticFunction( "age", 2, fcnAge, "Date and Time" )
2231  << new StaticFunction( "year", 1, fcnYear, "Date and Time" )
2232  << new StaticFunction( "month", 1, fcnMonth, "Date and Time" )
2233  << new StaticFunction( "week", 1, fcnWeek, "Date and Time" )
2234  << new StaticFunction( "day", 1, fcnDay, "Date and Time" )
2235  << new StaticFunction( "hour", 1, fcnHour, "Date and Time" )
2236  << new StaticFunction( "minute", 1, fcnMinute, "Date and Time" )
2237  << new StaticFunction( "second", 1, fcnSeconds, "Date and Time" )
2238  << new StaticFunction( "day_of_week", 1, fcnDayOfWeek, "Date and Time" )
2239  << new StaticFunction( "lower", 1, fcnLower, "String" )
2240  << new StaticFunction( "upper", 1, fcnUpper, "String" )
2241  << new StaticFunction( "title", 1, fcnTitle, "String" )
2242  << new StaticFunction( "trim", 1, fcnTrim, "String" )
2243  << new StaticFunction( "levenshtein", 2, fcnLevenshtein, "Fuzzy Matching" )
2244  << new StaticFunction( "longest_common_substring", 2, fcnLCS, "Fuzzy Matching" )
2245  << new StaticFunction( "hamming_distance", 2, fcnHamming, "Fuzzy Matching" )
2246  << new StaticFunction( "soundex", 1, fcnSoundex, "Fuzzy Matching" )
2247  << new StaticFunction( "wordwrap", -1, fcnWordwrap, "String" )
2248  << new StaticFunction( "length", 1, fcnLength, "String" )
2249  << new StaticFunction( "replace", 3, fcnReplace, "String" )
2250  << new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
2251  << new StaticFunction( "regexp_substr", 2, fcnRegexpSubstr, "String" )
2252  << new StaticFunction( "substr", 3, fcnSubstr, "String" )
2253  << new StaticFunction( "concat", -1, fcnConcat, "String", QString(), false, QStringList(), false, QStringList(), true )
2254  << new StaticFunction( "strpos", 2, fcnStrpos, "String" )
2255  << new StaticFunction( "left", 2, fcnLeft, "String" )
2256  << new StaticFunction( "right", 2, fcnRight, "String" )
2257  << new StaticFunction( "rpad", 3, fcnRPad, "String" )
2258  << new StaticFunction( "lpad", 3, fcnLPad, "String" )
2259  << new StaticFunction( "format", -1, fcnFormatString, "String" )
2260  << new StaticFunction( "format_number", 2, fcnFormatNumber, "String" )
2261  << new StaticFunction( "format_date", 2, fcnFormatDate, "String" )
2262  << new StaticFunction( "color_rgb", 3, fcnColorRgb, "Color" )
2263  << new StaticFunction( "color_rgba", 4, fncColorRgba, "Color" )
2264  << new StaticFunction( "ramp_color", 2, fcnRampColor, "Color" )
2265  << new StaticFunction( "color_hsl", 3, fcnColorHsl, "Color" )
2266  << new StaticFunction( "color_hsla", 4, fncColorHsla, "Color" )
2267  << new StaticFunction( "color_hsv", 3, fcnColorHsv, "Color" )
2268  << new StaticFunction( "color_hsva", 4, fncColorHsva, "Color" )
2269  << new StaticFunction( "color_cmyk", 4, fcnColorCmyk, "Color" )
2270  << new StaticFunction( "color_cmyka", 5, fncColorCmyka, "Color" )
2271  << new StaticFunction( "color_part", 2, fncColorPart, "Color" )
2272  << new StaticFunction( "set_color_part", 3, fncSetColorPart, "Color" )
2273  << new StaticFunction( "$geometry", 0, fcnGeometry, "GeometryGroup", QString(), true )
2274  << new StaticFunction( "$area", 0, fcnGeomArea, "GeometryGroup", QString(), true )
2275  << new StaticFunction( "area", 1, fcnArea, "GeometryGroup" )
2276  << new StaticFunction( "$length", 0, fcnGeomLength, "GeometryGroup", QString(), true )
2277  << new StaticFunction( "$perimeter", 0, fcnGeomPerimeter, "GeometryGroup", QString(), true )
2278  << new StaticFunction( "perimeter", 1, fcnPerimeter, "GeometryGroup" )
2279  << new StaticFunction( "$x", 0, fcnX, "GeometryGroup", QString(), true )
2280  << new StaticFunction( "$y", 0, fcnY, "GeometryGroup", QString(), true )
2281  << new StaticFunction( "x", 1, fcnGeomX, "GeometryGroup" )
2282  << new StaticFunction( "y", 1, fcnGeomY, "GeometryGroup" )
2283  << new StaticFunction( "point_n", 2, fcnPointN, "GeometryGroup" )
2284  << new StaticFunction( "start_point", 1, fcnStartPoint, "GeometryGroup" )
2285  << new StaticFunction( "end_point", 1, fcnEndPoint, "GeometryGroup" )
2286  << new StaticFunction( "make_point", 2, fcnMakePoint, "GeometryGroup" )
2287  << new StaticFunction( "$x_at", 1, fcnXat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "xat" << "x_at" )
2288  << new StaticFunction( "$y_at", 1, fcnYat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "yat" << "y_at" )
2289  << new StaticFunction( "x_min", 1, fcnXMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmin" )
2290  << new StaticFunction( "x_max", 1, fcnXMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmax" )
2291  << new StaticFunction( "y_min", 1, fcnYMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymin" )
2292  << new StaticFunction( "y_max", 1, fcnYMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymax" )
2293  << new StaticFunction( "geom_from_wkt", 1, fcnGeomFromWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromWKT" )
2294  << new StaticFunction( "geom_from_gml", 1, fcnGeomFromGML, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromGML" )
2295  << new StaticFunction( "intersects_bbox", 2, fcnBbox, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "bbox" )
2296  << new StaticFunction( "disjoint", 2, fcnDisjoint, "GeometryGroup" )
2297  << new StaticFunction( "intersects", 2, fcnIntersects, "GeometryGroup" )
2298  << new StaticFunction( "touches", 2, fcnTouches, "GeometryGroup" )
2299  << new StaticFunction( "crosses", 2, fcnCrosses, "GeometryGroup" )
2300  << new StaticFunction( "contains", 2, fcnContains, "GeometryGroup" )
2301  << new StaticFunction( "overlaps", 2, fcnOverlaps, "GeometryGroup" )
2302  << new StaticFunction( "within", 2, fcnWithin, "GeometryGroup" )
2303  << new StaticFunction( "buffer", -1, fcnBuffer, "GeometryGroup" )
2304  << new StaticFunction( "centroid", 1, fcnCentroid, "GeometryGroup" )
2305  << new StaticFunction( "bounds", 1, fcnBounds, "GeometryGroup" )
2306  << new StaticFunction( "num_points", 1, fcnGeomNumPoints, "GeometryGroup" )
2307  << new StaticFunction( "bounds_width", 1, fcnBoundsWidth, "GeometryGroup" )
2308  << new StaticFunction( "bounds_height", 1, fcnBoundsHeight, "GeometryGroup" )
2309  << new StaticFunction( "convex_hull", 1, fcnConvexHull, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "convexHull" )
2310  << new StaticFunction( "difference", 2, fcnDifference, "GeometryGroup" )
2311  << new StaticFunction( "distance", 2, fcnDistance, "GeometryGroup" )
2312  << new StaticFunction( "intersection", 2, fcnIntersection, "GeometryGroup" )
2313  << new StaticFunction( "sym_difference", 2, fcnSymDifference, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "symDifference" )
2314  << new StaticFunction( "combine", 2, fcnCombine, "GeometryGroup" )
2315  << new StaticFunction( "union", 2, fcnCombine, "GeometryGroup" )
2316  << new StaticFunction( "geom_to_wkt", -1, fcnGeomToWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomToWKT" )
2317  << new StaticFunction( "geometry", 1, fcnGetGeometry, "GeometryGroup" )
2318  << new StaticFunction( "transform", 3, fcnTransformGeometry, "GeometryGroup" )
2319  << new StaticFunction( "$rownum", 0, fcnRowNumber, "deprecated" )
2320  << new StaticFunction( "$id", 0, fcnFeatureId, "Record" )
2321  << new StaticFunction( "$currentfeature", 0, fcnFeature, "Record" )
2322  << new StaticFunction( "$scale", 0, fcnScale, "Record" )
2323  << new StaticFunction( "$map", 0, fcnMapId, "deprecated" )
2324  << new StaticFunction( "$numpages", 0, fcnComposerNumPages, "deprecated" )
2325  << new StaticFunction( "$page", 0, fcnComposerPage, "deprecated" )
2326  << new StaticFunction( "$feature", 0, fcnAtlasFeature, "deprecated" )
2327  << new StaticFunction( "$atlasfeatureid", 0, fcnAtlasFeatureId, "deprecated" )
2328  << new StaticFunction( "$atlasfeature", 0, fcnAtlasCurrentFeature, "deprecated" )
2329  << new StaticFunction( "$atlasgeometry", 0, fcnAtlasCurrentGeometry, "deprecated" )
2330  << new StaticFunction( "$numfeatures", 0, fcnAtlasNumFeatures, "deprecated" )
2331  << new StaticFunction( "uuid", 0, fcnUuid, "Record", QString(), false, QStringList(), false, QStringList() << "$uuid" )
2332  << new StaticFunction( "get_feature", 3, fcnGetFeature, "Record", QString(), false, QStringList(), false, QStringList() << "getFeature" )
2333  << new StaticFunction( "layer_property", 2, fcnGetLayerProperty, "General" )
2334  << new StaticFunction( "var", 1, fcnGetVariable, "General" )
2335 
2336  //return all attributes string for referencedColumns - this is caught by
2337  // QgsFeatureRequest::setSubsetOfAttributes and causes all attributes to be fetched by the
2338  // feature request
2339  << new StaticFunction( "attribute", 2, fcnAttribute, "Record", QString(), false, QStringList( QgsFeatureRequest::AllAttributes ) )
2340 
2341  << new StaticFunction( "_specialcol_", 1, fcnSpecialColumn, "Special" )
2342  ;
2343 
2345 
2346  //QgsExpression has ownership of all built-in functions
2347  Q_FOREACH ( QgsExpression::Function* func, gmFunctions )
2348  {
2349  gmOwnedFunctions << func;
2350  }
2351  }
2352  return gmFunctions;
2353 }
2354 
2357 
2358 void QgsExpression::setSpecialColumn( const QString& name, const QVariant& variant )
2359 {
2360  int fnIdx = functionIndex( name );
2361  if ( fnIdx != -1 )
2362  {
2363  // function of the same name already exists
2364  return;
2365  }
2366  gmSpecialColumns[ name ] = variant;
2367 }
2368 
2370 {
2372  if ( fit != gmSpecialColumns.end() )
2373  {
2374  gmSpecialColumns.erase( fit );
2375  }
2376 }
2377 
2379 {
2380  int fnIdx = functionIndex( name );
2381  if ( fnIdx != -1 )
2382  {
2383  // function of the same name already exists
2384  return QVariant();
2385  }
2387  if ( it == gmSpecialColumns.end() )
2388  {
2389  return QVariant();
2390  }
2391  return it.value();
2392 }
2393 
2395 {
2396  if ( functionIndex( name ) != -1 )
2397  return false;
2398  return gmSpecialColumns.contains( name );
2399 }
2400 
2401 bool QgsExpression::isValid( const QString &text, const QgsFields &fields, QString &errorMessage )
2402 {
2404  return isValid( text, &context, errorMessage );
2405 }
2406 
2407 bool QgsExpression::isValid( const QString &text, const QgsExpressionContext *context, QString &errorMessage )
2408 {
2409  QgsExpression exp( text );
2410  exp.prepare( context );
2411  errorMessage = exp.parserErrorString();
2412  return !exp.hasParserError();
2413 }
2414 
2416 {
2417  QList<Function*> defs;
2419  {
2420  //check for special column group name
2421  QString group = gmSpecialColumnGroups.value( it.key(), "Record" );
2422  defs << new StaticFunction( it.key(), 0, ( FcnEvalContext )0, group );
2423  }
2424  return defs;
2425 }
2426 
2428 {
2429  return QString( "\"%1\"" ).arg( name.replace( "\"", "\"\"" ) );
2430 }
2431 
2433 {
2434  text.replace( "'", "''" );
2435  text.replace( '\\', "\\\\" );
2436  text.replace( '\n', "\\n" );
2437  text.replace( '\t', "\\t" );
2438  return QString( "'%1'" ).arg( text );
2439 }
2440 
2442 {
2443  return functionIndex( name ) != -1;
2444 }
2445 
2447 {
2448  int count = functionCount();
2449  for ( int i = 0; i < count; i++ )
2450  {
2451  if ( QString::compare( name, Functions()[i]->name(), Qt::CaseInsensitive ) == 0 )
2452  return i;
2453  Q_FOREACH ( const QString& alias, Functions()[i]->aliases() )
2454  {
2455  if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
2456  return i;
2457  }
2458  }
2459  return -1;
2460 }
2461 
2463 {
2464  return Functions().size();
2465 }
2466 
2467 
2469  : mRowNumber( 0 )
2470  , mScale( 0 )
2471  , mExp( expr )
2472  , mCalc( 0 )
2473 {
2475 
2476  if ( mParserErrorString.isNull() )
2477  Q_ASSERT( mRootNode );
2478 }
2479 
2481 {
2482  delete mCalc;
2483  delete mRootNode;
2484 }
2485 
2487 {
2488  if ( !mRootNode )
2489  return QStringList();
2490 
2492 
2493  // filter out duplicates
2494  for ( int i = 0; i < columns.count(); i++ )
2495  {
2496  QString col = columns.at( i );
2497  for ( int j = i + 1; j < columns.count(); j++ )
2498  {
2499  if ( QString::compare( col, columns[j], Qt::CaseInsensitive ) == 0 )
2500  {
2501  // this column is repeated: remove it!
2502  columns.removeAt( j-- );
2503  }
2504  }
2505  }
2506 
2507  return columns;
2508 }
2509 
2511 {
2512  if ( !mRootNode )
2513  return false;
2514  return mRootNode->needsGeometry();
2515 }
2516 
2518 {
2519  if ( mCalc )
2520  return;
2521 
2522  // Use planimetric as default
2523  mCalc = new QgsDistanceArea();
2524  mCalc->setEllipsoidalMode( false );
2525 }
2526 
2528 {
2529  delete mCalc;
2530  mCalc = new QgsDistanceArea( calc );
2531 }
2532 
2533 bool QgsExpression::prepare( const QgsFields& fields )
2534 {
2536  return prepare( &fc );
2537 }
2538 
2540 {
2542  if ( !mRootNode )
2543  {
2544  //re-parse expression. Creation of QgsExpressionContexts may have added extra
2545  //known functions since this expression was created, so we have another try
2546  //at re-parsing it now that the context must have been created
2548  }
2549 
2550  if ( !mRootNode )
2551  {
2552  mEvalErrorString = tr( "No root node! Parsing failed?" );
2553  return false;
2554  }
2555 
2556  return mRootNode->prepare( this, context );
2557 }
2558 
2560 {
2562  if ( !mRootNode )
2563  {
2564  mEvalErrorString = tr( "No root node! Parsing failed?" );
2565  return QVariant();
2566  }
2567 
2569  return mRootNode->eval( this, &context );
2570 }
2571 
2573 {
2575  return evaluate( &f );
2577 }
2578 
2580 {
2581  // first prepare
2583  bool res = prepare( &context );
2584  if ( !res )
2585  return QVariant();
2586 
2587  // then evaluate
2588  return evaluate( &context );
2589 }
2590 
2591 inline QVariant QgsExpression::evaluate( const QgsFeature& f, const QgsFields& fields )
2592 {
2594  return evaluate( &f, fields );
2596 }
2597 
2599 {
2601  if ( !mRootNode )
2602  {
2603  mEvalErrorString = tr( "No root node! Parsing failed?" );
2604  return QVariant();
2605  }
2606 
2607  return mRootNode->eval( this, ( QgsExpressionContext* )0 );
2608 }
2609 
2611 {
2613  if ( !mRootNode )
2614  {
2615  mEvalErrorString = tr( "No root node! Parsing failed?" );
2616  return QVariant();
2617  }
2618 
2619  return mRootNode->eval( this, context );
2620 }
2621 
2623 {
2624  if ( !mRootNode )
2625  return tr( "(no root)" );
2626 
2627  return mRootNode->dump();
2628 }
2629 
2631 {
2632  if ( mRootNode )
2633  mRootNode->accept( v );
2634 }
2635 
2637  QgsVectorLayer *layer,
2638  const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
2639 {
2640  QgsExpressionContext context = QgsExpressionContextUtils::createFeatureBasedContext( feat ? *feat : QgsFeature(), layer ? layer->fields() : QgsFields() );
2641  return replaceExpressionText( action, &context, substitutionMap, distanceArea );
2642 }
2643 
2644 QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
2645 {
2646  QString expr_action;
2647 
2648  QMap<QString, QVariant> savedValues;
2649  if ( substitutionMap )
2650  {
2651  // variables with a local scope (must be restored after evaluation)
2652  for ( QMap<QString, QVariant>::const_iterator sit = substitutionMap->begin(); sit != substitutionMap->end(); ++sit )
2653  {
2655  QVariant oldValue = QgsExpression::specialColumn( sit.key() );
2656  if ( !oldValue.isNull() )
2657  savedValues.insert( sit.key(), oldValue );
2658 
2659  // set the new value
2660  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
2662  }
2663  }
2664 
2665  int index = 0;
2666  while ( index < action.size() )
2667  {
2668  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
2669 
2670  int pos = rx.indexIn( action, index );
2671  if ( pos < 0 )
2672  break;
2673 
2674  int start = index;
2675  index = pos + rx.matchedLength();
2676  QString to_replace = rx.cap( 1 ).trimmed();
2677  QgsDebugMsg( "Found expression: " + to_replace );
2678 
2679  QgsExpression exp( to_replace );
2680  if ( exp.hasParserError() )
2681  {
2682  QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
2683  expr_action += action.midRef( start, index - start );
2684  continue;
2685  }
2686 
2687  if ( distanceArea )
2688  {
2689  //if QgsDistanceArea specified for area/distance conversion, use it
2690  exp.setGeomCalculator( *distanceArea );
2691  }
2692 
2693  QVariant result = exp.evaluate( context );
2694 
2695  if ( exp.hasEvalError() )
2696  {
2697  QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
2698  expr_action += action.midRef( start, index - start );
2699  continue;
2700  }
2701 
2702  QgsDebugMsg( "Expression result is: " + result.toString() );
2703  expr_action += action.mid( start, pos - start ) + result.toString();
2704  }
2705 
2706  expr_action += action.midRef( index );
2707 
2708  // restore overwritten local values
2710  for ( QMap<QString, QVariant>::const_iterator sit = savedValues.begin(); sit != savedValues.end(); ++sit )
2711  {
2712  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
2713  }
2715 
2716  return expr_action;
2717 }
2718 
2719 double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
2720 {
2721  bool ok;
2722  //first test if text is directly convertible to double
2723  double convertedValue = text.toDouble( &ok );
2724  if ( ok )
2725  {
2726  return convertedValue;
2727  }
2728 
2729  //otherwise try to evalute as expression
2730  QgsExpression expr( text );
2731 
2732  QgsExpressionContext context;
2735 
2736  QVariant result = expr.evaluate( &context );
2737  convertedValue = result.toDouble( &ok );
2738  if ( expr.hasEvalError() || !ok )
2739  {
2740  return fallbackValue;
2741  }
2742  return convertedValue;
2743 }
2744 
2745 
2747 // nodes
2748 
2750 {
2751  QString msg; bool first = true;
2752  Q_FOREACH ( Node* n, mList )
2753  {
2754  if ( !first ) msg += ", "; else first = false;
2755  msg += n->dump();
2756  }
2757  return msg;
2758 }
2759 
2760 
2761 //
2762 
2764 {
2765  QVariant val = mOperand->eval( parent, context );
2767 
2768  switch ( mOp )
2769  {
2770  case uoNot:
2771  {
2772  TVL tvl = getTVLValue( val, parent );
2774  return tvl2variant( NOT[tvl] );
2775  }
2776 
2777  case uoMinus:
2778  if ( isIntSafe( val ) )
2779  return QVariant( - getIntValue( val, parent ) );
2780  else if ( isDoubleSafe( val ) )
2781  return QVariant( - getDoubleValue( val, parent ) );
2782  else
2783  SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) );
2784  break;
2785  default:
2786  Q_ASSERT( 0 && "unknown unary operation" );
2787  }
2788  return QVariant();
2789 }
2790 
2792 {
2793  return mOperand->prepare( parent, context );
2794 }
2795 
2797 {
2798  return QString( "%1 %2" ).arg( UnaryOperatorText[mOp], mOperand->dump() );
2799 }
2800 
2801 //
2802 
2804 {
2805  QVariant vL = mOpLeft->eval( parent, context );
2807  QVariant vR = mOpRight->eval( parent, context );
2809 
2810  switch ( mOp )
2811  {
2812  case boPlus:
2813  if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
2814  {
2815  QString sL = isNull( vL ) ? QString() : getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2816  QString sR = isNull( vR ) ? QString() : getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2817  return QVariant( sL + sR );
2818  }
2819  //intentional fall-through
2820  case boMinus:
2821  case boMul:
2822  case boDiv:
2823  case boMod:
2824  {
2825  if ( isNull( vL ) || isNull( vR ) )
2826  return QVariant();
2827  else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
2828  {
2829  // both are integers - let's use integer arithmetics
2830  int iL = getIntValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2831  int iR = getIntValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2832 
2833  if ( mOp == boMod && iR == 0 )
2834  return QVariant();
2835 
2836  return QVariant( computeInt( iL, iR ) );
2837  }
2838  else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
2839  {
2840  QDateTime dL = getDateTimeValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2842  if ( mOp == boDiv || mOp == boMul || mOp == boMod )
2843  {
2844  parent->setEvalErrorString( tr( "Can't preform /, *, or % on DateTime and Interval" ) );
2845  return QVariant();
2846  }
2847  return QVariant( computeDateTimeFromInterval( dL, &iL ) );
2848  }
2849  else
2850  {
2851  // general floating point arithmetic
2852  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2853  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2854  if (( mOp == boDiv || mOp == boMod ) && fR == 0. )
2855  return QVariant(); // silently handle division by zero and return NULL
2856  return QVariant( computeDouble( fL, fR ) );
2857  }
2858  }
2859  case boIntDiv:
2860  {
2861  //integer division
2862  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2863  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2864  if ( fR == 0. )
2865  return QVariant(); // silently handle division by zero and return NULL
2866  return QVariant( qFloor( fL / fR ) );
2867  }
2868  case boPow:
2869  if ( isNull( vL ) || isNull( vR ) )
2870  return QVariant();
2871  else
2872  {
2873  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2874  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2875  return QVariant( pow( fL, fR ) );
2876  }
2877 
2878  case boAnd:
2879  {
2880  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
2882  return tvl2variant( AND[tvlL][tvlR] );
2883  }
2884 
2885  case boOr:
2886  {
2887  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
2889  return tvl2variant( OR[tvlL][tvlR] );
2890  }
2891 
2892  case boEQ:
2893  case boNE:
2894  case boLT:
2895  case boGT:
2896  case boLE:
2897  case boGE:
2898  if ( isNull( vL ) || isNull( vR ) )
2899  {
2900  return TVL_Unknown;
2901  }
2902  else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) )
2903  {
2904  // do numeric comparison if both operators can be converted to numbers
2905  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2906  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2907  return compare( fL - fR ) ? TVL_True : TVL_False;
2908  }
2909  else
2910  {
2911  // do string comparison otherwise
2912  QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2913  QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2914  int diff = QString::compare( sL, sR );
2915  return compare( diff ) ? TVL_True : TVL_False;
2916  }
2917 
2918  case boIs:
2919  case boIsNot:
2920  if ( isNull( vL ) && isNull( vR ) ) // both operators null
2921  return ( mOp == boIs ? TVL_True : TVL_False );
2922  else if ( isNull( vL ) || isNull( vR ) ) // one operator null
2923  return ( mOp == boIs ? TVL_False : TVL_True );
2924  else // both operators non-null
2925  {
2926  bool equal = false;
2927  if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) )
2928  {
2929  double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2930  double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2931  equal = fL == fR;
2932  }
2933  else
2934  {
2935  QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2936  QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2937  equal = QString::compare( sL, sR ) == 0;
2938  }
2939  if ( equal )
2940  return mOp == boIs ? TVL_True : TVL_False;
2941  else
2942  return mOp == boIs ? TVL_False : TVL_True;
2943  }
2944 
2945  case boRegexp:
2946  case boLike:
2947  case boNotLike:
2948  case boILike:
2949  case boNotILike:
2950  if ( isNull( vL ) || isNull( vR ) )
2951  return TVL_Unknown;
2952  else
2953  {
2954  QString str = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2955  QString regexp = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2956  // TODO: cache QRegExp in case that regexp is a literal string (i.e. it will stay constant)
2957  bool matches;
2958  if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
2959  {
2960  QString esc_regexp = QRegExp::escape( regexp );
2961  // XXX escape % and _ ???
2962  esc_regexp.replace( "%", ".*" );
2963  esc_regexp.replace( "_", "." );
2964  matches = QRegExp( esc_regexp, mOp == boLike || mOp == boNotLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( str );
2965  }
2966  else
2967  {
2968  matches = QRegExp( regexp ).indexIn( str ) != -1;
2969  }
2970 
2971  if ( mOp == boNotLike || mOp == boNotILike )
2972  {
2973  matches = !matches;
2974  }
2975 
2976  return matches ? TVL_True : TVL_False;
2977  }
2978 
2979  case boConcat:
2980  if ( isNull( vL ) || isNull( vR ) )
2981  return QVariant();
2982  else
2983  {
2984  QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
2985  QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
2986  return QVariant( sL + sR );
2987  }
2988 
2989  default: break;
2990  }
2991  Q_ASSERT( false );
2992  return QVariant();
2993 }
2994 
2996 {
2997  switch ( mOp )
2998  {
2999  case boEQ: return diff == 0;
3000  case boNE: return diff != 0;
3001  case boLT: return diff < 0;
3002  case boGT: return diff > 0;
3003  case boLE: return diff <= 0;
3004  case boGE: return diff >= 0;
3005  default: Q_ASSERT( false ); return false;
3006  }
3007 }
3008 
3010 {
3011  switch ( mOp )
3012  {
3013  case boPlus: return x+y;
3014  case boMinus: return x-y;
3015  case boMul: return x*y;
3016  case boDiv: return x/y;
3017  case boMod: return x%y;
3018  default: Q_ASSERT( false ); return 0;
3019  }
3020 }
3021 
3023 {
3024  switch ( mOp )
3025  {
3026  case boPlus: return d.addSecs( i->seconds() );
3027  case boMinus: return d.addSecs( -i->seconds() );
3028  default: Q_ASSERT( false ); return QDateTime();
3029  }
3030 }
3031 
3033 {
3034  switch ( mOp )
3035  {
3036  case boPlus: return x+y;
3037  case boMinus: return x-y;
3038  case boMul: return x*y;
3039  case boDiv: return x/y;
3040  case boMod: return fmod( x,y );
3041  default: Q_ASSERT( false ); return 0;
3042  }
3043 }
3044 
3046 {
3047  bool resL = mOpLeft->prepare( parent, context );
3048  bool resR = mOpRight->prepare( parent, context );
3049  return resL && resR;
3050 }
3051 
3053 {
3054  // see left/right in qgsexpressionparser.yy
3055  switch ( mOp )
3056  {
3057  case boOr:
3058  return 1;
3059 
3060  case boAnd:
3061  return 2;
3062 
3063  case boEQ:
3064  case boNE:
3065  case boLE:
3066  case boGE:
3067  case boLT:
3068  case boGT:
3069  case boRegexp:
3070  case boLike:
3071  case boILike:
3072  case boNotLike:
3073  case boNotILike:
3074  case boIs:
3075  case boIsNot:
3076  return 3;
3077 
3078  case boPlus:
3079  case boMinus:
3080  return 4;
3081 
3082  case boMul:
3083  case boDiv:
3084  case boIntDiv:
3085  case boMod:
3086  return 5;
3087 
3088  case boPow:
3089  return 6;
3090 
3091  case boConcat:
3092  return 7;
3093  }
3094  Q_ASSERT( 0 && "unexpected binary operator" );
3095  return -1;
3096 }
3097 
3099 {
3100  // see left/right in qgsexpressionparser.yy
3101  switch ( mOp )
3102  {
3103  case boOr:
3104  case boAnd:
3105  case boEQ:
3106  case boNE:
3107  case boLE:
3108  case boGE:
3109  case boLT:
3110  case boGT:
3111  case boRegexp:
3112  case boLike:
3113  case boILike:
3114  case boNotLike:
3115  case boNotILike:
3116  case boIs:
3117  case boIsNot:
3118  case boPlus:
3119  case boMinus:
3120  case boMul:
3121  case boDiv:
3122  case boIntDiv:
3123  case boMod:
3124  case boConcat:
3125  return true;
3126 
3127  case boPow:
3128  return false;
3129  }
3130  Q_ASSERT( 0 && "unexpected binary operator" );
3131  return false;
3132 }
3133 
3135 {
3136  QgsExpression::NodeBinaryOperator *lOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpLeft );
3137  QgsExpression::NodeBinaryOperator *rOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpRight );
3138 
3139  QString fmt;
3140  if ( leftAssociative() )
3141  {
3142  fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";
3143  fmt += " %2 ";
3144  fmt += rOp && ( rOp->precedence() <= precedence() ) ? "(%3)" : "%3";
3145  }
3146  else
3147  {
3148  fmt += lOp && ( lOp->precedence() <= precedence() ) ? "(%1)" : "%1";
3149  fmt += " %2 ";
3150  fmt += rOp && ( rOp->precedence() < precedence() ) ? "(%3)" : "%3";
3151  }
3152 
3153  return fmt.arg( mOpLeft->dump(), BinaryOperatorText[mOp], mOpRight->dump() );
3154 }
3155 
3156 //
3157 
3159 {
3160  if ( mList->count() == 0 )
3161  return mNotIn ? TVL_True : TVL_False;
3162  QVariant v1 = mNode->eval( parent, context );
3164  if ( isNull( v1 ) )
3165  return TVL_Unknown;
3166 
3167  bool listHasNull = false;
3168 
3169  Q_FOREACH ( Node* n, mList->list() )
3170  {
3171  QVariant v2 = n->eval( parent, context );
3173  if ( isNull( v2 ) )
3174  listHasNull = true;
3175  else
3176  {
3177  bool equal = false;
3178  // check whether they are equal
3179  if ( isDoubleSafe( v1 ) && isDoubleSafe( v2 ) )
3180  {
3181  double f1 = getDoubleValue( v1, parent ); ENSURE_NO_EVAL_ERROR;
3182  double f2 = getDoubleValue( v2, parent ); ENSURE_NO_EVAL_ERROR;
3183  equal = f1 == f2;
3184  }
3185  else
3186  {
3187  QString s1 = getStringValue( v1, parent ); ENSURE_NO_EVAL_ERROR;
3188  QString s2 = getStringValue( v2, parent ); ENSURE_NO_EVAL_ERROR;
3189  equal = QString::compare( s1, s2 ) == 0;
3190  }
3191 
3192  if ( equal ) // we know the result
3193  return mNotIn ? TVL_False : TVL_True;
3194  }
3195  }
3196 
3197  // item not found
3198  if ( listHasNull )
3199  return TVL_Unknown;
3200  else
3201  return mNotIn ? TVL_True : TVL_False;
3202 }
3203 
3205 {
3206  bool res = mNode->prepare( parent, context );
3207  Q_FOREACH ( Node* n, mList->list() )
3208  {
3209  res = res && n->prepare( parent, context );
3210  }
3211  return res;
3212 }
3213 
3215 {
3216  return QString( "%1 %2 IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
3217 }
3218 
3219 //
3220 
3222 {
3223  QString name = Functions()[mFnIndex]->name();
3224  Function* fd = context && context->hasFunction( name ) ? context->function( name ) : Functions()[mFnIndex];
3225 
3226  // evaluate arguments
3227  QVariantList argValues;
3228  if ( mArgs )
3229  {
3230  Q_FOREACH ( Node* n, mArgs->list() )
3231  {
3232  QVariant v;
3233  if ( fd->lazyEval() )
3234  {
3235  // Pass in the node for the function to eval as it needs.
3236  v = QVariant::fromValue( n );
3237  }
3238  else
3239  {
3240  v = n->eval( parent, context );
3242  if ( isNull( v ) && !fd->handlesNull() )
3243  return QVariant(); // all "normal" functions return NULL, when any parameter is NULL (so coalesce is abnormal)
3244  }
3245  argValues.append( v );
3246  }
3247  }
3248 
3249  // run the function
3250  QVariant res = fd->func( argValues, context, parent );
3252 
3253  // everything went fine
3254  return res;
3255 }
3256 
3258 {
3259  bool res = true;
3260  if ( mArgs )
3261  {
3262  Q_FOREACH ( Node* n, mArgs->list() )
3263  {
3264  res = res && n->prepare( parent, context );
3265  }
3266  }
3267  return res;
3268 }
3269 
3271 {
3272  Function* fd = Functions()[mFnIndex];
3273  if ( fd->params() == 0 )
3274  return QString( "%1%2" ).arg( fd->name(), fd->name().startsWith( '$' ) ? "" : "()" ); // special column
3275  else
3276  return QString( "%1(%2)" ).arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
3277 }
3278 
3280 {
3281  Function* fd = Functions()[mFnIndex];
3282  QStringList functionColumns = fd->referencedColumns();
3283 
3284  if ( !mArgs )
3285  {
3286  //no referenced columns in arguments, just return function's referenced columns
3287  return functionColumns;
3288  }
3289 
3290  Q_FOREACH ( Node* n, mArgs->list() )
3291  {
3292  functionColumns.append( n->referencedColumns() );
3293  }
3294 
3295  //remove duplicates and return
3296  return functionColumns.toSet().toList();
3297 }
3298 
3299 //
3300 
3302 {
3303  Q_UNUSED( context );
3304  Q_UNUSED( parent );
3305  return mValue;
3306 }
3307 
3309 {
3310  Q_UNUSED( parent );
3311  Q_UNUSED( context );
3312  return true;
3313 }
3314 
3315 
3317 {
3318  if ( mValue.isNull() )
3319  return "NULL";
3320 
3321  switch ( mValue.type() )
3322  {
3323  case QVariant::Int: return QString::number( mValue.toInt() );
3324  case QVariant::Double: return QString::number( mValue.toDouble() );
3325  case QVariant::String: return quotedString( mValue.toString() );
3326  case QVariant::Bool: return mValue.toBool() ? "TRUE" : "FALSE";
3327  default: return tr( "[unsupported type;%1; value:%2]" ).arg( mValue.typeName(), mValue.toString() );
3328  }
3329 }
3330 
3331 //
3332 
3334 {
3335  Q_UNUSED( parent );
3336  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) )
3337  {
3338  QgsFeature feature = qvariant_cast<QgsFeature>( context->variable( QgsExpressionContext::EXPR_FEATURE ) );
3339  if ( mIndex >= 0 )
3340  return feature.attribute( mIndex );
3341  else
3342  return feature.attribute( mName );
3343  }
3344  return QVariant( "[" + mName + "]" );
3345 }
3346 
3348 {
3349  if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
3350  return false;
3351 
3352  QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
3353 
3354  for ( int i = 0; i < fields.count(); ++i )
3355  {
3356  if ( QString::compare( fields.at( i ).name(), mName, Qt::CaseInsensitive ) == 0 )
3357  {
3358  mIndex = i;
3359  return true;
3360  }
3361  }
3362  parent->mEvalErrorString = tr( "Column '%1' not found" ).arg( mName );
3363  mIndex = -1;
3364  return false;
3365 }
3366 
3368 {
3369  return QRegExp( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ).exactMatch( mName ) ? mName : quotedColumnRef( mName );
3370 }
3371 
3372 //
3373 
3375 {
3376  Q_FOREACH ( WhenThen* cond, mConditions )
3377  {
3378  QVariant vWhen = cond->mWhenExp->eval( parent, context );
3379  TVL tvl = getTVLValue( vWhen, parent );
3381  if ( tvl == True )
3382  {
3383  QVariant vRes = cond->mThenExp->eval( parent, context );
3385  return vRes;
3386  }
3387  }
3388 
3389  if ( mElseExp )
3390  {
3391  QVariant vElse = mElseExp->eval( parent, context );
3393  return vElse;
3394  }
3395 
3396  // return NULL if no condition is matching
3397  return QVariant();
3398 }
3399 
3401 {
3402  bool res;
3403  Q_FOREACH ( WhenThen* cond, mConditions )
3404  {
3405  res = cond->mWhenExp->prepare( parent, context )
3406  & cond->mThenExp->prepare( parent, context );
3407  if ( !res ) return false;
3408  }
3409 
3410  if ( mElseExp )
3411  return mElseExp->prepare( parent, context );
3412 
3413  return true;
3414 }
3415 
3417 {
3418  QString msg( "CASE" );
3419  Q_FOREACH ( WhenThen* cond, mConditions )
3420  {
3421  msg += QString( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
3422  }
3423  if ( mElseExp )
3424  msg += QString( " ELSE %1" ).arg( mElseExp->dump() );
3425  msg += QString( " END" );
3426  return msg;
3427 }
3428 
3430 {
3431  QStringList lst;
3432  Q_FOREACH ( WhenThen* cond, mConditions )
3433  {
3434  lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
3435  }
3436 
3437  if ( mElseExp )
3438  lst += mElseExp->referencedColumns();
3439 
3440  return lst;
3441 }
3442 
3444 {
3445  Q_FOREACH ( WhenThen* cond, mConditions )
3446  {
3447  if ( cond->mWhenExp->needsGeometry() ||
3448  cond->mThenExp->needsGeometry() )
3449  return true;
3450  }
3451 
3452  if ( mElseExp && mElseExp->needsGeometry() )
3453  return true;
3454 
3455  return false;
3456 }
3457 
3458 
3460 {
3462 
3463  if ( !gFunctionHelpTexts.contains( name ) )
3464  return tr( "function help for %1 missing" ).arg( name );
3465 
3466  const Help &f = gFunctionHelpTexts[ name ];
3467 
3468  name = f.mName;
3469  if ( f.mType == tr( "group" ) )
3470  name = group( name );
3471 
3472 #if QT_VERSION < 0x050000
3473  name = Qt::escape( name );
3474 #else
3475  name = name.toHtmlEscaped();
3476 #endif
3477 
3478  QString helpContents( QString( "<h3>%1</h3>\n<div class=\"description\"><p>%2</p></div>" )
3479  .arg( tr( "%1 %2" ).arg( f.mType, name ),
3480  f.mDescription ) );
3481 
3482  Q_FOREACH ( const HelpVariant &v, f.mVariants )
3483  {
3484  if ( f.mVariants.size() > 1 )
3485  {
3486  helpContents += QString( "<h3>%1</h3>\n<div class=\"description\">%2</p></div>" ).arg( v.mName, v.mDescription );
3487  }
3488 
3489  if ( f.mType != tr( "group" ) )
3490  helpContents += QString( "<h4>%1</h4>\n<div class=\"syntax\">\n" ).arg( tr( "Syntax" ) );
3491 
3492  if ( f.mType == tr( "operator" ) )
3493  {
3494  if ( v.mArguments.size() == 1 )
3495  {
3496  helpContents += QString( "<code><span class=\"functionname\">%1</span> <span class=\"argument\">%2</span></code>" )
3497  .arg( name, v.mArguments[0].mArg );
3498  }
3499  else if ( v.mArguments.size() == 2 )
3500  {
3501  helpContents += QString( "<code><span class=\"argument\">%1</span> <span class=\"functionname\">%2</span> <span class=\"argument\">%3</span></code>" )
3502  .arg( v.mArguments[0].mArg, name, v.mArguments[1].mArg );
3503  }
3504  }
3505  else if ( f.mType != tr( "group" ) )
3506  {
3507  helpContents += QString( "<code><span class=\"functionname\">%1</span>" ).arg( name );
3508 
3509  if ( f.mType == tr( "function" ) && ( f.mName[0] != '$' || v.mArguments.size() > 0 || v.mVariableLenArguments ) )
3510  {
3511  helpContents += "(";
3512 
3513  QString delim;
3514  Q_FOREACH ( const HelpArg &a, v.mArguments )
3515  {
3516  helpContents += delim;
3517  delim = ", ";
3518  if ( !a.mDescOnly )
3519  helpContents += QString( "<span class=\"argument\">%1</span>" ).arg( a.mArg );
3520  }
3521 
3522  if ( v.mVariableLenArguments )
3523  {
3524  helpContents += "...";
3525  }
3526 
3527  helpContents += ")";
3528  }
3529 
3530  helpContents += "</code>";
3531  }
3532 
3533  if ( v.mArguments.size() > 0 )
3534  {
3535  helpContents += QString( "<h4>%1</h4>\n<div class=\"arguments\">\n<table>" ).arg( tr( "Arguments" ) );
3536 
3537  Q_FOREACH ( const HelpArg &a, v.mArguments )
3538  {
3539  if ( a.mSyntaxOnly )
3540  continue;
3541 
3542  helpContents += QString( "<tr><td class=\"argument\">%1</td><td>%2</td></tr>" ).arg( a.mArg, a.mDescription );
3543  }
3544 
3545  helpContents += "</table>\n</div>\n";
3546  }
3547 
3548  if ( v.mExamples.size() > 0 )
3549  {
3550  helpContents += QString( "<h4>%1</h4>\n<div class=\"examples\">\n<ul>\n" ).arg( tr( "Examples" ) );
3551 
3552  Q_FOREACH ( const HelpExample &e, v.mExamples )
3553  {
3554  helpContents += "<li><code>" + e.mExpression + "</code> &rarr; <code>" + e.mReturns + "</code>";
3555 
3556  if ( !e.mNote.isEmpty() )
3557  helpContents += QString( " (%1)" ).arg( e.mNote );
3558 
3559  helpContents += "</li>\n";
3560  }
3561 
3562  helpContents += "</ul>\n</div>\n";
3563  }
3564 
3565  if ( !v.mNotes.isEmpty() )
3566  {
3567  helpContents += QString( "<h4>%1</h4>\n<div class=\"notes\"><p>%2</p></div>\n" ).arg( tr( "Notes" ), v.mNotes );
3568  }
3569  }
3570 
3571  return helpContents;
3572 }
3573 
3575 
3577 {
3578  if ( !gVariableHelpTexts.isEmpty() )
3579  return;
3580 
3581  //global variables
3582  gVariableHelpTexts.insert( "qgis_version", QCoreApplication::translate( "variable_help", "Current QGIS version string." ) );
3583  gVariableHelpTexts.insert( "qgis_version_no", QCoreApplication::translate( "variable_help", "Current QGIS version number." ) );
3584  gVariableHelpTexts.insert( "qgis_release_name", QCoreApplication::translate( "variable_help", "Current QGIS release name." ) );
3585 
3586  //project variables
3587  gVariableHelpTexts.insert( "project_title", QCoreApplication::translate( "variable_help", "Title of current project." ) );
3588  gVariableHelpTexts.insert( "project_path", QCoreApplication::translate( "variable_help", "Full path (including file name) of current project." ) );
3589  gVariableHelpTexts.insert( "project_folder", QCoreApplication::translate( "variable_help", "Folder for current project." ) );
3590  gVariableHelpTexts.insert( "project_filename", QCoreApplication::translate( "variable_help", "Filename of current project." ) );
3591 
3592  //layer variables
3593  gVariableHelpTexts.insert( "layer_name", QCoreApplication::translate( "variable_help", "Name of current layer." ) );
3594  gVariableHelpTexts.insert( "layer_id", QCoreApplication::translate( "variable_help", "ID of current layer." ) );
3595 
3596  //composition variables
3597  gVariableHelpTexts.insert( "layout_numpages", QCoreApplication::translate( "variable_help", "Number of pages in composition." ) );
3598  gVariableHelpTexts.insert( "layout_pageheight", QCoreApplication::translate( "variable_help", "Composition page height in mm." ) );
3599  gVariableHelpTexts.insert( "layout_pagewidth", QCoreApplication::translate( "variable_help", "Composition page width in mm." ) );
3600  gVariableHelpTexts.insert( "layout_dpi", QCoreApplication::translate( "variable_help", "Composition resolution (DPI)." ) );
3601 
3602  //atlas variables
3603  gVariableHelpTexts.insert( "atlas_totalfeatures", QCoreApplication::translate( "variable_help", "Total number of features in atlas." ) );
3604  gVariableHelpTexts.insert( "atlas_featurenumber", QCoreApplication::translate( "variable_help", "Current atlas feature number." ) );
3605  gVariableHelpTexts.insert( "atlas_filename", QCoreApplication::translate( "variable_help", "Current atlas file name." ) );
3606  gVariableHelpTexts.insert( "atlas_pagename", QCoreApplication::translate( "variable_help", "Current atlas page name." ) );
3607  gVariableHelpTexts.insert( "atlas_feature", QCoreApplication::translate( "variable_help", "Current atlas feature (as feature object)." ) );
3608  gVariableHelpTexts.insert( "atlas_featureid", QCoreApplication::translate( "variable_help", "Current atlas feature ID." ) );
3609  gVariableHelpTexts.insert( "atlas_geometry", QCoreApplication::translate( "variable_help", "Current atlas feature geometry." ) );
3610 
3611  //composer item variables
3612  gVariableHelpTexts.insert( "item_id", QCoreApplication::translate( "variable_help", "Composer item user ID (not necessarily unique)." ) );
3613  gVariableHelpTexts.insert( "item_uuid", QCoreApplication::translate( "variable_help", "Composer item unique ID." ) );
3614  gVariableHelpTexts.insert( "item_left", QCoreApplication::translate( "variable_help", "Left position of composer item (in mm)." ) );
3615  gVariableHelpTexts.insert( "item_top", QCoreApplication::translate( "variable_help", "Top position of composer item (in mm)." ) );
3616  gVariableHelpTexts.insert( "item_width", QCoreApplication::translate( "variable_help", "Width of composer item (in mm)." ) );
3617  gVariableHelpTexts.insert( "item_height", QCoreApplication::translate( "variable_help", "Height of composer item (in mm)." ) );
3618 
3619  //map settings item variables
3620  gVariableHelpTexts.insert( "map_id", QCoreApplication::translate( "variable_help", "ID of current map destination. This will be 'canvas' for canvas renders, and the item ID for composer map renders." ) );
3621  gVariableHelpTexts.insert( "map_rotation", QCoreApplication::translate( "variable_help", "Current rotation of map." ) );
3622  gVariableHelpTexts.insert( "map_scale", QCoreApplication::translate( "variable_help", "Current scale of map." ) );
3623 
3624  gVariableHelpTexts.insert( "row_number", QCoreApplication::translate( "variable_help", "Stores the number of the current row." ) );
3625  gVariableHelpTexts.insert( "grid_number", QCoreApplication::translate( "variable_help", "Current grid annotation value." ) );
3626  gVariableHelpTexts.insert( "grid_axis", QCoreApplication::translate( "variable_help", "Current grid annotation axis (eg, 'x' for longitude, 'y' for latitude)." ) );
3627 }
3628 
3629 QString QgsExpression::variableHelpText( const QString &variableName, bool showValue, const QVariant &value )
3630 {
3632  QString text = gVariableHelpTexts.contains( variableName ) ? QString( "<p>%1</p>" ).arg( gVariableHelpTexts.value( variableName ) ) : QString();
3633  if ( showValue )
3634  {
3635  QString valueString;
3636  if ( !value.isValid() )
3637  {
3638  valueString = QCoreApplication::translate( "variable_help", "not set" );
3639  }
3640  else if ( value.type() == QVariant::String )
3641  {
3642  valueString = QString( "'<b>%1</b>'" ).arg( value.toString() );
3643  }
3644  else
3645  {
3646  valueString = QString( "<b>%1</b>" ).arg( value.toString() );
3647  }
3648  text.append( QCoreApplication::translate( "variable_help", "<p>Current value: %1</p>" ).arg( valueString ) );
3649  }
3650  return text;
3651 }
3652 
3654 
3656 {
3657  if ( gGroups.isEmpty() )
3658  {
3659  gGroups.insert( "General", tr( "General" ) );
3660  gGroups.insert( "Operators", tr( "Operators" ) );
3661  gGroups.insert( "Conditionals", tr( "Conditionals" ) );
3662  gGroups.insert( "Fields and Values", tr( "Fields and Values" ) );
3663  gGroups.insert( "Math", tr( "Math" ) );
3664  gGroups.insert( "Conversions", tr( "Conversions" ) );
3665  gGroups.insert( "Date and Time", tr( "Date and Time" ) );
3666  gGroups.insert( "String", tr( "String" ) );
3667  gGroups.insert( "Color", tr( "Color" ) );
3668  gGroups.insert( "GeometryGroup", tr( "Geometry" ) );
3669  gGroups.insert( "Record", tr( "Record" ) );
3670  gGroups.insert( "Variables", tr( "Variables" ) );
3671  gGroups.insert( "Fuzzy Matching", tr( "Fuzzy Matching" ) );
3672  gGroups.insert( "Recent (%1)", tr( "Recent (%1)" ) );
3673  }
3674 
3675  //return the translated name for this group. If group does not
3676  //have a translated name in the gGroups hash, return the name
3677  //unchanged
3678  return gGroups.value( name, name );
3679 }
3680 
3681 
3682 QVariant QgsExpression::Function::func( const QVariantList& values, const QgsFeature* feature, QgsExpression* parent )
3683 {
3684  //default implementation creates a QgsFeatureBasedExpressionContext
3686  return func( values, &c, parent );
3687 }
3688 
3689 QVariant QgsExpression::Function::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
3690 {
3691  //base implementation calls deprecated func to avoid API breakage
3692  QgsFeature f;
3693  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) )
3694  f = qvariant_cast<QgsFeature>( context->variable( QgsExpressionContext::EXPR_FEATURE ) );
3695 
3697  return func( values, &f, parent );
3699 }
3700 
3702 {
3703  //default implementation creates a QgsFeatureBasedExpressionContext
3705  return eval( parent, &c );
3706 }
3707 
3709 {
3710  //base implementation calls deprecated eval to avoid API breakage
3711  QgsFeature f;
3712  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) )
3713  f = qvariant_cast<QgsFeature>( context->variable( QgsExpressionContext::EXPR_FEATURE ) );
3714 
3716  return eval( parent, &f );
3718 }
3719 
3721 {
3723  return prepare( parent, &c );
3724 }
3725 
3727 {
3728  //base implementation calls deprecated prepare to avoid API breakage
3729  QgsFields f;
3730  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
3731  f = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
3732 
3734  return prepare( parent, f );
3736 }
3737 
3738 QVariant QgsExpression::StaticFunction::func( const QVariantList &values, const QgsFeature* f, QgsExpression* parent )
3739 {
3741  return mFnc ? mFnc( values, f, parent ) : QVariant();
3743 }
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:92
qlonglong toLongLong(bool *ok) const
const QString & name() const
Gets the name of the field.
Definition: qgsfield.cpp:72
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
const QgsVectorColorRampV2 * colorRampRef(const QString &name) const
return a const pointer to a symbol (doesn't create new instance)
Definition: qgsstylev2.cpp:266
static QVariant fcnGeomLength(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
int minute() const
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.
static QVariant fcnAtlasCurrentGeometry(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
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. ...
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...
qreal alphaF() const
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.
static QString group(const QString &group)
Returns the translated name for a function group.
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:196
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QgsFields fields() const
Returns the list of fields of this layer.
double computeDouble(double x, double y)
static QVariant fcnIf(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
static QString encodeColor(const QColor &color)
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.
int value() const
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 fcnMapId(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
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:390
QgsExpression()
Used by QgsOgcUtils to create an empty.
QgsRectangle boundingBox() const
Returns the bounding box of this feature.
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
bool isValid() const
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
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)
void setBlue(int blue)
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:76
Q_DECL_DEPRECATED int currentRowNumber()
Return the number used for $rownum special column.
void setAlpha(int alpha)
static const char * vectorGeometryType(GeometryType type)
description strings for geometry types
Definition: qgis.cpp:398
QgsExpression::Node * parseExpression(const QString &str, QString &parserErrorMsg)
QSet< T > toSet() const
static QVariant fcnTouches(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
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:176
static QVariant fcnMax(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QList< HelpVariant > mVariants
static QVariant fcnLCS(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnXMin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void setRed(int red)
static TVL getTVLValue(const QVariant &value, QgsExpression *parent)
static QVariant fcnFormatNumber(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int month() const
qreal hslHueF() 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)
qreal cyanF() const
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 QVariant fncColorPart(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QString soundex(const QString &string)
Returns the Soundex representation of a string.
QString mEvalErrorString
double x() const
Get the x value of the point.
Definition: qgspoint.h:126
int second() const
static QVariant fcnComposerPage(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
int nCoordinates() const
Returns the number of nodes contained in the geometry.
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
QgsMapLayer * mapLayer(const QString &theLayerId)
Retrieve a pointer to a loaded layer by id.
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 Q_DECL_DEPRECATED void setSpecialColumn(const QString &name, const QVariant &value)
Assign a special column.
static QVariant fcnYat(const QVariantList &values, const QgsExpressionContext *f, QgsExpression *parent)
virtual QString dump() const override
Abstract virtual dump method.
int lightness() const
static QVariant fcnCos(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static const QStringList & BuiltinFunctions()
int dayOfWeek() const
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 bool unregisterFunction(const QString &name)
Unregisters a function from the expression engine.
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 QVariant fncSetColorPart(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.
static QVariant fcnAtlasFeature(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
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...
static QVariant fcnMinute(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
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)
static QVariant fcnStartPoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
qreal x() const
qreal y() const
void append(const T &value)
void setGreen(int green)
static QVariant fcnLn(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnMakePoint(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) ...
static QVariant fcnGeomY(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
#define TVL_Unknown
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
int toInt(bool *ok) const
bool isNull() const
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:201
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:186
static QVariant fcnWeek(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QString rightJustified(int width, QChar fill, bool truncate) const
Utility class for identifying a unique vertex within a geometry.
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
int red() const
static QVariant fcnRowNumber(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
qreal valueF() const
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)
Point geometry type.
Definition: qgspointv2.h:29
int toInt(bool *ok, int base) const
static QHash< QString, QString > gGroups
bool isEmpty() const
static QVariant fcnAtlasFeatureId(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
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.
qreal lightnessF() const
This class wraps a request for features to a vector layer (or directly its vector data provider)...
static QVariant fcnGeomX(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
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
A special attribute that if set matches all attributes.
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:311
#define TVL_False
QGis::GeometryType geometryType() const
Returns point, line or polygon.
QgsFeatureRequest & setFlags(const QgsFeatureRequest::Flags &flags)
Set flags that affect how features will be fetched.
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)
QList< HelpArg > mArguments
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)
qreal hsvHueF() const
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)
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:331
static QVariant fcnGetFeature(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QList< HelpExample > mExamples
static QVariant fcnToString(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int alpha() const
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)
QList< QgsMapLayer * > mapLayersByName(const QString &layerName)
Retrieve a pointer to a loaded layer by name.
static QVariant fcnBbox(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnRound(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int hour() const
int green() 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.
double measureArea(const QgsGeometry *geometry) const
Measures the area of a geometry.
static QVariant fcnGeomFromGML(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool contains(QChar ch, Qt::CaseSensitivity cs) const
virtual QgsPointV2 vertexAt(const QgsVertexId &id) const =0
Returns the point corresponding to a specified vertex id.
void setHslF(qreal h, qreal s, qreal l, qreal a)
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)
void setHsvF(qreal h, qreal s, qreal v, qreal a)
static QVariant fcnArea(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnCeil(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnHour(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnGeomNumPoints(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QStringRef midRef(int position, int n) const
static QVariant fcnLeft(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QVariant fromValue(const T &value)
double length() const
Returns the length of geometry using GEOS.
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:391
General purpose distance and area calculator.
static QVariant fcnAtlasCurrentFeature(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
QgsGeometry * intersection(const QgsGeometry *geometry) const
Returns a geometry representing the points shared by this geometry and other.
bool vertexIdFromVertexNr(int nr, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
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. ...
int blue() const
double measureLength(const QgsGeometry *geometry) const
Measures the length of a geometry.
static QVariant fcnPointN(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnBounds(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
qreal yellowF() const
static QVariant fcnFeature(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static QVariant fcnGetVariable(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
QVariant(* FcnEvalContext)(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
Function definition for evaluation against an expression context.
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:238
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)
static QVariant fcnComposerNumPages(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
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)
QString escape(const QString &plain)
static QVariant fcnReplace(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QgsExpression::Interval fromString(const QString &string)
qreal hsvSaturationF() const
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]
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
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:70
static QVariant fcnAtlasNumFeatures(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
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.
qreal hslSaturationF() const
void setHsl(int h, int s, int l, int a)
virtual bool needsGeometry() const =0
Abstract virtual method which returns if the geometry is required to evaluate this expression...
void setHsv(int h, int s, int v, int a)
static QVariant fcnGeomToWKT(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QHash< QString, Help > gFunctionHelpTexts
void setGeomCalculator(const QgsDistanceArea &calc)
Sets the geometry calculator used in evaluation of expressions,.
static QVariant fcnColorCmyk(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double y() const
Get the y value of the point.
Definition: qgspoint.h:134
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
int indexOf(const QRegExp &rx, int from) const
static QVariant fcnRnd(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double toDouble(bool *ok) const
static QColor decodeColor(const QString &str)
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)
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
static QVariant fcnGeometry(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static QVariant fcnUuid(const QVariantList &, const QgsExpressionContext *, QgsExpression *)
qreal magentaF() const
bool touches(const QgsGeometry *geometry) const
Test for if geometry touch another (uses GEOS)
static Q_DECL_DEPRECATED 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...
static QgsGeometry * fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
static QVariant fcnEndPoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsExpression::Function * function(const QString &name) const
Fetches a matching function from the context.
void setValid(bool valid)
double ANALYSIS_EXPORT min(double x, double y)
Returns the minimum of two doubles or the first argument if both are equal.
bool nextFeature(QgsFeature &f)
QDateTime computeDateTimeFromInterval(const QDateTime &d, QgsExpression::Interval *i)
static QList< Function * > gmOwnedFunctions
List of functions owned by the expression engine.
static QVariant fcnTan(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QDateTime addSecs(int s) const
Type type() const
static QVariant fcnPerimeter(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
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:206
QgsPoint asPoint() const
Return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
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 hslSaturation() const
int compare(const QString &other) const
void setCmykF(qreal c, qreal m, qreal y, qreal k, qreal a)
QString parserErrorString() const
Returns parser error.
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:191
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)
static QVariant fcnDayOfWeek(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
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.
double area() const
Returns the area of the geometry using GEOS.
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.
int hsvSaturation() const
qreal blackF() const
static QVariant fcnRegexpSubstr(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:211
bool isValid() const
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 Q_DECL_DEPRECATED 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)
#define tr(sourceText)
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