30#include <QRegularExpression> 
   38HelpTextHash QgsExpression::sFunctionHelpTexts;
 
   39QRecursiveMutex QgsExpression::sFunctionsMutex;
 
   40QMap< QString, int> QgsExpression::sFunctionIndexMap;
 
   43HelpTextHash &QgsExpression::functionHelpTexts()
 
   45  return sFunctionHelpTexts;
 
   61  d->mEvalErrorString = QString();
 
   63  d->mIsPrepared = 
false;
 
 
   68  if ( !d->mExp.isNull() )
 
 
   76  return QStringLiteral( 
"\"%1\"" ).arg( name.replace( 
'\"', QLatin1String( 
"\"\"" ) ) );
 
 
   81  text.replace( 
'\'', QLatin1String( 
"''" ) );
 
   82  text.replace( 
'\\', QLatin1String( 
"\\\\" ) );
 
   83  text.replace( 
'\n', QLatin1String( 
"\\n" ) );
 
   84  text.replace( 
'\t', QLatin1String( 
"\\t" ) );
 
   85  return QStringLiteral( 
"'%1'" ).arg( text );
 
 
   96    return QStringLiteral( 
"NULL" );
 
  101    case QVariant::LongLong:
 
  102    case QVariant::Double:
 
  103      return value.toString();
 
  106      return value.toBool() ? QStringLiteral( 
"TRUE" ) : QStringLiteral( 
"FALSE" );
 
  109    case QVariant::StringList:
 
  111      QStringList quotedValues;
 
  112      const QVariantList values = value.toList();
 
  113      quotedValues.reserve( values.count() );
 
  114      for ( 
const QVariant &v : values )
 
  118      return QStringLiteral( 
"array( %1 )" ).arg( quotedValues.join( QLatin1String( 
", " ) ) );
 
  122    case QVariant::String:
 
 
  135  QMutexLocker locker( &sFunctionsMutex );
 
  137  auto it = sFunctionIndexMap.constFind( name );
 
  138  if ( it != sFunctionIndexMap.constEnd() )
 
  145    if ( QString::compare( name, function->name(), Qt::CaseInsensitive ) == 0 )
 
  147      sFunctionIndexMap.insert( name, i );
 
  150    const QStringList aliases = function->aliases();
 
  151    for ( 
const QString &alias : aliases )
 
  153      if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
 
  155        sFunctionIndexMap.insert( name, i );
 
 
  171  : d( new QgsExpressionPrivate )
 
  173  d->mRootNode = 
::parseExpression( expr, d->mParserErrorString, d->mParserErrors );
 
  175  Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
 
 
  186  if ( 
this != &other )
 
  188    if ( !d->ref.deref() )
 
 
  199QgsExpression::operator QString()
 const 
 
  205  : d( new QgsExpressionPrivate )
 
 
  212  if ( !d->ref.deref() )
 
 
  218  return ( d == other.d || d->mExp == other.d->mExp );
 
 
  228  return d->mParserErrors.count() > 0;
 
 
  233  return d->mParserErrorString;
 
 
  238  return d->mParserErrors;
 
 
  244    return QSet<QString>();
 
  246  return d->mRootNode->referencedColumns();
 
 
  252    return QSet<QString>();
 
  254  return d->mRootNode->referencedVariables();
 
 
  260    return QSet<QString>();
 
  262  return d->mRootNode->referencedFunctions();
 
 
  270  const QSet<QString> referencedFields = d->mRootNode->referencedColumns();
 
  271  QSet<int> referencedIndexes;
 
  273  for ( 
const QString &fieldName : referencedFields )
 
  278      referencedIndexes = QSet<int>( attributesList.begin(), attributesList.end() );
 
  284      referencedIndexes << idx;
 
  288  return referencedIndexes;
 
 
  295  return d->mRootNode->needsGeometry();
 
 
  301  if ( context && ! d->mCalc )
 
  305    d->mDaEllipsoid = context->
variable( QStringLiteral( 
"project_ellipsoid" ) ).toString();
 
  306    d->mDaCrs = std::make_unique<QgsCoordinateReferenceSystem>( context->
variable( QStringLiteral( 
"_layer_crs" ) ).value<QgsCoordinateReferenceSystem>() );
 
  307    d->mDaTransformContext = std::make_unique<QgsCoordinateTransformContext>( context->
variable( QStringLiteral( 
"_project_transform_context" ) ).value<QgsCoordinateTransformContext>() );
 
  313    QString distanceUnitsStr = context->
variable( QStringLiteral( 
"project_distance_units" ) ).toString();
 
  314    if ( ! distanceUnitsStr.isEmpty() )
 
  321    QString areaUnitsStr = context->
variable( QStringLiteral( 
"project_area_units" ) ).toString();
 
  322    if ( ! areaUnitsStr.isEmpty() )
 
  327void QgsExpression::detach()
 
  333    ( void )d->ref.deref();
 
  335    d = 
new QgsExpressionPrivate( *d );
 
  343    d->mCalc = std::shared_ptr<QgsDistanceArea>( 
new QgsDistanceArea( *calc ) );
 
 
  351  d->mEvalErrorString = QString();
 
  357    d->mRootNode = 
::parseExpression( d->mExp, d->mParserErrorString, d->mParserErrors );
 
  362    d->mEvalErrorString = tr( 
"No root node! Parsing failed?" );
 
  366  initGeomCalculator( context );
 
  367  d->mIsPrepared = 
true;
 
  368  return d->mRootNode->prepare( 
this, context );
 
 
  373  d->mEvalErrorString = QString();
 
  376    d->mEvalErrorString = tr( 
"No root node! Parsing failed?" );
 
 
  385  d->mEvalErrorString = QString();
 
  388    d->mEvalErrorString = tr( 
"No root node! Parsing failed?" );
 
  392  if ( ! d->mIsPrepared )
 
  396  return d->mRootNode->eval( 
this, context );
 
 
  401  return !d->mEvalErrorString.isNull();
 
 
  406  return d->mEvalErrorString;
 
 
  411  d->mEvalErrorString = 
str;
 
 
  419  return d->mRootNode->dump();
 
 
  424  if ( !d->mCalc && d->mDaCrs && d->mDaCrs->isValid() && d->mDaTransformContext )
 
  428    d->mCalc->setEllipsoid( d->mDaEllipsoid.isEmpty() ? 
geoNone() : d->mDaEllipsoid );
 
  429    d->mCalc->setSourceCrs( *d->mDaCrs.get(), *d->mDaTransformContext.get() );
 
  432  return d->mCalc.get();
 
 
  437  return d->mDistanceUnit;
 
 
  442  d->mDistanceUnit = unit;
 
 
  460  while ( index < action.size() )
 
  462    static const QRegularExpression sRegEx{ QStringLiteral( 
"\\[%(.*?)%\\]" ),  QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption };
 
  464    const QRegularExpressionMatch match = sRegEx.match( action, index );
 
  465    if ( !match.hasMatch() )
 
  468    const int pos = action.indexOf( sRegEx, index );
 
  469    const int start = index;
 
  470    index = pos + match.capturedLength( 0 );
 
  471    const QString toReplace = match.captured( 1 ).trimmed();
 
  478#if QT_VERSION < QT_VERSION_CHECK(5, 15, 2) 
  479      expr_action += action.midRef( start, index - start );
 
  481      expr_action += QStringView {action} .mid( start, index - start );
 
  492    QVariant result = exp.
