31#include <QRegularExpression> 
   39HelpTextHash QgsExpression::sFunctionHelpTexts;
 
   40QRecursiveMutex QgsExpression::sFunctionsMutex;
 
   41QMap< QString, int> QgsExpression::sFunctionIndexMap;
 
   44HelpTextHash &QgsExpression::functionHelpTexts()
 
   46  return sFunctionHelpTexts;
 
   62  d->mEvalErrorString = QString();
 
   64  d->mIsPrepared = 
false;
 
 
   69  if ( !d->mExp.isNull() )
 
 
   77  return QStringLiteral( 
"\"%1\"" ).arg( name.replace( 
'\"', QLatin1String( 
"\"\"" ) ) );
 
 
   82  text.replace( 
'\'', QLatin1String( 
"''" ) );
 
   83  text.replace( 
'\\', QLatin1String( 
"\\\\" ) );
 
   84  text.replace( 
'\n', QLatin1String( 
"\\n" ) );
 
   85  text.replace( 
'\t', QLatin1String( 
"\\t" ) );
 
   86  return QStringLiteral( 
"'%1'" ).arg( text );
 
 
   91  return quotedValue( value, 
static_cast<QMetaType::Type
>( value.userType() ) );
 
 
   97    return QStringLiteral( 
"NULL" );
 
  101    case QMetaType::Type::Int:
 
  102    case QMetaType::Type::LongLong:
 
  103    case QMetaType::Type::Double:
 
  104      return value.toString();
 
  106    case QMetaType::Type::Bool:
 
  107      return value.toBool() ? QStringLiteral( 
"TRUE" ) : QStringLiteral( 
"FALSE" );
 
  109    case QMetaType::Type::QVariantList:
 
  110    case QMetaType::Type::QStringList:
 
  112      QStringList quotedValues;
 
  113      const QVariantList values = value.toList();
 
  114      quotedValues.reserve( values.count() );
 
  115      for ( 
const QVariant &v : values )
 
  119      return QStringLiteral( 
"array( %1 )" ).arg( quotedValues.join( QLatin1String( 
", " ) ) );
 
  123    case QMetaType::Type::QString:
 
 
  141  QMutexLocker locker( &sFunctionsMutex );
 
  143  auto it = sFunctionIndexMap.constFind( name );
 
  144  if ( it != sFunctionIndexMap.constEnd() )
 
  151    if ( QString::compare( name, function->name(), Qt::CaseInsensitive ) == 0 )
 
  153      sFunctionIndexMap.insert( name, i );
 
  156    const QStringList aliases = function->aliases();
 
  157    for ( 
const QString &alias : aliases )
 
  159      if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
 
  161        sFunctionIndexMap.insert( name, i );
 
 
  177  : d( new QgsExpressionPrivate )
 
  179  d->mRootNode.reset( 
::parseExpression( expr, d->mParserErrorString, d->mParserErrors ) );
 
  181  Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
 
 
  192  if ( 
this != &other )
 
  194    if ( !d->ref.deref() )
 
 
  205QgsExpression::operator QString()
 const 
 
  211  : d( new QgsExpressionPrivate )
 
 
  218  if ( !d->ref.deref() )
 
 
  224  return ( d == other.d || d->mExp == other.d->mExp );
 
 
  229  return d->mRootNode.get();
 
 
  234  return d->mParserErrors.count() > 0;
 
 
  239  return d->mParserErrorString.replace( 
"syntax error, unexpected end of file",
 
  240                                        tr( 
"Incomplete expression. You might not have finished the full expression." ) );
 
 
  245  return d->mParserErrors;
 
 
  251    return QSet<QString>();
 
  253  return d->mRootNode->referencedColumns();
 
 
  259    return QSet<QString>();
 
  261  return d->mRootNode->referencedVariables();
 
 
  267    return QSet<QString>();
 
  269  return d->mRootNode->referencedFunctions();
 
 
  277  const QSet<QString> referencedFields = d->mRootNode->referencedColumns();
 
  278  QSet<int> referencedIndexes;
 
  280  for ( 
const QString &fieldName : referencedFields )
 
  285      referencedIndexes = QSet<int>( attributesList.begin(), attributesList.end() );
 
  291      referencedIndexes << idx;
 
  295  return referencedIndexes;
 
 
  302  return d->mRootNode->needsGeometry();
 
 
  308  if ( context && ! d->mCalc )
 
  312    d->mDaEllipsoid = context->
variable( QStringLiteral( 
"project_ellipsoid" ) ).toString();
 
  313    d->mDaCrs = std::make_unique<QgsCoordinateReferenceSystem>( context->
variable( QStringLiteral( 
"_layer_crs" ) ).value<QgsCoordinateReferenceSystem>() );
 
  314    d->mDaTransformContext = std::make_unique<QgsCoordinateTransformContext>( context->
variable( QStringLiteral( 
"_project_transform_context" ) ).value<QgsCoordinateTransformContext>() );
 
  320    QString distanceUnitsStr = context->
variable( QStringLiteral( 
"project_distance_units" ) ).toString();
 
  321    if ( ! distanceUnitsStr.isEmpty() )
 
  328    QString areaUnitsStr = context->
variable( QStringLiteral( 
"project_area_units" ) ).toString();
 
  329    if ( ! areaUnitsStr.isEmpty() )
 
  334void QgsExpression::detach()
 
  340    ( void )d->ref.deref();
 
  342    d = 
new QgsExpressionPrivate( *d );
 
  346void QgsExpression::initFunctionHelp()
 
  348  static std::once_flag initialized;
 
  349  std::call_once( initialized, buildFunctionHelp );
 
  356    d->mCalc = std::shared_ptr<QgsDistanceArea>( 
new QgsDistanceArea( *calc ) );
 
 
  364  d->mEvalErrorString = QString();
 
  370    d->mRootNode.reset( 
::parseExpression( d->mExp, d->mParserErrorString, d->mParserErrors ) );
 
  375    d->mEvalErrorString = tr( 
"No root node! Parsing failed?" );
 
  379  initGeomCalculator( context );
 
  380  d->mIsPrepared = 
