QGIS API Documentation  2.17.0-Master (3a3b9ab7)
qgsexpression.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsexpression.cpp
3  -------------------
4  begin : August 2011
5  copyright : (C) 2011 Martin Dobias
6  email : wonder.sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsexpression.h"
17 
18 #include <QtDebug>
19 #include <QDomDocument>
20 #include <QDate>
21 #include <QRegExp>
22 #include <QColor>
23 #include <QUuid>
24 #include <QMutex>
25 
26 #include <math.h>
27 #include <limits>
28 
29 #include "qgsdistancearea.h"
30 #include "qgsfeature.h"
31 #include "qgsgeometry.h"
32 #include "qgsgeometryengine.h"
33 #include "qgsgeometryutils.h"
34 #include "qgslogger.h"
35 #include "qgsmaplayerregistry.h"
36 #include "qgsogcutils.h"
37 #include "qgsvectorlayer.h"
38 #include "qgssymbollayerv2utils.h"
39 #include "qgsvectorcolorrampv2.h"
40 #include "qgsstylev2.h"
41 #include "qgsexpressioncontext.h"
42 #include "qgsproject.h"
43 #include "qgsstringutils.h"
45 #include "qgspointv2.h"
46 #include "qgspolygonv2.h"
47 #include "qgsmultipointv2.h"
48 #include "qgsmultilinestringv2.h"
49 #include "qgscurvepolygonv2.h"
50 #include "qgsexpressionprivate.h"
51 #include "qgsexpressionsorter.h"
52 #include "qgscrscache.h"
53 
54 #if QT_VERSION < 0x050000
55 #include <qtextdocument.h>
56 #endif
57 
58 // from parser
59 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
60 
62 // three-value logic
63 
64 enum TVL
65 {
69 };
70 
71 static TVL AND[3][3] =
72 {
73  // false true unknown
74  { False, False, False }, // false
75  { False, True, Unknown }, // true
76  { False, Unknown, Unknown } // unknown
77 };
78 
79 static TVL OR[3][3] =
80 {
81  { False, True, Unknown }, // false
82  { True, True, True }, // true
83  { Unknown, True, Unknown } // unknown
84 };
85 
86 static TVL NOT[3] = { True, False, Unknown };
87 
89 {
90  switch ( v )
91  {
92  case False:
93  return 0;
94  case True:
95  return 1;
96  case Unknown:
97  default:
98  return QVariant();
99  }
100 }
101 
102 #define TVL_True QVariant(1)
103 #define TVL_False QVariant(0)
104 #define TVL_Unknown QVariant()
105 
107 // QVariant checks and conversions
108 
109 inline bool isIntSafe( const QVariant& v )
110 {
111  if ( v.type() == QVariant::Int ) return true;
112  if ( v.type() == QVariant::UInt ) return true;
113  if ( v.type() == QVariant::LongLong ) return true;
114  if ( v.type() == QVariant::ULongLong ) return true;
115  if ( v.type() == QVariant::Double ) return false;
116  if ( v.type() == QVariant::String ) { bool ok; v.toString().toInt( &ok ); return ok; }
117  return false;
118 }
119 inline bool isDoubleSafe( const QVariant& v )
120 {
121  if ( v.type() == QVariant::Double ) return true;
122  if ( v.type() == QVariant::Int ) return true;
123  if ( v.type() == QVariant::UInt ) return true;
124  if ( v.type() == QVariant::LongLong ) return true;
125  if ( v.type() == QVariant::ULongLong ) return true;
126  if ( v.type() == QVariant::String )
127  {
128  bool ok;
129  double val = v.toString().toDouble( &ok );
130  ok = ok && qIsFinite( val ) && !qIsNaN( val );
131  return ok;
132  }
133  return false;
134 }
135 
136 inline bool isDateTimeSafe( const QVariant& v )
137 {
138  return v.type() == QVariant::DateTime || v.type() == QVariant::Date ||
139  v.type() == QVariant::Time;
140 }
141 
142 inline bool isIntervalSafe( const QVariant& v )
143 {
144  if ( v.canConvert<QgsInterval>() )
145  {
146  return true;
147  }
148 
149  if ( v.type() == QVariant::String )
150  {
151  return QgsInterval::fromString( v.toString() ).isValid();
152  }
153  return false;
154 }
155 
156 inline bool isNull( const QVariant& v ) { return v.isNull(); }
157 
159 // evaluation error macros
160 
161 #define ENSURE_NO_EVAL_ERROR { if (parent->hasEvalError()) return QVariant(); }
162 #define SET_EVAL_ERROR(x) { parent->setEvalErrorString(x); return QVariant(); }
163 
165 // operators
166 
167 const char* QgsExpression::BinaryOperatorText[] =
168 {
169  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
170  "OR", "AND",
171  "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
172  "+", "-", "*", "/", "//", "%", "^",
173  "||"
174 };
175 
176 const char* QgsExpression::UnaryOperatorText[] =
177 {
178  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
179  "NOT", "-"
180 };
181 
183 // functions
184 
185 // implicit conversion to string
187 {
188  return value.toString();
189 }
190 
191 static double getDoubleValue( const QVariant& value, QgsExpression* parent )
192 {
193  bool ok;
194  double x = value.toDouble( &ok );
195  if ( !ok || qIsNaN( x ) || !qIsFinite( x ) )
196  {
197  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
198  return 0;
199  }
200  return x;
201 }
202 
203 static int getIntValue( const QVariant& value, QgsExpression* parent )
204 {
205  bool ok;
206  qint64 x = value.toLongLong( &ok );
208  {
209  return x;
210  }
211  else
212  {
213  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
214  return 0;
215  }
216 }
217 
218 static QDateTime getDateTimeValue( const QVariant& value, QgsExpression* parent )
219 {
220  QDateTime d = value.toDateTime();
221  if ( d.isValid() )
222  {
223  return d;
224  }
225  else
226  {
227  QTime t = value.toTime();
228  if ( t.isValid() )
229  {
230  return QDateTime( QDate( 1, 1, 1 ), t );
231  }
232 
233  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
234  return QDateTime();
235  }
236 }
237 
238 static QDate getDateValue( const QVariant& value, QgsExpression* parent )
239 {
240  QDate d = value.toDate();
241  if ( d.isValid() )
242  {
243  return d;
244  }
245  else
246  {
247  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
248  return QDate();
249  }
250 }
251 
252 static QTime getTimeValue( const QVariant& value, QgsExpression* parent )
253 {
254  QTime t = value.toTime();
255  if ( t.isValid() )
256  {
257  return t;
258  }
259  else
260  {
261  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
262  return QTime();
263  }
264 }
265 
266 static QgsInterval getInterval( const QVariant& value, QgsExpression* parent, bool report_error = false )
267 {
268  if ( value.canConvert<QgsInterval>() )
269  return value.value<QgsInterval>();
270 
271  QgsInterval inter = QgsInterval::fromString( value.toString() );
272  if ( inter.isValid() )
273  {
274  return inter;
275  }
276  // If we get here then we can't convert so we just error and return invalid.
277  if ( report_error )
278  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Interval" ).arg( value.toString() ) );
279 
280  return QgsInterval();
281 }
282 
283 static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent )
284 {
285  if ( value.canConvert<QgsGeometry>() )
286  return value.value<QgsGeometry>();
287 
288  parent->setEvalErrorString( "Cannot convert to QgsGeometry" );
289  return QgsGeometry();
290 }
291 
292 static QgsFeature getFeature( const QVariant& value, QgsExpression* parent )
293 {
294  if ( value.canConvert<QgsFeature>() )
295  return value.value<QgsFeature>();
296 
297  parent->setEvalErrorString( "Cannot convert to QgsFeature" );
298  return 0;
299 }
300 
301 #define FEAT_FROM_CONTEXT(c, f) if (!c || !c->hasVariable(QgsExpressionContext::EXPR_FEATURE)) return QVariant(); \
302  QgsFeature f = qvariant_cast<QgsFeature>( c->variable( QgsExpressionContext::EXPR_FEATURE ) );
303 
304 static QgsExpression::Node* getNode( const QVariant& value, QgsExpression* parent )
305 {
306  if ( value.canConvert<QgsExpression::Node*>() )
307  return value.value<QgsExpression::Node*>();
308 
309  parent->setEvalErrorString( "Cannot convert to Node" );
310  return nullptr;
311 }
312 
314 {
315  QString layerString = value.toString();
316  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerString ) ); //search by id first
317  if ( !vl )
318  {
319  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerString );
320  if ( !layersByName.isEmpty() )
321  {
322  vl = qobject_cast<QgsVectorLayer*>( layersByName.at( 0 ) );
323  }
324  }
325 
326  return vl;
327 }
328 
329 
330 // this handles also NULL values
331 static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
332 {
333  // we need to convert to TVL
334  if ( value.isNull() )
335  return Unknown;
336 
337  //handle some special cases
338  if ( value.canConvert<QgsGeometry>() )
339  {
340  //geom is false if empty
341  QgsGeometry geom = value.value<QgsGeometry>();
342  return geom.isEmpty() ? False : True;
343  }
344  else if ( value.canConvert<QgsFeature>() )
345  {
346  //feat is false if non-valid
347  QgsFeature feat = value.value<QgsFeature>();
348  return feat.isValid() ? True : False;
349  }
350 
351  if ( value.type() == QVariant::Int )
352  return value.toInt() != 0 ? True : False;
353 
354  bool ok;
355  double x = value.toDouble( &ok );
356  if ( !ok )
357  {
358  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
359  return Unknown;
360  }
361  return !qgsDoubleNear( x, 0.0 ) ? True : False;
362 }
363 
365 
366 static QVariant fcnGetVariable( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
367 {
368  if ( !context )
369  return QVariant();
370 
371  QString name = getStringValue( values.at( 0 ), parent );
372  return context->variable( name );
373 }
374 
375 static QVariant fcnEval( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
376 {
377  if ( !context )
378  return QVariant();
379 
380  QString expString = getStringValue( values.at( 0 ), parent );
381  QgsExpression expression( expString );
382  return expression.evaluate( context );
383 }
384 
385 static QVariant fcnSqrt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
386 {
387  double x = getDoubleValue( values.at( 0 ), parent );
388  return QVariant( sqrt( x ) );
389 }
390 
391 static QVariant fcnAbs( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
392 {
393  double val = getDoubleValue( values.at( 0 ), parent );
394  return QVariant( fabs( val ) );
395 }
396 
397 static QVariant fcnRadians( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
398 {
399  double deg = getDoubleValue( values.at( 0 ), parent );
400  return ( deg * M_PI ) / 180;
401 }
402 static QVariant fcnDegrees( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
403 {
404  double rad = getDoubleValue( values.at( 0 ), parent );
405  return ( 180 * rad ) / M_PI;
406 }
407 static QVariant fcnSin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
408 {
409  double x = getDoubleValue( values.at( 0 ), parent );
410  return QVariant( sin( x ) );
411 }
412 static QVariant fcnCos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
413 {
414  double x = getDoubleValue( values.at( 0 ), parent );
415  return QVariant( cos( x ) );
416 }
417 static QVariant fcnTan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
418 {
419  double x = getDoubleValue( values.at( 0 ), parent );
420  return QVariant( tan( x ) );
421 }
422 static QVariant fcnAsin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
423 {
424  double x = getDoubleValue( values.at( 0 ), parent );
425  return QVariant( asin( x ) );
426 }
427 static QVariant fcnAcos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
428 {
429  double x = getDoubleValue( values.at( 0 ), parent );
430  return QVariant( acos( x ) );
431 }
432 static QVariant fcnAtan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
433 {
434  double x = getDoubleValue( values.at( 0 ), parent );
435  return QVariant( atan( x ) );
436 }
437 static QVariant fcnAtan2( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
438 {
439  double y = getDoubleValue( values.at( 0 ), parent );
440  double x = getDoubleValue( values.at( 1 ), parent );
441  return QVariant( atan2( y, x ) );
442 }
443 static QVariant fcnExp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
444 {
445  double x = getDoubleValue( values.at( 0 ), parent );
446  return QVariant( exp( x ) );
447 }
448 static QVariant fcnLn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
449 {
450  double x = getDoubleValue( values.at( 0 ), parent );
451  if ( x <= 0 )
452  return QVariant();
453  return QVariant( log( x ) );
454 }
455 static QVariant fcnLog10( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
456 {
457  double x = getDoubleValue( values.at( 0 ), parent );
458  if ( x <= 0 )
459  return QVariant();
460  return QVariant( log10( x ) );
461 }
462 static QVariant fcnLog( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
463 {
464  double b = getDoubleValue( values.at( 0 ), parent );
465  double x = getDoubleValue( values.at( 1 ), parent );
466  if ( x <= 0 || b <= 0 )
467  return QVariant();
468  return QVariant( log( x ) / log( b ) );
469 }
470 static QVariant fcnRndF( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
471 {
472  double min = getDoubleValue( values.at( 0 ), parent );
473  double max = getDoubleValue( values.at( 1 ), parent );
474  if ( max < min )
475  return QVariant();
476 
477  // Return a random double in the range [min, max] (inclusive)
478  double f = static_cast< double >( qrand() ) / RAND_MAX;
479  return QVariant( min + f * ( max - min ) );
480 }
481 static QVariant fcnRnd( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
482 {
483  int min = getIntValue( values.at( 0 ), parent );
484  int max = getIntValue( values.at( 1 ), parent );
485  if ( max < min )
486  return QVariant();
487 
488  // Return a random integer in the range [min, max] (inclusive)
489  return QVariant( min + ( qrand() % static_cast< int >( max - min + 1 ) ) );
490 }
491 
492 static QVariant fcnLinearScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
493 {
494  double val = getDoubleValue( values.at( 0 ), parent );
495  double domainMin = getDoubleValue( values.at( 1 ), parent );
496  double domainMax = getDoubleValue( values.at( 2 ), parent );
497  double rangeMin = getDoubleValue( values.at( 3 ), parent );
498  double rangeMax = getDoubleValue( values.at( 4 ), parent );
499 
500  if ( domainMin >= domainMax )
501  {
502  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
503  return QVariant();
504  }
505 
506  // outside of domain?
507  if ( val >= domainMax )
508  {
509  return rangeMax;
510  }
511  else if ( val <= domainMin )
512  {
513  return rangeMin;
514  }
515 
516  // calculate linear scale
517  double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
518  double c = rangeMin - ( domainMin * m );
519 
520  // Return linearly scaled value
521  return QVariant( m * val + c );
522 }
523 
524 static QVariant fcnExpScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
525 {
526  double val = getDoubleValue( values.at( 0 ), parent );
527  double domainMin = getDoubleValue( values.at( 1 ), parent );
528  double domainMax = getDoubleValue( values.at( 2 ), parent );
529  double rangeMin = getDoubleValue( values.at( 3 ), parent );
530  double rangeMax = getDoubleValue( values.at( 4 ), parent );
531  double exponent = getDoubleValue( values.at( 5 ), parent );
532 
533  if ( domainMin >= domainMax )
534  {
535  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
536  return QVariant();
537  }
538  if ( exponent <= 0 )
539  {
540  parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
541  return QVariant();
542  }
543 
544  // outside of domain?
545  if ( val >= domainMax )
546  {
547  return rangeMax;
548  }
549  else if ( val <= domainMin )
550  {
551  return rangeMin;
552  }
553 
554  // Return exponentially scaled value
555  return QVariant((( rangeMax - rangeMin ) / pow( domainMax - domainMin, exponent ) ) * pow( val - domainMin, exponent ) + rangeMin );
556 }
557 
558 static QVariant fcnMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
559 {
560  //initially set max as first value
561  double maxVal = getDoubleValue( values.at( 0 ), parent );
562 
563  //check against all other values
564  for ( int i = 1; i < values.length(); ++i )
565  {
566  double testVal = getDoubleValue( values[i], parent );
567  if ( testVal > maxVal )
568  {
569  maxVal = testVal;
570  }
571  }
572 
573  return QVariant( maxVal );
574 }
575 
576 static QVariant fcnMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
577 {
578  //initially set min as first value
579  double minVal = getDoubleValue( values.at( 0 ), parent );
580 
581  //check against all other values
582  for ( int i = 1; i < values.length(); ++i )
583  {
584  double testVal = getDoubleValue( values[i], parent );
585  if ( testVal < minVal )
586  {
587  minVal = testVal;
588  }
589  }
590 
591  return QVariant( minVal );
592 }
593 
594 static QVariant fcnAggregate( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
595 {
596  //lazy eval, so we need to evaluate nodes now
597 
598  //first node is layer id or name
599  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
601  QVariant value = node->eval( parent, context );
603  QgsVectorLayer* vl = getVectorLayer( value, parent );
604  if ( !vl )
605  {
606  parent->setEvalErrorString( QObject::tr( "Cannot find layer with name or ID '%1'" ).arg( value.toString() ) );
607  return QVariant();
608  }
609 
610  // second node is aggregate type
611  node = getNode( values.at( 1 ), parent );
613  value = node->eval( parent, context );
615  bool ok = false;
617  if ( !ok )
618  {
619  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
620  return QVariant();
621  }
622 
623  // third node is subexpression (or field name)
624  node = getNode( values.at( 2 ), parent );
626  QString subExpression = node->dump();
627 
629  //optional forth node is filter
630  if ( values.count() > 3 )
631  {
632  node = getNode( values.at( 3 ), parent );
634  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
635  if ( !nl || nl->value().isValid() )
636  parameters.filter = node->dump();
637  }
638 
639  //optional fifth node is concatenator
640  if ( values.count() > 4 )
641  {
642  node = getNode( values.at( 4 ), parent );
644  value = node->eval( parent, context );
646  parameters.delimiter = value.toString();
647  }
648 
649  QString cacheKey = QString( "aggfcn:%1:%2:%3:%4" ).arg( vl->id(), QString::number( static_cast< int >( aggregate ) ), subExpression, parameters.filter );
650  if ( context && context->hasCachedValue( cacheKey ) )
651  return context->cachedValue( cacheKey );
652 
653  QVariant result;
654  if ( context )
655  {
656  QgsExpressionContext subContext( *context );
657  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
658  }
659  else
660  {
661  result = vl->aggregate( aggregate, subExpression, parameters, nullptr, &ok );
662  }
663  if ( !ok )
664  {
665  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
666  return QVariant();
667  }
668 
669  // cache value
670  if ( context )
671  context->setCachedValue( cacheKey, result );
672  return result;
673 }
674 
675 static QVariant fcnAggregateRelation( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
676 {
677  if ( !context )
678  {
679  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
680  return QVariant();
681  }
682 
683  // first step - find current layer
684  QString layerId = context->variable( "layer_id" ).toString();
685  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
686  if ( !vl )
687  {
688  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
689  return QVariant();
690  }
691 
692  //lazy eval, so we need to evaluate nodes now
693 
694  //first node is relation name
695  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
697  QVariant value = node->eval( parent, context );
699  QString relationId = value.toString();
700  // check relation exists
701  QgsRelation relation = QgsProject::instance()->relationManager()->relation( relationId );
702  if ( !relation.isValid() || relation.referencedLayer() != vl )
703  {
704  // check for relations by name
706  if ( relations.isEmpty() || relations.at( 0 ).referencedLayer() != vl )
707  {
708  parent->setEvalErrorString( QObject::tr( "Cannot find relation with id '%1'" ).arg( relationId ) );
709  return QVariant();
710  }
711  else
712  {
713  relation = relations.at( 0 );
714  }
715  }
716 
717  QgsVectorLayer* childLayer = relation.referencingLayer();
718 
719  // second node is aggregate type
720  node = getNode( values.at( 1 ), parent );
722  value = node->eval( parent, context );
724  bool ok = false;
726  if ( !ok )
727  {
728  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
729  return QVariant();
730  }
731 
732  //third node is subexpression (or field name)
733  node = getNode( values.at( 2 ), parent );
735  QString subExpression = node->dump();
736 
737  //optional fourth node is concatenator
739  if ( values.count() > 3 )
740  {
741  node = getNode( values.at( 3 ), parent );
743  value = node->eval( parent, context );
745  parameters.delimiter = value.toString();
746  }
747 
748  FEAT_FROM_CONTEXT( context, f );
749  parameters.filter = relation.getRelatedFeaturesFilter( f );
750 
751  QString cacheKey = QString( "relagg:%1:%2:%3:%4" ).arg( vl->id(),
752  QString::number( static_cast< int >( aggregate ) ),
753  subExpression,
754  parameters.filter );
755  if ( context && context->hasCachedValue( cacheKey ) )
756  return context->cachedValue( cacheKey );
757 
758  QVariant result;
759  ok = false;
760 
761 
762  QgsExpressionContext subContext( *context );
763  result = childLayer->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
764 
765  if ( !ok )
766  {
767  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
768  return QVariant();
769  }
770 
771  // cache value
772  if ( context )
773  context->setCachedValue( cacheKey, result );
774  return result;
775 }
776 
777 
779 {
780  if ( !context )
781  {
782  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
783  return QVariant();
784  }
785 
786  // first step - find current layer
787  QString layerId = context->variable( "layer_id" ).toString();
788  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
789  if ( !vl )
790  {
791  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
792  return QVariant();
793  }
794 
795  //lazy eval, so we need to evaluate nodes now
796 
797  //first node is subexpression (or field name)
798  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
800  QString subExpression = node->dump();
801 
802  //optional second node is group by
803  QString groupBy;
804  if ( values.count() > 1 )
805  {
806  node = getNode( values.at( 1 ), parent );
808  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
809  if ( !nl || nl->value().isValid() )
810  groupBy = node->dump();
811  }
812 
813  //optional third node is filter
814  if ( values.count() > 2 )
815  {
816  node = getNode( values.at( 2 ), parent );
818  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
819  if ( !nl || nl->value().isValid() )
820  parameters.filter = node->dump();
821  }
822 
823  // build up filter with group by
824 
825  // find current group by value
826  if ( !groupBy.isEmpty() )
827  {
828  QgsExpression groupByExp( groupBy );
829  QVariant groupByValue = groupByExp.evaluate( context );
830  if ( !parameters.filter.isEmpty() )
831  parameters.filter = QString( "(%1) AND (%2=%3)" ).arg( parameters.filter, groupBy, QgsExpression::quotedValue( groupByValue ) );
832  else
833  parameters.filter = QString( "(%2 = %3)" ).arg( groupBy, QgsExpression::quotedValue( groupByValue ) );
834  }
835 
836  QString cacheKey = QString( "agg:%1:%2:%3:%4" ).arg( vl->id(),
837  QString::number( static_cast< int >( aggregate ) ),
838  subExpression,
839  parameters.filter );
840  if ( context && context->hasCachedValue( cacheKey ) )
841  return context->cachedValue( cacheKey );
842 
843  QVariant result;
844  bool ok = false;
845 
846  QgsExpressionContext subContext( *context );
847  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
848 
849  if ( !ok )
850  {
851  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
852  return QVariant();
853  }
854 
855  // cache value
856  if ( context )
857  context->setCachedValue( cacheKey, result );
858  return result;
859 }
860 
861 
862 static QVariant fcnAggregateCount( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
863 {
865 }
866 
867 static QVariant fcnAggregateCountDistinct( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
868 {
870 }
871 
872 static QVariant fcnAggregateCountMissing( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
873 {
875 }
876 
877 static QVariant fcnAggregateMin( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
878 {
880 }
881 
882 static QVariant fcnAggregateMax( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
883 {
885 }
886 
887 static QVariant fcnAggregateSum( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
888 {
890 }
891 
892 static QVariant fcnAggregateMean( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
893 {
895 }
896 
897 static QVariant fcnAggregateMedian( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
898 {
900 }
901 
902 static QVariant fcnAggregateStdev( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
903 {
905 }
906 
907 static QVariant fcnAggregateRange( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
908 {
910 }
911 
912 static QVariant fcnAggregateMinority( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
913 {
915 }
916 
917 static QVariant fcnAggregateMajority( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
918 {
920 }
921 
922 static QVariant fcnAggregateQ1( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
923 {
925 }
926 
927 static QVariant fcnAggregateQ3( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
928 {
930 }
931 
932 static QVariant fcnAggregateIQR( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
933 {
935 }
936 
937 static QVariant fcnAggregateMinLength( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
938 {
940 }
941 
942 static QVariant fcnAggregateMaxLength( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
943 {
945 }
946 
947 static QVariant fcnAggregateStringConcat( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
948 {
950 
951  //fourth node is concatenator
952  if ( values.count() > 3 )
953  {
954  QgsExpression::Node* node = getNode( values.at( 3 ), parent );
956  QVariant value = node->eval( parent, context );
958  parameters.delimiter = value.toString();
959  }
960 
961  return fcnAggregateGeneric( QgsAggregateCalculator::StringConcatenate, values, parameters, context, parent );
962 }
963 
964 static QVariant fcnClamp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
965 {
966  double minValue = getDoubleValue( values.at( 0 ), parent );
967  double testValue = getDoubleValue( values.at( 1 ), parent );
968  double maxValue = getDoubleValue( values.at( 2 ), parent );
969 
970  // force testValue to sit inside the range specified by the min and max value
971  if ( testValue <= minValue )
972  {
973  return QVariant( minValue );
974  }
975  else if ( testValue >= maxValue )
976  {
977  return QVariant( maxValue );
978  }
979  else
980  {
981  return QVariant( testValue );
982  }
983 }
984 
985 static QVariant fcnFloor( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
986 {
987  double x = getDoubleValue( values.at( 0 ), parent );
988  return QVariant( floor( x ) );
989 }
990 
991 static QVariant fcnCeil( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
992 {
993  double x = getDoubleValue( values.at( 0 ), parent );
994  return QVariant( ceil( x ) );
995 }
996 
997 static QVariant fcnToInt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
998 {
999  return QVariant( getIntValue( values.at( 0 ), parent ) );
1000 }
1001 static QVariant fcnToReal( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1002 {
1003  return QVariant( getDoubleValue( values.at( 0 ), parent ) );
1004 }
1005 static QVariant fcnToString( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1006 {
1007  return QVariant( getStringValue( values.at( 0 ), parent ) );
1008 }
1009 
1010 static QVariant fcnToDateTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1011 {
1012  return QVariant( getDateTimeValue( values.at( 0 ), parent ) );
1013 }
1014 
1015 static QVariant fcnCoalesce( const QVariantList& values, const QgsExpressionContext*, QgsExpression* )
1016 {
1017  Q_FOREACH ( const QVariant &value, values )
1018  {
1019  if ( value.isNull() )
1020  continue;
1021  return value;
1022  }
1023  return QVariant();
1024 }
1025 static QVariant fcnLower( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1026 {
1027  QString str = getStringValue( values.at( 0 ), parent );
1028  return QVariant( str.toLower() );
1029 }
1030 static QVariant fcnUpper( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1031 {
1032  QString str = getStringValue( values.at( 0 ), parent );
1033  return QVariant( str.toUpper() );
1034 }
1035 static QVariant fcnTitle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1036 {
1037  QString str = getStringValue( values.at( 0 ), parent );
1038  QStringList elems = str.split( ' ' );
1039  for ( int i = 0; i < elems.size(); i++ )
1040  {
1041  if ( elems[i].size() > 1 )
1042  elems[i] = elems[i].at( 0 ).toUpper() + elems[i].mid( 1 ).toLower();
1043  }
1044  return QVariant( elems.join( " " ) );
1045 }
1046 
1047 static QVariant fcnTrim( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1048 {
1049  QString str = getStringValue( values.at( 0 ), parent );
1050  return QVariant( str.trimmed() );
1051 }
1052 
1053 static QVariant fcnLevenshtein( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1054 {
1055  QString string1 = getStringValue( values.at( 0 ), parent );
1056  QString string2 = getStringValue( values.at( 1 ), parent );
1057  return QVariant( QgsStringUtils::levenshteinDistance( string1, string2, true ) );
1058 }
1059 
1060 static QVariant fcnLCS( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1061 {
1062  QString string1 = getStringValue( values.at( 0 ), parent );
1063  QString string2 = getStringValue( values.at( 1 ), parent );
1064  return QVariant( QgsStringUtils::longestCommonSubstring( string1, string2, true ) );
1065 }
1066 
1067 static QVariant fcnHamming( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1068 {
1069  QString string1 = getStringValue( values.at( 0 ), parent );
1070  QString string2 = getStringValue( values.at( 1 ), parent );
1071  int dist = QgsStringUtils::hammingDistance( string1, string2 );
1072  return ( dist < 0 ? QVariant() : QVariant( QgsStringUtils::hammingDistance( string1, string2, true ) ) );
1073 }
1074 
1075 static QVariant fcnSoundex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1076 {
1077  QString string = getStringValue( values.at( 0 ), parent );
1078  return QVariant( QgsStringUtils::soundex( string ) );
1079 }
1080 
1081 static QVariant fcnChar( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1082 {
1083  QChar character = QChar( getIntValue( values.at( 0 ), parent ) );
1084  return QVariant( QString( character ) );
1085 }
1086 
1087 static QVariant fcnWordwrap( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1088 {
1089  if ( values.length() == 2 || values.length() == 3 )
1090  {
1091  QString str = getStringValue( values.at( 0 ), parent );
1092  int wrap = getIntValue( values.at( 1 ), parent );
1093 
1094  if ( !str.isEmpty() && wrap != 0 )
1095  {
1096  QString newstr;
1097  QString delimiterstr;
1098  if ( values.length() == 3 ) delimiterstr = getStringValue( values.at( 2 ), parent );
1099  if ( delimiterstr.isEmpty() ) delimiterstr = ' ';
1100  int delimiterlength = delimiterstr.length();
1101 
1102  QStringList lines = str.split( '\n' );
1103  int strlength, strcurrent, strhit, lasthit;
1104 
1105  for ( int i = 0; i < lines.size(); i++ )
1106  {
1107  strlength = lines[i].length();
1108  strcurrent = 0;
1109  strhit = 0;
1110  lasthit = 0;
1111 
1112  while ( strcurrent < strlength )
1113  {
1114  // positive wrap value = desired maximum line width to wrap
1115  // negative wrap value = desired minimum line width before wrap
1116  if ( wrap > 0 )
1117  {
1118  //first try to locate delimiter backwards
1119  strhit = lines[i].lastIndexOf( delimiterstr, strcurrent + wrap );
1120  if ( strhit == lasthit || strhit == -1 )
1121  {
1122  //if no new backward delimiter found, try to locate forward
1123  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
1124  }
1125  lasthit = strhit;
1126  }
1127  else
1128  {
1129  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
1130  }
1131  if ( strhit > -1 )
1132  {
1133  newstr.append( lines[i].midRef( strcurrent, strhit - strcurrent ) );
1134  newstr.append( '\n' );
1135  strcurrent = strhit + delimiterlength;
1136  }
1137  else
1138  {
1139  newstr.append( lines[i].midRef( strcurrent ) );
1140  strcurrent = strlength;
1141  }
1142  }
1143  if ( i < lines.size() - 1 ) newstr.append( '\n' );
1144  }
1145 
1146  return QVariant( newstr );
1147  }
1148  }
1149 
1150  return QVariant();
1151 }
1152 
1153 static QVariant fcnLength( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1154 {
1155  // two variants, one for geometry, one for string
1156  if ( values.at( 0 ).canConvert<QgsGeometry>() )
1157  {
1158  //geometry variant
1159  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1160  if ( geom.type() != QGis::Line )
1161  return QVariant();
1162 
1163  return QVariant( geom.length() );
1164  }
1165 
1166  //otherwise fall back to string variant
1167  QString str = getStringValue( values.at( 0 ), parent );
1168  return QVariant( str.length() );
1169 }
1170 
1171 static QVariant fcnReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1172 {
1173  QString str = getStringValue( values.at( 0 ), parent );
1174  QString before = getStringValue( values.at( 1 ), parent );
1175  QString after = getStringValue( values.at( 2 ), parent );
1176  return QVariant( str.replace( before, after ) );
1177 }
1178 static QVariant fcnRegexpReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1179 {
1180  QString str = getStringValue( values.at( 0 ), parent );
1181  QString regexp = getStringValue( values.at( 1 ), parent );
1182  QString after = getStringValue( values.at( 2 ), parent );
1183 
1184  QRegExp re( regexp );
1185  if ( !re.isValid() )
1186  {
1187  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1188  return QVariant();
1189  }
1190  return QVariant( str.replace( re, after ) );
1191 }
1192 
1193 static QVariant fcnRegexpMatch( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1194 {
1195  QString str = getStringValue( values.at( 0 ), parent );
1196  QString regexp = getStringValue( values.at( 1 ), parent );
1197 
1198  QRegExp re( regexp );
1199  if ( !re.isValid() )
1200  {
1201  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1202  return QVariant();
1203  }
1204  return QVariant( str.contains( re ) ? 1 : 0 );
1205 }
1206 
1207 static QVariant fcnRegexpSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1208 {
1209  QString str = getStringValue( values.at( 0 ), parent );
1210  QString regexp = getStringValue( values.at( 1 ), parent );
1211 
1212  QRegExp re( regexp );
1213  if ( !re.isValid() )
1214  {
1215  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1216  return QVariant();
1217  }
1218 
1219  // extract substring
1220  ( void )re.indexIn( str );
1221  if ( re.captureCount() > 0 )
1222  {
1223  // return first capture
1224  return QVariant( re.capturedTexts().at( 1 ) );
1225  }
1226  else
1227  {
1228  return QVariant( "" );
1229  }
1230 }
1231 
1232 static QVariant fcnUuid( const QVariantList&, const QgsExpressionContext*, QgsExpression* )
1233 {
1234  return QUuid::createUuid().toString();
1235 }
1236 
1237 static QVariant fcnSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1238 {
1239  QString str = getStringValue( values.at( 0 ), parent );
1240  int from = getIntValue( values.at( 1 ), parent );
1241  int len = getIntValue( values.at( 2 ), parent );
1242  return QVariant( str.mid( from -1, len ) );
1243 }
1244 
1245 static QVariant fcnRowNumber( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1246 {
1247  if ( context && context->hasVariable( "row_number" ) )
1248  return context->variable( "row_number" );
1249 
1251  return QVariant( parent->currentRowNumber() );
1253  //when above is removed - return QVariant()
1254 }
1255 
1256 static QVariant fcnMapId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1257 {
1258  if ( context && context->hasVariable( "map_id" ) )
1259  return context->variable( "map_id" );
1260 
1262  return QgsExpression::specialColumn( "$map" );
1264 }
1265 
1266 static QVariant fcnComposerNumPages( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1267 {
1268  if ( context && context->hasVariable( "layout_numpages" ) )
1269  return context->variable( "layout_numpages" );
1270 
1272  return QgsExpression::specialColumn( "$numpages" );
1274 }
1275 
1276 static QVariant fcnComposerPage( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1277 {
1278  if ( context && context->hasVariable( "layout_page" ) )
1279  return context->variable( "layout_page" );
1280 
1282  return QgsExpression::specialColumn( "$page" );
1284 }
1285 
1286 static QVariant fcnAtlasFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1287 {
1288  if ( context && context->hasVariable( "atlas_featurenumber" ) )
1289  return context->variable( "atlas_featurenumber" );
1290 
1292  return QgsExpression::specialColumn( "$feature" );
1294 }
1295 
1296 static QVariant fcnAtlasFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1297 {
1298  if ( context && context->hasVariable( "atlas_featureid" ) )
1299  return context->variable( "atlas_featureid" );
1300 
1302  return QgsExpression::specialColumn( "$atlasfeatureid" );
1304 }
1305 
1306 
1307 static QVariant fcnAtlasCurrentFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1308 {
1309  if ( context && context->hasVariable( "atlas_feature" ) )
1310  return context->variable( "atlas_feature" );
1311 
1313  return QgsExpression::specialColumn( "$atlasfeature" );
1315 }
1316 
1317 static QVariant fcnAtlasCurrentGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1318 {
1319  if ( context && context->hasVariable( "atlas_geometry" ) )
1320  return context->variable( "atlas_geometry" );
1321 
1323  return QgsExpression::specialColumn( "$atlasgeometry" );
1325 }
1326 
1327 static QVariant fcnAtlasNumFeatures( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1328 {
1329  if ( context && context->hasVariable( "atlas_totalfeatures" ) )
1330  return context->variable( "atlas_totalfeatures" );
1331 
1333  return QgsExpression::specialColumn( "$numfeatures" );
1335 }
1336 
1337 static QVariant fcnFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1338 {
1339  FEAT_FROM_CONTEXT( context, f );
1340  // TODO: handling of 64-bit feature ids?
1341  return QVariant( static_cast< int >( f.id() ) );
1342 }
1343 
1344 static QVariant fcnFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1345 {
1346  if ( !context )
1347  return QVariant();
1348 
1349  return context->variable( QgsExpressionContext::EXPR_FEATURE );
1350 }
1351 static QVariant fcnAttribute( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1352 {
1353  QgsFeature feat = getFeature( values.at( 0 ), parent );
1354  QString attr = getStringValue( values.at( 1 ), parent );
1355 
1356  return feat.attribute( attr );
1357 }
1358 static QVariant fcnConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1359 {
1360  QString concat;
1361  Q_FOREACH ( const QVariant &value, values )
1362  {
1363  concat += getStringValue( value, parent );
1364  }
1365  return concat;
1366 }
1367 
1368 static QVariant fcnStrpos( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1369 {
1370  QString string = getStringValue( values.at( 0 ), parent );
1371  return string.indexOf( QRegExp( getStringValue( values.at( 1 ), parent ) ) ) + 1;
1372 }
1373 
1374 static QVariant fcnRight( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1375 {
1376  QString string = getStringValue( values.at( 0 ), parent );
1377  int pos = getIntValue( values.at( 1 ), parent );
1378  return string.right( pos );
1379 }
1380 
1381 static QVariant fcnLeft( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1382 {
1383  QString string = getStringValue( values.at( 0 ), parent );
1384  int pos = getIntValue( values.at( 1 ), parent );
1385  return string.left( pos );
1386 }
1387 
1388 static QVariant fcnRPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1389 {
1390  QString string = getStringValue( values.at( 0 ), parent );
1391  int length = getIntValue( values.at( 1 ), parent );
1392  QString fill = getStringValue( values.at( 2 ), parent );
1393  return string.leftJustified( length, fill.at( 0 ), true );
1394 }
1395 
1396 static QVariant fcnLPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1397 {
1398  QString string = getStringValue( values.at( 0 ), parent );
1399  int length = getIntValue( values.at( 1 ), parent );
1400  QString fill = getStringValue( values.at( 2 ), parent );
1401  return string.rightJustified( length, fill.at( 0 ), true );
1402 }
1403 
1404 static QVariant fcnFormatString( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1405 {
1406  QString string = getStringValue( values.at( 0 ), parent );
1407  for ( int n = 1; n < values.length(); n++ )
1408  {
1409  string = string.arg( getStringValue( values.at( n ), parent ) );
1410  }
1411  return string;
1412 }
1413 
1414 
1415 static QVariant fcnNow( const QVariantList&, const QgsExpressionContext*, QgsExpression * )
1416 {
1418 }
1419 
1420 static QVariant fcnToDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1421 {
1422  return QVariant( getDateValue( values.at( 0 ), parent ) );
1423 }
1424 
1425 static QVariant fcnToTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1426 {
1427  return QVariant( getTimeValue( values.at( 0 ), parent ) );
1428 }
1429 
1430 static QVariant fcnToInterval( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1431 {
1432  return QVariant::fromValue( getInterval( values.at( 0 ), parent ) );
1433 }
1434 
1435 static QVariant fcnAge( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1436 {
1437  QDateTime d1 = getDateTimeValue( values.at( 0 ), parent );
1438  QDateTime d2 = getDateTimeValue( values.at( 1 ), parent );
1439  int seconds = d2.secsTo( d1 );
1440  return QVariant::fromValue( QgsInterval( seconds ) );
1441 }
1442 
1443 static QVariant fcnDayOfWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1444 {
1445  if ( !values.at( 0 ).canConvert<QDate>() )
1446  return QVariant();
1447 
1448  QDate date = getDateValue( values.at( 0 ), parent );
1449  if ( !date.isValid() )
1450  return QVariant();
1451 
1452  // return dayOfWeek() % 7 so that values range from 0 (sun) to 6 (sat)
1453  // (to match PostgreSQL behaviour)
1454  return date.dayOfWeek() % 7;
1455 }
1456 
1457 static QVariant fcnDay( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1458 {
1459  QVariant value = values.at( 0 );
1460  QgsInterval inter = getInterval( value, parent, false );
1461  if ( inter.isValid() )
1462  {
1463  return QVariant( inter.days() );
1464  }
1465  else
1466  {
1467  QDateTime d1 = getDateTimeValue( value, parent );
1468  return QVariant( d1.date().day() );
1469  }
1470 }
1471 
1472 static QVariant fcnYear( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1473 {
1474  QVariant value = values.at( 0 );
1475  QgsInterval inter = getInterval( value, parent, false );
1476  if ( inter.isValid() )
1477  {
1478  return QVariant( inter.years() );
1479  }
1480  else
1481  {
1482  QDateTime d1 = getDateTimeValue( value, parent );
1483  return QVariant( d1.date().year() );
1484  }
1485 }
1486 
1487 static QVariant fcnMonth( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1488 {
1489  QVariant value = values.at( 0 );
1490  QgsInterval inter = getInterval( value, parent, false );
1491  if ( inter.isValid() )
1492  {
1493  return QVariant( inter.months() );
1494  }
1495  else
1496  {
1497  QDateTime d1 = getDateTimeValue( value, parent );
1498  return QVariant( d1.date().month() );
1499  }
1500 }
1501 
1502 static QVariant fcnWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1503 {
1504  QVariant value = values.at( 0 );
1505  QgsInterval inter = getInterval( value, parent, false );
1506  if ( inter.isValid() )
1507  {
1508  return QVariant( inter.weeks() );
1509  }
1510  else
1511  {
1512  QDateTime d1 = getDateTimeValue( value, parent );
1513  return QVariant( d1.date().weekNumber() );
1514  }
1515 }
1516 
1517 static QVariant fcnHour( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1518 {
1519  QVariant value = values.at( 0 );
1520  QgsInterval inter = getInterval( value, parent, false );
1521  if ( inter.isValid() )
1522  {
1523  return QVariant( inter.hours() );
1524  }
1525  else
1526  {
1527  QTime t1 = getTimeValue( value, parent );
1528  return QVariant( t1.hour() );
1529  }
1530 }
1531 
1532 static QVariant fcnMinute( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1533 {
1534  QVariant value = values.at( 0 );
1535  QgsInterval inter = getInterval( value, parent, false );
1536  if ( inter.isValid() )
1537  {
1538  return QVariant( inter.minutes() );
1539  }
1540  else
1541  {
1542  QTime t1 = getTimeValue( value, parent );
1543  return QVariant( t1.minute() );
1544  }
1545 }
1546 
1547 static QVariant fcnSeconds( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1548 {
1549  QVariant value = values.at( 0 );
1550  QgsInterval inter = getInterval( value, parent, false );
1551  if ( inter.isValid() )
1552  {
1553  return QVariant( inter.seconds() );
1554  }
1555  else
1556  {
1557  QTime t1 = getTimeValue( value, parent );
1558  return QVariant( t1.second() );
1559  }
1560 }
1561 
1562 
1563 #define ENSURE_GEOM_TYPE(f, g, geomtype) const QgsGeometry* g = f.constGeometry(); \
1564  if (!g || g->type() != geomtype) return QVariant();
1565 
1566 static QVariant fcnX( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1567 {
1568  FEAT_FROM_CONTEXT( context, f );
1569  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1570  if ( g->isMultipart() )
1571  {
1572  return g->asMultiPoint().at( 0 ).x();
1573  }
1574  else
1575  {
1576  return g->asPoint().x();
1577  }
1578 }
1579 
1580 static QVariant fcnY( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1581 {
1582  FEAT_FROM_CONTEXT( context, f );
1583  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1584  if ( g->isMultipart() )
1585  {
1586  return g->asMultiPoint().at( 0 ).y();
1587  }
1588  else
1589  {
1590  return g->asPoint().y();
1591  }
1592 }
1593 
1594 static QVariant fcnGeomX( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1595 {
1596  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1597  if ( geom.isEmpty() )
1598  return QVariant();
1599 
1600  //if single point, return the point's x coordinate
1601  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1602  {
1603  return geom.asPoint().x();
1604  }
1605 
1606  //otherwise return centroid x
1607  QgsGeometry* centroid = geom.centroid();
1608  QVariant result( centroid->asPoint().x() );
1609  delete centroid;
1610  return result;
1611 }
1612 
1613 static QVariant fcnGeomY( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1614 {
1615  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1616  if ( geom.isEmpty() )
1617  return QVariant();
1618 
1619  //if single point, return the point's y coordinate
1620  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1621  {
1622  return geom.asPoint().y();
1623  }
1624 
1625  //otherwise return centroid y
1626  QgsGeometry* centroid = geom.centroid();
1627  QVariant result( centroid->asPoint().y() );
1628  delete centroid;
1629  return result;
1630 }
1631 
1632 static QVariant fcnGeomZ( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1633 {
1634  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1635  if ( geom.isEmpty() )
1636  return QVariant(); //or 0?
1637 
1638  //if single point, return the point's z coordinate
1639  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1640  {
1641  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1642  if ( point )
1643  return point->z();
1644  }
1645 
1646  return QVariant();
1647 }
1648 
1649 static QVariant fcnGeomM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1650 {
1651  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1652  if ( geom.isEmpty() )
1653  return QVariant(); //or 0?
1654 
1655  //if single point, return the point's m value
1656  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1657  {
1658  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1659  if ( point )
1660  return point->m();
1661  }
1662 
1663  return QVariant();
1664 }
1665 
1666 static QVariant fcnPointN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1667 {
1668  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1669 
1670  if ( geom.isEmpty() )
1671  return QVariant();
1672 
1673  //idx is 1 based
1674  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1675 
1676  QgsVertexId vId;
1677  if ( idx < 0 || !geom.vertexIdFromVertexNr( idx, vId ) )
1678  {
1679  parent->setEvalErrorString( QObject::tr( "Point index is out of range" ) );
1680  return QVariant();
1681  }
1682 
1683  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1684  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1685 }
1686 
1687 static QVariant fcnStartPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1688 {
1689  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1690 
1691  if ( geom.isEmpty() )
1692  return QVariant();
1693 
1694  QgsVertexId vId;
1695  if ( !geom.vertexIdFromVertexNr( 0, vId ) )
1696  {
1697  return QVariant();
1698  }
1699 
1700  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1701  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1702 }
1703 
1704 static QVariant fcnEndPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1705 {
1706  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1707 
1708  if ( geom.isEmpty() )
1709  return QVariant();
1710 
1711  QgsVertexId vId;
1712  if ( !geom.vertexIdFromVertexNr( geom.geometry()->nCoordinates() - 1, vId ) )
1713  {
1714  return QVariant();
1715  }
1716 
1717  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1718  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1719 }
1720 
1721 static QVariant fcnNodesToPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1722 {
1723  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1724 
1725  if ( geom.isEmpty() )
1726  return QVariant();
1727 
1728  bool ignoreClosing = false;
1729  if ( values.length() > 1 )
1730  {
1731  ignoreClosing = getIntValue( values.at( 1 ), parent );
1732  }
1733 
1734  QgsMultiPointV2* mp = new QgsMultiPointV2();
1735 
1736  Q_FOREACH ( const QgsRingSequenceV2 &part, geom.geometry()->coordinateSequence() )
1737  {
1738  Q_FOREACH ( const QgsPointSequenceV2 &ring, part )
1739  {
1740  bool skipLast = false;
1741  if ( ignoreClosing && ring.count() > 2 && ring.first() == ring.last() )
1742  {
1743  skipLast = true;
1744  }
1745 
1746  for ( int i = 0; i < ( skipLast ? ring.count() - 1 : ring.count() ); ++ i )
1747  {
1748  mp->addGeometry( ring.at( i ).clone() );
1749  }
1750  }
1751  }
1752 
1753  return QVariant::fromValue( QgsGeometry( mp ) );
1754 }
1755 
1756 static QVariant fcnSegmentsToLines( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1757 {
1758  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1759 
1760  if ( geom.isEmpty() )
1761  return QVariant();
1762 
1764 
1765  //ok, now we have a complete list of segmentized lines from the geometry
1767  Q_FOREACH ( QgsLineStringV2* line, linesToProcess )
1768  {
1769  for ( int i = 0; i < line->numPoints() - 1; ++i )
1770  {
1771  QgsLineStringV2* segment = new QgsLineStringV2();
1772  segment->setPoints( QgsPointSequenceV2()
1773  << line->pointN( i )
1774  << line->pointN( i + 1 ) );
1775  ml->addGeometry( segment );
1776  }
1777  delete line;
1778  }
1779 
1780  return QVariant::fromValue( QgsGeometry( ml ) );
1781 }
1782 
1783 static QVariant fcnInteriorRingN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1784 {
1785  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1786 
1787  if ( geom.isEmpty() )
1788  return QVariant();
1789 
1790  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
1791  if ( !curvePolygon )
1792  return QVariant();
1793 
1794  //idx is 1 based
1795  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1796 
1797  if ( idx >= curvePolygon->numInteriorRings() || idx < 0 )
1798  return QVariant();
1799 
1800  QgsCurveV2* curve = static_cast< QgsCurveV2* >( curvePolygon->interiorRing( idx )->clone() );
1801  QVariant result = curve ? QVariant::fromValue( QgsGeometry( curve ) ) : QVariant();
1802  return result;
1803 }
1804 
1805 static QVariant fcnGeometryN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1806 {
1807  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1808 
1809  if ( geom.isEmpty() )
1810  return QVariant();
1811 
1812  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
1813  if ( !collection )
1814  return QVariant();
1815 
1816  //idx is 1 based
1817  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1818 
1819  if ( idx < 0 || idx >= collection->numGeometries() )
1820  return QVariant();
1821 
1822  QgsAbstractGeometryV2* part = collection->geometryN( idx )->clone();
1823  QVariant result = part ? QVariant::fromValue( QgsGeometry( part ) ) : QVariant();
1824  return result;
1825 }
1826 
1827 static QVariant fcnBoundary( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1828 {
1829  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1830 
1831  if ( geom.isEmpty() )
1832  return QVariant();
1833 
1834  QgsAbstractGeometryV2* boundary = geom.geometry()->boundary();
1835  if ( !boundary )
1836  return QVariant();
1837 
1838  return QVariant::fromValue( QgsGeometry( boundary ) );
1839 }
1840 
1841 static QVariant fcnLineMerge( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1842 {
1843  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1844 
1845  if ( geom.isEmpty() )
1846  return QVariant();
1847 
1848  QgsGeometry merged = geom.mergeLines();
1849  if ( merged.isEmpty() )
1850  return QVariant();
1851 
1852  return QVariant::fromValue( merged );
1853 }
1854 
1855 static QVariant fcnMakePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1856 {
1857  if ( values.count() < 2 || values.count() > 4 )
1858  {
1859  parent->setEvalErrorString( QObject::tr( "Function make_point requires 2-4 arguments" ) );
1860  return QVariant();
1861  }
1862 
1863  double x = getDoubleValue( values.at( 0 ), parent );
1864  double y = getDoubleValue( values.at( 1 ), parent );
1865  double z = values.count() >= 3 ? getDoubleValue( values.at( 2 ), parent ) : 0.0;
1866  double m = values.count() >= 4 ? getDoubleValue( values.at( 3 ), parent ) : 0.0;
1867  switch ( values.count() )
1868  {
1869  case 2:
1870  return QVariant::fromValue( QgsGeometry( new QgsPointV2( x, y ) ) );
1871  case 3:
1872  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZ, x, y, z ) ) );
1873  case 4:
1874  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZM, x, y, z, m ) ) );
1875  }
1876  return QVariant(); //avoid warning
1877 }
1878 
1879 static QVariant fcnMakePointM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1880 {
1881  double x = getDoubleValue( values.at( 0 ), parent );
1882  double y = getDoubleValue( values.at( 1 ), parent );
1883  double m = getDoubleValue( values.at( 2 ), parent );
1884  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointM, x, y, 0.0, m ) ) );
1885 }
1886 
1887 static QVariant fcnMakeLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1888 {
1889  if ( values.count() < 2 )
1890  {
1891  return QVariant();
1892  }
1893 
1894  QgsLineStringV2* lineString = new QgsLineStringV2();
1895  lineString->clear();
1896 
1897  Q_FOREACH ( const QVariant& value, values )
1898  {
1899  QgsGeometry geom = getGeometry( value, parent );
1900  if ( geom.isEmpty() )
1901  continue;
1902 
1903  if ( geom.type() != QGis::Point || geom.isMultipart() )
1904  continue;
1905 
1906  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1907  if ( !point )
1908  continue;
1909 
1910  lineString->addVertex( *point );
1911  }
1912 
1913  return QVariant::fromValue( QgsGeometry( lineString ) );
1914 }
1915 
1916 static QVariant fcnMakePolygon( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1917 {
1918  if ( values.count() < 1 )
1919  {
1920  parent->setEvalErrorString( QObject::tr( "Function make_polygon requires an argument" ) );
1921  return QVariant();
1922  }
1923 
1924  QgsGeometry outerRing = getGeometry( values.at( 0 ), parent );
1925  if ( outerRing.type() != QGis::Line || outerRing.isMultipart() || outerRing.isEmpty() )
1926  return QVariant();
1927 
1928  QgsPolygonV2* polygon = new QgsPolygonV2();
1929  polygon->setExteriorRing( dynamic_cast< QgsCurveV2* >( outerRing.geometry()->clone() ) );
1930 
1931  for ( int i = 1; i < values.count(); ++i )
1932  {
1933  QgsGeometry ringGeom = getGeometry( values.at( i ), parent );
1934  if ( ringGeom.isEmpty() )
1935  continue;
1936 
1937  if ( ringGeom.type() != QGis::Line || ringGeom.isMultipart() || ringGeom.isEmpty() )
1938  continue;
1939 
1940  polygon->addInteriorRing( dynamic_cast< QgsCurveV2* >( ringGeom.geometry()->clone() ) );
1941  }
1942 
1943  return QVariant::fromValue( QgsGeometry( polygon ) );
1944 }
1945 
1946 static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
1947 {
1948  FEAT_FROM_CONTEXT( context, f );
1949  int idx = getIntValue( values.at( 0 ), parent );
1950  const QgsGeometry* g = f.constGeometry();
1951  if ( !g || g->isEmpty() )
1952  return QVariant();
1953 
1954  if ( idx < 0 )
1955  {
1956  idx += g->geometry()->nCoordinates();
1957  }
1958  if ( idx < 0 || idx >= g->geometry()->nCoordinates() )
1959  {
1960  parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
1961  return QVariant();
1962  }
1963 
1964  QgsPoint p = g->vertexAt( idx );
1965  return QVariant( QPointF( p.x(), p.y() ) );
1966 }
1967 
1968 static QVariant fcnXat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1969 {
1970  QVariant v = pointAt( values, f, parent );
1971  if ( v.type() == QVariant::PointF )
1972  return QVariant( v.toPointF().x() );
1973  else
1974  return QVariant();
1975 }
1976 static QVariant fcnYat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1977 {
1978  QVariant v = pointAt( values, f, parent );
1979  if ( v.type() == QVariant::PointF )
1980  return QVariant( v.toPointF().y() );
1981  else
1982  return QVariant();
1983 }
1984 static QVariant fcnGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1985 {
1986  FEAT_FROM_CONTEXT( context, f );
1987  const QgsGeometry* geom = f.constGeometry();
1988  if ( geom )
1989  return QVariant::fromValue( *geom );
1990  else
1991  return QVariant();
1992 }
1993 static QVariant fcnGeomFromWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1994 {
1995  QString wkt = getStringValue( values.at( 0 ), parent );
1996  QgsGeometry* geom = QgsGeometry::fromWkt( wkt );
1997  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1998  delete geom;
1999  return result;
2000 }
2001 static QVariant fcnGeomFromGML( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2002 {
2003  QString gml = getStringValue( values.at( 0 ), parent );
2005  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2006  delete geom;
2007  return result;
2008 }
2009 
2010 static QVariant fcnGeomArea( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2011 {
2012  FEAT_FROM_CONTEXT( context, f );
2014  QgsDistanceArea* calc = parent->geomCalculator();
2015  if ( calc )
2016  {
2017  double area = calc->measureArea( f.constGeometry() );
2018  area = calc->convertAreaMeasurement( area, parent->areaUnits() );
2019  return QVariant( area );
2020  }
2021  else
2022  {
2023  return QVariant( f.constGeometry()->area() );
2024  }
2025 }
2026 
2027 static QVariant fcnArea( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2028 {
2029  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2030 
2031  if ( geom.type() != QGis::Polygon )
2032  return QVariant();
2033 
2034  return QVariant( geom.area() );
2035 }
2036 
2037 static QVariant fcnGeomLength( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2038 {
2039  FEAT_FROM_CONTEXT( context, f );
2040  ENSURE_GEOM_TYPE( f, g, QGis::Line );
2041  QgsDistanceArea* calc = parent->geomCalculator();
2042  if ( calc )
2043  {
2044  double len = calc->measureLength( f.constGeometry() );
2045  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
2046  return QVariant( len );
2047  }
2048  else
2049  {
2050  return QVariant( f.constGeometry()->length() );
2051  }
2052 }
2053 
2054 static QVariant fcnGeomPerimeter( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2055 {
2056  FEAT_FROM_CONTEXT( context, f );
2058  QgsDistanceArea* calc = parent->geomCalculator();
2059  if ( calc )
2060  {
2061  double len = calc->measurePerimeter( f.constGeometry() );
2062  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
2063  return QVariant( len );
2064  }
2065  else
2066  {
2067  return f.constGeometry()->isEmpty() ? QVariant( 0 ) : QVariant( f.constGeometry()->geometry()->perimeter() );
2068  }
2069 }
2070 
2071 static QVariant fcnPerimeter( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2072 {
2073  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2074 
2075  if ( geom.type() != QGis::Polygon )
2076  return QVariant();
2077 
2078  //length for polygons = perimeter
2079  return QVariant( geom.length() );
2080 }
2081 
2082 static QVariant fcnGeomNumPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2083 {
2084  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2085  return QVariant( geom.isEmpty() ? 0 : geom.geometry()->nCoordinates() );
2086 }
2087 
2088 static QVariant fcnGeomNumGeometries( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2089 {
2090  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2091  if ( geom.isEmpty() )
2092  return QVariant();
2093 
2094  return QVariant( geom.geometry()->partCount() );
2095 }
2096 
2097 static QVariant fcnGeomNumInteriorRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2098 {
2099  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2100 
2101  if ( geom.isEmpty() )
2102  return QVariant();
2103 
2104  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
2105  if ( curvePolygon )
2106  return QVariant( curvePolygon->numInteriorRings() );
2107 
2108  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
2109  if ( collection )
2110  {
2111  //find first CurvePolygon in collection
2112  for ( int i = 0; i < collection->numGeometries(); ++i )
2113  {
2114  curvePolygon = dynamic_cast< QgsCurvePolygonV2*>( collection->geometryN( i ) );
2115  if ( !curvePolygon )
2116  continue;
2117 
2118  return QVariant( curvePolygon->isEmpty() ? 0 : curvePolygon->numInteriorRings() );
2119  }
2120  }
2121 
2122  return QVariant();
2123 }
2124 
2125 static QVariant fcnGeomNumRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2126 {
2127  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2128 
2129  if ( geom.isEmpty() )
2130  return QVariant();
2131 
2132  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
2133  if ( curvePolygon )
2134  return QVariant( curvePolygon->ringCount() );
2135 
2136  bool foundPoly = false;
2137  int ringCount = 0;
2138  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
2139  if ( collection )
2140  {
2141  //find CurvePolygons in collection
2142  for ( int i = 0; i < collection->numGeometries(); ++i )
2143  {
2144  curvePolygon = dynamic_cast< QgsCurvePolygonV2*>( collection->geometryN( i ) );
2145  if ( !curvePolygon )
2146  continue;
2147 
2148  foundPoly = true;
2149  ringCount += curvePolygon->ringCount();
2150  }
2151  }
2152 
2153  if ( !foundPoly )
2154  return QVariant();
2155 
2156  return QVariant( ringCount );
2157 }
2158 
2159 static QVariant fcnBounds( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2160 {
2161  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2162  QgsGeometry* geomBounds = QgsGeometry::fromRect( geom.boundingBox() );
2163  QVariant result = geomBounds ? QVariant::fromValue( *geomBounds ) : QVariant();
2164  delete geomBounds;
2165  return result;
2166 }
2167 
2168 static QVariant fcnBoundsWidth( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2169 {
2170  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2171  return QVariant::fromValue( geom.boundingBox().width() );
2172 }
2173 
2174 static QVariant fcnBoundsHeight( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2175 {
2176  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2177  return QVariant::fromValue( geom.boundingBox().height() );
2178 }
2179 
2180 static QVariant fcnXMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2181 {
2182  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2183  return QVariant::fromValue( geom.boundingBox().xMinimum() );
2184 }
2185 
2186 static QVariant fcnXMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2187 {
2188  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2189  return QVariant::fromValue( geom.boundingBox().xMaximum() );
2190 }
2191 
2192 static QVariant fcnYMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2193 {
2194  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2195  return QVariant::fromValue( geom.boundingBox().yMinimum() );
2196 }
2197 
2198 static QVariant fcnYMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2199 {
2200  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2201  return QVariant::fromValue( geom.boundingBox().yMaximum() );
2202 }
2203 
2204 static QVariant fcnIsClosed( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2205 {
2206  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2207  if ( fGeom.isEmpty() )
2208  return QVariant();
2209 
2210  QgsCurveV2* curve = dynamic_cast< QgsCurveV2* >( fGeom.geometry() );
2211  if ( !curve )
2212  return QVariant();
2213 
2214  return QVariant::fromValue( curve->isClosed() );
2215 }
2216 
2217 static QVariant fcnRelate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2218 {
2219  if ( values.length() < 2 || values.length() > 3 )
2220  return QVariant();
2221 
2222  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2223  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2224 
2225  if ( fGeom.isEmpty() || sGeom.isEmpty() )
2226  return QVariant();
2227 
2229 
2230  if ( values.length() == 2 )
2231  {
2232  //two geometry arguments, return relation
2233  QString result = engine->relate( *sGeom.geometry() );
2234  return QVariant::fromValue( result );
2235  }
2236  else
2237  {
2238  //three arguments, test pattern
2239  QString pattern = getStringValue( values.at( 2 ), parent );
2240  bool result = engine->relatePattern( *sGeom.geometry(), pattern );
2241  return QVariant::fromValue( result );
2242  }
2243 }
2244 
2245 static QVariant fcnBbox( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2246 {
2247  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2248  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2249  return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
2250 }
2251 static QVariant fcnDisjoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2252 {
2253  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2254  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2255  return fGeom.disjoint( &sGeom ) ? TVL_True : TVL_False;
2256 }
2257 static QVariant fcnIntersects( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2258 {
2259  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2260  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2261  return fGeom.intersects( &sGeom ) ? TVL_True : TVL_False;
2262 }
2263 static QVariant fcnTouches( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2264 {
2265  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2266  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2267  return fGeom.touches( &sGeom ) ? TVL_True : TVL_False;
2268 }
2269 static QVariant fcnCrosses( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2270 {
2271  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2272  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2273  return fGeom.crosses( &sGeom ) ? TVL_True : TVL_False;
2274 }
2275 static QVariant fcnContains( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2276 {
2277  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2278  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2279  return fGeom.contains( &sGeom ) ? TVL_True : TVL_False;
2280 }
2281 static QVariant fcnOverlaps( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2282 {
2283  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2284  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2285  return fGeom.overlaps( &sGeom ) ? TVL_True : TVL_False;
2286 }
2287 static QVariant fcnWithin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2288 {
2289  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2290  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2291  return fGeom.within( &sGeom ) ? TVL_True : TVL_False;
2292 }
2293 static QVariant fcnBuffer( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2294 {
2295  if ( values.length() < 2 || values.length() > 3 )
2296  return QVariant();
2297 
2298  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2299  double dist = getDoubleValue( values.at( 1 ), parent );
2300  int seg = 8;
2301  if ( values.length() == 3 )
2302  seg = getIntValue( values.at( 2 ), parent );
2303 
2304  QgsGeometry* geom = fGeom.buffer( dist, seg );
2305  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2306  delete geom;
2307  return result;
2308 }
2309 static QVariant fcnTranslate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2310 {
2311  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2312  double dx = getDoubleValue( values.at( 1 ), parent );
2313  double dy = getDoubleValue( values.at( 2 ), parent );
2314  fGeom.translate( dx, dy );
2315  return QVariant::fromValue( fGeom );
2316 }
2317 static QVariant fcnCentroid( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2318 {
2319  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2320  QgsGeometry* geom = fGeom.centroid();
2321  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2322  delete geom;
2323  return result;
2324 }
2325 static QVariant fcnPointOnSurface( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2326 {
2327  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2328  QgsGeometry* geom = fGeom.pointOnSurface();
2329  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2330  delete geom;
2331  return result;
2332 }
2333 static QVariant fcnConvexHull( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2334 {
2335  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2336  QgsGeometry* geom = fGeom.convexHull();
2337  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2338  delete geom;
2339  return result;
2340 }
2341 static QVariant fcnDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2342 {
2343  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2344  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2345  QgsGeometry* geom = fGeom.difference( &sGeom );
2346  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2347  delete geom;
2348  return result;
2349 }
2350 
2351 static QVariant fcnReverse( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2352 {
2353  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2354  if ( fGeom.isEmpty() )
2355  return QVariant();
2356 
2357  QgsCurveV2* curve = dynamic_cast< QgsCurveV2* >( fGeom.geometry() );
2358  if ( !curve )
2359  return QVariant();
2360 
2361  QgsCurveV2* reversed = curve->reversed();
2362  QVariant result = reversed ? QVariant::fromValue( QgsGeometry( reversed ) ) : QVariant();
2363  return result;
2364 }
2365 
2366 static QVariant fcnExteriorRing( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2367 {
2368  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2369  if ( fGeom.isEmpty() )
2370  return QVariant();
2371 
2372  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( fGeom.geometry() );
2373  if ( !curvePolygon || !curvePolygon->exteriorRing() )
2374  return QVariant();
2375 
2376  QgsCurveV2* exterior = static_cast< QgsCurveV2* >( curvePolygon->exteriorRing()->clone() );
2377  QVariant result = exterior ? QVariant::fromValue( QgsGeometry( exterior ) ) : QVariant();
2378  return result;
2379 }
2380 
2381 static QVariant fcnDistance( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2382 {
2383  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2384  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2385  return QVariant( fGeom.distance( sGeom ) );
2386 }
2387 static QVariant fcnIntersection( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2388 {
2389  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2390  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2391  QgsGeometry* geom = fGeom.intersection( &sGeom );
2392  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2393  delete geom;
2394  return result;
2395 }
2396 static QVariant fcnSymDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2397 {
2398  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2399  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2400  QgsGeometry* geom = fGeom.symDifference( &sGeom );
2401  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2402  delete geom;
2403  return result;
2404 }
2405 static QVariant fcnCombine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2406 {
2407  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2408  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2409  QgsGeometry* geom = fGeom.combine( &sGeom );
2410  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2411  delete geom;
2412  return result;
2413 }
2414 static QVariant fcnGeomToWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2415 {
2416  if ( values.length() < 1 || values.length() > 2 )
2417  return QVariant();
2418 
2419  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2420  int prec = 8;
2421  if ( values.length() == 2 )
2422  prec = getIntValue( values.at( 1 ), parent );
2423  QString wkt = fGeom.exportToWkt( prec );
2424  return QVariant( wkt );
2425 }
2426 
2427 static QVariant fcnAzimuth( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2428 {
2429  if ( values.length() != 2 )
2430  {
2431  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires exactly two parameters. %1 given." ).arg( values.length() ) );
2432  return QVariant();
2433  }
2434 
2435  QgsGeometry fGeom1 = getGeometry( values.at( 0 ), parent );
2436  QgsGeometry fGeom2 = getGeometry( values.at( 1 ), parent );
2437 
2438  const QgsPointV2* pt1 = dynamic_cast<const QgsPointV2*>( fGeom1.geometry() );
2439  const QgsPointV2* pt2 = dynamic_cast<const QgsPointV2*>( fGeom2.geometry() );
2440 
2441  if ( !pt1 || !pt2 )
2442  {
2443  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires two points as arguments." ) );
2444  return QVariant();
2445  }
2446 
2447  // Code from postgis
2448  if ( pt1->x() == pt2->x() )
2449  {
2450  if ( pt1->y() < pt2->y() )
2451  return 0.0;
2452  else if ( pt1->y() > pt2->y() )
2453  return M_PI;
2454  else
2455  return 0;
2456  }
2457 
2458  if ( pt1->y() == pt2->y() )
2459  {
2460  if ( pt1->x() < pt2->x() )
2461  return M_PI / 2;
2462  else if ( pt1->x() > pt2->x() )
2463  return M_PI + ( M_PI / 2 );
2464  else
2465  return 0;
2466  }
2467 
2468  if ( pt1->x() < pt2->x() )
2469  {
2470  if ( pt1->y() < pt2->y() )
2471  {
2472  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) );
2473  }
2474  else /* ( pt1->y() > pt2->y() ) - equality case handled above */
2475  {
2476  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2477  + ( M_PI / 2 );
2478  }
2479  }
2480 
2481  else /* ( pt1->x() > pt2->x() ) - equality case handled above */
2482  {
2483  if ( pt1->y() > pt2->y() )
2484  {
2485  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) )
2486  + M_PI;
2487  }
2488  else /* ( pt1->y() < pt2->y() ) - equality case handled above */
2489  {
2490  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2491  + ( M_PI + ( M_PI / 2 ) );
2492  }
2493  }
2494 }
2495 
2496 static QVariant fcnProject( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2497 {
2498  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2499 
2500  if ( geom.type() != QGis::Point )
2501  {
2502  parent->setEvalErrorString( "'project' requires a point geometry" );
2503  return QVariant();
2504  }
2505 
2506  double distance = getDoubleValue( values.at( 1 ), parent );
2507  double bearing = getDoubleValue( values.at( 2 ), parent );
2508 
2509  QgsPoint p = geom.asPoint();
2510  QgsPoint newPoint = p.project( distance, ( 180 * bearing ) / M_PI );
2511 
2512  return QVariant::fromValue( QgsGeometry( new QgsPointV2( newPoint.x(), newPoint.y() ) ) );
2513 }
2514 
2515 static QVariant fcnExtrude( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2516 {
2517  if ( values.length() != 3 )
2518  return QVariant();
2519 
2520  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2521  double x = getDoubleValue( values.at( 1 ), parent );
2522  double y = getDoubleValue( values.at( 2 ), parent );
2523 
2524  QgsGeometry geom = fGeom.extrude( x, y );
2525 
2526  QVariant result = geom.geometry() ? QVariant::fromValue( geom ) : QVariant();
2527  return result;
2528 }
2529 
2530 static QVariant fcnOrderParts( const QVariantList& values, const QgsExpressionContext* ctx, QgsExpression* parent )
2531 {
2532  if ( values.length() < 2 )
2533  return QVariant();
2534 
2535  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2536 
2537  if ( !fGeom.isMultipart() )
2538  return values.at( 0 );
2539 
2540  QString expString = getStringValue( values.at( 1 ), parent );
2541  bool asc = values.value( 2 ).toBool();
2542 
2543  QgsExpressionContext* unconstedContext;
2544  QgsFeature f;
2545  if ( ctx )
2546  {
2547  // ExpressionSorter wants a modifiable expression context, but it will return it in the same shape after
2548  // so no reason to worry
2549  unconstedContext = const_cast<QgsExpressionContext*>( ctx );
2550  f = ctx->feature();
2551  }
2552  else
2553  {
2554  // If there's no context provided, create a fake one
2555  unconstedContext = new QgsExpressionContext();
2556  }
2557 
2558  QgsGeometryCollectionV2* collection = dynamic_cast<QgsGeometryCollectionV2*>( fGeom.geometry() );
2559  Q_ASSERT( collection ); // Should have failed the multipart check above
2560 
2562  orderBy.append( QgsFeatureRequest::OrderByClause( expString, asc ) );
2563  QgsExpressionSorter sorter( orderBy );
2564 
2565  QList<QgsFeature> partFeatures;
2566  for ( int i = 0; i < collection->partCount(); ++i )
2567  {
2568  f.setGeometry( QgsGeometry( collection->geometryN( i )->clone() ) );
2569  partFeatures << f;
2570  }
2571 
2572  sorter.sortFeatures( partFeatures, unconstedContext );
2573 
2574  QgsGeometryCollectionV2* orderedGeom = dynamic_cast<QgsGeometryCollectionV2*>( fGeom.geometry()->clone() );
2575 
2576  Q_ASSERT( orderedGeom );
2577 
2578  while ( orderedGeom->partCount() )
2579  orderedGeom->removeGeometry( 0 );
2580 
2581  Q_FOREACH ( const QgsFeature& feature, partFeatures )
2582  {
2583  orderedGeom->addGeometry( feature.constGeometry()->geometry()->clone() );
2584  }
2585 
2586  QVariant result = QVariant::fromValue( QgsGeometry( orderedGeom ) );
2587 
2588  if ( !ctx )
2589  delete unconstedContext;
2590 
2591  return result;
2592 }
2593 
2594 static QVariant fcnClosestPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2595 {
2596  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2597  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2598 
2599  QgsGeometry geom = fromGeom.nearestPoint( toGeom );
2600 
2601  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2602  return result;
2603 }
2604 
2605 static QVariant fcnShortestLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2606 {
2607  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2608  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2609 
2610  QgsGeometry geom = fromGeom.shortestLine( toGeom );
2611 
2612  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2613  return result;
2614 }
2615 
2616 static QVariant fcnRound( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2617 {
2618  if ( values.length() == 2 )
2619  {
2620  double number = getDoubleValue( values.at( 0 ), parent );
2621  double scaler = pow( 10.0, getIntValue( values.at( 1 ), parent ) );
2622  return QVariant( qRound( number * scaler ) / scaler );
2623  }
2624 
2625  if ( values.length() == 1 )
2626  {
2627  double number = getIntValue( values.at( 0 ), parent );
2628  return QVariant( qRound( number ) ).toInt();
2629  }
2630 
2631  return QVariant();
2632 }
2633 
2634 static QVariant fcnPi( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2635 {
2636  Q_UNUSED( values );
2637  Q_UNUSED( parent );
2638  return M_PI;
2639 }
2640 
2641 static QVariant fcnScale( const QVariantList&, const QgsExpressionContext*, QgsExpression* parent )
2642 {
2643  return QVariant( parent->scale() );
2644 }
2645 
2646 static QVariant fcnFormatNumber( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2647 {
2648  double value = getDoubleValue( values.at( 0 ), parent );
2649  int places = getIntValue( values.at( 1 ), parent );
2650  if ( places < 0 )
2651  {
2652  parent->setEvalErrorString( QObject::tr( "Number of places must be positive" ) );
2653  return QVariant();
2654  }
2655  return QString( "%L1" ).arg( value, 0, 'f', places );
2656 }
2657 
2658 static QVariant fcnFormatDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2659 {
2660  QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
2661  QString format = getStringValue( values.at( 1 ), parent );
2662  return dt.toString( format );
2663 }
2664 
2665 static QVariant fcnColorRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2666 {
2667  int red = getIntValue( values.at( 0 ), parent );
2668  int green = getIntValue( values.at( 1 ), parent );
2669  int blue = getIntValue( values.at( 2 ), parent );
2670  QColor color = QColor( red, green, blue );
2671  if ( ! color.isValid() )
2672  {
2673  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
2674  color = QColor( 0, 0, 0 );
2675  }
2676 
2677  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2678 }
2679 
2680 static QVariant fcnIf( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
2681 {
2682  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
2684  QVariant value = node->eval( parent, context );
2686  if ( value.toBool() )
2687  {
2688  node = getNode( values.at( 1 ), parent );
2690  value = node->eval( parent, context );
2692  }
2693  else
2694  {
2695  node = getNode( values.at( 2 ), parent );
2697  value = node->eval( parent, context );
2699  }
2700  return value;
2701 }
2702 
2703 static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2704 {
2705  int red = getIntValue( values.at( 0 ), parent );
2706  int green = getIntValue( values.at( 1 ), parent );
2707  int blue = getIntValue( values.at( 2 ), parent );
2708  int alpha = getIntValue( values.at( 3 ), parent );
2709  QColor color = QColor( red, green, blue, alpha );
2710  if ( ! color.isValid() )
2711  {
2712  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
2713  color = QColor( 0, 0, 0 );
2714  }
2715  return QgsSymbolLayerV2Utils::encodeColor( color );
2716 }
2717 
2718 QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2719 {
2720  QString rampName = getStringValue( values.at( 0 ), parent );
2721  const QgsVectorColorRampV2 *mRamp = QgsStyleV2::defaultStyle()->colorRampRef( rampName );
2722  if ( ! mRamp )
2723  {
2724  parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
2725  return QColor( 0, 0, 0 ).name();
2726  }
2727  double value = getDoubleValue( values.at( 1 ), parent );
2728  QColor color = mRamp->color( value );
2729  return QgsSymbolLayerV2Utils::encodeColor( color );
2730 }
2731 
2732 static QVariant fcnColorHsl( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2733 {
2734  // Hue ranges from 0 - 360
2735  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2736  // Saturation ranges from 0 - 100
2737  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2738  // Lightness ranges from 0 - 100
2739  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
2740 
2741  QColor color = QColor::fromHslF( hue, saturation, lightness );
2742 
2743  if ( ! color.isValid() )
2744  {
2745  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
2746  color = QColor( 0, 0, 0 );
2747  }
2748 
2749  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2750 }
2751 
2752 static QVariant fncColorHsla( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2753 {
2754  // Hue ranges from 0 - 360
2755  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2756  // Saturation ranges from 0 - 100
2757  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2758  // Lightness ranges from 0 - 100
2759  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
2760  // Alpha ranges from 0 - 255
2761  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
2762 
2763  QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
2764  if ( ! color.isValid() )
2765  {
2766  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
2767  color = QColor( 0, 0, 0 );
2768  }
2769  return QgsSymbolLayerV2Utils::encodeColor( color );
2770 }
2771 
2772 static QVariant fcnColorHsv( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2773 {
2774  // Hue ranges from 0 - 360
2775  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2776  // Saturation ranges from 0 - 100
2777  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2778  // Value ranges from 0 - 100
2779  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
2780 
2781  QColor color = QColor::fromHsvF( hue, saturation, value );
2782 
2783  if ( ! color.isValid() )
2784  {
2785  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
2786  color = QColor( 0, 0, 0 );
2787  }
2788 
2789  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2790 }
2791 
2792 static QVariant fncColorHsva( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2793 {
2794  // Hue ranges from 0 - 360
2795  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2796  // Saturation ranges from 0 - 100
2797  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2798  // Value ranges from 0 - 100
2799  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
2800  // Alpha ranges from 0 - 255
2801  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
2802 
2803  QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
2804  if ( ! color.isValid() )
2805  {
2806  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
2807  color = QColor( 0, 0, 0 );
2808  }
2809  return QgsSymbolLayerV2Utils::encodeColor( color );
2810 }
2811 
2812 static QVariant fcnColorCmyk( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2813 {
2814  // Cyan ranges from 0 - 100
2815  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
2816  // Magenta ranges from 0 - 100
2817  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
2818  // Yellow ranges from 0 - 100
2819  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
2820  // Black ranges from 0 - 100
2821  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
2822 
2823  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
2824 
2825  if ( ! color.isValid() )
2826  {
2827  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
2828  color = QColor( 0, 0, 0 );
2829  }
2830 
2831  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2832 }
2833 
2834 static QVariant fncColorCmyka( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2835 {
2836  // Cyan ranges from 0 - 100
2837  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
2838  // Magenta ranges from 0 - 100
2839  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
2840  // Yellow ranges from 0 - 100
2841  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
2842  // Black ranges from 0 - 100
2843  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
2844  // Alpha ranges from 0 - 255
2845  double alpha = getIntValue( values.at( 4 ), parent ) / 255.0;
2846 
2847  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
2848  if ( ! color.isValid() )
2849  {
2850  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
2851  color = QColor( 0, 0, 0 );
2852  }
2853  return QgsSymbolLayerV2Utils::encodeColor( color );
2854 }
2855 
2856 static QVariant fncColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2857 {
2858  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2859  if ( ! color.isValid() )
2860  {
2861  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2862  return QVariant();
2863  }
2864 
2865  QString part = getStringValue( values.at( 1 ), parent );
2866  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
2867  return color.red();
2868  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
2869  return color.green();
2870  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
2871  return color.blue();
2872  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
2873  return color.alpha();
2874  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
2875  return color.hsvHueF() * 360;
2876  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
2877  return color.hsvSaturationF() * 100;
2878  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
2879  return color.valueF() * 100;
2880  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
2881  return color.hslHueF() * 360;
2882  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
2883  return color.hslSaturationF() * 100;
2884  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
2885  return color.lightnessF() * 100;
2886  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
2887  return color.cyanF() * 100;
2888  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
2889  return color.magentaF() * 100;
2890  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
2891  return color.yellowF() * 100;
2892  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
2893  return color.blackF() * 100;
2894 
2895  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
2896  return QVariant();
2897 }
2898 
2899 static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2900 {
2901  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2902  if ( ! color.isValid() )
2903  {
2904  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2905  return QVariant();
2906  }
2907 
2908  QString part = getStringValue( values.at( 1 ), parent );
2909  int value = getIntValue( values.at( 2 ), parent );
2910  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
2911  color.setRed( value );
2912  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
2913  color.setGreen( value );
2914  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
2915  color.setBlue( value );
2916  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
2917  color.setAlpha( value );
2918  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
2919  color.setHsv( value, color.hsvSaturation(), color.value(), color.alpha() );
2920  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
2921  color.setHsvF( color.hsvHueF(), value / 100.0, color.valueF(), color.alphaF() );
2922  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
2923  color.setHsvF( color.hsvHueF(), color.hsvSaturationF(), value / 100.0, color.alphaF() );
2924  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
2925  color.setHsl( value, color.hslSaturation(), color.lightness(), color.alpha() );
2926  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
2927  color.setHslF( color.hslHueF(), value / 100.0, color.lightnessF(), color.alphaF() );
2928  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
2929  color.setHslF( color.hslHueF(), color.hslSaturationF(), value / 100.0, color.alphaF() );
2930  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
2931  color.setCmykF( value / 100.0, color.magentaF(), color.yellowF(), color.blackF(), color.alphaF() );
2932  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
2933  color.setCmykF( color.cyanF(), value / 100.0, color.yellowF(), color.blackF(), color.alphaF() );
2934  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
2935  color.setCmykF( color.cyanF(), color.magentaF(), value / 100.0, color.blackF(), color.alphaF() );
2936  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
2937  color.setCmykF( color.cyanF(), color.magentaF(), color.yellowF(), value / 100.0, color.alphaF() );
2938  else
2939  {
2940  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
2941  return QVariant();
2942  }
2943  return QgsSymbolLayerV2Utils::encodeColor( color );
2944 }
2945 
2946 static QVariant fncDarker( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2947 {
2948  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2949  if ( ! color.isValid() )
2950  {
2951  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2952  return QVariant();
2953  }
2954 
2955  color = color.darker( getIntValue( values.at( 1 ), parent ) );
2956 
2957  return QgsSymbolLayerV2Utils::encodeColor( color );
2958 }
2959 
2960 static QVariant fncLighter( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2961 {
2962  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2963  if ( ! color.isValid() )
2964  {
2965  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2966  return QVariant();
2967  }
2968 
2969  color = color.lighter( getIntValue( values.at( 1 ), parent ) );
2970 
2971  return QgsSymbolLayerV2Utils::encodeColor( color );
2972 }
2973 
2974 static QVariant fcnSpecialColumn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2975 {
2976  QString varName = getStringValue( values.at( 0 ), parent );
2978  return QgsExpression::specialColumn( varName );
2980 }
2981 
2982 static QVariant fcnGetGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2983 {
2984  QgsFeature feat = getFeature( values.at( 0 ), parent );
2985  const QgsGeometry* geom = feat.constGeometry();
2986  if ( geom )
2987  return QVariant::fromValue( *geom );
2988  return QVariant();
2989 }
2990 
2991 static QVariant fcnTransformGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2992 {
2993  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2994  QString sAuthId = getStringValue( values.at( 1 ), parent );
2995  QString dAuthId = getStringValue( values.at( 2 ), parent );
2996 
2998  if ( ! s.isValid() )
2999  return QVariant::fromValue( fGeom );
3001  if ( ! d.isValid() )
3002  return QVariant::fromValue( fGeom );
3003 
3004  QgsCoordinateTransform t( s, d );
3005  if ( fGeom.transform( t ) == 0 )
3006  return QVariant::fromValue( fGeom );
3007  return QVariant();
3008 }
3009 
3010 
3011 static QVariant fcnGetFeature( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3012 {
3013  //arguments: 1. layer id / name, 2. key attribute, 3. eq value
3014  QgsVectorLayer* vl = getVectorLayer( values.at( 0 ), parent );
3015 
3016  //no layer found
3017  if ( !vl )
3018  {
3019  return QVariant();
3020  }
3021 
3022  QString attribute = getStringValue( values.at( 1 ), parent );
3023  int attributeId = vl->fieldNameIndex( attribute );
3024  if ( attributeId == -1 )
3025  {
3026  return QVariant();
3027  }
3028 
3029  const QVariant& attVal = values.at( 2 );
3030  QgsFeatureRequest req;
3031  req.setFilterExpression( QString( "%1=%2" ).arg( QgsExpression::quotedColumnRef( attribute ),
3032  QgsExpression::quotedString( attVal.toString() ) ) );
3033  req.setLimit( 1 );
3034  if ( !parent->needsGeometry() )
3035  {
3037  }
3038  QgsFeatureIterator fIt = vl->getFeatures( req );
3039 
3040  QgsFeature fet;
3041  if ( fIt.nextFeature( fet ) )
3042  return QVariant::fromValue( fet );
3043 
3044  return QVariant();
3045 }
3046 
3047 static QVariant fcnGetLayerProperty( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3048 {
3049  QString layerIdOrName = getStringValue( values.at( 0 ), parent );
3050 
3051  //try to find a matching layer by name
3052  QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerIdOrName ); //search by id first
3053  if ( !layer )
3054  {
3055  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerIdOrName );
3056  if ( !layersByName.isEmpty() )
3057  {
3058  layer = layersByName.at( 0 );
3059  }
3060  }
3061 
3062  if ( !layer )
3063  return QVariant();
3064 
3065  QString layerProperty = getStringValue( values.at( 1 ), parent );
3066  if ( QString::compare( layerProperty, QString( "name" ), Qt::CaseInsensitive ) == 0 )
3067  return layer->name();
3068  else if ( QString::compare( layerProperty, QString( "id" ), Qt::CaseInsensitive ) == 0 )
3069  return layer->id();
3070  else if ( QString::compare( layerProperty, QString( "title" ), Qt::CaseInsensitive ) == 0 )
3071  return layer->title();
3072  else if ( QString::compare( layerProperty, QString( "abstract" ), Qt::CaseInsensitive ) == 0 )
3073  return layer->abstract();
3074  else if ( QString::compare( layerProperty, QString( "keywords" ), Qt::CaseInsensitive ) == 0 )
3075  return layer->keywordList();
3076  else if ( QString::compare( layerProperty, QString( "data_url" ), Qt::CaseInsensitive ) == 0 )
3077  return layer->dataUrl();
3078  else if ( QString::compare( layerProperty, QString( "attribution" ), Qt::CaseInsensitive ) == 0 )
3079  return layer->attribution();
3080  else if ( QString::compare( layerProperty, QString( "attribution_url" ), Qt::CaseInsensitive ) == 0 )
3081  return layer->attributionUrl();
3082  else if ( QString::compare( layerProperty, QString( "source" ), Qt::CaseInsensitive ) == 0 )
3083  return layer->publicSource();
3084  else if ( QString::compare( layerProperty, QString( "min_scale" ), Qt::CaseInsensitive ) == 0 )
3085  return layer->minimumScale();
3086  else if ( QString::compare( layerProperty, QString( "max_scale" ), Qt::CaseInsensitive ) == 0 )
3087  return layer->maximumScale();
3088  else if ( QString::compare( layerProperty, QString( "crs" ), Qt::CaseInsensitive ) == 0 )
3089  return layer->crs().authid();
3090  else if ( QString::compare( layerProperty, QString( "crs_definition" ), Qt::CaseInsensitive ) == 0 )
3091  return layer->crs().toProj4();
3092  else if ( QString::compare( layerProperty, QString( "extent" ), Qt::CaseInsensitive ) == 0 )
3093  {
3094  QgsGeometry* extentGeom = QgsGeometry::fromRect( layer->extent() );
3095  QVariant result = QVariant::fromValue( *extentGeom );
3096  delete extentGeom;
3097  return result;
3098  }
3099  else if ( QString::compare( layerProperty, QString( "type" ), Qt::CaseInsensitive ) == 0 )
3100  {
3101  switch ( layer->type() )
3102  {
3104  return QCoreApplication::translate( "expressions", "Vector" );
3106  return QCoreApplication::translate( "expressions", "Raster" );
3108  return QCoreApplication::translate( "expressions", "Plugin" );
3109  }
3110  }
3111  else
3112  {
3113  //vector layer methods
3114  QgsVectorLayer* vLayer = dynamic_cast< QgsVectorLayer* >( layer );
3115  if ( vLayer )
3116  {
3117  if ( QString::compare( layerProperty, QString( "storage_type" ), Qt::CaseInsensitive ) == 0 )
3118  return vLayer->storageType();
3119  else if ( QString::compare( layerProperty, QString( "geometry_type" ), Qt::CaseInsensitive ) == 0 )
3120  return QGis::vectorGeometryType( vLayer->geometryType() );
3121  else if ( QString::compare( layerProperty, QString( "feature_count" ), Qt::CaseInsensitive ) == 0 )
3122  return QVariant::fromValue( vLayer->featureCount() );
3123  }
3124  }
3125 
3126  return QVariant();
3127 }
3128 
3129 bool QgsExpression::registerFunction( QgsExpression::Function* function, bool transferOwnership )
3130 {
3131  int fnIdx = functionIndex( function->name() );
3132  if ( fnIdx != -1 )
3133  {
3134  return false;
3135  }
3136  QgsExpression::gmFunctions.append( function );
3137  if ( transferOwnership )
3138  QgsExpression::gmOwnedFunctions.append( function );
3139  return true;
3140 }
3141 
3143 {
3144  // You can never override the built in functions.
3145  if ( QgsExpression::BuiltinFunctions().contains( name ) )
3146  {
3147  return false;
3148  }
3149  int fnIdx = functionIndex( name );
3150  if ( fnIdx != -1 )
3151  {
3152  QgsExpression::gmFunctions.removeAt( fnIdx );
3153  return true;
3154  }
3155  return false;
3156 }
3157 
3159 {
3160  qDeleteAll( QgsExpression::gmOwnedFunctions );
3162 }
3163 
3165 
3167 {
3168  if ( gmBuiltinFunctions.isEmpty() )
3169  {
3171  << "abs" << "sqrt" << "cos" << "sin" << "tan"
3172  << "asin" << "acos" << "atan" << "atan2"
3173  << "exp" << "ln" << "log10" << "log"
3174  << "round" << "rand" << "randf" << "max" << "min" << "clamp"
3175  << "scale_linear" << "scale_exp" << "floor" << "ceil" << "$pi"
3176  << "toint" << "to_int" << "toreal" << "to_real" << "tostring" << "to_string"
3177  << "todatetime" << "to_datetime" << "todate" << "to_date"
3178  << "totime" << "to_time" << "tointerval" << "to_interval"
3179  << "coalesce" << "if" << "regexp_match" << "age" << "year"
3180  << "month" << "week" << "day" << "hour" << "day_of_week"
3181  << "minute" << "second" << "lower" << "upper"
3182  << "title" << "length" << "replace" << "trim" << "wordwrap"
3183  << "regexp_replace" << "regexp_substr"
3184  << "substr" << "concat" << "strpos" << "left"
3185  << "right" << "rpad" << "lpad" << "format"
3186  << "format_number" << "format_date"
3187  << "color_rgb" << "color_rgba" << "ramp_color"
3188  << "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
3189  << "color_cmyk" << "color_cmyka" << "color_part" << "set_color_part"
3190  << "xat" << "yat" << "$area" << "area" << "perimeter"
3191  << "$length" << "$perimeter" << "x" << "y" << "$x" << "$y" << "z" << "m" << "num_points"
3192  << "num_interior_rings" << "num_rings" << "num_geometries"
3193  << "geometry_n" << "interior_ring_n"
3194  << "point_n" << "start_point" << "end_point" << "make_point" << "make_point_m"
3195  << "nodes_to_points" << "segments_to_lines"
3196  << "make_line" << "make_polygon"
3197  << "$x_at" << "x_at" << "xat" << "$y_at" << "y_at" << "yat" << "x_min" << "xmin" << "x_max" << "xmax"
3198  << "y_min" << "ymin" << "y_max" << "ymax" << "geom_from_wkt" << "geomFromWKT"
3199  << "geom_from_gml" << "geomFromGML" << "intersects_bbox" << "bbox"
3200  << "disjoint" << "intersects" << "touches" << "crosses" << "contains"
3201  << "relate"
3202  << "overlaps" << "within" << "buffer" << "centroid" << "bounds" << "reverse" << "exterior_ring"
3203  << "boundary" << "line_merge"
3204  << "bounds_width" << "bounds_height" << "is_closed" << "convex_hull" << "difference"
3205  << "distance" << "intersection" << "sym_difference" << "combine"
3206  << "extrude" << "azimuth" << "project" << "closest_point" << "shortest_line"
3207  << "union" << "geom_to_wkt" << "geomToWKT" << "geometry"
3208  << "transform" << "get_feature" << "getFeature"
3209  << "levenshtein" << "longest_common_substring" << "hamming_distance"
3210  << "soundex"
3211  << "aggregate" << "relation_aggregate" << "count" << "count_distinct"
3212  << "count_missing" << "minimum" << "maximum" << "sum" << "mean"
3213  << "median" << "stdev" << "range" << "minority" << "majority"
3214  << "q1" << "q3" << "iqr" << "min_length" << "max_length" << "concatenate"
3215  << "attribute" << "var" << "layer_property"
3216  << "$id" << "$scale" << "_specialcol_";
3217  }
3218  return gmBuiltinFunctions;
3219 }
3220 
3223 
3225 {
3226  // The construction of the list isn't thread-safe, and without the mutex,
3227  // crashes in the WFS provider may occur, since it can parse expressions
3228  // in parallel.
3229  // The mutex needs to be recursive.
3230  static QMutex sFunctionsMutex( QMutex::Recursive );
3231  QMutexLocker locker( &sFunctionsMutex );
3232 
3233  if ( gmFunctions.isEmpty() )
3234  {
3235  ParameterList aggParams = ParameterList() << Parameter( "expression" )
3236  << Parameter( "group_by", true )
3237  << Parameter( "filter", true );
3238 
3239  gmFunctions
3240  << new StaticFunction( "sqrt", ParameterList() << Parameter( "value" ), fcnSqrt, "Math" )
3241  << new StaticFunction( "radians", ParameterList() << Parameter( "degrees" ), fcnRadians, "Math" )
3242  << new StaticFunction( "degrees", ParameterList() << Parameter( "radians" ), fcnDegrees, "Math" )
3243  << new StaticFunction( "azimuth", ParameterList() << Parameter( "point_a" ) << Parameter( "point_b" ), fcnAzimuth, "Math" )
3244  << new StaticFunction( "project", ParameterList() << Parameter( "point" ) << Parameter( "distance" ) << Parameter( "bearing" ), fcnProject, "GeometryGroup" )
3245  << new StaticFunction( "abs", ParameterList() << Parameter( "value" ), fcnAbs, "Math" )
3246  << new StaticFunction( "cos", ParameterList() << Parameter( "angle" ), fcnCos, "Math" )
3247  << new StaticFunction( "sin", ParameterList() << Parameter( "angle" ), fcnSin, "Math" )
3248  << new StaticFunction( "tan", ParameterList() << Parameter( "angle" ), fcnTan, "Math" )
3249  << new StaticFunction( "asin", ParameterList() << Parameter( "value" ), fcnAsin, "Math" )
3250  << new StaticFunction( "acos", ParameterList() << Parameter( "value" ), fcnAcos, "Math" )
3251  << new StaticFunction( "atan", ParameterList() << Parameter( "value" ), fcnAtan, "Math" )
3252  << new StaticFunction( "atan2", ParameterList() << Parameter( "dx" ) << Parameter( "dy" ), fcnAtan2, "Math" )
3253  << new StaticFunction( "exp", ParameterList() << Parameter( "value" ), fcnExp, "Math" )
3254  << new StaticFunction( "ln", ParameterList() << Parameter( "value" ), fcnLn, "Math" )
3255  << new StaticFunction( "log10", ParameterList() << Parameter( "value" ), fcnLog10, "Math" )
3256  << new StaticFunction( "log", ParameterList() << Parameter( "base" ) << Parameter( "value" ), fcnLog, "Math" )
3257  << new StaticFunction( "round", ParameterList() << Parameter( "value" ) << Parameter( "places", true, 0 ), fcnRound, "Math" )
3258  << new StaticFunction( "rand", ParameterList() << Parameter( "min" ) << Parameter( "max" ), fcnRnd, "Math" )
3259  << new StaticFunction( "randf", ParameterList() << Parameter( "min", true, 0.0 ) << Parameter( "max", true, 1.0 ), fcnRndF, "Math" )
3260  << new StaticFunction( "max", -1, fcnMax, "Math" )
3261  << new StaticFunction( "min", -1, fcnMin, "Math" )
3262  << new StaticFunction( "clamp", ParameterList() << Parameter( "min" ) << Parameter( "value" ) << Parameter( "max" ), fcnClamp, "Math" )
3263  << new StaticFunction( "scale_linear", 5, fcnLinearScale, "Math" )
3264  << new StaticFunction( "scale_exp", 6, fcnExpScale, "Math" )
3265  << new StaticFunction( "floor", 1, fcnFloor, "Math" )
3266  << new StaticFunction( "ceil", 1, fcnCeil, "Math" )
3267  << new StaticFunction( "pi", 0, fcnPi, "Math", QString(), false, QStringList(), false, QStringList() << "$pi" )
3268  << new StaticFunction( "to_int", 1, fcnToInt, "Conversions", QString(), false, QStringList(), false, QStringList() << "toint" )
3269  << new StaticFunction( "to_real", 1, fcnToReal, "Conversions", QString(), false, QStringList(), false, QStringList() << "toreal" )
3270  << new StaticFunction( "to_string", 1, fcnToString, "Conversions", QString(), false, QStringList(), false, QStringList() << "tostring" )
3271  << new StaticFunction( "to_datetime", 1, fcnToDateTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "todatetime" )
3272  << new StaticFunction( "to_date", 1, fcnToDate, "Conversions", QString(), false, QStringList(), false, QStringList() << "todate" )
3273  << new StaticFunction( "to_time", 1, fcnToTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "totime" )
3274  << new StaticFunction( "to_interval", 1, fcnToInterval, "Conversions", QString(), false, QStringList(), false, QStringList() << "tointerval" )
3275  << new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals", QString(), false, QStringList(), false, QStringList(), true )
3276  << new StaticFunction( "if", 3, fcnIf, "Conditionals", QString(), False, QStringList(), true )
3277  << new StaticFunction( "aggregate", ParameterList() << Parameter( "layer" ) << Parameter( "aggregate" ) << Parameter( "expression" )
3278  << Parameter( "filter", true ) << Parameter( "concatenator", true ), fcnAggregate, "Aggregates", QString(), False, QStringList(), true )
3279  << new StaticFunction( "relation_aggregate", ParameterList() << Parameter( "relation" ) << Parameter( "aggregate" ) << Parameter( "expression" ) << Parameter( "concatenator", true ),
3281 
3282  << new StaticFunction( "count", aggParams, fcnAggregateCount, "Aggregates", QString(), False, QStringList(), true )
3283  << new StaticFunction( "count_distinct", aggParams, fcnAggregateCountDistinct, "Aggregates", QString(), False, QStringList(), true )
3284  << new StaticFunction( "count_missing", aggParams, fcnAggregateCountMissing, "Aggregates", QString(), False, QStringList(), true )
3285  << new StaticFunction( "minimum", aggParams, fcnAggregateMin, "Aggregates", QString(), False, QStringList(), true )
3286  << new StaticFunction( "maximum", aggParams, fcnAggregateMax, "Aggregates", QString(), False, QStringList(), true )
3287  << new StaticFunction( "sum", aggParams, fcnAggregateSum, "Aggregates", QString(), False, QStringList(), true )
3288  << new StaticFunction( "mean", aggParams, fcnAggregateMean, "Aggregates", QString(), False, QStringList(), true )
3289  << new StaticFunction( "median", aggParams, fcnAggregateMedian, "Aggregates", QString(), False, QStringList(), true )
3290  << new StaticFunction( "stdev", aggParams, fcnAggregateStdev, "Aggregates", QString(), False, QStringList(), true )
3291  << new StaticFunction( "range", aggParams, fcnAggregateRange, "Aggregates", QString(), False, QStringList(), true )
3292  << new StaticFunction( "minority", aggParams, fcnAggregateMinority, "Aggregates", QString(), False, QStringList(), true )
3293  << new StaticFunction( "majority", aggParams, fcnAggregateMajority, "Aggregates", QString(), False, QStringList(), true )
3294  << new StaticFunction( "q1", aggParams, fcnAggregateQ1, "Aggregates", QString(), False, QStringList(), true )
3295  << new StaticFunction( "q3", aggParams, fcnAggregateQ3, "Aggregates", QString(), False, QStringList(), true )
3296  << new StaticFunction( "iqr", aggParams, fcnAggregateIQR, "Aggregates", QString(), False, QStringList(), true )
3297  << new StaticFunction( "min_length", aggParams, fcnAggregateMinLength, "Aggregates", QString(), False, QStringList(), true )
3298  << new StaticFunction( "max_length", aggParams, fcnAggregateMaxLength, "Aggregates", QString(), False, QStringList(), true )
3299  << new StaticFunction( "concatenate", aggParams << Parameter( "concatenator", true ), fcnAggregateStringConcat, "Aggregates", QString(), False, QStringList(), true )
3300 
3301  << new StaticFunction( "regexp_match", 2, fcnRegexpMatch, "Conditionals" )
3302  << new StaticFunction( "now", 0, fcnNow, "Date and Time", QString(), false, QStringList(), false, QStringList() << "$now" )
3303  << new StaticFunction( "age", 2, fcnAge, "Date and Time" )
3304  << new StaticFunction( "year", 1, fcnYear, "Date and Time" )
3305  << new StaticFunction( "month", 1, fcnMonth, "Date and Time" )
3306  << new StaticFunction( "week", 1, fcnWeek, "Date and Time" )
3307  << new StaticFunction( "day", 1, fcnDay, "Date and Time" )
3308  << new StaticFunction( "hour", 1, fcnHour, "Date and Time" )
3309  << new StaticFunction( "minute", 1, fcnMinute, "Date and Time" )
3310  << new StaticFunction( "second", 1, fcnSeconds, "Date and Time" )
3311  << new StaticFunction( "day_of_week", 1, fcnDayOfWeek, "Date and Time" )
3312  << new StaticFunction( "lower", 1, fcnLower, "String" )
3313  << new StaticFunction( "upper", 1, fcnUpper, "String" )
3314  << new StaticFunction( "title", 1, fcnTitle, "String" )
3315  << new StaticFunction( "trim", 1, fcnTrim, "String" )
3316  << new StaticFunction( "levenshtein", 2, fcnLevenshtein, "Fuzzy Matching" )
3317  << new StaticFunction( "longest_common_substring", 2, fcnLCS, "Fuzzy Matching" )
3318  << new StaticFunction( "hamming_distance", 2, fcnHamming, "Fuzzy Matching" )
3319  << new StaticFunction( "soundex", 1, fcnSoundex, "Fuzzy Matching" )
3320  << new StaticFunction( "char", 1, fcnChar, "String" )
3321  << new StaticFunction( "wordwrap", ParameterList() << Parameter( "text" ) << Parameter( "length" ) << Parameter( "delimiter", true, " " ), fcnWordwrap, "String" )
3322  << new StaticFunction( "length", 1, fcnLength, "String" )
3323  << new StaticFunction( "replace", 3, fcnReplace, "String" )
3324  << new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
3325  << new StaticFunction( "regexp_substr", 2, fcnRegexpSubstr, "String" )
3326  << new StaticFunction( "substr", 3, fcnSubstr, "String" )
3327  << new StaticFunction( "concat", -1, fcnConcat, "String", QString(), false, QStringList(), false, QStringList(), true )
3328  << new StaticFunction( "strpos", 2, fcnStrpos, "String" )
3329  << new StaticFunction( "left", 2, fcnLeft, "String" )
3330  << new StaticFunction( "right", 2, fcnRight, "String" )
3331  << new StaticFunction( "rpad", 3, fcnRPad, "String" )
3332  << new StaticFunction( "lpad", 3, fcnLPad, "String" )
3333  << new StaticFunction( "format", -1, fcnFormatString, "String" )
3334  << new StaticFunction( "format_number", 2, fcnFormatNumber, "String" )
3335  << new StaticFunction( "format_date", 2, fcnFormatDate, "String" )
3336  << new StaticFunction( "color_rgb", 3, fcnColorRgb, "Color" )
3337  << new StaticFunction( "color_rgba", 4, fncColorRgba, "Color" )
3338  << new StaticFunction( "ramp_color", 2, fcnRampColor, "Color" )
3339  << new StaticFunction( "color_hsl", 3, fcnColorHsl, "Color" )
3340  << new StaticFunction( "color_hsla", 4, fncColorHsla, "Color" )
3341  << new StaticFunction( "color_hsv", 3, fcnColorHsv, "Color" )
3342  << new StaticFunction( "color_hsva", 4, fncColorHsva, "Color" )
3343  << new StaticFunction( "color_cmyk", 4, fcnColorCmyk, "Color" )
3344  << new StaticFunction( "color_cmyka", 5, fncColorCmyka, "Color" )
3345  << new StaticFunction( "color_part", 2, fncColorPart, "Color" )
3346  << new StaticFunction( "darker", 2, fncDarker, "Color" )
3347  << new StaticFunction( "lighter", 2, fncLighter, "Color" )
3348  << new StaticFunction( "set_color_part", 3, fncSetColorPart, "Color" )
3349  << new StaticFunction( "$geometry", 0, fcnGeometry, "GeometryGroup", QString(), true )
3350  << new StaticFunction( "$area", 0, fcnGeomArea, "GeometryGroup", QString(), true )
3351  << new StaticFunction( "area", 1, fcnArea, "GeometryGroup" )
3352  << new StaticFunction( "$length", 0, fcnGeomLength, "GeometryGroup", QString(), true )
3353  << new StaticFunction( "$perimeter", 0, fcnGeomPerimeter, "GeometryGroup", QString(), true )
3354  << new StaticFunction( "perimeter", 1, fcnPerimeter, "GeometryGroup" )
3355  << new StaticFunction( "$x", 0, fcnX, "GeometryGroup", QString(), true )
3356  << new StaticFunction( "$y", 0, fcnY, "GeometryGroup", QString(), true )
3357  << new StaticFunction( "x", 1, fcnGeomX, "GeometryGroup" )
3358  << new StaticFunction( "y", 1, fcnGeomY, "GeometryGroup" )
3359  << new StaticFunction( "z", 1, fcnGeomZ, "GeometryGroup" )
3360  << new StaticFunction( "m", 1, fcnGeomM, "GeometryGroup" )
3361  << new StaticFunction( "point_n", 2, fcnPointN, "GeometryGroup" )
3362  << new StaticFunction( "start_point", 1, fcnStartPoint, "GeometryGroup" )
3363  << new StaticFunction( "end_point", 1, fcnEndPoint, "GeometryGroup" )
3364  << new StaticFunction( "nodes_to_points", -1, fcnNodesToPoints, "GeometryGroup" )
3365  << new StaticFunction( "segments_to_lines", 1, fcnSegmentsToLines, "GeometryGroup" )
3366  << new StaticFunction( "make_point", -1, fcnMakePoint, "GeometryGroup" )
3367  << new StaticFunction( "make_point_m", 3, fcnMakePointM, "GeometryGroup" )
3368  << new StaticFunction( "make_line", -1, fcnMakeLine, "GeometryGroup" )
3369  << new StaticFunction( "make_polygon", -1, fcnMakePolygon, "GeometryGroup" )
3370  << new StaticFunction( "$x_at", 1, fcnXat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "xat" << "x_at" )
3371  << new StaticFunction( "$y_at", 1, fcnYat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "yat" << "y_at" )
3372  << new StaticFunction( "x_min", 1, fcnXMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmin" )
3373  << new StaticFunction( "x_max", 1, fcnXMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmax" )
3374  << new StaticFunction( "y_min", 1, fcnYMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymin" )
3375  << new StaticFunction( "y_max", 1, fcnYMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymax" )
3376  << new StaticFunction( "geom_from_wkt", 1, fcnGeomFromWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromWKT" )
3377  << new StaticFunction( "geom_from_gml", 1, fcnGeomFromGML, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromGML" )
3378  << new StaticFunction( "relate", -1, fcnRelate, "GeometryGroup" )
3379  << new StaticFunction( "intersects_bbox", 2, fcnBbox, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "bbox" )
3380  << new StaticFunction( "disjoint", 2, fcnDisjoint, "GeometryGroup" )
3381  << new StaticFunction( "intersects", 2, fcnIntersects, "GeometryGroup" )
3382  << new StaticFunction( "touches", 2, fcnTouches, "GeometryGroup" )
3383  << new StaticFunction( "crosses", 2, fcnCrosses, "GeometryGroup" )
3384  << new StaticFunction( "contains", 2, fcnContains, "GeometryGroup" )
3385  << new StaticFunction( "overlaps", 2, fcnOverlaps, "GeometryGroup" )
3386  << new StaticFunction( "within", 2, fcnWithin, "GeometryGroup" )
3387  << new StaticFunction( "translate", 3, fcnTranslate, "GeometryGroup" )
3388  << new StaticFunction( "buffer", -1, fcnBuffer, "GeometryGroup" )
3389  << new StaticFunction( "centroid", 1, fcnCentroid, "GeometryGroup" )
3390  << new StaticFunction( "point_on_surface", 1, fcnPointOnSurface, "GeometryGroup" )
3391  << new StaticFunction( "reverse", 1, fcnReverse, "GeometryGroup" )
3392  << new StaticFunction( "exterior_ring", 1, fcnExteriorRing, "GeometryGroup" )
3393  << new StaticFunction( "interior_ring_n", 2, fcnInteriorRingN, "GeometryGroup" )
3394  << new StaticFunction( "geometry_n", 2, fcnGeometryN, "GeometryGroup" )
3395  << new StaticFunction( "boundary", ParameterList() << Parameter( "geometry" ), fcnBoundary, "GeometryGroup" )
3396  << new StaticFunction( "line_merge", ParameterList() << Parameter( "geometry" ), fcnLineMerge, "GeometryGroup" )
3397  << new StaticFunction( "bounds", 1, fcnBounds, "GeometryGroup" )
3398  << new StaticFunction( "num_points", 1, fcnGeomNumPoints, "GeometryGroup" )
3399  << new StaticFunction( "num_interior_rings", 1, fcnGeomNumInteriorRings, "GeometryGroup" )
3400  << new StaticFunction( "num_rings", 1, fcnGeomNumRings, "GeometryGroup" )
3401  << new StaticFunction( "num_geometries", 1, fcnGeomNumGeometries, "GeometryGroup" )
3402  << new StaticFunction( "bounds_width", 1, fcnBoundsWidth, "GeometryGroup" )
3403  << new StaticFunction( "bounds_height", 1, fcnBoundsHeight, "GeometryGroup" )
3404  << new StaticFunction( "is_closed", 1, fcnIsClosed, "GeometryGroup" )
3405  << new StaticFunction( "convex_hull", 1, fcnConvexHull, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "convexHull" )
3406  << new StaticFunction( "difference", 2, fcnDifference, "GeometryGroup" )
3407  << new StaticFunction( "distance", 2, fcnDistance, "GeometryGroup" )
3408  << new StaticFunction( "intersection", 2, fcnIntersection, "GeometryGroup" )
3409  << new StaticFunction( "sym_difference", 2, fcnSymDifference, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "symDifference" )
3410  << new StaticFunction( "combine", 2, fcnCombine, "GeometryGroup" )
3411  << new StaticFunction( "union", 2, fcnCombine, "GeometryGroup" )
3412  << new StaticFunction( "geom_to_wkt", -1, fcnGeomToWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomToWKT" )
3413  << new StaticFunction( "geometry", 1, fcnGetGeometry, "GeometryGroup", QString(), true )
3414  << new StaticFunction( "transform", 3, fcnTransformGeometry, "GeometryGroup" )
3415  << new StaticFunction( "extrude", 3, fcnExtrude, "GeometryGroup", QString() )
3416  << new StaticFunction( "order_parts", 3, fcnOrderParts, "GeometryGroup", QString() )
3417  << new StaticFunction( "closest_point", 2, fcnClosestPoint, "GeometryGroup" )
3418  << new StaticFunction( "shortest_line", 2, fcnShortestLine, "GeometryGroup" )
3419  << new StaticFunction( "$rownum", 0, fcnRowNumber, "deprecated" )
3420  << new StaticFunction( "$id", 0, fcnFeatureId, "Record" )
3421  << new StaticFunction( "$currentfeature", 0, fcnFeature, "Record" )
3422  << new StaticFunction( "$scale", 0, fcnScale, "Record" )
3423  << new StaticFunction( "$map", 0, fcnMapId, "deprecated" )
3424  << new StaticFunction( "$numpages", 0, fcnComposerNumPages, "deprecated" )
3425  << new StaticFunction( "$page", 0, fcnComposerPage, "deprecated" )
3426  << new StaticFunction( "$feature", 0, fcnAtlasFeature, "deprecated" )
3427  << new StaticFunction( "$atlasfeatureid", 0, fcnAtlasFeatureId, "deprecated" )
3428  << new StaticFunction( "$atlasfeature", 0, fcnAtlasCurrentFeature, "deprecated" )
3429  << new StaticFunction( "$atlasgeometry", 0, fcnAtlasCurrentGeometry, "deprecated" )
3430  << new StaticFunction( "$numfeatures", 0, fcnAtlasNumFeatures, "deprecated" )
3431  << new StaticFunction( "uuid", 0, fcnUuid, "Record", QString(), false, QStringList(), false, QStringList() << "$uuid" )
3432  << new StaticFunction( "get_feature", 3, fcnGetFeature, "Record", QString(), false, QStringList(), false, QStringList() << "getFeature" )
3433  << new StaticFunction( "layer_property", 2, fcnGetLayerProperty, "General" )
3434  << new StaticFunction( "var", 1, fcnGetVariable, "General" )
3435 
3436  //return all attributes string for referencedColumns - this is caught by
3437  // QgsFeatureRequest::setSubsetOfAttributes and causes all attributes to be fetched by the
3438  // feature request
3439  << new StaticFunction( "eval", 1, fcnEval, "General", QString(), true, QStringList( QgsFeatureRequest::AllAttributes ) )
3440  << new StaticFunction( "attribute", 2, fcnAttribute, "Record", QString(), false, QStringList( QgsFeatureRequest::AllAttributes ) )
3441 
3442  << new StaticFunction( "_specialcol_", 1, fcnSpecialColumn, "Special" )
3443  ;
3444 
3446 
3447  //QgsExpression has ownership of all built-in functions
3448  Q_FOREACH ( QgsExpression::Function* func, gmFunctions )
3449  {
3450  gmOwnedFunctions << func;
3451  }
3452  }
3453  return gmFunctions;
3454 }
3455 
3458 
3459 void QgsExpression::setSpecialColumn( const QString& name, const QVariant& variant )
3460 {
3461  int fnIdx = functionIndex( name );
3462  if ( fnIdx != -1 )
3463  {
3464  // function of the same name already exists
3465  return;
3466  }
3467  gmSpecialColumns[ name ] = variant;
3468 }
3469 
3471 {
3473  if ( fit != gmSpecialColumns.end() )
3474  {
3475  gmSpecialColumns.erase( fit );
3476  }
3477 }
3478 
3480 {
3481  int fnIdx = functionIndex( name );
3482  if ( fnIdx != -1 )
3483  {
3484  // function of the same name already exists
3485  return QVariant();
3486  }
3488  if ( it == gmSpecialColumns.constEnd() )
3489  {
3490  return QVariant();
3491  }
3492  return it.value();
3493 }
3494 
3496 {
3497  if ( functionIndex( name ) != -1 )
3498  return false;
3499  return gmSpecialColumns.contains( name );
3500 }
3501 
3502 bool QgsExpression::isValid( const QString &text, const QgsFields &fields, QString &errorMessage )
3503 {
3505  return isValid( text, &context, errorMessage );
3506 }
3507 
3508 bool QgsExpression::isValid( const QString &text, const QgsExpressionContext *context, QString &errorMessage )
3509 {
3510  QgsExpression exp( text );
3511  exp.prepare( context );
3512  errorMessage = exp.parserErrorString();
3513  return !exp.hasParserError();
3514 }
3515 
3516 void QgsExpression::setScale( double scale ) { d->mScale = scale; }
3517 
3518 double QgsExpression::scale() { return d->mScale; }
3519 
3521 {
3522  if ( !d->mExp.isNull() )
3523  return d->mExp;
3524  else
3525  return dump();
3526 }
3527 
3529 {
3530  QList<Function*> defs;
3532  {
3533  //check for special column group name
3534  QString group = gmSpecialColumnGroups.value( it.key(), "Record" );
3535  defs << new StaticFunction( it.key(), 0, static_cast< FcnEvalContext >( nullptr ), group );
3536  }
3537  return defs;
3538 }
3539 
3541 {
3542  return QString( "\"%1\"" ).arg( name.replace( '\"', "\"\"" ) );
3543 }
3544 
3546 {
3547  text.replace( '\'', "''" );
3548  text.replace( '\\', "\\\\" );
3549  text.replace( '\n', "\\n" );
3550  text.replace( '\t', "\\t" );
3551  return QString( "'%1'" ).arg( text );
3552 }
3553 
3555 {
3556  return quotedValue( value, value.type() );
3557 }
3558 
3559 QString QgsExpression::quotedValue( const QVariant& value, QVariant::Type type )
3560 {
3561  if ( value.isNull() )
3562  return "NULL";
3563 
3564  switch ( type )
3565  {
3566  case QVariant::Int:
3567  case QVariant::LongLong:
3568  case QVariant::Double:
3569  return value.toString();
3570 
3571  case QVariant::Bool:
3572  return value.toBool() ? "TRUE" : "FALSE";
3573 
3574  default:
3575  case QVariant::String:
3576  return quotedString( value.toString() );
3577  }
3578 
3579 }
3580 
3582 {
3583  return functionIndex( name ) != -1;
3584 }
3585 
3587 {
3588  int count = functionCount();
3589  for ( int i = 0; i < count; i++ )
3590  {
3591  if ( QString::compare( name, Functions()[i]->name(), Qt::CaseInsensitive ) == 0 )
3592  return i;
3593  Q_FOREACH ( const QString& alias, Functions()[i]->aliases() )
3594  {
3595  if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
3596  return i;
3597  }
3598  }
3599  return -1;
3600 }
3601 
3603 {
3604  return Functions().size();
3605 }
3606 
3607 
3609  : d( new QgsExpressionPrivate )
3610 {
3611  d->mRootNode = ::parseExpression( expr, d->mParserErrorString );
3612  d->mExp = expr;
3613  Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
3614 }
3615 
3617  : d( other.d )
3618 {
3619  d->ref.ref();
3620 }
3621 
3623 {
3624  d = other.d;
3625  d->ref.ref();
3626  return *this;
3627 }
3628 
3630  : d( new QgsExpressionPrivate )
3631 {
3632 }
3633 
3635 {
3636  Q_ASSERT( d );
3637  if ( !d->ref.deref() )
3638  delete d;
3639 }
3640 
3641 bool QgsExpression::hasParserError() const { return !d->mParserErrorString.isNull(); }
3642 
3643 QString QgsExpression::parserErrorString() const { return d->mParserErrorString; }
3644 
3646 {
3647  if ( !d->mRootNode )
3648  return QStringList();
3649 
3650  QStringList columns = d->mRootNode->referencedColumns();
3651 
3652  // filter out duplicates
3653  for ( int i = 0; i < columns.count(); i++ )
3654  {
3655  QString col = columns.at( i );
3656  for ( int j = i + 1; j < columns.count(); j++ )
3657  {
3658  if ( QString::compare( col, columns[j], Qt::CaseInsensitive ) == 0 )
3659  {
3660  // this column is repeated: remove it!
3661  columns.removeAt( j-- );
3662  }
3663  }
3664  }
3665 
3666  return columns;
3667 }
3668 
3670 {
3671  if ( !d->mRootNode )
3672  return false;
3673  return d->mRootNode->needsGeometry();
3674 }
3675 
3677 {
3678  if ( d->mCalc.data() )
3679  return;
3680 
3681  // Use planimetric as default
3683  d->mCalc->setEllipsoidalMode( false );
3684 }
3685 
3687 {
3688  Q_ASSERT( d );
3689 
3690  if ( d->ref > 1 )
3691  {
3692  ( void )d->ref.deref();
3693 
3694  d = new QgsExpressionPrivate( *d );
3695  }
3696 }
3697 
3699 {
3700  d->mCalc = QSharedPointer<QgsDistanceArea>( new QgsDistanceArea( calc ) );
3701 }
3702 
3703 bool QgsExpression::prepare( const QgsFields& fields )
3704 {
3705  detach();
3707  return prepare( &fc );
3708 }
3709 
3711 {
3712  detach();
3713  d->mEvalErrorString = QString();
3714  if ( !d->mRootNode )
3715  {
3716  //re-parse expression. Creation of QgsExpressionContexts may have added extra
3717  //known functions since this expression was created, so we have another try
3718  //at re-parsing it now that the context must have been created
3719  d->mRootNode = ::parseExpression( d->mExp, d->mParserErrorString );
3720  }
3721 
3722  if ( !d->mRootNode )
3723  {
3724  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3725  return false;
3726  }
3727 
3728  return d->mRootNode->prepare( this, context );
3729 }
3730 
3732 {
3733  d->mEvalErrorString = QString();
3734  if ( !d->mRootNode )
3735  {
3736  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3737  return QVariant();
3738  }
3739 
3741  return d->mRootNode->eval( this, &context );
3742 }
3743 
3745 {
3747  return evaluate( &f );
3749 }
3750 
3752 {
3753  // first prepare
3755  bool res = prepare( &context );
3756  if ( !res )
3757  return QVariant();
3758 
3759  // then evaluate
3760  return evaluate( &context );
3761 }
3762 
3763 inline QVariant QgsExpression::evaluate( const QgsFeature& f, const QgsFields& fields )
3764 {
3766  return evaluate( &f, fields );
3768 }
3769 
3771 {
3772  d->mEvalErrorString = QString();
3773  if ( !d->mRootNode )
3774  {
3775  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3776  return QVariant();
3777  }
3778 
3779  return d->mRootNode->eval( this, static_cast<const QgsExpressionContext*>( nullptr ) );
3780 }
3781 
3783 {
3784  d->mEvalErrorString = QString();
3785  if ( !d->mRootNode )
3786  {
3787  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3788  return QVariant();
3789  }
3790 
3791  return d->mRootNode->eval( this, context );
3792 }
3793 
3795 {
3796  return !d->mEvalErrorString.isNull();
3797 }
3798 
3800 {
3801  return d->mEvalErrorString;
3802 }
3803 
3805 {
3806  d->mEvalErrorString = str;
3807 }
3808 
3810 {
3811  d->mRowNumber = rowNumber;
3812 }
3813 
3814 int QgsExpression::currentRowNumber() { return d->mRowNumber; }
3815 
3817 {
3818  if ( !d->mRootNode )
3819  return tr( "(no root)" );
3820 
3821  return d->mRootNode->dump();
3822 }
3823 
3825 {
3826  return d->mCalc.data();
3827 }
3828 
3830 {
3831  return d->mDistanceUnit;
3832 }
3833 
3835 {
3836  d->mDistanceUnit = unit;
3837 }
3838 
3840 {
3841  return d->mAreaUnit;
3842 }
3843 
3845 {
3846  d->mAreaUnit = unit;
3847 }
3848 
3850 {
3851  if ( d->mRootNode )
3852  d->mRootNode->accept( v );
3853 }
3854 
3856  QgsVectorLayer *layer,
3857  const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
3858 {
3859  QgsExpressionContext context = QgsExpressionContextUtils::createFeatureBasedContext( feat ? *feat : QgsFeature(), layer ? layer->fields() : QgsFields() );
3860  return replaceExpressionText( action, &context, substitutionMap, distanceArea );
3861 }
3862 
3863 QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
3864 {
3865  QString expr_action;
3866 
3867  QMap<QString, QVariant> savedValues;
3868  if ( substitutionMap )
3869  {
3870  // variables with a local scope (must be restored after evaluation)
3871  for ( QMap<QString, QVariant>::const_iterator sit = substitutionMap->begin(); sit != substitutionMap->end(); ++sit )
3872  {
3874  QVariant oldValue = QgsExpression::specialColumn( sit.key() );
3875  if ( !oldValue.isNull() )
3876  savedValues.insert( sit.key(), oldValue );
3877 
3878  // set the new value
3879  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
3881  }
3882  }
3883 
3884  int index = 0;
3885  while ( index < action.size() )
3886  {
3887  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
3888 
3889  int pos = rx.indexIn( action, index );
3890  if ( pos < 0 )
3891  break;
3892 
3893  int start = index;
3894  index = pos + rx.matchedLength();
3895  QString to_replace = rx.cap( 1 ).trimmed();
3896  QgsDebugMsg( "Found expression: " + to_replace );
3897 
3898  QgsExpression exp( to_replace );
3899  if ( exp.hasParserError() )
3900  {
3901  QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
3902  expr_action += action.midRef( start, index - start );
3903  continue;
3904  }
3905 
3906  if ( distanceArea )
3907  {
3908  //if QgsDistanceArea specified for area/distance conversion, use it
3909  exp.setGeomCalculator( *distanceArea );
3910  }
3911 
3912  QVariant result = exp.evaluate( context );
3913 
3914  if ( exp.hasEvalError() )
3915  {
3916  QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
3917  expr_action += action.midRef( start, index - start );
3918  continue;
3919  }
3920 
3921  QgsDebugMsg( "Expression result is: " + result.toString() );
3922  expr_action += action.mid( start, pos - start ) + result.toString();
3923  }
3924 
3925  expr_action += action.midRef( index );
3926 
3927  // restore overwritten local values
3929  for ( QMap<QString, QVariant>::const_iterator sit = savedValues.begin(); sit != savedValues.end(); ++sit )
3930  {
3931  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
3932  }
3934 
3935  return expr_action;
3936 }
3937 
3938 double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
3939 {
3940  bool ok;
3941  //first test if text is directly convertible to double
3942  double convertedValue = text.toDouble( &ok );
3943  if ( ok )
3944  {
3945  return convertedValue;
3946  }
3947 
3948  //otherwise try to evalute as expression
3949  QgsExpression expr( text );
3950 
3951  QgsExpressionContext context;
3954 
3955  QVariant result = expr.evaluate( &context );
3956  convertedValue = result.toDouble( &ok );
3957  if ( expr.hasEvalError() || !ok )
3958  {
3959  return fallbackValue;
3960  }
3961  return convertedValue;
3962 }
3963 
3964 
3966 // nodes
3967 
3969 {
3970  NodeList* nl = new NodeList;
3971  Q_FOREACH ( Node* node, mList )
3972  {
3973  nl->mList.append( node->clone() );
3974  }
3975  nl->mNameList = mNameList;
3976 
3977  return nl;
3978 }
3979 
3981 {
3982  QString msg;
3983  bool first = true;
3984  Q_FOREACH ( Node* n, mList )
3985  {
3986  if ( !first ) msg += ", ";
3987  else first = false;
3988  msg += n->dump();
3989  }
3990  return msg;
3991 }
3992 
3993 
3994 //
3995 
3997 {
3998  QVariant val = mOperand->eval( parent, context );
4000 
4001  switch ( mOp )
4002  {
4003  case uoNot:
4004  {
4005  TVL tvl = getTVLValue( val, parent );
4007  return tvl2variant( NOT[tvl] );
4008  }
4009 
4010  case uoMinus:
4011  if ( isIntSafe( val ) )
4012  return QVariant( - getIntValue( val, parent ) );
4013  else if ( isDoubleSafe( val ) )
4014  return QVariant( - getDoubleValue( val, parent ) );
4015  else
4016  SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) );
4017  default:
4018  Q_ASSERT( 0 && "unknown unary operation" );
4019  }
4020  return QVariant();
4021 }
4022 
4024 {
4025  return mOperand->prepare( parent, context );
4026 }
4027 
4029 {
4030  return QString( "%1 %2" ).arg( UnaryOperatorText[mOp], mOperand->dump() );
4031 }
4032 
4034 {
4035  return new NodeUnaryOperator( mOp, mOperand->clone() );
4036 }
4037 
4038 //
4039 
4041 {
4042  QVariant vL = mOpLeft->eval( parent, context );
4044  QVariant vR = mOpRight->eval( parent, context );
4046 
4047  switch ( mOp )
4048  {
4049  case boPlus:
4050  if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
4051  {
4052  QString sL = isNull( vL ) ? QString() : getStringValue( vL, parent );
4054  QString sR = isNull( vR ) ? QString() : getStringValue( vR, parent );
4056  return QVariant( sL + sR );
4057  }
4058  //intentional fall-through
4059  FALLTHROUGH;
4060  case boMinus:
4061  case boMul:
4062  case boDiv:
4063  case boMod:
4064  {
4065  if ( isNull( vL ) || isNull( vR ) )
4066  return QVariant();
4067  else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
4068  {
4069  // both are integers - let's use integer arithmetics
4070  int iL = getIntValue( vL, parent );
4072  int iR = getIntValue( vR, parent );
4074 
4075  if ( mOp == boMod && iR == 0 )
4076  return QVariant();
4077 
4078  return QVariant( computeInt( iL, iR ) );
4079  }
4080  else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
4081  {
4082  QDateTime dL = getDateTimeValue( vL, parent );
4084  QgsInterval iL = getInterval( vR, parent );
4086  if ( mOp == boDiv || mOp == boMul || mOp == boMod )
4087  {
4088  parent->setEvalErrorString( tr( "Can't preform /, *, or % on DateTime and Interval" ) );
4089  return QVariant();
4090  }
4091  return QVariant( computeDateTimeFromInterval( dL, &iL ) );
4092  }
4093  else if ( mOp == boPlus && (( vL.type() == QVariant::Date && vR.type() == QVariant::Time ) ||
4094  ( vR.type() == QVariant::Date && vL.type() == QVariant::Time ) ) )
4095  {
4096  QDate date = getDateValue( vL.type() == QVariant::Date ? vL : vR, parent );
4098  QTime time = getTimeValue( vR.type() == QVariant::Time ? vR : vL, parent );
4100  QDateTime dt = QDateTime( date, time );
4101  return QVariant( dt );
4102  }
4103  else if ( mOp == boMinus && vL.type() == QVariant::Date && vR.type() == QVariant::Date )
4104  {
4105  QDate date1 = getDateValue( vL, parent );
4107  QDate date2 = getDateValue( vR, parent );
4109  return date1 - date2;
4110  }
4111  else if ( mOp == boMinus && vL.type() == QVariant::Time && vR.type() == QVariant::Time )
4112  {
4113  QTime time1 = getTimeValue( vL, parent );
4115  QTime time2 = getTimeValue( vR, parent );
4117  return time1 - time2;
4118  }
4119  else if ( mOp == boMinus && vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime )
4120  {
4121  QDateTime datetime1 = getDateTimeValue( vL, parent );
4123  QDateTime datetime2 = getDateTimeValue( vR, parent );
4125  return datetime1 - datetime2;
4126  }
4127  else
4128  {
4129  // general floating point arithmetic
4130  double fL = getDoubleValue( vL, parent );
4132  double fR = getDoubleValue( vR, parent );
4134  if (( mOp == boDiv || mOp == boMod ) && fR == 0. )
4135  return QVariant(); // silently handle division by zero and return NULL
4136  return QVariant( computeDouble( fL, fR ) );
4137  }
4138  }
4139  case boIntDiv:
4140  {
4141  //integer division
4142  double fL = getDoubleValue( vL, parent );
4144  double fR = getDoubleValue( vR, parent );
4146  if ( fR == 0. )
4147  return QVariant(); // silently handle division by zero and return NULL
4148  return QVariant( qFloor( fL / fR ) );
4149  }
4150  case boPow:
4151  if ( isNull( vL ) || isNull( vR ) )
4152  return QVariant();
4153  else
4154  {
4155  double fL = getDoubleValue( vL, parent );
4157  double fR = getDoubleValue( vR, parent );
4159  return QVariant( pow( fL, fR ) );
4160  }
4161 
4162  case boAnd:
4163  {
4164  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
4166  return tvl2variant( AND[tvlL][tvlR] );
4167  }
4168 
4169  case boOr:
4170  {
4171  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
4173  return tvl2variant( OR[tvlL][tvlR] );
4174  }
4175 
4176  case boEQ:
4177  case boNE:
4178  case boLT:
4179  case boGT:
4180  case boLE:
4181  case boGE:
4182  if ( isNull( vL ) || isNull( vR ) )
4183  {
4184  return TVL_Unknown;
4185  }
4186  else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) &&
4187  ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
4188  {
4189  // do numeric comparison if both operators can be converted to numbers,
4190  // and they aren't both string
4191  double fL = getDoubleValue( vL, parent );
4193  double fR = getDoubleValue( vR, parent );
4194  ENSURE