QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 #include "qgsexpressionfunction.h"
18 #include "qgsexpressionprivate.h"
19 #include "qgsexpressionnodeimpl.h"
20 #include "qgsfeaturerequest.h"
21 #include "qgscolorramp.h"
22 #include "qgslogger.h"
23 #include "qgsexpressioncontext.h"
24 #include "qgsgeometry.h"
25 #include "qgsproject.h"
27 
28 // from parser
29 extern QgsExpressionNode *parseExpression( const QString &str, QString &parserErrorMsg, QList<QgsExpression::ParserError> &parserErrors );
30 
32 // QVariant checks and conversions
33 
35 // evaluation error macros
36 
38 // functions
39 
41 
42 bool QgsExpression::registerFunction( QgsExpressionFunction *function, bool transferOwnership )
43 {
44  int fnIdx = functionIndex( function->name() );
45  if ( fnIdx != -1 )
46  {
47  return false;
48  }
49  QgsExpression::sFunctions.append( function );
50  if ( transferOwnership )
51  QgsExpression::sOwnedFunctions.append( function );
52  return true;
53 }
54 
55 bool QgsExpression::unregisterFunction( const QString &name )
56 {
57  // You can never override the built in functions.
58  if ( QgsExpression::BuiltinFunctions().contains( name ) )
59  {
60  return false;
61  }
62  int fnIdx = functionIndex( name );
63  if ( fnIdx != -1 )
64  {
65  QgsExpression::sFunctions.removeAt( fnIdx );
66  return true;
67  }
68  return false;
69 }
70 
72 {
73  qDeleteAll( QgsExpression::sOwnedFunctions );
75 }
76 
78 
79 const QStringList &QgsExpression::BuiltinFunctions()
80 {
81  if ( sBuiltinFunctions.isEmpty() )
82  {
83  Functions(); // this method builds the gmBuiltinFunctions as well
84  }
85  return sBuiltinFunctions;
86 }
87 
88 QList<QgsExpressionFunction *> QgsExpression::sFunctions;
89 QList<QgsExpressionFunction *> QgsExpression::sOwnedFunctions;
90 
91 bool QgsExpression::checkExpression( const QString &text, const QgsExpressionContext *context, QString &errorMessage )
92 {
93  QgsExpression exp( text );
94  exp.prepare( context );
95  errorMessage = exp.parserErrorString();
96  return !exp.hasParserError();
97 }
98 
100 {
101  detach();
102  d->mRootNode = ::parseExpression( expression, d->mParserErrorString, d->mParserErrors );
103  d->mEvalErrorString = QString();
104  d->mExp = expression;
105  d->mIsPrepared = false;
106 }
107 
109 {
110  if ( !d->mExp.isNull() )
111  return d->mExp;
112  else
113  return dump();
114 }
115 
116 QString QgsExpression::quotedColumnRef( QString name )
117 {
118  return QStringLiteral( "\"%1\"" ).arg( name.replace( '\"', QLatin1String( "\"\"" ) ) );
119 }
120 
121 QString QgsExpression::quotedString( QString text )
122 {
123  text.replace( '\'', QLatin1String( "''" ) );
124  text.replace( '\\', QLatin1String( "\\\\" ) );
125  text.replace( '\n', QLatin1String( "\\n" ) );
126  text.replace( '\t', QLatin1String( "\\t" ) );
127  return QStringLiteral( "'%1'" ).arg( text );
128 }
129 
130 QString QgsExpression::quotedValue( const QVariant &value )
131 {
132  return quotedValue( value, value.type() );
133 }
134 
135 QString QgsExpression::quotedValue( const QVariant &value, QVariant::Type type )
136 {
137  if ( value.isNull() )
138  return QStringLiteral( "NULL" );
139 
140  switch ( type )
141  {
142  case QVariant::Int:
143  case QVariant::LongLong:
144  case QVariant::Double:
145  return value.toString();
146 
147  case QVariant::Bool:
148  return value.toBool() ? QStringLiteral( "TRUE" ) : QStringLiteral( "FALSE" );
149 
150  case QVariant::List:
151  {
152  QStringList quotedValues;
153  const QVariantList values = value.toList();
154  quotedValues.reserve( values.count() );
155  for ( const QVariant &v : values )
156  {
157  quotedValues += quotedValue( v );
158  }
159  return QStringLiteral( "array( %1 )" ).arg( quotedValues.join( QStringLiteral( ", " ) ) );
160  }
161 
162  default:
163  case QVariant::String:
164  return quotedString( value.toString() );
165  }
166 
167 }
168 
169 bool QgsExpression::isFunctionName( const QString &name )
170 {
171  return functionIndex( name ) != -1;
172 }
173 
174 int QgsExpression::functionIndex( const QString &name )
175 {
176  int count = functionCount();
177  for ( int i = 0; i < count; i++ )
178  {
179  if ( QString::compare( name, QgsExpression::Functions()[i]->name(), Qt::CaseInsensitive ) == 0 )
180  return i;
181  const QStringList aliases = QgsExpression::Functions()[i]->aliases();
182  for ( const QString &alias : aliases )
183  {
184  if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
185  return i;
186  }
187  }
188  return -1;
189 }
190 
192 {
193  return Functions().size();
194 }
195 
196 
197 QgsExpression::QgsExpression( const QString &expr )
198  : d( new QgsExpressionPrivate )
199 {
200  d->mRootNode = ::parseExpression( expr, d->mParserErrorString, d->mParserErrors );
201  d->mExp = expr;
202  Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
203 }
204 
206  : d( other.d )
207 {
208  d->ref.ref();
209 }
210 
212 {
213  if ( !d->ref.deref() )
214  {
215  delete d;
216  }
217 
218  d = other.d;
219  d->ref.ref();
220  return *this;
221 }
222 
223 QgsExpression::operator QString() const
224 {
225  return d->mExp;
226 }
227 
229  : d( new QgsExpressionPrivate )
230 {
231 }
232 
234 {
235  Q_ASSERT( d );
236  if ( !d->ref.deref() )
237  delete d;
238 }
239 
240 bool QgsExpression::operator==( const QgsExpression &other ) const
241 {
242  return ( d == other.d || d->mExp == other.d->mExp );
243 }
244 
246 {
247  return d->mRootNode;
248 }
249 
251 {
252  return d->mParserErrors.count() > 0;
253 }
254 
256 {
257  return d->mParserErrorString;
258 }
259 
260 QList<QgsExpression::ParserError> QgsExpression::parserErrors() const
261 {
262  return d->mParserErrors;
263 }
264 
265 QSet<QString> QgsExpression::referencedColumns() const
266 {
267  if ( !d->mRootNode )
268  return QSet<QString>();
269 
270  return d->mRootNode->referencedColumns();
271 }
272 
274 {
275  if ( !d->mRootNode )
276  return QSet<QString>();
277 
278  return d->mRootNode->referencedVariables();
279 }
280 
282 {
283  if ( !d->mRootNode )
284  return QSet<QString>();
285 
286  return d->mRootNode->referencedFunctions();
287 }
288 
289 QSet<int> QgsExpression::referencedAttributeIndexes( const QgsFields &fields ) const
290 {
291  if ( !d->mRootNode )
292  return QSet<int>();
293 
294  const QSet<QString> referencedFields = d->mRootNode->referencedColumns();
295  QSet<int> referencedIndexes;
296 
297  for ( const QString &fieldName : referencedFields )
298  {
299  if ( fieldName == QgsFeatureRequest::ALL_ATTRIBUTES )
300  {
301  referencedIndexes = fields.allAttributesList().toSet();
302  break;
303  }
304  referencedIndexes << fields.lookupField( fieldName );
305  }
306 
307  return referencedIndexes;
308 }
309 
311 {
312  if ( !d->mRootNode )
313  return false;
314  return d->mRootNode->needsGeometry();
315 }
316 
317 void QgsExpression::initGeomCalculator( const QgsExpressionContext *context )
318 {
319  // Set the geometry calculator from the context if it has not been set by setGeomCalculator()
320  if ( context && ! d->mCalc )
321  {
322  QString ellipsoid = context->variable( QStringLiteral( "project_ellipsoid" ) ).toString();
323  QgsCoordinateReferenceSystem crs = context->variable( QStringLiteral( "_layer_crs" ) ).value<QgsCoordinateReferenceSystem>();
324  QgsCoordinateTransformContext tContext = context->variable( QStringLiteral( "_project_transform_context" ) ).value<QgsCoordinateTransformContext>();
325  if ( crs.isValid() )
326  {
327  d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea() );
328  d->mCalc->setEllipsoid( ellipsoid.isEmpty() ? GEO_NONE : ellipsoid );
329  d->mCalc->setSourceCrs( crs, tContext );
330  }
331  }
332 
333  // Set the distance units from the context if it has not been set by setDistanceUnits()
334  if ( context && distanceUnits() == QgsUnitTypes::DistanceUnknownUnit )
335  {
336  QString distanceUnitsStr = context->variable( QStringLiteral( "project_distance_units" ) ).toString();
337  if ( ! distanceUnitsStr.isEmpty() )
339  }
340 
341  // Set the area units from the context if it has not been set by setAreaUnits()
342  if ( context && areaUnits() == QgsUnitTypes::AreaUnknownUnit )
343  {
344  QString areaUnitsStr = context->variable( QStringLiteral( "project_area_units" ) ).toString();
345  if ( ! areaUnitsStr.isEmpty() )
346  setAreaUnits( QgsUnitTypes::stringToAreaUnit( areaUnitsStr ) );
347  }
348 }
349 
350 void QgsExpression::detach()
351 {
352  Q_ASSERT( d );
353 
354  if ( d->ref > 1 )
355  {
356  ( void )d->ref.deref();
357 
358  d = new QgsExpressionPrivate( *d );
359  }
360 }
361 
363 {
364  detach();
365  if ( calc )
366  d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea( *calc ) );
367  else
368  d->mCalc.reset();
369 }
370 
372 {
373  detach();
374  d->mEvalErrorString = QString();
375  if ( !d->mRootNode )
376  {
377  //re-parse expression. Creation of QgsExpressionContexts may have added extra
378  //known functions since this expression was created, so we have another try
379  //at re-parsing it now that the context must have been created
380  d->mRootNode = ::parseExpression( d->mExp, d->mParserErrorString, d->mParserErrors );
381  }
382 
383  if ( !d->mRootNode )
384  {
385  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
386  return false;
387  }
388 
389  initGeomCalculator( context );
390  d->mIsPrepared = true;
391  return d->mRootNode->prepare( this, context );
392 }
393 
395 {
396  d->mEvalErrorString = QString();
397  if ( !d->mRootNode )
398  {
399  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
400  return QVariant();
401  }
402 
403  return d->mRootNode->eval( this, static_cast<const QgsExpressionContext *>( nullptr ) );
404 }
405 
407 {
408  d->mEvalErrorString = QString();
409  if ( !d->mRootNode )
410  {
411  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
412  return QVariant();
413  }
414 
415  if ( ! d->mIsPrepared )
416  {
417  prepare( context );
418  }
419  return d->mRootNode->eval( this, context );
420 }
421 
423 {
424  return !d->mEvalErrorString.isNull();
425 }
426 
428 {
429  return d->mEvalErrorString;
430 }
431 
432 void QgsExpression::setEvalErrorString( const QString &str )
433 {
434  d->mEvalErrorString = str;
435 }
436 
437 QString QgsExpression::dump() const
438 {
439  if ( !d->mRootNode )
440  return QString();
441 
442  return d->mRootNode->dump();
443 }
444 
446 {
447  return d->mCalc.get();
448 }
449 
451 {
452  return d->mDistanceUnit;
453 }
454 
456 {
457  d->mDistanceUnit = unit;
458 }
459 
461 {
462  return d->mAreaUnit;
463 }
464 
466 {
467  d->mAreaUnit = unit;
468 }
469 
470 QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea )
471 {
472  QString expr_action;
473 
474  int index = 0;
475  while ( index < action.size() )
476  {
477  static const QRegularExpression sRegEx{ QStringLiteral( "\\[%(.*?)%\\]" ), QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption };
478 
479  const QRegularExpressionMatch match = sRegEx.match( action, index );
480  if ( !match.hasMatch() )
481  break;
482 
483  const int pos = action.indexOf( sRegEx, index );
484  const int start = index;
485  index = pos + match.capturedLength( 0 );
486  const QString toReplace = match.captured( 1 ).trimmed();
487  QgsDebugMsg( "Found expression: " + toReplace );
488 
489  QgsExpression exp( toReplace );
490  if ( exp.hasParserError() )
491  {
492  QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
493  expr_action += action.midRef( start, index - start );
494  continue;
495  }
496 
497  if ( distanceArea )
498  {
499  //if QgsDistanceArea specified for area/distance conversion, use it
500  exp.setGeomCalculator( distanceArea );
501  }
502 
503  QVariant result = exp.evaluate( context );
504 
505  if ( exp.hasEvalError() )
506  {
507  QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
508  expr_action += action.midRef( start, index - start );
509  continue;
510  }
511 
512  QgsDebugMsg( "Expression result is: " + result.toString() );
513  expr_action += action.mid( start, pos - start ) + result.toString();
514  }
515 
516  expr_action += action.midRef( index );
517 
518  return expr_action;
519 }
520 
521 QSet<QString> QgsExpression::referencedVariables( const QString &text )
522 {
523  QSet<QString> variables;
524  int index = 0;
525  while ( index < text.size() )
526  {
527  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
528 
529  int pos = rx.indexIn( text, index );
530  if ( pos < 0 )
531  break;
532 
533  index = pos + rx.matchedLength();
534  QString to_replace = rx.cap( 1 ).trimmed();
535 
536  QgsExpression exp( to_replace );
537  variables.unite( exp.referencedVariables() );
538  }
539 
540  return variables;
541 }
542 
543 double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
544 {
545  bool ok;
546  //first test if text is directly convertible to double
547  // use system locale: e.g. in German locale, user is presented with numbers "1,23" instead of "1.23" in C locale
548  // so we also want to allow user to rewrite it to "5,23" and it is still accepted
549  double convertedValue = QLocale().toDouble( text, &ok );
550  if ( ok )
551  {
552  return convertedValue;
553  }
554 
555  //otherwise try to evaluate as expression
556  QgsExpression expr( text );
557 
558  QgsExpressionContext context;
561 
562  QVariant result = expr.evaluate( &context );
563  convertedValue = result.toDouble( &ok );
564  if ( expr.hasEvalError() || !ok )
565  {
566  return fallbackValue;
567  }
568  return convertedValue;
569 }
570 
571 
572 
573 QString QgsExpression::helpText( QString name )
574 {
575  QgsExpression::initFunctionHelp();
576 
577  if ( !sFunctionHelpTexts.contains( name ) )
578  return tr( "function help for %1 missing" ).arg( name );
579 
580  const Help &f = sFunctionHelpTexts[ name ];
581 
582  name = f.mName;
583  if ( f.mType == tr( "group" ) )
584  {
585  name = group( name );
586  name = name.toLower();
587  }
588 
589  name = name.toHtmlEscaped();
590 
591  QString helpContents( QStringLiteral( "<h3>%1</h3>\n<div class=\"description\"><p>%2</p></div>" )
592  .arg( tr( "%1 %2" ).arg( f.mType, name ),
593  f.mDescription ) );
594 
595  for ( const HelpVariant &v : qgis::as_const( f.mVariants ) )
596  {
597  if ( f.mVariants.size() > 1 )
598  {
599  helpContents += QStringLiteral( "<h3>%1</h3>\n<div class=\"description\">%2</p></div>" ).arg( v.mName, v.mDescription );
600  }
601 
602  if ( f.mType != tr( "group" ) && f.mType != tr( "expression" ) )
603  helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"syntax\">\n" ).arg( tr( "Syntax" ) );
604 
605  if ( f.mType == tr( "operator" ) )
606  {
607  if ( v.mArguments.size() == 1 )
608  {
609  helpContents += QStringLiteral( "<code><span class=\"functionname\">%1</span> <span class=\"argument\">%2</span></code>" )
610  .arg( name, v.mArguments[0].mArg );
611  }
612  else if ( v.mArguments.size() == 2 )
613  {
614  helpContents += QStringLiteral( "<code><span class=\"argument\">%1</span> <span class=\"functionname\">%2</span> <span class=\"argument\">%3</span></code>" )
615  .arg( v.mArguments[0].mArg, name, v.mArguments[1].mArg );
616  }
617  }
618  else if ( f.mType != tr( "group" ) && f.mType != tr( "expression" ) )
619  {
620  helpContents += QStringLiteral( "<code><span class=\"functionname\">%1</span>" ).arg( name );
621 
622  bool hasOptionalArgs = false;
623 
624  if ( f.mType == tr( "function" ) && ( f.mName[0] != '$' || !v.mArguments.isEmpty() || v.mVariableLenArguments ) )
625  {
626  helpContents += '(';
627 
628  QString delim;
629  for ( const HelpArg &a : qgis::as_const( v.mArguments ) )
630  {
631  if ( !a.mDescOnly )
632  {
633  if ( a.mOptional )
634  {
635  hasOptionalArgs = true;
636  helpContents += QStringLiteral( "[" );
637  }
638 
639  helpContents += delim;
640  helpContents += QStringLiteral( "<span class=\"argument\">%2%3</span>" ).arg(
641  a.mArg,
642  a.mDefaultVal.isEmpty() ? QString() : '=' + a.mDefaultVal
643  );
644 
645  if ( a.mOptional )
646  helpContents += QStringLiteral( "]" );
647  }
648  delim = QStringLiteral( "," );
649  }
650 
651  if ( v.mVariableLenArguments )
652  {
653  helpContents += QChar( 0x2026 );
654  }
655 
656  helpContents += ')';
657  }
658 
659  helpContents += QLatin1String( "</code>" );
660 
661  if ( hasOptionalArgs )
662  {
663  helpContents += QLatin1String( "<br/><br/>" ) + tr( "[ ] marks optional components" );
664  }
665  }
666 
667  if ( !v.mArguments.isEmpty() )
668  {
669  helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"arguments\">\n<table>" ).arg( tr( "Arguments" ) );
670 
671  for ( const HelpArg &a : qgis::as_const( v.mArguments ) )
672  {
673  if ( a.mSyntaxOnly )
674  continue;
675 
676  helpContents += QStringLiteral( "<tr><td class=\"argument\">%1</td><td>%2</td></tr>" ).arg( a.mArg, a.mDescription );
677  }
678 
679  helpContents += QLatin1String( "</table>\n</div>\n" );
680  }
681 
682  if ( !v.mExamples.isEmpty() )
683  {
684  helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"examples\">\n<ul>\n" ).arg( tr( "Examples" ) );
685 
686  for ( const HelpExample &e : qgis::as_const( v.mExamples ) )
687  {
688  helpContents += "<li><code>" + e.mExpression + "</code> &rarr; <code>" + e.mReturns + "</code>";
689 
690  if ( !e.mNote.isEmpty() )
691  helpContents += QStringLiteral( " (%1)" ).arg( e.mNote );
692 
693  helpContents += QLatin1String( "</li>\n" );
694  }
695 
696  helpContents += QLatin1String( "</ul>\n</div>\n" );
697  }
698 
699  if ( !v.mNotes.isEmpty() )
700  {
701  helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"notes\"><p>%2</p></div>\n" ).arg( tr( "Notes" ), v.mNotes );
702  }
703  }
704 
705  return helpContents;
706 }
707 
708 QHash<QString, QString> QgsExpression::sVariableHelpTexts;
709 
710 void QgsExpression::initVariableHelp()
711 {
712  if ( !sVariableHelpTexts.isEmpty() )
713  return;
714 
715  //global variables
716  sVariableHelpTexts.insert( QStringLiteral( "qgis_version" ), QCoreApplication::translate( "variable_help", "Current QGIS version string." ) );
717  sVariableHelpTexts.insert( QStringLiteral( "qgis_version_no" ), QCoreApplication::translate( "variable_help", "Current QGIS version number." ) );
718  sVariableHelpTexts.insert( QStringLiteral( "qgis_release_name" ), QCoreApplication::translate( "variable_help", "Current QGIS release name." ) );
719  sVariableHelpTexts.insert( QStringLiteral( "qgis_short_version" ), QCoreApplication::translate( "variable_help", "Short QGIS version string." ) );
720  sVariableHelpTexts.insert( QStringLiteral( "qgis_os_name" ), QCoreApplication::translate( "variable_help", "Operating system name, e.g., 'windows', 'linux' or 'osx'." ) );
721  sVariableHelpTexts.insert( QStringLiteral( "qgis_platform" ), QCoreApplication::translate( "variable_help", "QGIS platform, e.g., 'desktop' or 'server'." ) );
722  sVariableHelpTexts.insert( QStringLiteral( "qgis_locale" ), QCoreApplication::translate( "variable_help", "Two letter identifier for current QGIS locale." ) );
723  sVariableHelpTexts.insert( QStringLiteral( "user_account_name" ), QCoreApplication::translate( "variable_help", "Current user's operating system account name." ) );
724  sVariableHelpTexts.insert( QStringLiteral( "user_full_name" ), QCoreApplication::translate( "variable_help", "Current user's operating system user name (if available)." ) );
725 
726  //project variables
727  sVariableHelpTexts.insert( QStringLiteral( "project_title" ), QCoreApplication::translate( "variable_help", "Title of current project." ) );
728  sVariableHelpTexts.insert( QStringLiteral( "project_path" ), QCoreApplication::translate( "variable_help", "Full path (including file name) of current project." ) );
729  sVariableHelpTexts.insert( QStringLiteral( "project_folder" ), QCoreApplication::translate( "variable_help", "Folder for current project." ) );
730  sVariableHelpTexts.insert( QStringLiteral( "project_filename" ), QCoreApplication::translate( "variable_help", "Filename of current project." ) );
731  sVariableHelpTexts.insert( QStringLiteral( "project_basename" ), QCoreApplication::translate( "variable_help", "Base name of current project's filename (without path and extension)." ) );
732  sVariableHelpTexts.insert( QStringLiteral( "project_home" ), QCoreApplication::translate( "variable_help", "Home path of current project." ) );
733  sVariableHelpTexts.insert( QStringLiteral( "project_crs" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of project (e.g., 'EPSG:4326')." ) );
734  sVariableHelpTexts.insert( QStringLiteral( "project_crs_definition" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of project (full definition)." ) );
735  sVariableHelpTexts.insert( QStringLiteral( "project_author" ), QCoreApplication::translate( "variable_help", "Project author, taken from project metadata." ) );
736  sVariableHelpTexts.insert( QStringLiteral( "project_abstract" ), QCoreApplication::translate( "variable_help", "Project abstract, taken from project metadata." ) );
737  sVariableHelpTexts.insert( QStringLiteral( "project_creation_date" ), QCoreApplication::translate( "variable_help", "Project creation date, taken from project metadata." ) );
738  sVariableHelpTexts.insert( QStringLiteral( "project_identifier" ), QCoreApplication::translate( "variable_help", "Project identifier, taken from project metadata." ) );
739  sVariableHelpTexts.insert( QStringLiteral( "project_keywords" ), QCoreApplication::translate( "variable_help", "Project keywords, taken from project metadata." ) );
740  sVariableHelpTexts.insert( QStringLiteral( "project_area_units" ), QCoreApplication::translate( "variable_help", "Area unit for current project, used when calculating areas of geometries." ) );
741  sVariableHelpTexts.insert( QStringLiteral( "project_distance_units" ), QCoreApplication::translate( "variable_help", "Distance unit for current project, used when calculating lengths of geometries." ) );
742  sVariableHelpTexts.insert( QStringLiteral( "project_ellipsoid" ), QCoreApplication::translate( "variable_help", "Name of ellipsoid of current project, used when calculating geodetic areas and lengths of geometries." ) );
743 
744  //layer variables
745  sVariableHelpTexts.insert( QStringLiteral( "layer_name" ), QCoreApplication::translate( "variable_help", "Name of current layer." ) );
746  sVariableHelpTexts.insert( QStringLiteral( "layer_id" ), QCoreApplication::translate( "variable_help", "ID of current layer." ) );
747  sVariableHelpTexts.insert( QStringLiteral( "layer" ), QCoreApplication::translate( "variable_help", "The current layer." ) );
748 
749  //composition variables
750  sVariableHelpTexts.insert( QStringLiteral( "layout_name" ), QCoreApplication::translate( "variable_help", "Name of composition." ) );
751  sVariableHelpTexts.insert( QStringLiteral( "layout_numpages" ), QCoreApplication::translate( "variable_help", "Number of pages in composition." ) );
752  sVariableHelpTexts.insert( QStringLiteral( "layout_page" ), QCoreApplication::translate( "variable_help", "Current page number in composition." ) );
753  sVariableHelpTexts.insert( QStringLiteral( "layout_pageheight" ), QCoreApplication::translate( "variable_help", "Composition page height in mm." ) );
754  sVariableHelpTexts.insert( QStringLiteral( "layout_pagewidth" ), QCoreApplication::translate( "variable_help", "Composition page width in mm." ) );
755  sVariableHelpTexts.insert( QStringLiteral( "layout_dpi" ), QCoreApplication::translate( "variable_help", "Composition resolution (DPI)." ) );
756 
757  //atlas variables
758  sVariableHelpTexts.insert( QStringLiteral( "atlas_layerid" ), QCoreApplication::translate( "variable_help", "Current atlas coverage layer ID." ) );
759  sVariableHelpTexts.insert( QStringLiteral( "atlas_layername" ), QCoreApplication::translate( "variable_help", "Current atlas coverage layer name." ) );
760  sVariableHelpTexts.insert( QStringLiteral( "atlas_totalfeatures" ), QCoreApplication::translate( "variable_help", "Total number of features in atlas." ) );
761  sVariableHelpTexts.insert( QStringLiteral( "atlas_featurenumber" ), QCoreApplication::translate( "variable_help", "Current atlas feature number." ) );
762  sVariableHelpTexts.insert( QStringLiteral( "atlas_filename" ), QCoreApplication::translate( "variable_help", "Current atlas file name." ) );
763  sVariableHelpTexts.insert( QStringLiteral( "atlas_pagename" ), QCoreApplication::translate( "variable_help", "Current atlas page name." ) );
764  sVariableHelpTexts.insert( QStringLiteral( "atlas_feature" ), QCoreApplication::translate( "variable_help", "Current atlas feature (as feature object)." ) );
765  sVariableHelpTexts.insert( QStringLiteral( "atlas_featureid" ), QCoreApplication::translate( "variable_help", "Current atlas feature ID." ) );
766  sVariableHelpTexts.insert( QStringLiteral( "atlas_geometry" ), QCoreApplication::translate( "variable_help", "Current atlas feature geometry." ) );
767 
768  //layout item variables
769  sVariableHelpTexts.insert( QStringLiteral( "item_id" ), QCoreApplication::translate( "variable_help", "Layout item user ID (not necessarily unique)." ) );
770  sVariableHelpTexts.insert( QStringLiteral( "item_uuid" ), QCoreApplication::translate( "variable_help", "layout item unique ID." ) );
771  sVariableHelpTexts.insert( QStringLiteral( "item_left" ), QCoreApplication::translate( "variable_help", "Left position of layout item (in mm)." ) );
772  sVariableHelpTexts.insert( QStringLiteral( "item_top" ), QCoreApplication::translate( "variable_help", "Top position of layout item (in mm)." ) );
773  sVariableHelpTexts.insert( QStringLiteral( "item_width" ), QCoreApplication::translate( "variable_help", "Width of layout item (in mm)." ) );
774  sVariableHelpTexts.insert( QStringLiteral( "item_height" ), QCoreApplication::translate( "variable_help", "Height of layout item (in mm)." ) );
775 
776  //map settings item variables
777  sVariableHelpTexts.insert( QStringLiteral( "map_id" ), QCoreApplication::translate( "variable_help", "ID of current map destination. This will be 'canvas' for canvas renders, and the item ID for layout map renders." ) );
778  sVariableHelpTexts.insert( QStringLiteral( "map_rotation" ), QCoreApplication::translate( "variable_help", "Current rotation of map." ) );
779  sVariableHelpTexts.insert( QStringLiteral( "map_scale" ), QCoreApplication::translate( "variable_help", "Current scale of map." ) );
780  sVariableHelpTexts.insert( QStringLiteral( "map_extent" ), QCoreApplication::translate( "variable_help", "Geometry representing the current extent of the map." ) );
781  sVariableHelpTexts.insert( QStringLiteral( "map_extent_center" ), QCoreApplication::translate( "variable_help", "Center of map." ) );
782  sVariableHelpTexts.insert( QStringLiteral( "map_extent_width" ), QCoreApplication::translate( "variable_help", "Width of map." ) );
783  sVariableHelpTexts.insert( QStringLiteral( "map_extent_height" ), QCoreApplication::translate( "variable_help", "Height of map." ) );
784  sVariableHelpTexts.insert( QStringLiteral( "map_crs" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of map (e.g., 'EPSG:4326')." ) );
785  sVariableHelpTexts.insert( QStringLiteral( "map_crs_description" ), QCoreApplication::translate( "variable_help", "Name of the coordinate reference system of the map." ) );
786  sVariableHelpTexts.insert( QStringLiteral( "map_units" ), QCoreApplication::translate( "variable_help", "Units for map measurements." ) );
787  sVariableHelpTexts.insert( QStringLiteral( "map_crs_definition" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of map (full definition)." ) );
788  sVariableHelpTexts.insert( QStringLiteral( "map_crs_acronym" ), QCoreApplication::translate( "variable_help", "Acronym of the coordinate reference system of the map." ) );
789  sVariableHelpTexts.insert( QStringLiteral( "map_crs_ellipsoid" ), QCoreApplication::translate( "variable_help", "Acronym of the ellipsoid of the coordinate reference system of the map." ) );
790  sVariableHelpTexts.insert( QStringLiteral( "map_crs_proj4" ), QCoreApplication::translate( "variable_help", "Proj4 definition of the coordinate reference system." ) );
791  sVariableHelpTexts.insert( QStringLiteral( "map_crs_wkt" ), QCoreApplication::translate( "variable_help", "WKT definition of the coordinate reference system." ) );
792  sVariableHelpTexts.insert( QStringLiteral( "map_layer_ids" ), QCoreApplication::translate( "variable_help", "List of map layer IDs visible in the map." ) );
793  sVariableHelpTexts.insert( QStringLiteral( "map_layers" ), QCoreApplication::translate( "variable_help", "List of map layers visible in the map." ) );
794 
795  sVariableHelpTexts.insert( QStringLiteral( "row_number" ), QCoreApplication::translate( "variable_help", "Stores the number of the current row." ) );
796  sVariableHelpTexts.insert( QStringLiteral( "grid_number" ), QCoreApplication::translate( "variable_help", "Current grid annotation value." ) );
797  sVariableHelpTexts.insert( QStringLiteral( "grid_axis" ), QCoreApplication::translate( "variable_help", "Current grid annotation axis (e.g., 'x' for longitude, 'y' for latitude)." ) );
798 
799  // map canvas item variables
800  sVariableHelpTexts.insert( QStringLiteral( "canvas_cursor_point" ), QCoreApplication::translate( "variable_help", "Last cursor position on the canvas in the project's geographical coordinates." ) );
801 
802  // legend canvas item variables
803  sVariableHelpTexts.insert( QStringLiteral( "legend_title" ), QCoreApplication::translate( "variable_help", "Title of the legend." ) );
804  sVariableHelpTexts.insert( QStringLiteral( "legend_column_count" ), QCoreApplication::translate( "variable_help", "Number of column in the legend." ) );
805  sVariableHelpTexts.insert( QStringLiteral( "legend_split_layers" ), QCoreApplication::translate( "variable_help", "Boolean indicating if layers can be split in the legend." ) );
806  sVariableHelpTexts.insert( QStringLiteral( "legend_wrap_string" ), QCoreApplication::translate( "variable_help", "Characters used to wrap the legend text." ) );
807  sVariableHelpTexts.insert( QStringLiteral( "legend_filter_by_map" ), QCoreApplication::translate( "variable_help", "Boolean indicating if the content of the legend is filtered by the map." ) );
808  sVariableHelpTexts.insert( QStringLiteral( "legend_filter_out_atlas" ), QCoreApplication::translate( "variable_help", "Boolean indicating if the Atlas is filtered out of the legend." ) );
809 
810 
811  // map tool capture variables
812  sVariableHelpTexts.insert( QStringLiteral( "snapping_results" ), QCoreApplication::translate( "variable_help",
813  "<p>An array with an item for each snapped point.</p>"
814  "<p>Each item is a map with the following keys:</p>"
815  "<dl>"
816  "<dt>valid</dt><dd>Boolean that indicates if the snapping result is valid</dd>"
817  "<dt>layer</dt><dd>The layer on which the snapped feature is</dd>"
818  "<dt>feature_id</dt><dd>The feature id of the snapped feature</dd>"
819  "<dt>vertex_index</dt><dd>The index of the snapped vertex</dd>"
820  "<dt>distance</dt><dd>The distance between the mouse cursor and the snapped point at the time of snapping</dd>"
821  "</dl>" ) );
822 
823 
824  //symbol variables
825  sVariableHelpTexts.insert( QStringLiteral( "geometry_part_count" ), QCoreApplication::translate( "variable_help", "Number of parts in rendered feature's geometry." ) );
826  sVariableHelpTexts.insert( QStringLiteral( "geometry_part_num" ), QCoreApplication::translate( "variable_help", "Current geometry part number for feature being rendered." ) );
827  sVariableHelpTexts.insert( QStringLiteral( "geometry_point_count" ), QCoreApplication::translate( "variable_help", "Number of points in the rendered geometry's part. It is only meaningful for line geometries and for symbol layers that set this variable." ) );
828  sVariableHelpTexts.insert( QStringLiteral( "geometry_point_num" ), QCoreApplication::translate( "variable_help", "Current point number in the rendered geometry's part. It is only meaningful for line geometries and for symbol layers that set this variable." ) );
829 
830  sVariableHelpTexts.insert( QStringLiteral( "symbol_color" ), QCoreApplication::translate( "symbol_color", "Color of symbol used to render the feature." ) );
831  sVariableHelpTexts.insert( QStringLiteral( "symbol_angle" ), QCoreApplication::translate( "symbol_angle", "Angle of symbol used to render the feature (valid for marker symbols only)." ) );
832 
833  //cluster variables
834  sVariableHelpTexts.insert( QStringLiteral( "cluster_color" ), QCoreApplication::translate( "cluster_color", "Color of symbols within a cluster, or NULL if symbols have mixed colors." ) );
835  sVariableHelpTexts.insert( QStringLiteral( "cluster_size" ), QCoreApplication::translate( "cluster_size", "Number of symbols contained within a cluster." ) );
836 
837  //processing variables
838  sVariableHelpTexts.insert( QStringLiteral( "algorithm_id" ), QCoreApplication::translate( "algorithm_id", "Unique ID for algorithm." ) );
839  sVariableHelpTexts.insert( QStringLiteral( "model_path" ), QCoreApplication::translate( "variable_help", "Full path (including file name) of current model (or project path if model is embedded in a project)." ) );
840  sVariableHelpTexts.insert( QStringLiteral( "model_folder" ), QCoreApplication::translate( "variable_help", "Folder containing current model (or project folder if model is embedded in a project)." ) );
841  sVariableHelpTexts.insert( QStringLiteral( "model_name" ), QCoreApplication::translate( "variable_help", "Name of current model." ) );
842  sVariableHelpTexts.insert( QStringLiteral( "model_group" ), QCoreApplication::translate( "variable_help", "Group for current model." ) );
843  sVariableHelpTexts.insert( QStringLiteral( "fullextent_minx" ), QCoreApplication::translate( "fullextent_minx", "Minimum x-value from full canvas extent (including all layers)." ) );
844  sVariableHelpTexts.insert( QStringLiteral( "fullextent_miny" ), QCoreApplication::translate( "fullextent_miny", "Minimum y-value from full canvas extent (including all layers)." ) );
845  sVariableHelpTexts.insert( QStringLiteral( "fullextent_maxx" ), QCoreApplication::translate( "fullextent_maxx", "Maximum x-value from full canvas extent (including all layers)." ) );
846  sVariableHelpTexts.insert( QStringLiteral( "fullextent_maxy" ), QCoreApplication::translate( "fullextent_maxy", "Maximum y-value from full canvas extent (including all layers)." ) );
847 
848  //provider notification
849  sVariableHelpTexts.insert( QStringLiteral( "notification_message" ), QCoreApplication::translate( "notification_message", "Content of the notification message sent by the provider (available only for actions triggered by provider notifications)." ) );
850 
851  //form context variable
852  sVariableHelpTexts.insert( QStringLiteral( "current_geometry" ), QCoreApplication::translate( "current_geometry", "Represents the geometry of the feature currently being edited in the form or the table row. Can be used in a form/row context to filter the related features." ) );
853  sVariableHelpTexts.insert( QStringLiteral( "current_feature" ), QCoreApplication::translate( "current_feature", "Represents the feature currently being edited in the form or the table row. Can be used in a form/row context to filter the related features." ) );
854 
855  //form variable
856  sVariableHelpTexts.insert( QStringLiteral( "form_mode" ), QCoreApplication::translate( "form_mode", "What the form is used for, like AddFeatureMode, SingleEditMode, MultiEditMode, SearchMode, AggregateSearchMode or IdentifyMode as string." ) );
857 }
858 
859 QString QgsExpression::variableHelpText( const QString &variableName )
860 {
861  QgsExpression::initVariableHelp();
862  return sVariableHelpTexts.value( variableName, QString() );
863 }
864 
865 QString QgsExpression::formatVariableHelp( const QString &description, bool showValue, const QVariant &value )
866 {
867  QString text = !description.isEmpty() ? QStringLiteral( "<p>%1</p>" ).arg( description ) : QString();
868  if ( showValue )
869  {
870  QString valueString;
871  if ( !value.isValid() )
872  {
873  valueString = QCoreApplication::translate( "variable_help", "not set" );
874  }
875  else
876  {
877  valueString = QStringLiteral( "<b>%1</b>" ).arg( formatPreviewString( value ) );
878  }
879  text.append( QCoreApplication::translate( "variable_help", "<p>Current value: %1</p>" ).arg( valueString ) );
880  }
881  return text;
882 }
883 
884 QHash<QString, QString> QgsExpression::sGroups;
885 
886 QString QgsExpression::group( const QString &name )
887 {
888  if ( sGroups.isEmpty() )
889  {
890  sGroups.insert( QStringLiteral( "Aggregates" ), tr( "Aggregates" ) );
891  sGroups.insert( QStringLiteral( "Arrays" ), tr( "Arrays" ) );
892  sGroups.insert( QStringLiteral( "Color" ), tr( "Color" ) );
893  sGroups.insert( QStringLiteral( "Conditionals" ), tr( "Conditionals" ) );
894  sGroups.insert( QStringLiteral( "Conversions" ), tr( "Conversions" ) );
895  sGroups.insert( QStringLiteral( "Date and Time" ), tr( "Date and Time" ) );
896  sGroups.insert( QStringLiteral( "Fields and Values" ), tr( "Fields and Values" ) );
897  sGroups.insert( QStringLiteral( "Files and Paths" ), tr( "Files and Paths" ) );
898  sGroups.insert( QStringLiteral( "Fuzzy Matching" ), tr( "Fuzzy Matching" ) );
899  sGroups.insert( QStringLiteral( "General" ), tr( "General" ) );
900  sGroups.insert( QStringLiteral( "GeometryGroup" ), tr( "Geometry" ) );
901  sGroups.insert( QStringLiteral( "Map Layers" ), tr( "Map Layers" ) );
902  sGroups.insert( QStringLiteral( "Maps" ), tr( "Maps" ) );
903  sGroups.insert( QStringLiteral( "Math" ), tr( "Math" ) );
904  sGroups.insert( QStringLiteral( "Operators" ), tr( "Operators" ) );
905  sGroups.insert( QStringLiteral( "Rasters" ), tr( "Rasters" ) );
906  sGroups.insert( QStringLiteral( "Record and Attributes" ), tr( "Record and Attributes" ) );
907  sGroups.insert( QStringLiteral( "String" ), tr( "String" ) );
908  sGroups.insert( QStringLiteral( "Variables" ), tr( "Variables" ) );
909  sGroups.insert( QStringLiteral( "Recent (%1)" ), tr( "Recent (%1)" ) );
910  }
911 
912  //return the translated name for this group. If group does not
913  //have a translated name in the gGroups hash, return the name
914  //unchanged
915  return sGroups.value( name, name );
916 }
917 
918 QString QgsExpression::formatPreviewString( const QVariant &value, const bool htmlOutput )
919 {
920  static const int MAX_PREVIEW = 60;
921 
922  const QString startToken = htmlOutput ? QStringLiteral( "<i>&lt;" ) : QStringLiteral( "<" );
923  const QString endToken = htmlOutput ? QStringLiteral( "&gt;</i>" ) : QStringLiteral( ">" );
924 
925  if ( value.canConvert<QgsGeometry>() )
926  {
927  //result is a geometry
928  QgsGeometry geom = value.value<QgsGeometry>();
929  if ( geom.isNull() )
930  return startToken + tr( "empty geometry" ) + endToken;
931  else
932  return startToken + tr( "geometry: %1" ).arg( QgsWkbTypes::displayString( geom.constGet()->wkbType() ) )
933  + endToken;
934  }
935  else if ( value.value< QgsWeakMapLayerPointer >().data() )
936  {
937  return startToken + tr( "map layer" ) + endToken;
938  }
939  else if ( !value.isValid() )
940  {
941  return htmlOutput ? tr( "<i>NULL</i>" ) : QString();
942  }
943  else if ( value.canConvert< QgsFeature >() )
944  {
945  //result is a feature
946  QgsFeature feat = value.value<QgsFeature>();
947  return startToken + tr( "feature: %1" ).arg( feat.id() ) + endToken;
948  }
949  else if ( value.canConvert< QgsInterval >() )
950  {
951  //result is a feature
952  QgsInterval interval = value.value<QgsInterval>();
953  return startToken + tr( "interval: %1 days" ).arg( interval.days() ) + endToken;
954  }
955  else if ( value.canConvert< QgsGradientColorRamp >() )
956  {
957  return startToken + tr( "gradient ramp" ) + endToken;
958  }
959  else if ( value.type() == QVariant::Date )
960  {
961  QDate dt = value.toDate();
962  return startToken + tr( "date: %1" ).arg( dt.toString( QStringLiteral( "yyyy-MM-dd" ) ) ) + endToken;
963  }
964  else if ( value.type() == QVariant::Time )
965  {
966  QTime tm = value.toTime();
967  return startToken + tr( "time: %1" ).arg( tm.toString( QStringLiteral( "hh:mm:ss" ) ) ) + endToken;
968  }
969  else if ( value.type() == QVariant::DateTime )
970  {
971  QDateTime dt = value.toDateTime();
972  return startToken + tr( "datetime: %1" ).arg( dt.toString( QStringLiteral( "yyyy-MM-dd hh:mm:ss" ) ) ) + endToken;
973  }
974  else if ( value.type() == QVariant::String )
975  {
976  const QString previewString = value.toString();
977  if ( previewString.length() > MAX_PREVIEW + 3 )
978  {
979  return tr( "'%1…'" ).arg( previewString.left( MAX_PREVIEW ) );
980  }
981  else
982  {
983  return '\'' + previewString + '\'';
984  }
985  }
986  else if ( value.type() == QVariant::Map )
987  {
988  QString mapStr = QStringLiteral( "{" );
989  const QVariantMap map = value.toMap();
990  QString separator;
991  for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
992  {
993  mapStr.append( separator );
994  if ( separator.isEmpty() )
995  separator = QStringLiteral( "," );
996 
997  mapStr.append( QStringLiteral( " '%1': %2" ).arg( it.key(), formatPreviewString( it.value(), htmlOutput ) ) );
998  if ( mapStr.length() > MAX_PREVIEW - 3 )
999  {
1000  mapStr = tr( "%1…" ).arg( mapStr.left( MAX_PREVIEW - 2 ) );
1001  break;
1002  }
1003  }
1004  if ( !map.empty() )
1005  mapStr += QStringLiteral( " " );
1006  mapStr += QStringLiteral( "}" );
1007  return mapStr;
1008  }
1009  else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
1010  {
1011  QString listStr = QStringLiteral( "[" );
1012  const QVariantList list = value.toList();
1013  QString separator;
1014  for ( const QVariant &arrayValue : list )
1015  {
1016  listStr.append( separator );
1017  if ( separator.isEmpty() )
1018  separator = QStringLiteral( "," );
1019 
1020  listStr.append( " " );
1021  listStr.append( formatPreviewString( arrayValue, htmlOutput ) );
1022  if ( listStr.length() > MAX_PREVIEW - 3 )
1023  {
1024  listStr = QString( tr( "%1…" ) ).arg( listStr.left( MAX_PREVIEW - 2 ) );
1025  break;
1026  }
1027  }
1028  if ( !list.empty() )
1029  listStr += QStringLiteral( " " );
1030  listStr += QStringLiteral( "]" );
1031  return listStr;
1032  }
1033  else
1034  {
1035  return value.toString();
1036  }
1037 }
1038 
1039 QString QgsExpression::createFieldEqualityExpression( const QString &fieldName, const QVariant &value )
1040 {
1041  QString expr;
1042 
1043  if ( value.isNull() )
1044  expr = QStringLiteral( "%1 IS NULL" ).arg( quotedColumnRef( fieldName ) );
1045  else
1046  expr = QStringLiteral( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value ) );
1047 
1048  return expr;
1049 }
1050 
1052 {
1053  return d->mRootNode;
1054 }
1055 
1057 {
1058  return d->mRootNode && d->mRootNode->nodeType() == QgsExpressionNode::ntColumnRef;
1059 }
1060 
1061 QList<const QgsExpressionNode *> QgsExpression::nodes() const
1062 {
1063  if ( !d->mRootNode )
1064  return QList<const QgsExpressionNode *>();
1065 
1066  return d->mRootNode->nodes();
1067 }
1068 
1069 
1070 
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:324
void setAreaUnits(QgsUnitTypes::AreaUnit unit)
Sets the desired areal units for calculations involving geomCalculator(), e.g., "$area".
static bool isFunctionName(const QString &name)
tells whether the identifier is a name of existing function
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsFeatureId id
Definition: qgsfeature.h:64
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
static QString formatPreviewString(const QVariant &value, bool htmlOutput=true)
Formats an expression result for friendly display to the user.
static QList< QgsExpressionFunction * > sOwnedFunctions
List of functions owned by the expression engine.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
void setExpression(const QString &expression)
Set the expression string, will reset the whole internal structure.
static QString group(const QString &group)
Returns the translated name for a function group.
bool operator==(const QgsExpression &other) const
Compares two expressions.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
static Q_INVOKABLE AreaUnit stringToAreaUnit(const QString &string, bool *ok=nullptr)
Converts a translated string to an areal unit.
QString dump() const
Returns an expression string, constructed from the internal abstract syntax tree. ...
QVariant evaluate()
Evaluate the feature and return the result.
QgsExpression()
Create an empty expression.
static double evaluateToDouble(const QString &text, double fallbackValue)
Attempts to evaluate a text string as an expression to a resultant double value.
QgsExpressionNode * parseExpression(const QString &str, QString &parserErrorMsg, QList< QgsExpression::ParserError > &parserErrors)
QString evalErrorString() const
Returns evaluation error.
Container of fields for a vector layer.
Definition: qgsfields.h:42
Unknown areal unit.
Definition: qgsunittypes.h:93
QSet< int > referencedAttributeIndexes(const QgsFields &fields) const
Returns a list of field name indexes obtained from the provided fields.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QList< QgsExpression::ParserError > parserErrors() const
Returns parser error details including location of error.
static QString variableHelpText(const QString &variableName)
Returns the help text for a specified variable.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
const QgsCoordinateReferenceSystem & crs
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.
Definition: qgsmaplayer.h:1576
QString parserErrorString() const
Returns parser error.
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
QSet< QString > referencedVariables() const
Returns a list of all variables which are used in this expression.
static QStringList sBuiltinFunctions
const QString GEO_NONE
Constant that holds the string representation for "No ellips/No CRS".
Definition: qgis.cpp:71
void setEvalErrorString(const QString &str)
Sets evaluation error (used internally by evaluation functions)
static const QStringList & BuiltinFunctions()
static bool unregisterFunction(const QString &name)
Unregisters a function from the expression engine.
QgsUnitTypes::AreaUnit areaUnits() const
Returns the desired areal units for calculations involving geomCalculator(), e.g., "$area".
static int functionCount()
Returns the number of functions defined in the parser.
static bool checkExpression(const QString &text, const QgsExpressionContext *context, QString &errorMessage)
Tests whether a string is a valid expression.
QgsDistanceArea * geomCalculator()
Returns calculator used for distance and area calculations (used by $length, $area and $perimeter fun...
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
Definition: qgsfields.cpp:351
static int functionIndex(const QString &name)
Returns index of the function in Functions array.
bool isValid() const
Checks if this expression is valid.
static void cleanRegisteredFunctions()
Deletes all registered functions whose ownership have been transferred to the expression engine...
QgsExpression & operator=(const QgsExpression &other)
Create a copy of this expression.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static bool registerFunction(QgsExpressionFunction *function, bool transferOwnership=false)
Registers a function to the expression engine.
static const QString ALL_ATTRIBUTES
A special attribute that if set matches all attributes.
Abstract base class for all nodes that can appear in an expression.
static QList< QgsExpressionFunction * > sFunctions
Contains information about the context in which a coordinate transform is executed.
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
static const QList< QgsExpressionFunction * > & Functions()
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value)
Create an expression allowing to evaluate if a field is equal to a value.
static QString formatVariableHelp(const QString &description, bool showValue=true, const QVariant &value=QVariant())
Returns formatted help text for a variable.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsUnitTypes::DistanceUnit distanceUnits() const
Returns the desired distance units for calculations involving geomCalculator(), e.g., "$length" and "$perimeter".
QString expression() const
Returns the original, unmodified expression string.
A representation of the interval between two datetime values.
Definition: qgsinterval.h:39
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:54
double days() const
Returns the interval duration in days.
Definition: qgsinterval.h:112
Unknown distance unit.
Definition: qgsunittypes.h:65
A general purpose distance and area calculator, capable of performing ellipsoid based calculations...
static Q_INVOKABLE QgsUnitTypes::DistanceUnit stringToDistanceUnit(const QString &string, bool *ok=nullptr)
Converts a translated string to a distance unit.
A abstract base class for defining QgsExpression functions.
void setGeomCalculator(const QgsDistanceArea *calc)
Sets the geometry calculator used for distance and area calculations in expressions.
const QgsExpressionNode * rootNode() const
Returns the root node of the expression.
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
void setDistanceUnits(QgsUnitTypes::DistanceUnit unit)
Sets the desired distance units for calculations involving geomCalculator(), e.g., "$length" and "$perimeter".
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:438
This class represents a coordinate reference system (CRS).
bool isField() const
Checks whether an expression consists only of a single field reference.
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
static QString displayString(Type type)
Returns a display string type for a WKB type, e.g., the geometry name used in WKT geometry representa...
static QString helpText(QString name)
Returns the help text for a specified function.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required...
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
Definition: qgscolorramp.h:139
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
QList< const QgsExpressionNode * > nodes() const
Returns a list of all nodes which are used in this expression.
AreaUnit
Units of area.
Definition: qgsunittypes.h:80
QSet< QString > referencedFunctions() const
Returns a list of the names of all functions which are used in this expression.
static QString replaceExpressionText(const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea=nullptr)
This function replaces each expression between [% and %] in the string with the result of its evaluat...
bool isValid() const
Returns whether this CRS is correctly initialized and usable.