true;
 
  381  return d->mRootNode->prepare( 
this, context );
 
 
  386  d->mEvalErrorString = QString();
 
  389    d->mEvalErrorString = tr( 
"No root node! Parsing failed?" );
 
 
  398  d->mEvalErrorString = QString();
 
  401    d->mEvalErrorString = tr( 
"No root node! Parsing failed?" );
 
  405  if ( ! d->mIsPrepared )
 
  409  return d->mRootNode->eval( 
this, context );
 
 
  414  return !d->mEvalErrorString.isNull();
 
 
  419  return d->mEvalErrorString;
 
 
  424  d->mEvalErrorString = str;
 
 
  432  return d->mRootNode->dump();
 
 
  437  if ( !d->mCalc && d->mDaCrs && d->mDaCrs->isValid() && d->mDaTransformContext )
 
  441    d->mCalc->setEllipsoid( d->mDaEllipsoid.isEmpty() ? 
Qgis::geoNone() : d->mDaEllipsoid );
 
  442    d->mCalc->setSourceCrs( *d->mDaCrs.get(), *d->mDaTransformContext.get() );
 
  445  return d->mCalc.get();
 
 
  450  return d->mDistanceUnit;
 
 
  455  d->mDistanceUnit = unit;
 
 
  473  while ( index < action.size() )
 
  475    static const QRegularExpression sRegEx{ QStringLiteral( 
"\\[%(.*?)%\\]" ),  QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption };
 
  477    const QRegularExpressionMatch match = sRegEx.match( action, index );
 
  478    if ( !match.hasMatch() )
 
  481    const int pos = action.indexOf( sRegEx, index );
 
  482    const int start = index;
 
  483    index = pos + match.capturedLength( 0 );
 
  484    const QString toReplace = match.captured( 1 ).trimmed();
 
  491      expr_action += QStringView {action} .mid( start, index - start );
 
  501    QVariant result = exp.
evaluate( context );
 
  506      expr_action += QStringView {action} .mid( start, index - start );
 
  510    QString resultString;
 
  512      resultString = result.toString();
 
  516    expr_action += action.mid( start, pos - start ) + resultString;
 
  519  expr_action += QStringView {action} .mid( index ).toString();
 
 
  525  QSet<QString> variables;
 
  527  while ( index < text.size() )
 
  529    const thread_local QRegularExpression rx( 
"\\[%([^\\]]+)%\\]" );
 
  530    const QRegularExpressionMatch match = rx.match( text );
 
  531    if ( !match.hasMatch() )
 
  534    index = match.capturedStart() + match.capturedLength();
 
  535    QString to_replace = match.captured( 1 ).trimmed();
 
 
  550  double convertedValue = QLocale().toDouble( text, &ok );
 
  553    return convertedValue;
 
  563  QVariant result = expr.
evaluate( &context );
 
  564  convertedValue = result.toDouble( &ok );
 
  567    return fallbackValue;
 
  569  return convertedValue;
 
 
  574  QgsExpression::initFunctionHelp();
 
  576  if ( !sFunctionHelpTexts.contains( name ) )
 
  577    return tr( 
"function help for %1 missing" ).arg( name );
 
  579  const Help &f = sFunctionHelpTexts[ name ];
 
  582  if ( f.mType == tr( 
"group" ) )
 
  584    name = 
group( name );
 
  585    name = name.toLower();
 
  588  name = name.toHtmlEscaped();
 
  590  QString helpContents( QStringLiteral( 
"<h3>%1</h3>\n<div class=\"description\"><p>%2</p></div>" )
 
  591                        .arg( tr( 
"%1 %2" ).arg( f.mType, name ),
 
  594  for ( 
const HelpVariant &v : std::as_const( f.mVariants ) )
 
  596    if ( f.mVariants.size() > 1 )
 
  598      helpContents += QStringLiteral( 
"<h3>%1</h3>\n<div class=\"description\">%2</p></div>" ).arg( v.mName, v.mDescription );
 
  601    if ( f.mType != tr( 
"group" ) && f.mType != tr( 
"expression" ) )
 
  602      helpContents += QStringLiteral( 
"<h4>%1</h4>\n<div class=\"syntax\">\n" ).arg( tr( 
"Syntax" ) );
 
  604    if ( f.mType == tr( 
"operator" ) )
 
  606      if ( v.mArguments.size() == 1 )
 
  608        helpContents += QStringLiteral( 
"<code><span class=\"functionname\">%1</span> <span class=\"argument\">%2</span></code>" )
 
  609                        .arg( name, v.mArguments[0].mArg );
 
  611      else if ( v.mArguments.size() == 2 )
 
  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 );
 
  617    else if ( f.mType != tr( 
"group" ) && f.mType != tr( 
"expression" ) )
 
  619      helpContents += QStringLiteral( 
"<code><span class=\"functionname\">%1</span>" ).arg( name );
 
  621      bool hasOptionalArgs = 
false;
 
  623      if ( f.mType == tr( 
"function" ) && ( f.mName[0] != 
'$' || !v.mArguments.isEmpty() || v.mVariableLenArguments ) )
 
  628        for ( 
const HelpArg &a : std::as_const( v.mArguments ) )
 
  634              hasOptionalArgs = 
true;
 
  635              helpContents += QLatin1Char( 
'[' );
 
  638            helpContents += delim;
 
  639            helpContents += QStringLiteral( 
"<span class=\"argument\">%2%3</span>" ).arg(
 
  641                              a.mDefaultVal.isEmpty() ? QString() : 
":=" + a.mDefaultVal
 
  645              helpContents += QLatin1Char( 
']' );
 
  647          delim = QStringLiteral( 
"," );
 
  650        if ( v.mVariableLenArguments )
 
  652          helpContents += QChar( 0x2026 );
 
  658      helpContents += QLatin1String( 
"</code>" );
 
  660      if ( hasOptionalArgs )
 
  662        helpContents += QLatin1String( 
"<br/><br/>" ) + tr( 
"[ ] marks optional components" );
 
  666    if ( !v.mArguments.isEmpty() )
 
  668      helpContents += QStringLiteral( 
"<h4>%1</h4>\n<div class=\"arguments\">\n<table>" ).arg( tr( 
"Arguments" ) );
 
  670      for ( 
const HelpArg &a : std::as_const( v.mArguments ) )
 
  675        helpContents += QStringLiteral( 
"<tr><td class=\"argument\">%1</td><td>%2</td></tr>" ).arg( a.mArg, a.mDescription );
 
  678      helpContents += QLatin1String( 
"</table>\n</div>\n" );
 
  681    if ( !v.mExamples.isEmpty() )
 
  683      helpContents += QStringLiteral( 
"<h4>%1</h4>\n<div class=\"examples\">\n<ul>\n" ).arg( tr( 
"Examples" ) );
 
  685      for ( 
const HelpExample &e : std::as_const( v.mExamples ) )
 
  687        helpContents += 
"<li><code>" + e.mExpression + 
"</code> → <code>" + e.mReturns + 
"</code>";
 
  689        if ( !e.mNote.isEmpty() )
 
  690          helpContents += QStringLiteral( 
" (%1)" ).arg( e.mNote );
 
  692        helpContents += QLatin1String( 
"</li>\n" );
 
  695      helpContents += QLatin1String( 
"</ul>\n</div>\n" );
 
  698    if ( !v.mNotes.isEmpty() )
 
  700      helpContents += QStringLiteral( 
"<h4>%1</h4>\n<div class=\"notes\"><p>%2</p></div>\n" ).arg( tr( 
"Notes" ), v.mNotes );
 
 
  709  QStringList 
tags = QStringList();
 
  711  QgsExpression::initFunctionHelp();
 
  713  if ( sFunctionHelpTexts.contains( name ) )
 
  715    const Help &f = sFunctionHelpTexts[ name ];
 
  717    for ( 
const HelpVariant &v : std::as_const( f.mVariants ) )
 
 
  726void QgsExpression::initVariableHelp()
 
  728  static std::once_flag initialized;
 
  729  std::call_once( initialized, buildVariableHelp );
 
  732void QgsExpression::buildVariableHelp()
 
  735  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_version" ), QCoreApplication::translate( 
"variable_help", 
"Current QGIS version string." ) );
 
  736  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_version_no" ), QCoreApplication::translate( 