evaluate( context );
 
  497#if QT_VERSION < QT_VERSION_CHECK(5, 15, 2) 
  498      expr_action += action.midRef( start, index - start );
 
  500      expr_action += QStringView {action} .mid( start, index - start );
 
  506    expr_action += action.mid( start, pos - start ) + result.toString();
 
  509#if QT_VERSION < QT_VERSION_CHECK(5, 15, 2) 
  510  expr_action += action.midRef( index );
 
  512  expr_action += QStringView {action} .mid( index ).toString();
 
 
  520  QSet<QString> variables;
 
  522  while ( index < text.size() )
 
  524    const thread_local QRegularExpression rx( 
"\\[%([^\\]]+)%\\]" );
 
  525    const QRegularExpressionMatch match = rx.match( text );
 
  526    if ( !match.hasMatch() )
 
  529    index = match.capturedStart() + match.capturedLength();
 
  530    QString to_replace = match.captured( 1 ).trimmed();
 
 
  545  double convertedValue = QLocale().toDouble( text, &ok );
 
  548    return convertedValue;
 
  558  QVariant result = expr.
evaluate( &context );
 
  559  convertedValue = result.toDouble( &ok );
 
  562    return fallbackValue;
 
  564  return convertedValue;
 
 
  569  QgsExpression::initFunctionHelp();
 
  571  if ( !sFunctionHelpTexts.contains( name ) )
 
  572    return tr( 
"function help for %1 missing" ).arg( name );
 
  574  const Help &f = sFunctionHelpTexts[ name ];
 
  577  if ( f.mType == tr( 
"group" ) )
 
  579    name = 
group( name );
 
  580    name = name.toLower();
 
  583  name = name.toHtmlEscaped();
 
  585  QString helpContents( QStringLiteral( 
"<h3>%1</h3>\n<div class=\"description\"><p>%2</p></div>" )
 
  586                        .arg( tr( 
"%1 %2" ).arg( f.mType, name ),
 
  589  for ( 
const HelpVariant &v : std::as_const( f.mVariants ) )
 
  591    if ( f.mVariants.size() > 1 )
 
  593      helpContents += QStringLiteral( 
"<h3>%1</h3>\n<div class=\"description\">%2</p></div>" ).arg( v.mName, v.mDescription );
 
  596    if ( f.mType != tr( 
"group" ) && f.mType != tr( 
"expression" ) )
 
  597      helpContents += QStringLiteral( 
"<h4>%1</h4>\n<div class=\"syntax\">\n" ).arg( tr( 
"Syntax" ) );
 
  599    if ( f.mType == tr( 
"operator" ) )
 
  601      if ( v.mArguments.size() == 1 )
 
  603        helpContents += QStringLiteral( 
"<code><span class=\"functionname\">%1</span> <span class=\"argument\">%2</span></code>" )
 
  604                        .arg( name, v.mArguments[0].mArg );
 
  606      else if ( v.mArguments.size() == 2 )
 
  608        helpContents += QStringLiteral( 
"<code><span class=\"argument\">%1</span> <span class=\"functionname\">%2</span> <span class=\"argument\">%3</span></code>" )
 
  609                        .arg( v.mArguments[0].mArg, name, v.mArguments[1].mArg );
 
  612    else if ( f.mType != tr( 
"group" ) && f.mType != tr( 
"expression" ) )
 
  614      helpContents += QStringLiteral( 
"<code><span class=\"functionname\">%1</span>" ).arg( name );
 
  616      bool hasOptionalArgs = 
false;
 
  618      if ( f.mType == tr( 
"function" ) && ( f.mName[0] != 
'$' || !v.mArguments.isEmpty() || v.mVariableLenArguments ) )
 
  623        for ( 
const HelpArg &a : std::as_const( v.mArguments ) )
 
  629              hasOptionalArgs = 
true;
 
  630              helpContents += QLatin1Char( 
'[' );
 
  633            helpContents += delim;
 
  634            helpContents += QStringLiteral( 
"<span class=\"argument\">%2%3</span>" ).arg(
 
  636                              a.mDefaultVal.isEmpty() ? QString() : 
":=" + a.mDefaultVal
 
  640              helpContents += QLatin1Char( 
']' );
 
  642          delim = QStringLiteral( 
"," );
 
  645        if ( v.mVariableLenArguments )
 
  647          helpContents += QChar( 0x2026 );
 
  653      helpContents += QLatin1String( 
"</code>" );
 
  655      if ( hasOptionalArgs )
 
  657        helpContents += QLatin1String( 
"<br/><br/>" ) + tr( 
"[ ] marks optional components" );
 
  661    if ( !v.mArguments.isEmpty() )
 
  663      helpContents += QStringLiteral( 
"<h4>%1</h4>\n<div class=\"arguments\">\n<table>" ).arg( tr( 
"Arguments" ) );
 
  665      for ( 
const HelpArg &a : std::as_const( v.mArguments ) )
 
  670        helpContents += QStringLiteral( 
"<tr><td class=\"argument\">%1</td><td>%2</td></tr>" ).arg( a.mArg, a.mDescription );
 
  673      helpContents += QLatin1String( 
"</table>\n</div>\n" );
 
  676    if ( !v.mExamples.isEmpty() )
 
  678      helpContents += QStringLiteral( 
"<h4>%1</h4>\n<div class=\"examples\">\n<ul>\n" ).arg( tr( 
"Examples" ) );
 
  680      for ( 
const HelpExample &e : std::as_const( v.mExamples ) )
 
  682        helpContents += 
"<li><code>" + e.mExpression + 
"</code> → <code>" + e.mReturns + 
"</code>";
 
  684        if ( !e.mNote.isEmpty() )
 
  685          helpContents += QStringLiteral( 
" (%1)" ).arg( e.mNote );
 
  687        helpContents += QLatin1String( 
"</li>\n" );
 
  690      helpContents += QLatin1String( 
"</ul>\n</div>\n" );
 
  693    if ( !v.mNotes.isEmpty() )
 
  695      helpContents += QStringLiteral( 
"<h4>%1</h4>\n<div class=\"notes\"><p>%2</p></div>\n" ).arg( tr( 
"Notes" ), v.mNotes );
 
 
  704  QStringList 
tags = QStringList();
 
  706  QgsExpression::initFunctionHelp();
 
  708  if ( sFunctionHelpTexts.contains( name ) )
 
  710    const Help &f = sFunctionHelpTexts[ name ];
 
  712    for ( 
const HelpVariant &v : std::as_const( f.mVariants ) )
 
 
  721void QgsExpression::initVariableHelp()
 
  723  if ( !sVariableHelpTexts()->isEmpty() )
 
  727  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_version" ), QCoreApplication::translate( 
"variable_help", 
"Current QGIS version string." ) );
 
  728  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_version_no" ), QCoreApplication::translate( 
"variable_help", 
"Current QGIS version number." ) );
 
  729  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_release_name" ), QCoreApplication::translate( 
