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