"variable_help", 
"Current QGIS version number." ) );
 
  737  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_release_name" ), QCoreApplication::translate( 
"variable_help", 
"Current QGIS release name." ) );
 
  738  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_short_version" ), QCoreApplication::translate( 
"variable_help", 
"Short QGIS version string." ) );
 
  739  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_os_name" ), QCoreApplication::translate( 
"variable_help", 
"Operating system name, e.g., 'windows', 'linux' or 'osx'." ) );
 
  740  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_platform" ), QCoreApplication::translate( 
"variable_help", 
"QGIS platform, e.g., 'desktop' or 'server'." ) );
 
  741  sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_locale" ), QCoreApplication::translate( 
"variable_help", 
"Two letter identifier for current QGIS locale." ) );
 
  742  sVariableHelpTexts()->insert( QStringLiteral( 
"user_account_name" ), QCoreApplication::translate( 
"variable_help", 
"Current user's operating system account name." ) );
 
  743  sVariableHelpTexts()->insert( QStringLiteral( 
"user_full_name" ), QCoreApplication::translate( 
"variable_help", 
"Current user's operating system user name (if available)." ) );
 
  746  sVariableHelpTexts()->insert( QStringLiteral( 
"project_title" ), QCoreApplication::translate( 
"variable_help", 
"Title of current project." ) );
 
  747  sVariableHelpTexts()->insert( QStringLiteral( 
"project_path" ), QCoreApplication::translate( 
"variable_help", 
"Full path (including file name) of current project." ) );
 
  748  sVariableHelpTexts()->insert( QStringLiteral( 
"project_folder" ), QCoreApplication::translate( 
"variable_help", 
"Folder for current project." ) );
 
  749  sVariableHelpTexts()->insert( QStringLiteral( 
"project_filename" ), QCoreApplication::translate( 
"variable_help", 
"Filename of current project." ) );
 
  750  sVariableHelpTexts()->insert( QStringLiteral( 
"project_basename" ), QCoreApplication::translate( 
"variable_help", 
"Base name of current project's filename (without path and extension)." ) );
 
  751  sVariableHelpTexts()->insert( QStringLiteral( 
"project_home" ), QCoreApplication::translate( 
"variable_help", 
"Home path of current project." ) );
 
  752  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs" ), QCoreApplication::translate( 
"variable_help", 
"Identifier for the coordinate reference system of project (e.g., 'EPSG:4326')." ) );
 
  753  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_definition" ), QCoreApplication::translate( 
"variable_help", 
"Coordinate reference system of project (full definition)." ) );
 
  754  sVariableHelpTexts()->insert( QStringLiteral( 
"project_units" ), QCoreApplication::translate( 
"variable_help", 
"Unit of the project's CRS." ) );
 
  755  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_description" ), QCoreApplication::translate( 
"variable_help", 
"Name of the coordinate reference system of the project." ) );
 
  756  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_acronym" ), QCoreApplication::translate( 
"variable_help", 
"Acronym of the coordinate reference system of the project." ) );
 
  757  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_ellipsoid" ), QCoreApplication::translate( 
"variable_help", 
"Acronym of the ellipsoid of the coordinate reference system of the project." ) );
 
  758  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_proj4" ), QCoreApplication::translate( 
"variable_help", 
"Proj4 definition of the coordinate reference system of the project." ) );
 
  759  sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_wkt" ), QCoreApplication::translate( 
"variable_help", 
"WKT definition of the coordinate reference system of the project." ) );
 
  761  sVariableHelpTexts()->insert( QStringLiteral( 
"project_vertical_crs" ), QCoreApplication::translate( 
"variable_help", 
"Identifier for the vertical coordinate reference system of the project (e.g., 'EPSG:5703')." ) );
 
  762  sVariableHelpTexts()->insert( QStringLiteral( 
"project_vertical_crs_definition" ), QCoreApplication::translate( 
"variable_help", 
"Vertical coordinate reference system of project (full definition)." ) );
 
  763  sVariableHelpTexts()->insert( QStringLiteral( 
"project_vertical_crs_description" ), QCoreApplication::translate( 
"variable_help", 
"Name of the vertical coordinate reference system of the project." ) );
 
  764  sVariableHelpTexts()->insert( QStringLiteral( 
"project_vertical_crs_wkt" ), QCoreApplication::translate( 
"variable_help", 
"WKT definition of the vertical coordinate reference system of the project." ) );
 
  766  sVariableHelpTexts()->insert( QStringLiteral( 
"project_author" ), QCoreApplication::translate( 
"variable_help", 
"Project author, taken from project metadata." ) );
 
  767  sVariableHelpTexts()->insert( QStringLiteral( 
"project_abstract" ), QCoreApplication::translate( 
"variable_help", 
"Project abstract, taken from project metadata." ) );
 
  768  sVariableHelpTexts()->insert( QStringLiteral( 
"project_creation_date" ), QCoreApplication::translate( 
"variable_help", 
"Project creation date, taken from project metadata." ) );
 
  769  sVariableHelpTexts()->insert( QStringLiteral( 
"project_identifier" ), QCoreApplication::translate( 
"variable_help", 
"Project identifier, taken from project metadata." ) );
 
  770  sVariableHelpTexts()->insert( QStringLiteral( 
"project_last_saved" ), QCoreApplication::translate( 
"variable_help", 
"Date/time when project was last saved." ) );
 
  771  sVariableHelpTexts()->insert( QStringLiteral( 
"project_keywords" ), QCoreApplication::translate( 
"variable_help", 
"Project keywords, taken from project metadata." ) );
 
  772  sVariableHelpTexts()->insert( QStringLiteral( 
"project_area_units" ), QCoreApplication::translate( 
"variable_help", 
"Area unit for current project, used when calculating areas of geometries." ) );
 
  773  sVariableHelpTexts()->insert( QStringLiteral( 
"project_distance_units" ), QCoreApplication::translate( 
"variable_help", 
"Distance unit for current project, used when calculating lengths of geometries." ) );
 
  774  sVariableHelpTexts()->insert( QStringLiteral( 
"project_ellipsoid" ), QCoreApplication::translate( 
"variable_help", 
"Name of ellipsoid of current project, used when calculating geodetic areas and lengths of geometries." ) );
 
  775  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_ids" ), QCoreApplication::translate( 
"variable_help", 
"List of all map layer IDs from the current project." ) );
 
  776  sVariableHelpTexts()->insert( QStringLiteral( 
"layers" ), QCoreApplication::translate( 
"variable_help", 
"List of all map layers from the current project." ) );
 
  779  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_name" ), QCoreApplication::translate( 