"variable_help", 
"Current QGIS release name." ) );
 
  730  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_short_version" ), QCoreApplication::translate( 
"variable_help", 
"Short QGIS version string." ) );
 
  731  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_os_name" ), QCoreApplication::translate( 
"variable_help", 
"Operating system name, e.g., 'windows', 'linux' or 'osx'." ) );
 
  732  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_platform" ), QCoreApplication::translate( 
"variable_help", 
"QGIS platform, e.g., 'desktop' or 'server'." ) );
 
  733  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_locale" ), QCoreApplication::translate( 
"variable_help", 
"Two letter identifier for current QGIS locale." ) );
 
  734  sVariableHelpTexts()->insert( QStringLiteral( 
"user_account_name" ), QCoreApplication::translate( 
"variable_help", 
"Current user's operating system account name." ) );
 
  735  sVariableHelpTexts()->insert( QStringLiteral( 
"user_full_name" ), QCoreApplication::translate( 
"variable_help", 
"Current user's operating system user name (if available)." ) );
 
  738  sVariableHelpTexts()->insert( QStringLiteral( 
"project_title" ), QCoreApplication::translate( 
"variable_help", 
"Title of current project." ) );
 
  739  sVariableHelpTexts()->insert( QStringLiteral( 
"project_path" ), QCoreApplication::translate( 
"variable_help", 
"Full path (including file name) of current project." ) );
 
  740  sVariableHelpTexts()->insert( QStringLiteral( 
"project_folder" ), QCoreApplication::translate( 
"variable_help", 
"Folder for current project." ) );
 
  741  sVariableHelpTexts()->insert( QStringLiteral( 
"project_filename" ), QCoreApplication::translate( 
"variable_help", 
"Filename of current project." ) );
 
  742  sVariableHelpTexts()->insert( QStringLiteral( 
"project_basename" ), QCoreApplication::translate( 
"variable_help", 
"Base name of current project's filename (without path and extension)." ) );
 
  743  sVariableHelpTexts()->insert( QStringLiteral( 
"project_home" ), QCoreApplication::translate( 
"variable_help", 
"Home path of current project." ) );
 
  744  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs" ), QCoreApplication::translate( 
"variable_help", 
"Coordinate reference system of project (e.g., 'EPSG:4326')." ) );
 
  745  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_definition" ), QCoreApplication::translate( 
"variable_help", 
"Coordinate reference system of project (full definition)." ) );
 
  746  sVariableHelpTexts()->insert( QStringLiteral( 
"project_units" ), QCoreApplication::translate( 
"variable_help", 
"Unit of the project's CRS." ) );
 
  747  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_description" ), QCoreApplication::translate( 
"variable_help", 
"Name of the coordinate reference system of the project." ) );
 
  748  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_acronym" ), QCoreApplication::translate( 
"variable_help", 
"Acronym of the coordinate reference system of the project." ) );
 
  749  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_ellipsoid" ), QCoreApplication::translate( 
"variable_help", 
"Acronym of the ellipsoid of the coordinate reference system of the project." ) );
 
  750  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_proj4" ), QCoreApplication::translate( 
"variable_help", 
"Proj4 definition of the coordinate reference system of the project." ) );
 
  751  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_wkt" ), QCoreApplication::translate( 
"variable_help", 
"WKT definition of the coordinate reference system of the project." ) );
 
  752  sVariableHelpTexts()->insert( QStringLiteral( 
"project_author" ), QCoreApplication::translate( 
"variable_help", 
"Project author, taken from project metadata." ) );
 
  753  sVariableHelpTexts()->insert( QStringLiteral( 
"project_abstract" ), QCoreApplication::translate( 
"variable_help", 
"Project abstract, taken from project metadata." ) );
 
  754  sVariableHelpTexts()->insert( QStringLiteral( 
"project_creation_date" ), QCoreApplication::translate( 
"variable_help", 
"Project creation date, taken from project metadata." ) );
 
  755  sVariableHelpTexts()->insert( QStringLiteral( 
"project_identifier" ), QCoreApplication::translate( 
"variable_help", 
"Project identifier, taken from project metadata." ) );
 
  756  sVariableHelpTexts()->insert( QStringLiteral( 
"project_last_saved" ), QCoreApplication::translate( 
"variable_help", 
"Date/time when project was last saved." ) );
 
  757  sVariableHelpTexts()->insert( QStringLiteral( 
"project_keywords" ), QCoreApplication::translate( 
"variable_help", 
"Project keywords, taken from project metadata." ) );
 
  758  sVariableHelpTexts()->insert( QStringLiteral( 
"project_area_units" ), QCoreApplication::translate( 
"variable_help", 
"Area unit for current project, used when calculating areas of geometries." ) );
 
  759  sVariableHelpTexts()->insert( QStringLiteral( 
"project_distance_units" ), QCoreApplication::translate( 
"variable_help", 
"Distance unit for current project, used when calculating lengths of geometries." ) );
 
  760  sVariableHelpTexts()->insert( QStringLiteral( 
"project_ellipsoid" ), QCoreApplication::translate( 
"variable_help", 
"Name of ellipsoid of current project, used when calculating geodetic areas and lengths of geometries." ) );
 
  761  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_ids" ), QCoreApplication::translate( 
"variable_help", 
"List of all map layer IDs from the current project." ) );
 
  762  sVariableHelpTexts()->insert( QStringLiteral( 
"layers" ), QCoreApplication::translate( 
"variable_help", 
"List of all map layers from the current project." ) );
 
  765  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_name" ), QCoreApplication::translate( 
"variable_help", 
"Name of current layer." ) );
 
  766  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_id" ), QCoreApplication::translate( 
"variable_help", 
"ID of current layer." ) );
 
  767  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_crs" ), QCoreApplication::translate( 
"variable_help", 
"CRS Authority ID of current layer." ) );
 
  768  sVariableHelpTexts()->insert( QStringLiteral( 
"layer" ), QCoreApplication::translate( 
"variable_help", 
"The current layer." ) );
 
  769  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_crs_ellipsoid" ), QCoreApplication::translate( 
"variable_help", 
"Ellipsoid acronym of current layer CRS." ) );
 
  772  sVariableHelpTexts()->insert( QStringLiteral( 
"feature" ), QCoreApplication::translate( 
"variable_help", 
"The current feature being evaluated. This can be used with the 'attribute' function to evaluate attribute values from the current feature." ) );
 
  773  sVariableHelpTexts()->insert( QStringLiteral( 
"id" ), QCoreApplication::translate( 
"variable_help", 
"The ID of the current feature being evaluated." ) );
 
  774  sVariableHelpTexts()->insert( QStringLiteral( 
"geometry" ), QCoreApplication::translate( 
"variable_help", 
"The geometry of the current feature being evaluated." ) );
 
  777  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_name" ), QCoreApplication::translate( 
"variable_help", 
"Name of composition." ) );
 
  778  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_numpages" ), QCoreApplication::translate( 
