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