"variable_help", 
"Name of current layer." ) );
 
  780  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_id" ), QCoreApplication::translate( 
"variable_help", 
"ID of current layer." ) );
 
  781  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_crs" ), QCoreApplication::translate( 
"variable_help", 
"CRS Authority ID of current layer." ) );
 
  782  sVariableHelpTexts()->insert( QStringLiteral( 
"layer" ), QCoreApplication::translate( 
"variable_help", 
"The current layer." ) );
 
  783  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_crs_ellipsoid" ), QCoreApplication::translate( 
"variable_help", 
"Ellipsoid acronym of current layer CRS." ) );
 
  785  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_vertical_crs" ), QCoreApplication::translate( 
"variable_help", 
"Identifier for the vertical coordinate reference system of the layer (e.g., 'EPSG:5703')." ) );
 
  786  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_vertical_crs_definition" ), QCoreApplication::translate( 
"variable_help", 
"Vertical coordinate reference system of layer (full definition)." ) );
 
  787  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_vertical_crs_description" ), QCoreApplication::translate( 
"variable_help", 
"Name of the vertical coordinate reference system of the layer." ) );
 
  788  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_vertical_crs_wkt" ), QCoreApplication::translate( 
"variable_help", 
"WKT definition of the vertical coordinate reference system of the layer." ) );
 
  791  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." ) );
 
  792  sVariableHelpTexts()->insert( QStringLiteral( 
"id" ), QCoreApplication::translate( 
"variable_help", 
"The ID of the current feature being evaluated." ) );
 
  793  sVariableHelpTexts()->insert( QStringLiteral( 
"geometry" ), QCoreApplication::translate( 
"variable_help", 
"The geometry of the current feature being evaluated." ) );
 
  796  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_name" ), QCoreApplication::translate( 
"variable_help", 
"Name of composition." ) );
 
  797  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_numpages" ), QCoreApplication::translate( 
"variable_help", 
"Number of pages in composition." ) );
 
  798  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_page" ), QCoreApplication::translate( 
"variable_help", 
"Current page number in composition." ) );
 
  799  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_pageheight" ), QCoreApplication::translate( 
"variable_help", 
"Composition page height in mm (or specified custom units)." ) );
 
  800  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_pagewidth" ), QCoreApplication::translate( 
"variable_help", 
"Composition page width in mm (or specified custom units)." ) );
 
  801  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_pageoffsets" ), QCoreApplication::translate( 
"variable_help", 
"Array of Y coordinate of the top of each page." ) );
 
  802  sVariableHelpTexts()->insert( QStringLiteral( 
"layout_dpi" ), QCoreApplication::translate( 
"variable_help", 
"Composition resolution (DPI)." ) );
 
  805  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_layerid" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas coverage layer ID." ) );
 
  806  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_layername" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas coverage layer name." ) );
 
  807  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_totalfeatures" ), QCoreApplication::translate( 
"variable_help", 
"Total number of features in atlas." ) );
 
  808  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_featurenumber" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas feature number." ) );
 
  809  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_filename" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas file name." ) );
 
  810  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_pagename" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas page name." ) );
 
  811  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_feature" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas feature (as feature object)." ) );
 
  812  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_featureid" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas feature ID." ) );
 
  813  sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_geometry" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas feature geometry." ) );
 
  816  sVariableHelpTexts()->insert( QStringLiteral( 
"item_id" ), QCoreApplication::translate( 
"variable_help", 
"Layout item user-assigned ID (not necessarily unique)." ) );
 
  817  sVariableHelpTexts()->insert( QStringLiteral( 
"item_uuid" ), QCoreApplication::translate( 
"variable_help", 
"layout item unique ID." ) );
 
  818  sVariableHelpTexts()->insert( QStringLiteral( 
"item_left" ), QCoreApplication::translate( 
"variable_help", 
"Left position of layout item (in mm)." ) );
 
  819  sVariableHelpTexts()->insert( QStringLiteral( 
"item_top" ), QCoreApplication::translate( 
"variable_help", 
"Top position of layout item (in mm)." ) );
 
  820  sVariableHelpTexts()->insert( QStringLiteral( 
"item_width" ), QCoreApplication::translate( 
"variable_help", 
"Width of layout item (in mm)." ) );
 
  821  sVariableHelpTexts()->insert( QStringLiteral( 
"item_height" ), QCoreApplication::translate( 
"variable_help", 
"Height of layout item (in mm)." ) );
 
  824  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." ) );
 
  825  sVariableHelpTexts()->insert( QStringLiteral( 
"map_rotation" ), QCoreApplication::translate( 
"variable_help", 
"Current rotation of map." ) );
 
  826  sVariableHelpTexts()->insert( QStringLiteral( 
"map_scale" ), QCoreApplication::translate( 
"variable_help", 
"Current scale of map." ) );
 
  827  sVariableHelpTexts()->insert( QStringLiteral( 
"map_extent" ), QCoreApplication::translate( 
"variable_help", 
"Geometry representing the current extent of the map." ) );
 
  828  sVariableHelpTexts()->insert( QStringLiteral( 
"map_extent_center" ), QCoreApplication::translate( 
"variable_help", 
"Center of map." ) );
 
  829  sVariableHelpTexts()->insert( QStringLiteral( 
"map_extent_width" ), QCoreApplication::translate( 
"variable_help", 
"Width of map." ) );
 
  830  sVariableHelpTexts()->insert( QStringLiteral( 
"map_extent_height" ), QCoreApplication::translate( 
"variable_help", 
"Height of map." ) );
 
  831  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs" ), QCoreApplication::translate( 
"variable_help", 
"Coordinate reference system of map (e.g., 'EPSG:4326')." ) );
 
  832  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_description" ), QCoreApplication::translate( 
"variable_help", 
"Name of the coordinate reference system of the map." ) );
 
  833  sVariableHelpTexts()->insert( QStringLiteral( 
"map_units" ), QCoreApplication::translate( 
"variable_help", 
"Units for map measurements." ) );
 
  834  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_definition" ), QCoreApplication::translate( 
"variable_help", 
"Coordinate reference system of the map (full definition)." ) );
 
  835  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_acronym" ), QCoreApplication::translate( 
"variable_help", 
"Acronym of the coordinate reference system of the map." ) );
 
  836  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_projection" ), QCoreApplication::translate( 
"variable_help", 
"Projection method used by the coordinate reference system of the map." ) );
 
  837  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_ellipsoid" ), QCoreApplication::translate( 
"variable_help", 
"Acronym of the ellipsoid of the coordinate reference system of the map." ) );
 
  838  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_proj4" ), QCoreApplication::translate( 
"variable_help", 
"Proj4 definition of the coordinate reference system of the map." ) );
 
  839  sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_wkt" ), QCoreApplication::translate( 