"variable_help", 
"Number of pages in composition." ) );
 
  779  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_page" ), QCoreApplication::translate( 
"variable_help", 
"Current page number in composition." ) );
 
  780  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_pageheight" ), QCoreApplication::translate( 
"variable_help", 
"Composition page height in mm (or specified custom units)." ) );
 
  781  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_pagewidth" ), QCoreApplication::translate( 
"variable_help", 
"Composition page width in mm (or specified custom units)." ) );
 
  782  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_pageoffsets" ), QCoreApplication::translate( 
"variable_help", 
"Array of Y coordinate of the top of each page." ) );
 
  783  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_dpi" ), QCoreApplication::translate( 
"variable_help", 
"Composition resolution (DPI)." ) );
 
  786  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_layerid" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas coverage layer ID." ) );
 
  787  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_layername" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas coverage layer name." ) );
 
  788  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_totalfeatures" ), QCoreApplication::translate( 
"variable_help", 
"Total number of features in atlas." ) );
 
  789  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_featurenumber" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas feature number." ) );
 
  790  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_filename" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas file name." ) );
 
  791  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_pagename" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas page name." ) );
 
  792  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_feature" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas feature (as feature object)." ) );
 
  793  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_featureid" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas feature ID." ) );
 
  794  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_geometry" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas feature geometry." ) );
 
  797  sVariableHelpTexts()->insert( QStringLiteral( 
"item_id" ), QCoreApplication::translate( 
"variable_help", 
"Layout item user-assigned ID (not necessarily unique)." ) );
 
  798  sVariableHelpTexts()->insert( QStringLiteral( 
"item_uuid" ), QCoreApplication::translate( 
"variable_help", 
"layout item unique ID." ) );
 
  799  sVariableHelpTexts()->insert( QStringLiteral( 
"item_left" ), QCoreApplication::translate( 
"variable_help", 
"Left position of layout item (in mm)." ) );
 
  800  sVariableHelpTexts()->insert( QStringLiteral( 
"item_top" ), QCoreApplication::translate( 
"variable_help", 
"Top position of layout item (in mm)." ) );
 
  801  sVariableHelpTexts()->insert( QStringLiteral( 
"item_width" ), QCoreApplication::translate( 
"variable_help", 
"Width of layout item (in mm)." ) );
 
  802  sVariableHelpTexts()->insert( QStringLiteral( 
"item_height" ), QCoreApplication::translate( 
"variable_help", 
"Height of layout item (in mm)." ) );
 
  805  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." ) );
 
  806  sVariableHelpTexts()->insert( QStringLiteral( 
"map_rotation" ), QCoreApplication::translate( 
"variable_help", 
"Current rotation of map." ) );
 
  807  sVariableHelpTexts()->insert( QStringLiteral( 
"map_scale" ), QCoreApplication::translate( 
"variable_help", 
"Current scale of map." ) );
 
  808  sVariableHelpTexts()->insert( QStringLiteral( 
"map_extent" ), QCoreApplication::translate( 
"variable_help", 
"Geometry representing the current extent of the map." ) );
 
  809  sVariableHelpTexts()->insert( QStringLiteral( 
"map_extent_center" ), QCoreApplication::translate( 
"variable_help", 
"Center of map." ) );
 
  810  sVariableHelpTexts()->insert( QStringLiteral( 
"map_extent_width" ), QCoreApplication::translate( 
"variable_help", 
"Width of map." ) );
 
  811  sVariableHelpTexts()->insert( QStringLiteral( 
"map_extent_height" ), QCoreApplication::translate( 
"variable_help", 
"Height of map." ) );
 
  812  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs" ), QCoreApplication::translate( 
"variable_help", 
"Coordinate reference system of map (e.g., 'EPSG:4326')." ) );
 
  813  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_description" ), QCoreApplication::translate( 
"variable_help", 
"Name of the coordinate reference system of the map." ) );
 
  814  sVariableHelpTexts()->insert( QStringLiteral( 
"map_units" ), QCoreApplication::translate( 
"variable_help", 
"Units for map measurements." ) );
 
  815  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_definition" ), QCoreApplication::translate( 
"variable_help", 
"Coordinate reference system of the map (full definition)." ) );
 
  816  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_acronym" ), QCoreApplication::translate( 
"variable_help", 
"Acronym of the coordinate reference system of the map." ) );
 
  817  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_projection" ), QCoreApplication::translate( 
"variable_help", 
"Projection method used by the coordinate reference system of the map." ) );
 
  818  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_ellipsoid" ), QCoreApplication::translate( 
"variable_help", 
"Acronym of the ellipsoid of the coordinate reference system of the map." ) );
 
  819  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_proj4" ), QCoreApplication::translate( 
"variable_help", 
"Proj4 definition of the coordinate reference system of the map." ) );
 
  820  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_wkt" ), QCoreApplication::translate( 
