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