"variable_help", 
"WKT definition of the coordinate reference system of the map." ) );
 
  840  sVariableHelpTexts()->insert( QStringLiteral( 
"map_layer_ids" ), QCoreApplication::translate( 
"variable_help", 
"List of map layer IDs visible in the map." ) );
 
  841  sVariableHelpTexts()->insert( QStringLiteral( 
"map_layers" ), QCoreApplication::translate( 
"variable_help", 
"List of map layers visible in the map." ) );
 
  843  sVariableHelpTexts()->insert( QStringLiteral( 
"map_start_time" ), QCoreApplication::translate( 
"variable_help", 
"Start of the map's temporal time range (as a datetime value)" ) );
 
  844  sVariableHelpTexts()->insert( QStringLiteral( 
"map_end_time" ), QCoreApplication::translate( 
"variable_help", 
"End of the map's temporal time range (as a datetime value)" ) );
 
  845  sVariableHelpTexts()->insert( QStringLiteral( 
"map_interval" ), QCoreApplication::translate( 
"variable_help", 
"Duration of the map's temporal time range (as an interval value)" ) );
 
  846  sVariableHelpTexts()->insert( QStringLiteral( 
"map_z_range_lower" ), QCoreApplication::translate( 
"variable_help", 
"Lower elevation of the map's elevation range" ) );
 
  847  sVariableHelpTexts()->insert( QStringLiteral( 
"map_z_range_upper" ), QCoreApplication::translate( 
"variable_help", 
"Upper elevation of the map's elevation range" ) );
 
  849  sVariableHelpTexts()->insert( QStringLiteral( 
"frame_rate" ), QCoreApplication::translate( 
"variable_help", 
"Number of frames per second during animation playback" ) );
 
  850  sVariableHelpTexts()->insert( QStringLiteral( 
"frame_number" ), QCoreApplication::translate( 
"variable_help", 
"Current frame number during animation playback" ) );
 
  851  sVariableHelpTexts()->insert( QStringLiteral( 
"frame_duration" ), QCoreApplication::translate( 
"variable_help", 
"Temporal duration of each animation frame (as an interval value)" ) );
 
  852  sVariableHelpTexts()->insert( QStringLiteral( 
"frame_timestep" ), QCoreApplication::translate( 
"variable_help", 
"Frame time step during animation playback" ) );
 
  853  sVariableHelpTexts()->insert( QStringLiteral( 
"frame_timestep_unit" ), QCoreApplication::translate( 
"variable_help", 
"Unit value of the frame time step during animation playback" ) );
 
  854  sVariableHelpTexts()->insert( QStringLiteral( 
"frame_timestep_units" ), QCoreApplication::translate( 
"variable_help", 
"String representation of the frame time step unit during animation playback" ) );
 
  855  sVariableHelpTexts()->insert( QStringLiteral( 
"animation_start_time" ), QCoreApplication::translate( 
"variable_help", 
"Start of the animation's overall temporal time range (as a datetime value)" ) );
 
  856  sVariableHelpTexts()->insert( QStringLiteral( 
"animation_end_time" ), QCoreApplication::translate( 
"variable_help", 
"End of the animation's overall temporal time range (as a datetime value)" ) );
 
  857  sVariableHelpTexts()->insert( QStringLiteral( 
"animation_interval" ), QCoreApplication::translate( 
"variable_help", 
"Duration of the animation's overall temporal time range (as an interval value)" ) );
 
  860  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]." ) );
 
  861  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." ) );
 
  863  sVariableHelpTexts()->insert( QStringLiteral( 
"row_number" ), QCoreApplication::translate( 
"variable_help", 
"Stores the number of the current row." ) + QStringLiteral( 
"\n\n" ) + QCoreApplication::translate( 
"variable_help", 
"When used for calculations within the attribute table the row number will respect the original order of features from the underlying data source." ) + QStringLiteral( 
"\n\n" ) + QCoreApplication::translate( 
"variable_help", 
"When used from the field calculator the row numbering starts at 1, otherwise (e.g. from Processing tools) the row numbering starts from 0." ) );
 
  864  sVariableHelpTexts()->insert( QStringLiteral( 
"grid_number" ), QCoreApplication::translate( 
"variable_help", 
"Current grid annotation value." ) );
 
  865  sVariableHelpTexts()->insert( QStringLiteral( 
"grid_axis" ), QCoreApplication::translate( 
"variable_help", 
"Current grid annotation axis (e.g., 'x' for longitude, 'y' for latitude)." ) );
 
  866  sVariableHelpTexts()->insert( QStringLiteral( 
"column_number" ), QCoreApplication::translate( 
"variable_help", 
"Stores the number of the current column." ) );
 
  869  sVariableHelpTexts()->insert( QStringLiteral( 
"canvas_cursor_point" ), QCoreApplication::translate( 
"variable_help", 
"Last cursor position on the canvas in the project's geographical coordinates." ) );
 
  870  sVariableHelpTexts()->insert( QStringLiteral( 
"layer_cursor_point" ), QCoreApplication::translate( 
"variable_help", 
"Last cursor position on the canvas in the current layers's geographical coordinates. QGIS Server: When used in a maptip expression for a raster layer, this variable holds the GetFeatureInfo position." ) );
 
  873  sVariableHelpTexts()->insert( QStringLiteral( 
"legend_title" ), QCoreApplication::translate( 
"variable_help", 
"Title of the legend." ) );
 
  874  sVariableHelpTexts()->insert( QStringLiteral( 
"legend_column_count" ), QCoreApplication::translate( 
"variable_help", 
"Number of column in the legend." ) );
 
  875  sVariableHelpTexts()->insert( QStringLiteral( 
"legend_split_layers" ), QCoreApplication::translate( 
"variable_help", 
"Boolean indicating if layers can be split in the legend." ) );
 
  876  sVariableHelpTexts()->insert( QStringLiteral( 
"legend_wrap_string" ), QCoreApplication::translate( 
"variable_help", 
"Characters used to wrap the legend text." ) );
 
  877  sVariableHelpTexts()->insert( QStringLiteral( 
"legend_filter_by_map" ), QCoreApplication::translate( 
"variable_help", 
"Boolean indicating if the content of the legend is filtered by the map." ) );
 
  878  sVariableHelpTexts()->insert( QStringLiteral( 
"legend_filter_out_atlas" ), QCoreApplication::translate( 
"variable_help", 
"Boolean indicating if the Atlas is filtered out of the legend." ) );
 
  881  sVariableHelpTexts()->insert( QStringLiteral( 
"scale_value" ), QCoreApplication::translate( 
"variable_help", 
"Current scale bar distance value." ) );
 
  884  sVariableHelpTexts()->insert( QStringLiteral( 
"snapping_results" ), QCoreApplication::translate( 
"variable_help",
 
  885                                "<p>An array with an item for each snapped point.</p>" 
  886                                "<p>Each item is a map with the following keys:</p>" 
  888                                "<dt>valid</dt><dd>Boolean that indicates if the snapping result is valid</dd>" 
  889                                "<dt>layer</dt><dd>The layer on which the snapped feature is</dd>" 
  890                                "<dt>feature_id</dt><dd>The feature id of the snapped feature</dd>" 
  891                                "<dt>vertex_index</dt><dd>The index of the snapped vertex</dd>" 
  892                                "<dt>distance</dt><dd>The distance between the mouse cursor and the snapped point at the time of snapping</dd>" 
  897  sVariableHelpTexts()->insert( QStringLiteral( 
"geometry_part_count" ), QCoreApplication::translate( 
"variable_help", 
"Number of parts in rendered feature's geometry." ) );
 
  898  sVariableHelpTexts()->insert( QStringLiteral( 
"geometry_part_num" ), QCoreApplication::translate( 
"variable_help", 
"Current geometry part number for feature being rendered." ) );
 
  899  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." ) );
 
  900  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." ) );
 
  901  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." ) );
 
  903  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_color" ), QCoreApplication::translate( 
"symbol_color", 
"Color of symbol used to render the feature." ) );
 
  904  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_angle" ), QCoreApplication::translate( 