"variable_help", 
"WKT definition of the coordinate reference system of the map." ) );
 
  821  sVariableHelpTexts()->insert( QStringLiteral( 
"map_layer_ids" ), QCoreApplication::translate( 
"variable_help", 
"List of map layer IDs visible in the map." ) );
 
  822  sVariableHelpTexts()->insert( QStringLiteral( 
"map_layers" ), QCoreApplication::translate( 
"variable_help", 
"List of map layers visible in the map." ) );
 
  824  sVariableHelpTexts()->insert( QStringLiteral( 
"map_start_time" ), QCoreApplication::translate( 
"variable_help", 
"Start of the map's temporal time range (as a datetime value)" ) );
 
  825  sVariableHelpTexts()->insert( QStringLiteral( 
"map_end_time" ), QCoreApplication::translate( 
"variable_help", 
"End of the map's temporal time range (as a datetime value)" ) );
 
  826  sVariableHelpTexts()->insert( QStringLiteral( 
"map_interval" ), QCoreApplication::translate( 
"variable_help", 
"Duration of the map's temporal time range (as an interval value)" ) );
 
  828  sVariableHelpTexts()->insert( QStringLiteral( 
"frame_rate" ), QCoreApplication::translate( 
"variable_help", 
"Number of frames per second during animation playback" ) );
 
  829  sVariableHelpTexts()->insert( QStringLiteral( 
"frame_number" ), QCoreApplication::translate( 
"variable_help", 
"Current frame number during animation playback" ) );
 
  830  sVariableHelpTexts()->insert( QStringLiteral( 
"frame_duration" ), QCoreApplication::translate( 
"variable_help", 
"Temporal duration of each animation frame (as an interval value)" ) );
 
  831  sVariableHelpTexts()->insert( QStringLiteral( 
"frame_timestep" ), QCoreApplication::translate( 
"variable_help", 
"Frame time step during animation playback" ) );
 
  832  sVariableHelpTexts()->insert( QStringLiteral( 
"frame_timestep_unit" ), QCoreApplication::translate( 
"variable_help", 
"Unit value of the frame time step during animation playback" ) );
 
  833  sVariableHelpTexts()->insert( QStringLiteral( 
"frame_timestep_units" ), QCoreApplication::translate( 
"variable_help", 
"String representation of the frame time step unit during animation playback" ) );
 
  834  sVariableHelpTexts()->insert( QStringLiteral( 
"animation_start_time" ), QCoreApplication::translate( 
"variable_help", 
"Start of the animation's overall temporal time range (as a datetime value)" ) );
 
  835  sVariableHelpTexts()->insert( QStringLiteral( 
"animation_end_time" ), QCoreApplication::translate( 
"variable_help", 
"End of the animation's overall temporal time range (as a datetime value)" ) );
 
  836  sVariableHelpTexts()->insert( QStringLiteral( 
"animation_interval" ), QCoreApplication::translate( 
"variable_help", 
"Duration of the animation's overall temporal time range (as an interval value)" ) );
 
  839  sVariableHelpTexts()->insert( QStringLiteral( 
"zoom_level" ), QCoreApplication::translate( 
"variable_help", 
"Vector tile zoom level of the map that is being rendered (derived from the current map scale). Normally in interval [0, 20]." ) );
 
  840  sVariableHelpTexts()->insert( QStringLiteral( 
"vector_tile_zoom" ), QCoreApplication::translate( 
"variable_help", 
"Exact vector tile zoom level of the map that is being rendered (derived from the current map scale). Normally in interval [0, 20]. Unlike @zoom_level, this variable is a floating point value which can be used to interpolate values between two integer zoom levels." ) );
 
  842  sVariableHelpTexts()->insert( QStringLiteral( 
"row_number" ), QCoreApplication::translate( 
"variable_help", 
"Stores the number of the current row." ) );
 
  843  sVariableHelpTexts()->insert( QStringLiteral( 
"grid_number" ), QCoreApplication::translate( 
"variable_help", 
"Current grid annotation value." ) );
 
  844  sVariableHelpTexts()->insert( QStringLiteral( 
"grid_axis" ), QCoreApplication::translate( 
"variable_help", 
"Current grid annotation axis (e.g., 'x' for longitude, 'y' for latitude)." ) );
 
  845  sVariableHelpTexts()->insert( QStringLiteral( 
"column_number" ), QCoreApplication::translate( 
"variable_help", 
"Stores the number of the current column." ) );
 
  848  sVariableHelpTexts()->insert( QStringLiteral( 
"canvas_cursor_point" ), QCoreApplication::translate( 
"variable_help", 
"Last cursor position on the canvas in the project's geographical coordinates." ) );
 
  849  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_cursor_point" ), QCoreApplication::translate( 
"variable_help", 
"Last cursor position on the canvas in the current layers's geographical coordinates." ) );
 
  852  sVariableHelpTexts()->insert( QStringLiteral( 
"legend_title" ), QCoreApplication::translate( 
"variable_help", 
"Title of the legend." ) );
 
  853  sVariableHelpTexts()->insert( QStringLiteral( 
"legend_column_count" ), QCoreApplication::translate( 
"variable_help", 
"Number of column in the legend." ) );
 
  854  sVariableHelpTexts()->insert( QStringLiteral( 
"legend_split_layers" ), QCoreApplication::translate( 
"variable_help", 
"Boolean indicating if layers can be split in the legend." ) );
 
  855  sVariableHelpTexts()->insert( QStringLiteral( 
"legend_wrap_string" ), QCoreApplication::translate( 
"variable_help", 
"Characters used to wrap the legend text." ) );
 
  856  sVariableHelpTexts()->insert( QStringLiteral( 
"legend_filter_by_map" ), QCoreApplication::translate( 
"variable_help", 
"Boolean indicating if the content of the legend is filtered by the map." ) );
 
  857  sVariableHelpTexts()->insert( QStringLiteral( 
"legend_filter_out_atlas" ), QCoreApplication::translate( 
"variable_help", 
"Boolean indicating if the Atlas is filtered out of the legend." ) );
 
  860  sVariableHelpTexts()->insert( QStringLiteral( 
"scale_value" ), QCoreApplication::translate( 
"variable_help", 
"Current scale bar distance value." ) );
 
  863  sVariableHelpTexts()->insert( QStringLiteral( 
"snapping_results" ), QCoreApplication::translate( 
"variable_help",
 
  864                                "<p>An array with an item for each snapped point.</p>" 
  865                                "<p>Each item is a map with the following keys:</p>" 
  867                                "<dt>valid</dt><dd>Boolean that indicates if the snapping result is valid</dd>" 
  868                                "<dt>layer</dt><dd>The layer on which the snapped feature is</dd>" 
  869                                "<dt>feature_id</dt><dd>The feature id of the snapped feature</dd>" 
  870                                "<dt>vertex_index</dt><dd>The index of the snapped vertex</dd>" 
  871                                "<dt>distance</dt><dd>The distance between the mouse cursor and the snapped point at the time of snapping</dd>" 
  876  sVariableHelpTexts()->insert( QStringLiteral( 
"geometry_part_count" ), QCoreApplication::translate( 
"variable_help", 
"Number of parts in rendered feature's geometry." ) );
 
  877  sVariableHelpTexts()->insert( QStringLiteral( 
"geometry_part_num" ), QCoreApplication::translate( 
"variable_help", 
"Current geometry part number for feature being rendered." ) );
 
  878  sVariableHelpTexts()->insert( QStringLiteral( 
"geometry_ring_num" ), QCoreApplication::translate( 
"variable_help", 
"Current geometry ring number for feature being rendered (for polygon features only). The exterior ring has a value of 0." ) );
 
  879  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." ) );
 
  880  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." ) );
 
  882  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_color" ), QCoreApplication::translate( 
"symbol_color", 
"Color of symbol used to render the feature." ) );
 
  883  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_angle" ), QCoreApplication::translate( 
"symbol_angle", 
"Angle of symbol used to render the feature (valid for marker symbols only)." ) );
 
  884  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_layer_count" ), QCoreApplication::translate( 
"symbol_layer_count", 
"Total number of symbol layers in the symbol." ) );
 
  885  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_layer_index" ), QCoreApplication::translate( 
"symbol_layer_index", 
"Current symbol layer index." ) );
 
  886  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_marker_row" ), QCoreApplication::translate( 
"symbol_marker_row", 
"Row number for marker (valid for point pattern fills only)." ) );
 
  887  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_marker_column" ), QCoreApplication::translate( 
"symbol_marker_column", 
"Column number for marker (valid for point pattern fills only)." ) );
 
  888  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_frame" ), QCoreApplication::translate( 
"symbol_frame", 
"Frame number (for animated symbols only)." ) );
 
  890  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_label" ), QCoreApplication::translate( 
"symbol_label", 
"Label for the symbol (either a user defined label or the default autogenerated label)." ) );
 
  891  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_id" ), QCoreApplication::translate( 
"symbol_id", 
"Internal ID of the symbol." ) );
 
  892  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_count" ), QCoreApplication::translate( 
