QGIS API Documentation  3.6.0-Noosa (5873452)
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  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
478 
479  int pos = rx.indexIn( action, index );
480  if ( pos < 0 )
481  break;
482 
483  int start = index;
484  index = pos + rx.matchedLength();
485  QString to_replace = rx.cap( 1 ).trimmed();
486  QgsDebugMsg( "Found expression: " + to_replace );
487 
488  QgsExpression exp( to_replace );
489  if ( exp.hasParserError() )
490  {
491  QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
492  expr_action += action.midRef( start, index - start );
493  continue;
494  }
495 
496  if ( distanceArea )
497  {
498  //if QgsDistanceArea specified for area/distance conversion, use it
499  exp.setGeomCalculator( distanceArea );
500  }
501 
502  QVariant result = exp.evaluate( context );
503 
504  if ( exp.hasEvalError() )
505  {
506  QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
507  expr_action += action.midRef( start, index - start );
508  continue;
509  }
510 
511  QgsDebugMsg( "Expression result is: " + result.toString() );
512  expr_action += action.mid( start, pos - start ) + result.toString();
513  }
514 
515  expr_action += action.midRef( index );
516 
517  return expr_action;
518 }
519 
520 QSet<QString> QgsExpression::referencedVariables( const QString &text )
521 {
522  QSet<QString> variables;
523  int index = 0;
524  while ( index < text.size() )
525  {
526  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
527 
528  int pos = rx.indexIn( text, index );
529  if ( pos < 0 )
530  break;
531 
532  index = pos + rx.matchedLength();
533  QString to_replace = rx.cap( 1 ).trimmed();
534 
535  QgsExpression exp( to_replace );
536  variables.unite( exp.referencedVariables() );
537  }
538 
539  return variables;
540 }
541 
542 double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
543 {
544  bool ok;
545  //first test if text is directly convertible to double
546  // use system locale: e.g. in German locale, user is presented with numbers "1,23" instead of "1.23" in C locale
547  // so we also want to allow user to rewrite it to "5,23" and it is still accepted
548  double convertedValue = QLocale().toDouble( text, &ok );
549  if ( ok )
550  {
551  return convertedValue;
552  }
553 
554  //otherwise try to evaluate as expression
555  QgsExpression expr( text );
556 
557  QgsExpressionContext context;
560 
561  QVariant result = expr.evaluate( &context );
562  convertedValue = result.toDouble( &ok );
563  if ( expr.hasEvalError() || !ok )
564  {
565  return fallbackValue;
566  }
567  return convertedValue;
568 }
569 
570 
571 
572 QString QgsExpression::helpText( QString name )
573 {
574  QgsExpression::initFunctionHelp();
575 
576  if ( !sFunctionHelpTexts.contains( name ) )
577  return tr( "function help for %1 missing" ).arg( name );
578 
579  const Help &f = sFunctionHelpTexts[ name ];
580 
581  name = f.mName;
582  if ( f.mType == tr( "group" ) )
583  {
584  name = group( name );
585  name = name.toLower();
586  }
587 
588  name = name.toHtmlEscaped();
589 
590  QString helpContents( QStringLiteral( "<h3>%1</h3>\n<div class=\"description\"><p>%2</p></div>" )
591  .arg( tr( "%1 %2" ).arg( f.mType, name ),
592  f.mDescription ) );
593 
594  for ( const HelpVariant &v : qgis::as_const( f.mVariants ) )
595  {
596  if ( f.mVariants.size() > 1 )
597  {
598  helpContents += QStringLiteral( "<h3>%1</h3>\n<div class=\"description\">%2</p></div>" ).arg( v.mName, v.mDescription );
599  }
600 
601  if ( f.mType != tr( "group" ) && f.mType != tr( "expression" ) )
602  helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"syntax\">\n" ).arg( tr( "Syntax" ) );
603 
604  if ( f.mType == tr( "operator" ) )
605  {
606  if ( v.mArguments.size() == 1 )
607  {
608  helpContents += QStringLiteral( "<code><span class=\"functionname\">%1</span> <span class=\"argument\">%2</span></code>" )
609  .arg( name, v.mArguments[0].mArg );
610  }
611  else if ( v.mArguments.size() == 2 )
612  {
613  helpContents += QStringLiteral( "<code><span class=\"argument\">%1</span> <span class=\"functionname\">%2</span> <span class=\"argument\">%3</span></code>" )
614  .arg( v.mArguments[0].mArg, name, v.mArguments[1].mArg );
615  }
616  }
617  else if ( f.mType != tr( "group" ) && f.mType != tr( "expression" ) )
618  {
619  helpContents += QStringLiteral( "<code><span class=\"functionname\">%1</span>" ).arg( name );
620 
621  bool hasOptionalArgs = false;
622 
623  if ( f.mType == tr( "function" ) && ( f.mName[0] != '$' || !v.mArguments.isEmpty() || v.mVariableLenArguments ) )
624  {
625  helpContents += '(';
626 
627  QString delim;
628  for ( const HelpArg &a : qgis::as_const( v.mArguments ) )
629  {
630  if ( !a.mDescOnly )
631  {
632  if ( a.mOptional )
633  {
634  hasOptionalArgs = true;
635  helpContents += QStringLiteral( "[" );
636  }
637 
638  helpContents += delim;
639  helpContents += QStringLiteral( "<span class=\"argument\">%2%3</span>" ).arg(
640  a.mArg,
641  a.mDefaultVal.isEmpty() ? QString() : '=' + a.mDefaultVal
642  );
643 
644  if ( a.mOptional )
645  helpContents += QStringLiteral( "]" );
646  }
647  delim = QStringLiteral( "," );
648  }
649 
650  if ( v.mVariableLenArguments )
651  {
652  helpContents += QChar( 0x2026 );
653  }
654 
655  helpContents += ')';
656  }
657 
658  helpContents += QLatin1String( "</code>" );
659 
660  if ( hasOptionalArgs )
661  {
662  helpContents += QLatin1String( "<br/><br/>" ) + tr( "[ ] marks optional components" );
663  }
664  }
665 
666  if ( !v.mArguments.isEmpty() )
667  {
668  helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"arguments\">\n<table>" ).arg( tr( "Arguments" ) );
669 
670  for ( const HelpArg &a : qgis::as_const( v.mArguments ) )
671  {
672  if ( a.mSyntaxOnly )
673  continue;
674 
675  helpContents += QStringLiteral( "<tr><td class=\"argument\">%1</td><td>%2</td></tr>" ).arg( a.mArg, a.mDescription );
676  }
677 
678  helpContents += QLatin1String( "</table>\n</div>\n" );
679  }
680 
681  if ( !v.mExamples.isEmpty() )
682  {
683  helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"examples\">\n<ul>\n" ).arg( tr( "Examples" ) );
684 
685  for ( const HelpExample &e : qgis::as_const( v.mExamples ) )
686  {
687  helpContents += "<li><code>" + e.mExpression + "</code> &rarr; <code>" + e.mReturns + "</code>";
688 
689  if ( !e.mNote.isEmpty() )
690  helpContents += QStringLiteral( " (%1)" ).arg( e.mNote );
691 
692  helpContents += QLatin1String( "</li>\n" );
693  }
694 
695  helpContents += QLatin1String( "</ul>\n</div>\n" );
696  }
697 
698  if ( !v.mNotes.isEmpty() )
699  {
700  helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"notes\"><p>%2</p></div>\n" ).arg( tr( "Notes" ), v.mNotes );
701  }
702  }
703 
704  return helpContents;
705 }
706 
707 QHash<QString, QString> QgsExpression::sVariableHelpTexts;
708 
709 void QgsExpression::initVariableHelp()
710 {
711  if ( !sVariableHelpTexts.isEmpty() )
712  return;
713 
714  //global variables
715  sVariableHelpTexts.insert( QStringLiteral( "qgis_version" ), QCoreApplication::translate( "variable_help", "Current QGIS version string." ) );
716  sVariableHelpTexts.insert( QStringLiteral( "qgis_version_no" ), QCoreApplication::translate( "variable_help", "Current QGIS version number." ) );
717  sVariableHelpTexts.insert( QStringLiteral( "qgis_release_name" ), QCoreApplication::translate( "variable_help", "Current QGIS release name." ) );
718  sVariableHelpTexts.insert( QStringLiteral( "qgis_short_version" ), QCoreApplication::translate( "variable_help", "Short QGIS version string." ) );
719  sVariableHelpTexts.insert( QStringLiteral( "qgis_os_name" ), QCoreApplication::translate( "variable_help", "Operating system name, e.g., 'windows', 'linux' or 'osx'." ) );
720  sVariableHelpTexts.insert( QStringLiteral( "qgis_platform" ), QCoreApplication::translate( "variable_help", "QGIS platform, e.g., 'desktop' or 'server'." ) );
721  sVariableHelpTexts.insert( QStringLiteral( "qgis_locale" ), QCoreApplication::translate( "variable_help", "Two letter identifier for current QGIS locale." ) );
722  sVariableHelpTexts.insert( QStringLiteral( "user_account_name" ), QCoreApplication::translate( "variable_help", "Current user's operating system account name." ) );
723  sVariableHelpTexts.insert( QStringLiteral( "user_full_name" ), QCoreApplication::translate( "variable_help", "Current user's operating system user name (if available)." ) );
724 
725  //project variables
726  sVariableHelpTexts.insert( QStringLiteral( "project_title" ), QCoreApplication::translate( "variable_help", "Title of current project." ) );
727  sVariableHelpTexts.insert( QStringLiteral( "project_path" ), QCoreApplication::translate( "variable_help", "Full path (including file name) of current project." ) );
728  sVariableHelpTexts.insert( QStringLiteral( "project_folder" ), QCoreApplication::translate( "variable_help", "Folder for current project." ) );
729  sVariableHelpTexts.insert( QStringLiteral( "project_filename" ), QCoreApplication::translate( "variable_help", "Filename of current project." ) );
730  sVariableHelpTexts.insert( QStringLiteral( "project_basename" ), QCoreApplication::translate( "variable_help", "Base name of current project's filename (without path and extension)." ) );
731  sVariableHelpTexts.insert( QStringLiteral( "project_home" ), QCoreApplication::translate( "variable_help", "Home path of current project." ) );
732  sVariableHelpTexts.insert( QStringLiteral( "project_crs" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of project (e.g., 'EPSG:4326')." ) );
733  sVariableHelpTexts.insert( QStringLiteral( "project_crs_definition" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of project (full definition)." ) );
734  sVariableHelpTexts.insert( QStringLiteral( "project_author" ), QCoreApplication::translate( "variable_help", "Project author, taken from project metadata." ) );
735  sVariableHelpTexts.insert( QStringLiteral( "project_abstract" ), QCoreApplication::translate( "variable_help", "Project abstract, taken from project metadata." ) );
736  sVariableHelpTexts.insert( QStringLiteral( "project_creation_date" ), QCoreApplication::translate( "variable_help", "Project creation date, taken from project metadata." ) );
737  sVariableHelpTexts.insert( QStringLiteral( "project_identifier" ), QCoreApplication::translate( "variable_help", "Project identifier, taken from project metadata." ) );
738  sVariableHelpTexts.insert( QStringLiteral( "project_keywords" ), QCoreApplication::translate( "variable_help", "Project keywords, taken from project metadata." ) );
739  sVariableHelpTexts.insert( QStringLiteral( "project_area_units" ), QCoreApplication::translate( "variable_help", "Area unit for current project, used when calculating areas of geometries." ) );
740  sVariableHelpTexts.insert( QStringLiteral( "project_distance_units" ), QCoreApplication::translate( "variable_help", "Distance unit for current project, used when calculating lengths of geometries." ) );
741  sVariableHelpTexts.insert( QStringLiteral( "project_ellipsoid" ), QCoreApplication::translate( "variable_help", "Name of ellipsoid of current project, used when calculating geodetic areas and lengths of geometries." ) );
742 
743  //layer variables
744  sVariableHelpTexts.insert( QStringLiteral( "layer_name" ), QCoreApplication::translate( "variable_help", "Name of current layer." ) );
745  sVariableHelpTexts.insert( QStringLiteral( "layer_id" ), QCoreApplication::translate( "variable_help", "ID of current layer." ) );
746  sVariableHelpTexts.insert( QStringLiteral( "layer" ), QCoreApplication::translate( "variable_help", "The current layer." ) );
747 
748  //composition variables
749  sVariableHelpTexts.insert( QStringLiteral( "layout_name" ), QCoreApplication::translate( "variable_help", "Name of composition." ) );
750  sVariableHelpTexts.insert( QStringLiteral( "layout_numpages" ), QCoreApplication::translate( "variable_help", "Number of pages in composition." ) );
751  sVariableHelpTexts.insert( QStringLiteral( "layout_page" ), QCoreApplication::translate( "variable_help", "Current page number in composition." ) );
752  sVariableHelpTexts.insert( QStringLiteral( "layout_pageheight" ), QCoreApplication::translate( "variable_help", "Composition page height in mm." ) );
753  sVariableHelpTexts.insert( QStringLiteral( "layout_pagewidth" ), QCoreApplication::translate( "variable_help", "Composition page width in mm." ) );
754  sVariableHelpTexts.insert( QStringLiteral( "layout_dpi" ), QCoreApplication::translate( "variable_help", "Composition resolution (DPI)." ) );
755 
756  //atlas variables
757  sVariableHelpTexts.insert( QStringLiteral( "atlas_layerid" ), QCoreApplication::translate( "variable_help", "Current atlas coverage layer ID." ) );
758  sVariableHelpTexts.insert( QStringLiteral( "atlas_layername" ), QCoreApplication::translate( "variable_help", "Current atlas coverage layer name." ) );
759  sVariableHelpTexts.insert( QStringLiteral( "atlas_totalfeatures" ), QCoreApplication::translate( "variable_help", "Total number of features in atlas." ) );
760  sVariableHelpTexts.insert( QStringLiteral( "atlas_featurenumber" ), QCoreApplication::translate( "variable_help", "Current atlas feature number." ) );
761  sVariableHelpTexts.insert( QStringLiteral( "atlas_filename" ), QCoreApplication::translate( "variable_help", "Current atlas file name." ) );
762  sVariableHelpTexts.insert( QStringLiteral( "atlas_pagename" ), QCoreApplication::translate( "variable_help", "Current atlas page name." ) );
763  sVariableHelpTexts.insert( QStringLiteral( "atlas_feature" ), QCoreApplication::translate( "variable_help", "Current atlas feature (as feature object)." ) );
764  sVariableHelpTexts.insert( QStringLiteral( "atlas_featureid" ), QCoreApplication::translate( "variable_help", "Current atlas feature ID." ) );
765  sVariableHelpTexts.insert( QStringLiteral( "atlas_geometry" ), QCoreApplication::translate( "variable_help", "Current atlas feature geometry." ) );
766 
767  //layout item variables
768  sVariableHelpTexts.insert( QStringLiteral( "item_id" ), QCoreApplication::translate( "variable_help", "Layout item user ID (not necessarily unique)." ) );
769  sVariableHelpTexts.insert( QStringLiteral( "item_uuid" ), QCoreApplication::translate( "variable_help", "layout item unique ID." ) );
770  sVariableHelpTexts.insert( QStringLiteral( "item_left" ), QCoreApplication::translate( "variable_help", "Left position of layout item (in mm)." ) );
771  sVariableHelpTexts.insert( QStringLiteral( "item_top" ), QCoreApplication::translate( "variable_help", "Top position of layout item (in mm)." ) );
772  sVariableHelpTexts.insert( QStringLiteral( "item_width" ), QCoreApplication::translate( "variable_help", "Width of layout item (in mm)." ) );
773  sVariableHelpTexts.insert( QStringLiteral( "item_height" ), QCoreApplication::translate( "variable_help", "Height of layout item (in mm)." ) );
774 
775  //map settings item variables
776  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." ) );
777  sVariableHelpTexts.insert( QStringLiteral( "map_rotation" ), QCoreApplication::translate( "variable_help", "Current rotation of map." ) );
778  sVariableHelpTexts.insert( QStringLiteral( "map_scale" ), QCoreApplication::translate( "variable_help", "Current scale of map." ) );
779  sVariableHelpTexts.insert( QStringLiteral( "map_extent" ), QCoreApplication::translate( "variable_help", "Geometry representing the current extent of the map." ) );
780  sVariableHelpTexts.insert( QStringLiteral( "map_extent_center" ), QCoreApplication::translate( "variable_help", "Center of map." ) );
781  sVariableHelpTexts.insert( QStringLiteral( "map_extent_width" ), QCoreApplication::translate( "variable_help", "Width of map." ) );
782  sVariableHelpTexts.insert( QStringLiteral( "map_extent_height" ), QCoreApplication::translate( "variable_help", "Height of map." ) );
783  sVariableHelpTexts.insert( QStringLiteral( "map_crs" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of map (e.g., 'EPSG:4326')." ) );
784  sVariableHelpTexts.insert( QStringLiteral( "map_crs_description" ), QCoreApplication::translate( "variable_help", "Name of the coordinate reference system of the map." ) );
785  sVariableHelpTexts.insert( QStringLiteral( "map_units" ), QCoreApplication::translate( "variable_help", "Units for map measurements." ) );
786  sVariableHelpTexts.insert( QStringLiteral( "map_crs_definition" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of map (full definition)." ) );
787  sVariableHelpTexts.insert( QStringLiteral( "map_crs_acronym" ), QCoreApplication::translate( "variable_help", "Acronym of the coordinate reference system of the map." ) );
788  sVariableHelpTexts.insert( QStringLiteral( "map_crs_ellipsoid" ), QCoreApplication::translate( "variable_help", "Acronym of the ellipsoid of the coordinate reference system of the map." ) );
789  sVariableHelpTexts.insert( QStringLiteral( "map_crs_proj4" ), QCoreApplication::translate( "variable_help", "Proj4 definition of the coordinate reference system." ) );
790  sVariableHelpTexts.insert( QStringLiteral( "map_crs_wkt" ), QCoreApplication::translate( "variable_help", "WKT definition of the coordinate reference system." ) );
791  sVariableHelpTexts.insert( QStringLiteral( "map_layer_ids" ), QCoreApplication::translate( "variable_help", "List of map layer IDs visible in the map." ) );
792  sVariableHelpTexts.insert( QStringLiteral( "map_layers" ), QCoreApplication::translate( "variable_help", "List of map layers visible in the map." ) );
793 
794  sVariableHelpTexts.insert( QStringLiteral( "row_number" ), QCoreApplication::translate( "variable_help", "Stores the number of the current row." ) );
795  sVariableHelpTexts.insert( QStringLiteral( "grid_number" ), QCoreApplication::translate( "variable_help", "Current grid annotation value." ) );
796  sVariableHelpTexts.insert( QStringLiteral( "grid_axis" ), QCoreApplication::translate( "variable_help", "Current grid annotation axis (e.g., 'x' for longitude, 'y' for latitude)." ) );
797 
798  // map canvas item variables
799  sVariableHelpTexts.insert( QStringLiteral( "canvas_cursor_point" ), QCoreApplication::translate( "variable_help", "Last cursor position on the canvas in the project's geographical coordinates." ) );
800 
801  // legend canvas item variables
802  sVariableHelpTexts.insert( QStringLiteral( "legend_title" ), QCoreApplication::translate( "variable_help", "Title of the legend." ) );
803  sVariableHelpTexts.insert( QStringLiteral( "legend_column_count" ), QCoreApplication::translate( "variable_help", "Number of column in the legend." ) );
804  sVariableHelpTexts.insert( QStringLiteral( "legend_split_layers" ), QCoreApplication::translate( "variable_help", "Boolean indicating if layers can be split in the legend." ) );
805  sVariableHelpTexts.insert( QStringLiteral( "legend_wrap_string" ), QCoreApplication::translate( "variable_help", "Characters used to wrap the legend text." ) );
806  sVariableHelpTexts.insert( QStringLiteral( "legend_filter_by_map" ), QCoreApplication::translate( "variable_help", "Boolean indicating if the content of the legend is filtered by the map." ) );
807  sVariableHelpTexts.insert( QStringLiteral( "legend_filter_out_atlas" ), QCoreApplication::translate( "variable_help", "Boolean indicating if the Atlas is filtered out of the legend." ) );
808 
809 
810  // map tool capture variables
811  sVariableHelpTexts.insert( QStringLiteral( "snapping_results" ), QCoreApplication::translate( "variable_help",
812  "<p>An array with an item for each snapped point.</p>"
813  "<p>Each item is a map with the following keys:</p>"
814  "<dl>"
815  "<dt>valid</dt><dd>Boolean that indicates if the snapping result is valid</dd>"
816  "<dt>layer</dt><dd>The layer on which the snapped feature is</dd>"
817  "<dt>feature_id</dt><dd>The feature id of the snapped feature</dd>"
818  "<dt>vertex_index</dt><dd>The index of the snapped vertex</dd>"
819  "<dt>distance</dt><dd>The distance between the mouse cursor and the snapped point at the time of snapping</dd>"
820  "</dl>" ) );
821 
822 
823  //symbol variables
824  sVariableHelpTexts.insert( QStringLiteral( "geometry_part_count" ), QCoreApplication::translate( "variable_help", "Number of parts in rendered feature's geometry." ) );
825  sVariableHelpTexts.insert( QStringLiteral( "geometry_part_num" ), QCoreApplication::translate( "variable_help", "Current geometry part number for feature being rendered." ) );
826  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." ) );
827  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." ) );
828 
829  sVariableHelpTexts.insert( QStringLiteral( "symbol_color" ), QCoreApplication::translate( "symbol_color", "Color of symbol used to render the feature." ) );
830  sVariableHelpTexts.insert( QStringLiteral( "symbol_angle" ), QCoreApplication::translate( "symbol_angle", "Angle of symbol used to render the feature (valid for marker symbols only)." ) );
831 
832  //cluster variables
833  sVariableHelpTexts.insert( QStringLiteral( "cluster_color" ), QCoreApplication::translate( "cluster_color", "Color of symbols within a cluster, or NULL if symbols have mixed colors." ) );
834  sVariableHelpTexts.insert( QStringLiteral( "cluster_size" ), QCoreApplication::translate( "cluster_size", "Number of symbols contained within a cluster." ) );
835 
836  //processing variables
837  sVariableHelpTexts.insert( QStringLiteral( "algorithm_id" ), QCoreApplication::translate( "algorithm_id", "Unique ID for algorithm." ) );
838  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)." ) );
839  sVariableHelpTexts.insert( QStringLiteral( "model_folder" ), QCoreApplication::translate( "variable_help", "Folder containing current model (or project folder if model is embedded in a project)." ) );
840  sVariableHelpTexts.insert( QStringLiteral( "model_name" ), QCoreApplication::translate( "variable_help", "Name of current model." ) );
841  sVariableHelpTexts.insert( QStringLiteral( "model_group" ), QCoreApplication::translate( "variable_help", "Group for current model." ) );
842  sVariableHelpTexts.insert( QStringLiteral( "fullextent_minx" ), QCoreApplication::translate( "fullextent_minx", "Minimum x-value from full canvas extent (including all layers)." ) );
843  sVariableHelpTexts.insert( QStringLiteral( "fullextent_miny" ), QCoreApplication::translate( "fullextent_miny", "Minimum y-value from full canvas extent (including all layers)." ) );
844  sVariableHelpTexts.insert( QStringLiteral( "fullextent_maxx" ), QCoreApplication::translate( "fullextent_maxx", "Maximum x-value from full canvas extent (including all layers)." ) );
845  sVariableHelpTexts.insert( QStringLiteral( "fullextent_maxy" ), QCoreApplication::translate( "fullextent_maxy", "Maximum y-value from full canvas extent (including all layers)." ) );
846 
847  //provider notification
848  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)." ) );
849 
850  //form context variable
851  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." ) );
852  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." ) );
853 
854  //form variable
855  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." ) );
856 }
857 
858 QString QgsExpression::variableHelpText( const QString &variableName )
859 {
860  QgsExpression::initVariableHelp();
861  return sVariableHelpTexts.value( variableName, QString() );
862 }
863 
864 QString QgsExpression::formatVariableHelp( const QString &description, bool showValue, const QVariant &value )
865 {
866  QString text = !description.isEmpty() ? QStringLiteral( "<p>%1</p>" ).arg( description ) : QString();
867  if ( showValue )
868  {
869  QString valueString;
870  if ( !value.isValid() )
871  {
872  valueString = QCoreApplication::translate( "variable_help", "not set" );
873  }
874  else
875  {
876  valueString = QStringLiteral( "<b>%1</b>" ).arg( formatPreviewString( value ) );
877  }
878  text.append( QCoreApplication::translate( "variable_help", "<p>Current value: %1</p>" ).arg( valueString ) );
879  }
880  return text;
881 }
882 
883 QHash<QString, QString> QgsExpression::sGroups;
884 
885 QString QgsExpression::group( const QString &name )
886 {
887  if ( sGroups.isEmpty() )
888  {
889  sGroups.insert( QStringLiteral( "Aggregates" ), tr( "Aggregates" ) );
890  sGroups.insert( QStringLiteral( "Arrays" ), tr( "Arrays" ) );
891  sGroups.insert( QStringLiteral( "General" ), tr( "General" ) );
892  sGroups.insert( QStringLiteral( "Operators" ), tr( "Operators" ) );
893  sGroups.insert( QStringLiteral( "Conditionals" ), tr( "Conditionals" ) );
894  sGroups.insert( QStringLiteral( "Fields and Values" ), tr( "Fields and Values" ) );
895  sGroups.insert( QStringLiteral( "Map Layers" ), tr( "Map Layers" ) );
896  sGroups.insert( QStringLiteral( "Maps" ), tr( "Maps" ) );
897  sGroups.insert( QStringLiteral( "Math" ), tr( "Math" ) );
898  sGroups.insert( QStringLiteral( "Conversions" ), tr( "Conversions" ) );
899  sGroups.insert( QStringLiteral( "Date and Time" ), tr( "Date and Time" ) );
900  sGroups.insert( QStringLiteral( "String" ), tr( "String" ) );
901  sGroups.insert( QStringLiteral( "Color" ), tr( "Color" ) );
902  sGroups.insert( QStringLiteral( "GeometryGroup" ), tr( "Geometry" ) );
903  sGroups.insert( QStringLiteral( "Rasters" ), tr( "Rasters" ) );
904  sGroups.insert( QStringLiteral( "Record and Attributes" ), tr( "Record and Attributes" ) );
905  sGroups.insert( QStringLiteral( "Variables" ), tr( "Variables" ) );
906  sGroups.insert( QStringLiteral( "Fuzzy Matching" ), tr( "Fuzzy Matching" ) );
907  sGroups.insert( QStringLiteral( "Recent (%1)" ), tr( "Recent (%1)" ) );
908  }
909 
910  //return the translated name for this group. If group does not
911  //have a translated name in the gGroups hash, return the name
912  //unchanged
913  return sGroups.value( name, name );
914 }
915 
916 QString QgsExpression::formatPreviewString( const QVariant &value, const bool htmlOutput )
917 {
918  static const int MAX_PREVIEW = 60;
919 
920  const QString startToken = htmlOutput ? QStringLiteral( "<i>&lt;" ) : QStringLiteral( "<" );
921  const QString endToken = htmlOutput ? QStringLiteral( "&gt;</i>" ) : QStringLiteral( ">" );
922 
923  if ( value.canConvert<QgsGeometry>() )
924  {
925  //result is a geometry
926  QgsGeometry geom = value.value<QgsGeometry>();
927  if ( geom.isNull() )
928  return startToken + tr( "empty geometry" ) + endToken;
929  else
930  return startToken + tr( "geometry: %1" ).arg( QgsWkbTypes::displayString( geom.constGet()->wkbType() ) )
931  + endToken;
932  }
933  else if ( value.value< QgsWeakMapLayerPointer >().data() )
934  {
935  return startToken + tr( "map layer" ) + endToken;
936  }
937  else if ( !value.isValid() )
938  {
939  return htmlOutput ? tr( "<i>NULL</i>" ) : QString();
940  }
941  else if ( value.canConvert< QgsFeature >() )
942  {
943  //result is a feature
944  QgsFeature feat = value.value<QgsFeature>();
945  return startToken + tr( "feature: %1" ).arg( feat.id() ) + endToken;
946  }
947  else if ( value.canConvert< QgsInterval >() )
948  {
949  //result is a feature
950  QgsInterval interval = value.value<QgsInterval>();
951  return startToken + tr( "interval: %1 days" ).arg( interval.days() ) + endToken;
952  }
953  else if ( value.canConvert< QgsGradientColorRamp >() )
954  {
955  return startToken + tr( "gradient ramp" ) + endToken;
956  }
957  else if ( value.type() == QVariant::Date )
958  {
959  QDate dt = value.toDate();
960  return startToken + tr( "date: %1" ).arg( dt.toString( QStringLiteral( "yyyy-MM-dd" ) ) ) + endToken;
961  }
962  else if ( value.type() == QVariant::Time )
963  {
964  QTime tm = value.toTime();
965  return startToken + tr( "time: %1" ).arg( tm.toString( QStringLiteral( "hh:mm:ss" ) ) ) + endToken;
966  }
967  else if ( value.type() == QVariant::DateTime )
968  {
969  QDateTime dt = value.toDateTime();
970  return startToken + tr( "datetime: %1" ).arg( dt.toString( QStringLiteral( "yyyy-MM-dd hh:mm:ss" ) ) ) + endToken;
971  }
972  else if ( value.type() == QVariant::String )
973  {
974  const QString previewString = value.toString();
975  if ( previewString.length() > MAX_PREVIEW + 3 )
976  {
977  return tr( "'%1…'" ).arg( previewString.left( MAX_PREVIEW ) );
978  }
979  else
980  {
981  return '\'' + previewString + '\'';
982  }
983  }
984  else if ( value.type() == QVariant::Map )
985  {
986  QString mapStr = QStringLiteral( "{" );
987  const QVariantMap map = value.toMap();
988  QString separator;
989  for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
990  {
991  mapStr.append( separator );
992  if ( separator.isEmpty() )
993  separator = QStringLiteral( "," );
994 
995  mapStr.append( QStringLiteral( " '%1': %2" ).arg( it.key(), formatPreviewString( it.value(), htmlOutput ) ) );
996  if ( mapStr.length() > MAX_PREVIEW - 3 )
997  {
998  mapStr = tr( "%1…" ).arg( mapStr.left( MAX_PREVIEW - 2 ) );
999  break;
1000  }
1001  }
1002  if ( !map.empty() )
1003  mapStr += QStringLiteral( " " );
1004  mapStr += QStringLiteral( "}" );
1005  return mapStr;
1006  }
1007  else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
1008  {
1009  QString listStr = QStringLiteral( "[" );
1010  const QVariantList list = value.toList();
1011  QString separator;
1012  for ( const QVariant &arrayValue : list )
1013  {
1014  listStr.append( separator );
1015  if ( separator.isEmpty() )
1016  separator = QStringLiteral( "," );
1017 
1018  listStr.append( " " );
1019  listStr.append( formatPreviewString( arrayValue, htmlOutput ) );
1020  if ( listStr.length() > MAX_PREVIEW - 3 )
1021  {
1022  listStr = QString( tr( "%1…" ) ).arg( listStr.left( MAX_PREVIEW - 2 ) );
1023  break;
1024  }
1025  }
1026  if ( !list.empty() )
1027  listStr += QStringLiteral( " " );
1028  listStr += QStringLiteral( "]" );
1029  return listStr;
1030  }
1031  else
1032  {
1033  return value.toString();
1034  }
1035 }
1036 
1037 QString QgsExpression::createFieldEqualityExpression( const QString &fieldName, const QVariant &value )
1038 {
1039  QString expr;
1040 
1041  if ( value.isNull() )
1042  expr = QStringLiteral( "%1 IS NULL" ).arg( quotedColumnRef( fieldName ) );
1043  else
1044  expr = QStringLiteral( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value ) );
1045 
1046  return expr;
1047 }
1048 
1050 {
1051  return d->mRootNode;
1052 }
1053 
1055 {
1056  return d->mRootNode && d->mRootNode->nodeType() == QgsExpressionNode::ntColumnRef;
1057 }
1058 
1059 QList<const QgsExpressionNode *> QgsExpression::nodes() const
1060 {
1061  if ( !d->mRootNode )
1062  return QList<const QgsExpressionNode *>();
1063 
1064  return d->mRootNode->nodes();
1065 }
1066 
1067 
1068 
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
Square millimeters.
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:106
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:1548
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 root node of the expression. Root node is null is parsing has failed.
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:430
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.