"symbol_angle", 
"Angle of symbol used to render the feature (valid for marker symbols only)." ) );
 
  905  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_layer_count" ), QCoreApplication::translate( 
"symbol_layer_count", 
"Total number of symbol layers in the symbol." ) );
 
  906  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_layer_index" ), QCoreApplication::translate( 
"symbol_layer_index", 
"Current symbol layer index." ) );
 
  907  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_marker_row" ), QCoreApplication::translate( 
"symbol_marker_row", 
"Row number for marker (valid for point pattern fills only)." ) );
 
  908  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_marker_column" ), QCoreApplication::translate( 
"symbol_marker_column", 
"Column number for marker (valid for point pattern fills only)." ) );
 
  909  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_frame" ), QCoreApplication::translate( 
"symbol_frame", 
"Frame number (for animated symbols only)." ) );
 
  911  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_label" ), QCoreApplication::translate( 
"symbol_label", 
"Label for the symbol (either a user defined label or the default autogenerated label)." ) );
 
  912  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_id" ), QCoreApplication::translate( 
"symbol_id", 
"Internal ID of the symbol." ) );
 
  913  sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_count" ), QCoreApplication::translate( 
"symbol_count", 
"Total number of features represented by the symbol." ) );
 
  916  sVariableHelpTexts()->insert( QStringLiteral( 
"cluster_color" ), QCoreApplication::translate( 
"cluster_color", 
"Color of symbols within a cluster, or NULL if symbols have mixed colors." ) );
 
  917  sVariableHelpTexts()->insert( QStringLiteral( 
"cluster_size" ), QCoreApplication::translate( 
"cluster_size", 
"Number of symbols contained within a cluster." ) );
 
  920  sVariableHelpTexts()->insert( QStringLiteral( 
"algorithm_id" ), QCoreApplication::translate( 
"algorithm_id", 
"Unique ID for algorithm." ) );
 
  921  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)." ) );
 
  922  sVariableHelpTexts()->insert( QStringLiteral( 
"model_folder" ), QCoreApplication::translate( 
"variable_help", 
"Folder containing current model (or project folder if model is embedded in a project)." ) );
 
  923  sVariableHelpTexts()->insert( QStringLiteral( 
"model_name" ), QCoreApplication::translate( 
"variable_help", 
"Name of current model." ) );
 
  924  sVariableHelpTexts()->insert( QStringLiteral( 
"model_group" ), QCoreApplication::translate( 
"variable_help", 
"Group for current model." ) );
 
  925  sVariableHelpTexts()->insert( QStringLiteral( 
"fullextent_minx" ), QCoreApplication::translate( 
"fullextent_minx", 
"Minimum x-value from full canvas extent (including all layers)." ) );
 
  926  sVariableHelpTexts()->insert( QStringLiteral( 
"fullextent_miny" ), QCoreApplication::translate( 
"fullextent_miny", 
"Minimum y-value from full canvas extent (including all layers)." ) );
 
  927  sVariableHelpTexts()->insert( QStringLiteral( 
"fullextent_maxx" ), QCoreApplication::translate( 
"fullextent_maxx", 
"Maximum x-value from full canvas extent (including all layers)." ) );
 
  928  sVariableHelpTexts()->insert( QStringLiteral( 
"fullextent_maxy" ), QCoreApplication::translate( 
"fullextent_maxy", 
"Maximum y-value from full canvas extent (including all layers)." ) );
 
  931  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)." ) );
 
  934  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." ) );
 
  935  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." ) );
 
  938  sVariableHelpTexts()->insert( QStringLiteral( 
"current_parent_geometry" ), QCoreApplication::translate( 
"current_parent_geometry",
 
  939                                "Only usable in an embedded form context, " 
  940                                "represents the geometry of the feature currently being edited in the parent form.\n" 
  941                                "Can be used in a form/row context to filter the related features using a value " 
  942                                "from the feature currently edited in the parent form, to make sure that the filter " 
  943                                "still works with standalone forms it is recommended to wrap this variable in a " 
  945  sVariableHelpTexts()->insert( QStringLiteral( 
"current_parent_feature" ), QCoreApplication::translate( 
"current_parent_feature",
 
  946                                "Only usable in an embedded form context, " 
  947                                "represents the feature currently being edited in the parent form.\n" 
  948                                "Can be used in a form/row context to filter the related features using a value " 
  949                                "from the feature currently edited in the parent form, to make sure that the filter " 
  950                                "still works with standalone forms it is recommended to wrap this variable in a " 
  954  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." ) );
 
  957  sVariableHelpTexts()->insert( QStringLiteral( 
"plot_axis" ), QCoreApplication::translate( 
"plot_axis", 
"The associated plot axis, e.g. 'x' or 'y'." ) );
 
  958  sVariableHelpTexts()->insert( QStringLiteral( 
"plot_axis_value" ), QCoreApplication::translate( 
"plot_axis_value", 
"The current value for the plot axis." ) );
 
  963  QgsExpression::initVariableHelp();
 
  964  if ( sVariableHelpTexts()->contains( name ) )
 
  968  sVariableHelpTexts()->insert( name, description );
 
 
  974  QgsExpression::initVariableHelp();
 
  975  return sVariableHelpTexts()->value( variableName, QString() );
 
 
  980  QString text = !description.isEmpty() ? QStringLiteral( 
"<p>%1</p>" ).arg( description ) : QString();
 
  984    if ( !value.isValid() )
 
  986      valueString = QCoreApplication::translate( 
"variable_help", 
"not set" );
 
  992    text.append( QCoreApplication::translate( 
"variable_help", 
"<p>Current value: %1</p>" ).arg( valueString ) );
 
 
  999  if ( sGroups()->isEmpty() )
 
 1001    sGroups()->insert( QStringLiteral( 
"Aggregates" ), tr( 
"Aggregates" ) );
 
 1002    sGroups()->insert( QStringLiteral( 
"Arrays" ), tr( 
"Arrays" ) );
 
 1003    sGroups()->insert( QStringLiteral( 
"Color" ), tr( 
"Color" ) );
 
 1004    sGroups()->insert( QStringLiteral( 
"Conditionals" ), tr( 
"Conditionals" ) );
 
 1005    sGroups()->insert( QStringLiteral( 
"Conversions" ), tr( 
"Conversions" ) );
 
 1006    sGroups()->insert( QStringLiteral( 
"Date and Time" ), tr( 
"Date and Time" ) );
 
 1007    sGroups()->insert( QStringLiteral( 
"Fields and Values" ), tr( 
"Fields and Values" ) );
 
 1008    sGroups()->insert( QStringLiteral( 
"Files and Paths" ), tr( 
"Files and Paths" ) );
 
 1009    sGroups()->insert( QStringLiteral( 
"Fuzzy Matching" ), tr( 
"Fuzzy Matching" ) );
 
 1010    sGroups()->insert( QStringLiteral( 
"General" ), tr( 
"General" ) );
 
 1011    sGroups()->insert( QStringLiteral( 
"GeometryGroup" ), tr( 
"Geometry" ) );
 
 1012    sGroups()->insert( QStringLiteral( 
"Map Layers" ), tr( 
"Map Layers" ) );
 
 1013    sGroups()->insert( QStringLiteral( 
"Maps" ), tr( 
"Maps" ) );
 
 1014    sGroups()->insert( QStringLiteral( 
"Math" ), tr( 
"Math" ) );
 
 1015    sGroups()->insert( QStringLiteral( 
"Operators" ), tr( 
"Operators" ) );
 
 1016    sGroups()->insert( QStringLiteral( 
"Rasters" ), tr( 
"Rasters" ) );
 
 1017    sGroups()->insert( QStringLiteral( 
"Record and Attributes" ), tr( 
"Record and Attributes" ) );
 
 1018    sGroups()->insert( QStringLiteral( 
"String" ), tr( 
"String" ) );
 
 1019    sGroups()->insert( QStringLiteral( 
"Variables" ), tr( 
"Variables" ) );
 
 1020    sGroups()->insert( QStringLiteral( 
"Recent (%1)" ), tr( 
"Recent (%1)" ) );
 
 1021    sGroups()->insert( QStringLiteral( 
"UserGroup" ), tr( 
"User expressions" ) );
 
 1027  return sGroups()->value( name, name );
 
 
 1032  const QString startToken = htmlOutput ? QStringLiteral( 
"<i><" ) : QStringLiteral( 
"<" );
 
 1033  const QString endToken = htmlOutput ? QStringLiteral( 
"></i>" ) : QStringLiteral( 
">" );
 
 1035  QgsGeometry geom = QgsExpressionUtils::getGeometry( value, 
nullptr );
 
 1040      return startToken + tr( 
"empty geometry" ) + endToken;
 
 1047    return startToken + tr( 
"map layer" ) + endToken;
 
 1049  else if ( !value.isValid() )
 
 1051    return htmlOutput ? tr( 
"<i>NULL</i>" ) : QString();
 
 1053  else if ( value.userType() == qMetaTypeId< QgsFeature>() )
 
 1057    return startToken + tr( 
"feature: %1" ).arg( feat.
id() ) + endToken;
 
 1059  else if ( value.userType() == qMetaTypeId< QgsCoordinateReferenceSystem>() )
 
 1064  else if ( value.userType() == qMetaTypeId< QgsInterval>() )
 
 1067    if ( interval.
days() > 1 )
 
 1069      return startToken + tr( 
"interval: %1 days" ).arg( interval.
days() ) + endToken;
 
 1071    else if ( interval.
hours() > 1 )
 
 1073      return startToken + tr( 
"interval: %1 hours" ).arg( interval.
hours() ) + endToken;
 
 1075    else if ( interval.
minutes() > 1 )
 
 1077      return startToken + tr( 
"interval: %1 minutes" ).arg( interval.
minutes() ) + endToken;
 
 1081      return startToken + tr( 
"interval: %1 seconds" ).arg( interval.
seconds() ) + endToken;
 
 1084  else if ( value.userType() == qMetaTypeId< QgsGradientColorRamp>() )
 
 1086    return startToken + tr( 
"gradient ramp" ) + endToken;
 
 1088  else if ( value.userType() == QMetaType::Type::QDate )
 
 1090    const QDate dt = value.toDate();
 
 1091    return startToken + tr( 
"date: %1" ).arg( dt.toString( QStringLiteral( 
"yyyy-MM-dd" ) ) ) + endToken;
 
 1093  else if ( value.userType() == QMetaType::Type::QTime )
 
 1095    const QTime tm = value.toTime();
 
 1096    return startToken + tr( 
"time: %1" ).arg( tm.toString( QStringLiteral( 
"hh:mm:ss" ) ) ) + endToken;
 
 1098  else if ( value.userType() == QMetaType::Type::QDateTime )
 
 1100    const QDateTime dt = value.toDateTime();
 
 1101    return startToken + tr( 
"datetime: %1 (%2)" ).arg( dt.toString( QStringLiteral( 
"yyyy-MM-dd hh:mm:ss" ) ), dt.timeZoneAbbreviation() ) + endToken;
 
 1103  else if ( value.userType() == QMetaType::Type::QString )
 
 1105    const QString previewString = value.toString();
 
 1106    if ( previewString.length() > maximumPreviewLength + 3 )
 
 1108      return tr( 
"'%1…'" ).arg( previewString.left( maximumPreviewLength ) );
 
 1112      return '\'' + previewString + 
'\'';
 
 1115  else if ( value.userType() == QMetaType::Type::QVariantMap )
 
 1117    QString mapStr = QStringLiteral( 
"{" );
 
 1118    const QVariantMap map = value.toMap();
 
 1120    for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
 
 1122      mapStr.append( separator );
 
 1123      if ( separator.isEmpty() )
 
 1124        separator = QStringLiteral( 
"," );
 
 1126      mapStr.append( QStringLiteral( 
" '%1': %2" ).arg( it.key(), 
formatPreviewString( it.value(), htmlOutput ) ) );
 
 1127      if ( mapStr.length() > maximumPreviewLength - 3 )
 
 1129        mapStr = tr( 
"%1…" ).arg( mapStr.left( maximumPreviewLength - 2 ) );
 
 1134      mapStr += QLatin1Char( 
' ' );
 
 1135    mapStr += QLatin1Char( 
'}' );
 
 1138  else if ( value.userType() == QMetaType::Type::QVariantList || value.userType() == QMetaType::Type::QStringList )
 
 1140    QString listStr = QStringLiteral( 
"[" );
 
 1141    const QVariantList list = value.toList();
 
 1143    for ( 
const QVariant &arrayValue : list )
 
 1145      listStr.append( separator );
 
 1146      if ( separator.isEmpty() )
 
 1147        separator = QStringLiteral( 
"," );
 
 1149      listStr.append( 
" " );
 
 1151      if ( listStr.length() > maximumPreviewLength - 3 )
 
 1153        listStr = QString( tr( 
"%1…" ) ).arg( listStr.left( maximumPreviewLength - 2 ) );
 
 1157    if ( !list.empty() )
 
 1158      listStr += QLatin1Char( 
' ' );
 
 1159    listStr += QLatin1Char( 
']' );
 
 1162  else if ( value.type() == QVariant::Color )
 
 1164    const QColor color = value.value<QColor>();
 
 1166    if ( !color.isValid() )
 
 1168      return tr( 
"<i>Invalid</i>" );
 
 1171    switch ( color.spec() )
 
 1173      case QColor::Spec::Cmyk:
 
 1174        return QStringLiteral( 
"CMYKA: %1,%2,%3,%4,%5" )
 
 1175               .arg( color.cyanF(), 0, 
'f', 2 ).arg( color.magentaF(), 0, 
'f', 2 )
 
 1176               .arg( color.yellowF(), 0, 
'f', 2 ).arg( color.blackF(), 0, 
'f', 2 )
 
 1177               .arg( color.alphaF(), 0, 
'f', 2 );
 
 1179      case QColor::Spec::Hsv:
 
 1180        return QStringLiteral( 
"HSVA: %1,%2,%3,%4" )
 
 1181               .arg( color.hsvHueF(), 0, 
'f', 2 ).arg( color.hsvSaturationF(), 0, 
'f', 2 )
 
 1182               .arg( color.valueF(), 0, 
'f', 2 ).arg( color.alphaF(), 0, 
'f', 2 );
 
 1184      case QColor::Spec::Hsl:
 
 1185        return QStringLiteral( 
"HSLA: %1,%2,%3,%4" )
 
 1186               .arg( color.hslHueF(), 0, 
'f', 2 ).arg( color.hslSaturationF(), 0, 
'f', 2 )
 
 1187               .arg( color.lightnessF(), 0, 
'f', 2 ).arg( color.alphaF(), 0, 
'f', 2 );
 
 1189      case QColor::Spec::Rgb:
 
 1190      case QColor::Spec::ExtendedRgb:
 
 1191        return QStringLiteral( 
"RGBA: %1,%2,%3,%4" )
 
 1192               .arg( color.redF(), 0, 
'f', 2 ).arg( color.greenF(), 0, 
'f', 2 )
 
 1193               .arg( color.blueF(), 0, 
'f', 2 ).arg( color.alphaF(), 0, 
'f', 2 );
 
 1195      case QColor::Spec::Invalid:
 
 1196        return tr( 
"<i>Invalid</i>" );
 
 1198    QgsDebugError( QStringLiteral( 
"Unknown color format: %1" ).arg( color.spec() ) );
 
 1199    return tr( 
"<i>Unknown color format: %1</i>" ).arg( color.spec() );
 
 1201  else if ( value.userType() == QMetaType::Type::Int ||
 
 1202            value.userType() == QMetaType::Type::UInt ||
 
 1203            value.userType() == QMetaType::Type::LongLong ||
 
 1204            value.userType() == QMetaType::Type::ULongLong ||
 
 1205            value.userType() == QMetaType::Type::Double ||
 
 1207            value.userType() == 
static_cast<QMetaType::Type
>( QMetaType::Float ) )
 
 1209    return QgsExpressionUtils::toLocalizedString( value );
 
 1213    QString str { value.toString() };
 
 1214    if ( str.length() > maximumPreviewLength - 3 )
 
 1216      str = tr( 
"%1…" ).arg( str.left( maximumPreviewLength - 2 ) );
 
 
 1227    expr = QStringLiteral( 
"%1 IS NULL" ).arg( 
quotedColumnRef( fieldName ) );
 
 1228  else if ( fieldType == QMetaType::Type::UnknownType )
 
 
 1254      if ( columnRef && literal )
 
 1256        field = columnRef->
name();
 
 1257        value = literal->
value();
 
 
 1267  if ( expressions.empty() )
 
 1273  for ( 
const QString &
expression : expressions )
 
 1284      else if ( field != inField )
 
 1300        if ( inOp->isNotIn() )
 
 1309          inField = columnRef->
name();
 
 1312        else if ( columnRef->
name() != inField )
 
 1319          const QList<QgsExpressionNode *> 
nodes = nodeList->list();
 
 1337          QStringList orParts;
 
 1342              orParts.append( collectOrs( leftOrOp->opLeft(), leftOrOp->opRight() ) );
 
 1346              orParts.append( leftOrOp->dump() );
 
 1351            orParts.append( leftInOp->dump() );
 
 1362              orParts.append( collectOrs( rightOrOp->opLeft(), rightOrOp->opRight() ) );
 
 1366              orParts.append( rightOrOp->dump() );
 
 1371            orParts.append( rightInOp->dump() );
 
 1384          const QStringList orParts = collectOrs( orOp->opLeft(), orOp->opRight() );
 
 1385          if ( orParts.isEmpty() )
 
 1391            QString orPartsResult;
 
 1396              if ( ! inExp.rootNode() )
 
 1408                const QString innerInfield { inOpInner->node()->
referencedColumns().values().first() };
 
 1412                  inField = innerInfield;
 
 1416                if ( innerInfield != inField )
 
 1422                  const auto constInnerValuesList { inOpInner->list()->list() };
 
 1423                  for ( 
const auto &innerInValueNode : std::as_const( constInnerValuesList ) )
 
 1425                    values.append( innerInValueNode->dump() );
 
 1452  result = QStringLiteral( 
"%1 IN (%2)" ).arg( 
quotedColumnRef( inField ), values.join( 
',' ) );
 
 
 1458  return d->mRootNode.get();
 
 
 1473  if ( attrIndex >= 0 )
 
 1480    const QString fieldName =  qgis::down_cast<const QgsExpressionNodeColumnRef *>( candidate.
rootNode() )->name();
 
 
 1492  if ( !
expression.contains( 
'\"' ) && fieldIndex != -1 )
 
 
 1505  if ( !d->mRootNode )
 
 1506    return QList<const QgsExpressionNode *>();
 
 1508  return d->mRootNode->nodes();
 
 
DistanceUnit
Units of distance.
 
@ Unknown
Unknown distance unit.
 
@ Unknown
Unknown areal unit.
 
static QString geoNone()
Constant that holds the string representation for "No ellipse/No CRS".
 
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
 
Represents a coordinate reference system (CRS).
 
QString userFriendlyIdentifier(Qgis::CrsIdentifierType type=Qgis::CrsIdentifierType::MediumString) const
Returns a user friendly identifier for the CRS.
 
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.
 
An abstract base class for defining QgsExpression functions.
 
A binary expression operator, which operates on two values.
 
An expression node which takes its 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.
 
Handles 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.
 
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.
 
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QMetaType::Type fieldType=QMetaType::Type::UnknownType)
Create an expression allowing to evaluate if a field is equal to a value.
 
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).
 
Q_INVOKABLE 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 QMetaType::Type variantTypeToMetaType(QVariant::Type variantType)
Converts a QVariant::Type to a QMetaType::Type.
 
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
 
Represents a vector layer which manages a vector based dataset.
 
static Q_INVOKABLE 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...
 
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.
 
const QgsCoordinateReferenceSystem & crs