QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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"
26 
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_definition" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of map (full definition)." ) );
786  sVariableHelpTexts.insert( QStringLiteral( "map_units" ), QCoreApplication::translate( "variable_help", "Units for map measurements." ) );
787  sVariableHelpTexts.insert( QStringLiteral( "map_layer_ids" ), QCoreApplication::translate( "variable_help", "List of map layer IDs visible in the map." ) );
788  sVariableHelpTexts.insert( QStringLiteral( "map_layers" ), QCoreApplication::translate( "variable_help", "List of map layers visible in the map." ) );
789 
790  sVariableHelpTexts.insert( QStringLiteral( "row_number" ), QCoreApplication::translate( "variable_help", "Stores the number of the current row." ) );
791  sVariableHelpTexts.insert( QStringLiteral( "grid_number" ), QCoreApplication::translate( "variable_help", "Current grid annotation value." ) );
792  sVariableHelpTexts.insert( QStringLiteral( "grid_axis" ), QCoreApplication::translate( "variable_help", "Current grid annotation axis (e.g., 'x' for longitude, 'y' for latitude)." ) );
793 
794  // map canvas item variables
795  sVariableHelpTexts.insert( QStringLiteral( "canvas_cursor_point" ), QCoreApplication::translate( "variable_help", "Last cursor position on the canvas in the project's geographical coordinates." ) );
796 
797  // map tool capture variables
798  sVariableHelpTexts.insert( QStringLiteral( "snapping_results" ), QCoreApplication::translate( "variable_help",
799  "<p>An array with an item for each snapped point.</p>"
800  "<p>Each item is a map with the following keys:</p>"
801  "<dl>"
802  "<dt>valid</dt><dd>Boolean that indicates if the snapping result is valid</dd>"
803  "<dt>layer</dt><dd>The layer on which the snapped feature is</dd>"
804  "<dt>feature_id</dt><dd>The feature id of the snapped feature</dd>"
805  "<dt>vertex_index</dt><dd>The index of the snapped vertex</dd>"
806  "<dt>distance</dt><dd>The distance between the mouse cursor and the snapped point at the time of snapping</dd>"
807  "</dl>" ) );
808 
809 
810  //symbol variables
811  sVariableHelpTexts.insert( QStringLiteral( "geometry_part_count" ), QCoreApplication::translate( "variable_help", "Number of parts in rendered feature's geometry." ) );
812  sVariableHelpTexts.insert( QStringLiteral( "geometry_part_num" ), QCoreApplication::translate( "variable_help", "Current geometry part number for feature being rendered." ) );
813  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." ) );
814  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." ) );
815 
816  sVariableHelpTexts.insert( QStringLiteral( "symbol_color" ), QCoreApplication::translate( "symbol_color", "Color of symbol used to render the feature." ) );
817  sVariableHelpTexts.insert( QStringLiteral( "symbol_angle" ), QCoreApplication::translate( "symbol_angle", "Angle of symbol used to render the feature (valid for marker symbols only)." ) );
818 
819  //cluster variables
820  sVariableHelpTexts.insert( QStringLiteral( "cluster_color" ), QCoreApplication::translate( "cluster_color", "Color of symbols within a cluster, or NULL if symbols have mixed colors." ) );
821  sVariableHelpTexts.insert( QStringLiteral( "cluster_size" ), QCoreApplication::translate( "cluster_size", "Number of symbols contained within a cluster." ) );
822 
823  //processing variables
824  sVariableHelpTexts.insert( QStringLiteral( "algorithm_id" ), QCoreApplication::translate( "algorithm_id", "Unique ID for algorithm." ) );
825  sVariableHelpTexts.insert( QStringLiteral( "fullextent_minx" ), QCoreApplication::translate( "fullextent_minx", "Minimum x-value from full canvas extent (including all layers)." ) );
826  sVariableHelpTexts.insert( QStringLiteral( "fullextent_miny" ), QCoreApplication::translate( "fullextent_miny", "Minimum y-value from full canvas extent (including all layers)." ) );
827  sVariableHelpTexts.insert( QStringLiteral( "fullextent_maxx" ), QCoreApplication::translate( "fullextent_maxx", "Maximum x-value from full canvas extent (including all layers)." ) );
828  sVariableHelpTexts.insert( QStringLiteral( "fullextent_maxy" ), QCoreApplication::translate( "fullextent_maxy", "Maximum y-value from full canvas extent (including all layers)." ) );
829 
830  //provider notification
831  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)." ) );
832 
833  //form context variable
834  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." ) );
835  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." ) );
836 
837  //form variable
838  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." ) );
839 }
840 
841 QString QgsExpression::variableHelpText( const QString &variableName )
842 {
843  QgsExpression::initVariableHelp();
844  return sVariableHelpTexts.value( variableName, QString() );
845 }
846 
847 QString QgsExpression::formatVariableHelp( const QString &description, bool showValue, const QVariant &value )
848 {
849  QString text = !description.isEmpty() ? QStringLiteral( "<p>%1</p>" ).arg( description ) : QString();
850  if ( showValue )
851  {
852  QString valueString;
853  if ( !value.isValid() )
854  {
855  valueString = QCoreApplication::translate( "variable_help", "not set" );
856  }
857  else
858  {
859  valueString = QStringLiteral( "<b>%1</b>" ).arg( formatPreviewString( value ) );
860  }
861  text.append( QCoreApplication::translate( "variable_help", "<p>Current value: %1</p>" ).arg( valueString ) );
862  }
863  return text;
864 }
865 
866 QHash<QString, QString> QgsExpression::sGroups;
867 
868 QString QgsExpression::group( const QString &name )
869 {
870  if ( sGroups.isEmpty() )
871  {
872  sGroups.insert( QStringLiteral( "Aggregates" ), tr( "Aggregates" ) );
873  sGroups.insert( QStringLiteral( "Arrays" ), tr( "Arrays" ) );
874  sGroups.insert( QStringLiteral( "General" ), tr( "General" ) );
875  sGroups.insert( QStringLiteral( "Operators" ), tr( "Operators" ) );
876  sGroups.insert( QStringLiteral( "Conditionals" ), tr( "Conditionals" ) );
877  sGroups.insert( QStringLiteral( "Fields and Values" ), tr( "Fields and Values" ) );
878  sGroups.insert( QStringLiteral( "Map Layers" ), tr( "Map Layers" ) );
879  sGroups.insert( QStringLiteral( "Maps" ), tr( "Maps" ) );
880  sGroups.insert( QStringLiteral( "Math" ), tr( "Math" ) );
881  sGroups.insert( QStringLiteral( "Conversions" ), tr( "Conversions" ) );
882  sGroups.insert( QStringLiteral( "Date and Time" ), tr( "Date and Time" ) );
883  sGroups.insert( QStringLiteral( "String" ), tr( "String" ) );
884  sGroups.insert( QStringLiteral( "Color" ), tr( "Color" ) );
885  sGroups.insert( QStringLiteral( "GeometryGroup" ), tr( "Geometry" ) );
886  sGroups.insert( QStringLiteral( "Rasters" ), tr( "Rasters" ) );
887  sGroups.insert( QStringLiteral( "Record and Attributes" ), tr( "Record and Attributes" ) );
888  sGroups.insert( QStringLiteral( "Variables" ), tr( "Variables" ) );
889  sGroups.insert( QStringLiteral( "Fuzzy Matching" ), tr( "Fuzzy Matching" ) );
890  sGroups.insert( QStringLiteral( "Recent (%1)" ), tr( "Recent (%1)" ) );
891  }
892 
893  //return the translated name for this group. If group does not
894  //have a translated name in the gGroups hash, return the name
895  //unchanged
896  return sGroups.value( name, name );
897 }
898 
899 QString QgsExpression::formatPreviewString( const QVariant &value, const bool htmlOutput )
900 {
901  static const int MAX_PREVIEW = 60;
902 
903  const QString startToken = htmlOutput ? QStringLiteral( "<i>&lt;" ) : QStringLiteral( "<" );
904  const QString endToken = htmlOutput ? QStringLiteral( "&gt;</i>" ) : QStringLiteral( ">" );
905 
906  if ( value.canConvert<QgsGeometry>() )
907  {
908  //result is a geometry
909  QgsGeometry geom = value.value<QgsGeometry>();
910  if ( geom.isNull() )
911  return startToken + tr( "empty geometry" ) + endToken;
912  else
913  return startToken + tr( "geometry: %1" ).arg( QgsWkbTypes::displayString( geom.constGet()->wkbType() ) )
914  + endToken;
915  }
916  else if ( value.value< QgsWeakMapLayerPointer >().data() )
917  {
918  return startToken + tr( "map layer" ) + endToken;
919  }
920  else if ( !value.isValid() )
921  {
922  return htmlOutput ? tr( "<i>NULL</i>" ) : QString();
923  }
924  else if ( value.canConvert< QgsFeature >() )
925  {
926  //result is a feature
927  QgsFeature feat = value.value<QgsFeature>();
928  return startToken + tr( "feature: %1" ).arg( feat.id() ) + endToken;
929  }
930  else if ( value.canConvert< QgsInterval >() )
931  {
932  //result is a feature
933  QgsInterval interval = value.value<QgsInterval>();
934  return startToken + tr( "interval: %1 days" ).arg( interval.days() ) + endToken;
935  }
936  else if ( value.canConvert< QgsGradientColorRamp >() )
937  {
938  return startToken + tr( "gradient ramp" ) + endToken;
939  }
940  else if ( value.type() == QVariant::Date )
941  {
942  QDate dt = value.toDate();
943  return startToken + tr( "date: %1" ).arg( dt.toString( QStringLiteral( "yyyy-MM-dd" ) ) ) + endToken;
944  }
945  else if ( value.type() == QVariant::Time )
946  {
947  QTime tm = value.toTime();
948  return startToken + tr( "time: %1" ).arg( tm.toString( QStringLiteral( "hh:mm:ss" ) ) ) + endToken;
949  }
950  else if ( value.type() == QVariant::DateTime )
951  {
952  QDateTime dt = value.toDateTime();
953  return startToken + tr( "datetime: %1" ).arg( dt.toString( QStringLiteral( "yyyy-MM-dd hh:mm:ss" ) ) ) + endToken;
954  }
955  else if ( value.type() == QVariant::String )
956  {
957  const QString previewString = value.toString();
958  if ( previewString.length() > MAX_PREVIEW + 3 )
959  {
960  return tr( "'%1…'" ).arg( previewString.left( MAX_PREVIEW ) );
961  }
962  else
963  {
964  return '\'' + previewString + '\'';
965  }
966  }
967  else if ( value.type() == QVariant::Map )
968  {
969  QString mapStr = QStringLiteral( "{" );
970  const QVariantMap map = value.toMap();
971  QString separator;
972  for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
973  {
974  mapStr.append( separator );
975  if ( separator.isEmpty() )
976  separator = QStringLiteral( "," );
977 
978  mapStr.append( QStringLiteral( " '%1': %2" ).arg( it.key(), formatPreviewString( it.value(), htmlOutput ) ) );
979  if ( mapStr.length() > MAX_PREVIEW - 3 )
980  {
981  mapStr = tr( "%1…" ).arg( mapStr.left( MAX_PREVIEW - 2 ) );
982  break;
983  }
984  }
985  if ( !map.empty() )
986  mapStr += QStringLiteral( " " );
987  mapStr += QStringLiteral( "}" );
988  return mapStr;
989  }
990  else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
991  {
992  QString listStr = QStringLiteral( "[" );
993  const QVariantList list = value.toList();
994  QString separator;
995  for ( const QVariant &arrayValue : list )
996  {
997  listStr.append( separator );
998  if ( separator.isEmpty() )
999  separator = QStringLiteral( "," );
1000 
1001  listStr.append( " " );
1002  listStr.append( formatPreviewString( arrayValue, htmlOutput ) );
1003  if ( listStr.length() > MAX_PREVIEW - 3 )
1004  {
1005  listStr = QString( tr( "%1…" ) ).arg( listStr.left( MAX_PREVIEW - 2 ) );
1006  break;
1007  }
1008  }
1009  if ( !list.empty() )
1010  listStr += QStringLiteral( " " );
1011  listStr += QStringLiteral( "]" );
1012  return listStr;
1013  }
1014  else
1015  {
1016  return value.toString();
1017  }
1018 }
1019 
1020 QString QgsExpression::createFieldEqualityExpression( const QString &fieldName, const QVariant &value )
1021 {
1022  QString expr;
1023 
1024  if ( value.isNull() )
1025  expr = QStringLiteral( "%1 IS NULL" ).arg( quotedColumnRef( fieldName ) );
1026  else
1027  expr = QStringLiteral( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value ) );
1028 
1029  return expr;
1030 }
1031 
1033 {
1034  return d->mRootNode;
1035 }
1036 
1038 {
1039  return d->mRootNode && d->mRootNode->nodeType() == QgsExpressionNode::ntColumnRef;
1040 }
1041 
1042 QList<const QgsExpressionNode *> QgsExpression::nodes() const
1043 {
1044  if ( !d->mRootNode )
1045  return QList<const QgsExpressionNode *>();
1046 
1047  return d->mRootNode->nodes();
1048 }
1049 
1050 
1051 
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 hasEvalError() const
Returns true if an error occurred when evaluating last input.
static QString formatPreviewString(const QVariant &value, bool htmlOutput=true)
Formats an expression result for friendly display to the user.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
static QList< QgsExpressionFunction * > sOwnedFunctions
List of functions owned by the expression engine.
QSet< QString > referencedVariables() const
Returns a list of all variables which are used in this expression.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
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 isValid() const
Checks if this expression is valid.
#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.
QSet< int > referencedAttributeIndexes(const QgsFields &fields) const
Returns a list of field name indexes obtained from the provided fields.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
QVariant evaluate()
Evaluate the feature and return the result.
QgsExpression()
Create an empty expression.
bool operator==(const QgsExpression &other) const
Compares two expressions.
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)
Container of fields for a vector layer.
Definition: qgsfields.h:42
Square millimeters.
Definition: qgsunittypes.h:92
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
QString dump() const
Returns an expression string, constructed from the internal abstract syntax tree. ...
QSet< QString > referencedFunctions() const
Returns a list of the names of all functions which are used in this expression.
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.
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:1482
static QStringList sBuiltinFunctions
const QString GEO_NONE
Constant that holds the string representation for "No ellips/No CRS".
Definition: qgis.cpp:71
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
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.
double days() const
Returns the interval duration in days.
Definition: qgsinterval.h:112
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.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
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...
static int functionIndex(const QString &name)
Returns index of the function in Functions array.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
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.
bool isField() const
Checks whether an expression consists only of a single field reference.
Abstract base class for all nodes that can appear in an expression.
QList< QgsExpression::ParserError > parserErrors() const
Returns parser error details including location of error.
static QList< QgsExpressionFunction * > sFunctions
QgsUnitTypes::AreaUnit areaUnits() const
Returns the desired areal units for calculations involving geomCalculator(), e.g., "$area".
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:320
Contains information about the context in which a coordinate transform is executed.
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.
QgsUnitTypes::DistanceUnit distanceUnits() const
Returns the desired distance units for calculations involving geomCalculator(), e.g., "$length" and "$perimeter".
A representation of the interval between two datetime values.
Definition: qgsinterval.h:39
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:53
Unknown distance unit.
Definition: qgsunittypes.h:64
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.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
void setGeomCalculator(const QgsDistanceArea *calc)
Sets the geometry calculator used for distance and area calculations in expressions.
QList< const QgsExpressionNode * > nodes() const
Returns a list of all nodes which are used in this 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:411
This class represents a coordinate reference system (CRS).
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...
const QgsExpressionNode * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
static QString helpText(QString name)
Returns the help text for a specified function.
QString expression() const
Returns the original, unmodified expression string.
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
QString parserErrorString() const
Returns parser error.
QString evalErrorString() const
Returns evaluation error.
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
Definition: qgsfields.cpp:347
AreaUnit
Units of area.
Definition: qgsunittypes.h:79
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...