"symbol_count", 
"Total number of features represented by the symbol." ) );
 
  895  sVariableHelpTexts()->insert( QStringLiteral( 
"cluster_color" ), QCoreApplication::translate( 
"cluster_color", 
"Color of symbols within a cluster, or NULL if symbols have mixed colors." ) );
 
  896  sVariableHelpTexts()->insert( QStringLiteral( 
"cluster_size" ), QCoreApplication::translate( 
"cluster_size", 
"Number of symbols contained within a cluster." ) );
 
  899  sVariableHelpTexts()->insert( QStringLiteral( 
"algorithm_id" ), QCoreApplication::translate( 
"algorithm_id", 
"Unique ID for algorithm." ) );
 
  900  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)." ) );
 
  901  sVariableHelpTexts()->insert( QStringLiteral( 
"model_folder" ), QCoreApplication::translate( 
"variable_help", 
"Folder containing current model (or project folder if model is embedded in a project)." ) );
 
  902  sVariableHelpTexts()->insert( QStringLiteral( 
"model_name" ), QCoreApplication::translate( 
"variable_help", 
"Name of current model." ) );
 
  903  sVariableHelpTexts()->insert( QStringLiteral( 
"model_group" ), QCoreApplication::translate( 
"variable_help", 
"Group for current model." ) );
 
  904  sVariableHelpTexts()->insert( QStringLiteral( 
"fullextent_minx" ), QCoreApplication::translate( 
"fullextent_minx", 
"Minimum x-value from full canvas extent (including all layers)." ) );
 
  905  sVariableHelpTexts()->insert( QStringLiteral( 
"fullextent_miny" ), QCoreApplication::translate( 
"fullextent_miny", 
"Minimum y-value from full canvas extent (including all layers)." ) );
 
  906  sVariableHelpTexts()->insert( QStringLiteral( 
"fullextent_maxx" ), QCoreApplication::translate( 
"fullextent_maxx", 
"Maximum x-value from full canvas extent (including all layers)." ) );
 
  907  sVariableHelpTexts()->insert( QStringLiteral( 
"fullextent_maxy" ), QCoreApplication::translate( 
"fullextent_maxy", 
"Maximum y-value from full canvas extent (including all layers)." ) );
 
  910  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)." ) );
 
  913  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." ) );
 
  914  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." ) );
 
  917  sVariableHelpTexts()->insert( QStringLiteral( 
"current_parent_geometry" ), QCoreApplication::translate( 
"current_parent_geometry",
 
  918                                "Only usable in an embedded form context, " 
  919                                "represents the geometry of the feature currently being edited in the parent form.\n" 
  920                                "Can be used in a form/row context to filter the related features using a value " 
  921                                "from the feature currently edited in the parent form, to make sure that the filter " 
  922                                "still works with standalone forms it is recommended to wrap this variable in a " 
  924  sVariableHelpTexts()->insert( QStringLiteral( 
"current_parent_feature" ), QCoreApplication::translate( 
"current_parent_feature",
 
  925                                "Only usable in an embedded form context, " 
  926                                "represents the feature currently being edited in the parent form.\n" 
  927                                "Can be used in a form/row context to filter the related features using a value " 
  928                                "from the feature currently edited in the parent form, to make sure that the filter " 
  929                                "still works with standalone forms it is recommended to wrap this variable in a " 
  933  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." ) );
 
  936  sVariableHelpTexts()->insert( QStringLiteral( 
"plot_axis" ), QCoreApplication::translate( 
"plot_axis", 
"The associated plot axis, e.g. 'x' or 'y'." ) );
 
  937  sVariableHelpTexts()->insert( QStringLiteral( 
"plot_axis_value" ), QCoreApplication::translate( 
"plot_axis_value", 
"The current value for the plot axis." ) );
 
  943  if ( sVariableHelpTexts()->contains( name ) )
 
  947  sVariableHelpTexts()->insert( name, description );
 
 
  953  QgsExpression::initVariableHelp();
 
  954  return sVariableHelpTexts()->value( variableName, QString() );
 
 
  959  QString text = !description.isEmpty() ? QStringLiteral( 
"<p>%1</p>" ).arg( description ) : QString();
 
  963    if ( !value.isValid() )
 
  965      valueString = QCoreApplication::translate( 
"variable_help", 
"not set" );
 
  971    text.append( QCoreApplication::translate( 
"variable_help", 
"<p>Current value: %1</p>" ).arg( valueString ) );
 
 
  978  if ( sGroups()->isEmpty() )
 
  980    sGroups()->insert( QStringLiteral( 
"Aggregates" ), tr( 
"Aggregates" ) );
 
  981    sGroups()->insert( QStringLiteral( 
"Arrays" ), tr( 
"Arrays" ) );
 
  982    sGroups()->insert( QStringLiteral( 
"Color" ), tr( 
"Color" ) );
 
  983    sGroups()->insert( QStringLiteral( 
"Conditionals" ), tr( 
"Conditionals" ) );
 
  984    sGroups()->insert( QStringLiteral( 
"Conversions" ), tr( 
"Conversions" ) );
 
  985    sGroups()->insert( QStringLiteral( 
"Date and Time" ), tr( 
"Date and Time" ) );
 
  986    sGroups()->insert( QStringLiteral( 
"Fields and Values" ), tr( 
"Fields and Values" ) );
 
  987    sGroups()->insert( QStringLiteral( 
"Files and Paths" ), tr( 
"Files and Paths" ) );
 
  988    sGroups()->insert( QStringLiteral( 
"Fuzzy Matching" ), tr( 
"Fuzzy Matching" ) );
 
  989    sGroups()->insert( QStringLiteral( 
"General" ), tr( 
"General" ) );
 
  990    sGroups()->insert( QStringLiteral( 
"GeometryGroup" ), tr( 
"Geometry" ) );
 
  991    sGroups()->insert( QStringLiteral( 
"Map Layers" ), tr( 
"Map Layers" ) );
 
  992    sGroups()->insert( QStringLiteral( 
"Maps" ), tr( 
"Maps" ) );
 
  993    sGroups()->insert( QStringLiteral( 
"Math" ), tr( 
"Math" ) );
 
  994    sGroups()->insert( QStringLiteral( 
"Operators" ), tr( 
"Operators" ) );
 
  995    sGroups()->insert( QStringLiteral( 
"Rasters" ), tr( 
"Rasters" ) );
 
  996    sGroups()->insert( QStringLiteral( 
"Record and Attributes" ), tr( 
"Record and Attributes" ) );
 
  997    sGroups()->insert( QStringLiteral( 
"String" ), tr( 
"String" ) );
 
  998    sGroups()->insert( QStringLiteral( 
"Variables" ), tr( 
"Variables" ) );
 
  999    sGroups()->insert( QStringLiteral( 
"Recent (%1)" ), tr( 
"Recent (%1)" ) );
 
 1000    sGroups()->insert( QStringLiteral( 
"UserGroup" ), tr( 
"User expressions" ) );
 
 1006  return sGroups()->value( name, name );
 
 
 1011  const QString startToken = htmlOutput ? QStringLiteral( 
"<i><" ) : QStringLiteral( 
"<" );
 
 1012  const QString endToken = htmlOutput ? QStringLiteral( 
"></i>" ) : QStringLiteral( 
">" );
 
 1014  if ( value.userType() == QMetaType::type( 
"QgsGeometry" ) )
 
 1019      return startToken + tr( 
"empty geometry" ) + endToken;
 
 1026    return startToken + tr( 
"map layer" ) + endToken;
 
 1028  else if ( !value.isValid() )
 
 1030    return htmlOutput ? tr( 
"<i>NULL</i>" ) : QString();
 
 1032  else if ( value.userType() == QMetaType::type( 
"QgsFeature" ) )
 
 1036    return startToken + tr( 
"feature: %1" ).arg( feat.
id() ) + endToken;
 
 1038  else if ( value.userType() == QMetaType::type( 
"QgsInterval" ) )
 
 1041    if ( interval.
days() > 1 )
 
 1043      return startToken + tr( 
"interval: %1 days" ).arg( interval.
days() ) + endToken;
 
 1045    else if ( interval.
hours() > 1 )
 
 1047      return startToken + tr( 
"interval: %1 hours" ).arg( interval.
hours() ) + endToken;
 
 1049    else if ( interval.
minutes() > 1 )
 
 1051      return startToken + tr( 
"interval: %1 minutes" ).arg( interval.
minutes() ) + endToken;
 
 1055      return startToken + tr( 
"interval: %1 seconds" ).arg( interval.
seconds() ) + endToken;
 
 1058  else if ( value.userType() == QMetaType::type( 
"QgsGradientColorRamp" ) )
 
 1060    return startToken + tr( 
"gradient ramp" ) + endToken;
 
 1062  else if ( value.type() == QVariant::Date )
 
 1064    const QDate dt = value.toDate();
 
 1065    return startToken + tr( 
"date: %1" ).arg( dt.toString( QStringLiteral( 
"yyyy-MM-dd" ) ) ) + endToken;
 
 1067  else if ( value.type() == QVariant::Time )
 
 1069    const QTime tm = value.toTime();
 
 1070    return startToken + tr( 
"time: %1" ).arg( tm.toString( QStringLiteral( 
"hh:mm:ss" ) ) ) + endToken;
 
 1072  else if ( value.type() == QVariant::DateTime )
 
 1074    const QDateTime dt = value.toDateTime();
 
 1075    return startToken + tr( 
"datetime: %1 (%2)" ).arg( dt.toString( QStringLiteral( 
"yyyy-MM-dd hh:mm:ss" ) ), dt.timeZoneAbbreviation() ) + endToken;
 
 1077  else if ( value.type() == QVariant::String )
 
 1079    const QString previewString = value.toString();
 
 1080    if ( previewString.length() > maximumPreviewLength + 3 )
 
 1082      return tr( 
"'%1…'" ).arg( previewString.left( maximumPreviewLength ) );
 
 1086      return '\'' + previewString + 
'\'';
 
 1089  else if ( value.type() == QVariant::Map )
 
 1091    QString mapStr = QStringLiteral( 
"{" );
 
 1092    const QVariantMap map = value.toMap();
 
 1094    for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
 
 1096      mapStr.append( separator );
 
 1097      if ( separator.isEmpty() )
 
 1098        separator = QStringLiteral( 
"," );
 
 1100      mapStr.append( QStringLiteral( 
" '%1': %2" ).arg( it.key(), 
formatPreviewString( it.value(), htmlOutput ) ) );
 
 1101      if ( mapStr.length() > maximumPreviewLength - 3 )
 
 1103        mapStr = tr( 
"%1…" ).arg( mapStr.left( maximumPreviewLength - 2 ) );
 
 1108      mapStr += QLatin1Char( 
' ' );
 
 1109    mapStr += QLatin1Char( 
'}' );
 
 1112  else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
 
 1114    QString listStr = QStringLiteral( 
"[" );
 
 1115    const QVariantList list = value.toList();
 
 1117    for ( 
const QVariant &arrayValue : list )
 
 1119      listStr.append( separator );
 
 1120      if ( separator.isEmpty() )
 
 1121        separator = QStringLiteral( 
"," );
 
 1123      listStr.append( 
" " );
 
 1125      if ( listStr.length() > maximumPreviewLength - 3 )
 
 1127        listStr = QString( tr( 
"%1…" ) ).arg( listStr.left( maximumPreviewLength - 2 ) );
 
 1131    if ( !list.empty() )
 
 1132      listStr += QLatin1Char( 
' ' );
 
 1133    listStr += QLatin1Char( 
']' );
 
 1136  else if ( value.type() == QVariant::Int ||
 
 1137            value.type() == QVariant::UInt ||
 
 1138            value.type() == QVariant::LongLong ||
 
 1139            value.type() == QVariant::ULongLong ||
 
 1140            value.type() == QVariant::Double ||
 
 1142            value.type() == 
static_cast<QVariant::Type
>( QMetaType::Float ) )
 
 1144    return QgsExpressionUtils::toLocalizedString( value );
 
 1148    QString 
str { value.toString() };
 
 1149    if ( 
str.length() > maximumPreviewLength - 3 )
 
 1151      str = tr( 
"%1…" ).arg( 
str.left( maximumPreviewLength - 2 ) );
 
 
 1162    expr = QStringLiteral( 
"%1 IS NULL" ).arg( 
quotedColumnRef( fieldName ) );
 
 1163  else if ( fieldType == QVariant::Type::Invalid )
 
 
 1184      if ( columnRef && literal )
 
 1186        field = columnRef->
name();
 
 1187        value = literal->
value();
 
 
 1197  if ( expressions.empty() )
 
 1203  for ( 
const QString &
expression : expressions )
 
 1214      else if ( field != inField )
 
 1230        if ( inOp->isNotIn() )
 
 1239          inField = columnRef->
name();
 
 1242        else if ( columnRef->
name() != inField )
 
 1249          const QList<QgsExpressionNode *> 
nodes = nodeList->list();
 
 1267          QStringList orParts;
 
 1272              orParts.append( collectOrs( leftOrOp->opLeft(), leftOrOp->opRight() ) );
 
 1276              orParts.append( leftOrOp->dump() );
 
 1281            orParts.append( leftInOp->dump() );
 
 1292              orParts.append( collectOrs( rightOrOp->opLeft(), rightOrOp->opRight() ) );
 
 1296              orParts.append( rightOrOp->dump() );
 
 1301            orParts.append( rightInOp->dump() );
 
 1314          const QStringList orParts = collectOrs( orOp->opLeft(), orOp->opRight() );
 
 1315          if ( orParts.isEmpty() )
 
 1321            QString orPartsResult;
 
 1326              if ( ! inExp.rootNode() )
 
 1338                const QString innerInfield { inOpInner->node()->
referencedColumns().values().first() };
 
 1342                  inField = innerInfield;
 
 1346                if ( innerInfield != inField )
 
 1352                  const auto constInnerValuesList { inOpInner->list()->list() };
 
 1353                  for ( 
const auto &innerInValueNode : std::as_const( constInnerValuesList ) )
 
 1355                    values.append( innerInValueNode->dump() );
 
 1382  result = QStringLiteral( 
"%1 IN (%2)" ).arg( 
quotedColumnRef( inField ), values.join( 
',' ) );
 
 
 1388  return d->mRootNode;
 
 
 1403  if ( attrIndex >= 0 )
 
 1410    const QString fieldName =  qgis::down_cast<const QgsExpressionNodeColumnRef *>( candidate.
rootNode() )->name();
 
 
 1422  if ( !
expression.contains( 
'\"' ) && fieldIndex != -1 )
 
 
 1435  if ( !d->mRootNode )
 
 1436    return QList<const QgsExpressionNode *>();
 
 1438  return d->mRootNode->nodes();
 
 
DistanceUnit
Units of distance.
 
@ Unknown
Unknown distance unit.
 
@ Unknown
Unknown areal unit.
 
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
 
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
 
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
 
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
 
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
 
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
 
A abstract base class for defining QgsExpression functions.
 
A binary expression operator, which operates on two values.
 
An expression node which takes it value from a feature's field.
 
QString name() const
The name of the column.
 
An expression node for value IN or NOT IN clauses.
 
An expression node for literal values.
 
QVariant value() const
The value of the literal.
 
A list of expression nodes.
 
QList< QgsExpressionNode * > list()
Gets a list of all the nodes.
 
Abstract base class for all nodes that can appear in an expression.
 
Class for parsing and evaluation of expressions (formerly called "search strings").
 
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
 
static const QList< QgsExpressionFunction * > & Functions()
 
QgsExpression & operator=(const QgsExpression &other)
Create a copy of this expression.
 
QString expression() const
Returns the original, unmodified expression string.
 
Qgis::DistanceUnit distanceUnits() const
Returns the desired distance units for calculations involving geomCalculator(), e....
 
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
 
void setExpression(const QString &expression)
Set the expression string, will reset the whole internal structure.
 
static int functionIndex(const QString &name)
Returns index of the function in Functions array.
 
static double evaluateToDouble(const QString &text, double fallbackValue)
Attempts to evaluate a text string as an expression to a resultant double value.
 
static QString quoteFieldExpression(const QString &expression, const QgsVectorLayer *layer)
Validate if the expression is a field in the layer and ensure it is quoted.
 
static int functionCount()
Returns the number of functions defined in the parser.
 
QList< const QgsExpressionNode * > nodes() const
Returns a list of all nodes which are used in this expression.
 
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
 
QSet< QString > referencedVariables() const
Returns a list of all variables which are used in this expression.
 
static bool isFunctionName(const QString &name)
tells whether the identifier is a name of existing function
 
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
 
static QString variableHelpText(const QString &variableName)
Returns the help text for a specified variable.
 
QList< QgsExpression::ParserError > parserErrors() const
Returns parser error details including location of error.
 
QString evalErrorString() const
Returns evaluation error.
 
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QVariant::Type fieldType=QVariant::Type::Invalid)
Create an expression allowing to evaluate if a field is equal to a value.
 
bool operator==(const QgsExpression &other) const
Compares two expressions.
 
QString parserErrorString() const
Returns parser error.
 
static QString formatPreviewString(const QVariant &value, bool htmlOutput=true, int maximumPreviewLength=60)
Formats an expression result for friendly display to the user.
 
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...
 
static QStringList tags(const QString &name)
Returns a string list of search tags for a specified function.
 
bool isField() const
Checks whether an expression consists only of a single field reference.
 
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
 
QgsExpression()
Create an empty expression.
 
QString dump() const
Returns an expression string, constructed from the internal abstract syntax tree.
 
static PRIVATE QString helpText(QString name)
Returns the help text for a specified function.
 
void setDistanceUnits(Qgis::DistanceUnit unit)
Sets the desired distance units for calculations involving geomCalculator(), e.g.,...
 
void setAreaUnits(Qgis::AreaUnit unit)
Sets the desired areal units for calculations involving geomCalculator(), e.g., "$area".
 
static bool isFieldEqualityExpression(const QString &expression, QString &field, QVariant &value)
Returns true if the given expression is a simple "field=value" type expression.
 
Qgis::AreaUnit areaUnits() const
Returns the desired areal units for calculations involving geomCalculator(), e.g.,...
 
QSet< QString > referencedFunctions() const
Returns a list of the names of all functions which are used in this expression.
 
static QString group(const QString &group)
Returns the translated name for a function group.
 
void setEvalErrorString(const QString &str)
Sets evaluation error (used internally by evaluation functions)
 
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
 
void setGeomCalculator(const QgsDistanceArea *calc)
Sets the geometry calculator used for distance and area calculations in expressions.
 
const QgsExpressionNode * rootNode() const
Returns the root node of the expression.
 
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
 
static QString formatVariableHelp(const QString &description, bool showValue=true, const QVariant &value=QVariant())
Returns formatted help text for a variable.
 
static int expressionToLayerFieldIndex(const QString &expression, const QgsVectorLayer *layer)
Attempts to resolve an expression to a field index from the given layer.
 
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
 
QVariant evaluate()
Evaluate the feature and return the result.
 
static bool attemptReduceToInClause(const QStringList &expressions, QString &result)
Attempts to reduce a list of expressions to a single "field IN (val1, val2, ... )" type expression.
 
bool isValid() const
Checks if this expression is valid.
 
static bool addVariableHelpText(const QString name, const QString &description)
Adds a help string for a custom variable.
 
QgsDistanceArea * geomCalculator()
Returns calculator used for distance and area calculations (used by $length, $area and $perimeter fun...
 
QSet< int > referencedAttributeIndexes(const QgsFields &fields) const
Returns a list of field name indexes obtained from the provided fields.
 
static bool checkExpression(const QString &text, const QgsExpressionContext *context, QString &errorMessage)
Tests whether a string is a valid expression.
 
static const QString ALL_ATTRIBUTES
A special attribute that if set matches all attributes.
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
Container of fields for a vector layer.
 
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
 
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
 
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
 
A geometry is the spatial representation of a feature.
 
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
 
A representation of the interval between two datetime values.
 
double days() const
Returns the interval duration in days.
 
double seconds() const
Returns the interval duration in seconds.
 
double hours() const
Returns the interval duration in hours.
 
double minutes() const
Returns the interval duration in minutes.
 
static QgsProject * instance()
Returns the QgsProject singleton instance.
 
static Q_INVOKABLE Qgis::DistanceUnit stringToDistanceUnit(const QString &string, bool *ok=nullptr)
Converts a translated string to a distance unit.
 
static Q_INVOKABLE Qgis::AreaUnit stringToAreaUnit(const QString &string, bool *ok=nullptr)
Converts a translated string to an areal unit.
 
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.
 
Represents a vector layer which manages a vector based data sets.
 
QgsFields fields() const FINAL
Returns the list of fields of this layer.
 
static QString displayString(Qgis::WkbType type)
Returns a non-translated display string type for a WKB type, e.g., the geometry name used in WKT geom...
 
CONSTLATIN1STRING geoNone()
Constant that holds the string representation for "No ellips/No CRS".
 
QMap< QString, QString > QgsStringMap
 
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
 
QgsExpressionNode * parseExpression(const QString &str, QString &parserErrorMsg, QList< QgsExpression::ParserError > &parserErrors)
 
QList< int > QgsAttributeList
 
#define QgsDebugMsgLevel(str, level)
 
#define QgsDebugError(str)
 
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.