29 #include <QRegularExpression> 
   40   return *sFunctionHelpTexts();
 
   55   d->mEvalErrorString = QString();
 
   57   d->mIsPrepared = 
false;
 
   62   if ( !d->mExp.isNull() )
 
   70   return QStringLiteral( 
"\"%1\"" ).arg( name.replace( 
'\"', QLatin1String( 
"\"\"" ) ) );
 
   75   text.replace( 
'\'', QLatin1String( 
"''" ) );
 
   76   text.replace( 
'\\', QLatin1String( 
"\\\\" ) );
 
   77   text.replace( 
'\n', QLatin1String( 
"\\n" ) );
 
   78   text.replace( 
'\t', QLatin1String( 
"\\t" ) );
 
   79   return QStringLiteral( 
"'%1'" ).arg( text );
 
   90     return QStringLiteral( 
"NULL" );
 
   95     case QVariant::LongLong:
 
   96     case QVariant::Double:
 
   97       return value.toString();
 
  100       return value.toBool() ? QStringLiteral( 
"TRUE" ) : QStringLiteral( 
"FALSE" );
 
  104       QStringList quotedValues;
 
  105       const QVariantList values = value.toList();
 
  106       quotedValues.reserve( values.count() );
 
  107       for ( 
const QVariant &v : values )
 
  111       return QStringLiteral( 
"array( %1 )" ).arg( quotedValues.join( QLatin1String( 
", " ) ) );
 
  115     case QVariant::String:
 
  129   for ( 
int i = 0; i < count; i++ )
 
  134     for ( 
const QString &alias : aliases )
 
  136       if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
 
  150   : d( new QgsExpressionPrivate )
 
  152   d->mRootNode = 
::parseExpression( expr, d->mParserErrorString, d->mParserErrors );
 
  154   Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
 
  165   if ( 
this != &other )
 
  167     if ( !d->ref.deref() )
 
  178 QgsExpression::operator QString()
 const 
  184   : d( new QgsExpressionPrivate )
 
  191   if ( !d->ref.deref() )
 
  197   return ( d == other.d || d->mExp == other.d->mExp );
 
  207   return d->mParserErrors.count() > 0;
 
  212   return d->mParserErrorString;
 
  217   return d->mParserErrors;
 
  223     return QSet<QString>();
 
  225   return d->mRootNode->referencedColumns();
 
  231     return QSet<QString>();
 
  233   return d->mRootNode->referencedVariables();
 
  239     return QSet<QString>();
 
  241   return d->mRootNode->referencedFunctions();
 
  249   const QSet<QString> referencedFields = d->mRootNode->referencedColumns();
 
  250   QSet<int> referencedIndexes;
 
  252   for ( 
const QString &fieldName : referencedFields )
 
  262       referencedIndexes << idx;
 
  266   return referencedIndexes;
 
  273   return d->mRootNode->needsGeometry();
 
  279   if ( context && ! d->mCalc )
 
  283     d->mDaEllipsoid = context->
variable( QStringLiteral( 
"project_ellipsoid" ) ).toString();
 
  284     d->mDaCrs = std::make_unique<QgsCoordinateReferenceSystem>( context->
variable( QStringLiteral( 
"_layer_crs" ) ).value<QgsCoordinateReferenceSystem>() );
 
  285     d->mDaTransformContext = std::make_unique<QgsCoordinateTransformContext>( context->
variable( QStringLiteral( 
"_project_transform_context" ) ).value<QgsCoordinateTransformContext>() );
 
  291     QString distanceUnitsStr = context->
variable( QStringLiteral( 
"project_distance_units" ) ).toString();
 
  292     if ( ! distanceUnitsStr.isEmpty() )
 
  299     QString areaUnitsStr = context->
variable( QStringLiteral( 
"project_area_units" ) ).toString();
 
  300     if ( ! areaUnitsStr.isEmpty() )
 
  305 void QgsExpression::detach()
 
  311     ( void )d->ref.deref();
 
  313     d = 
new QgsExpressionPrivate( *d );
 
  321     d->mCalc = std::shared_ptr<QgsDistanceArea>( 
new QgsDistanceArea( *calc ) );
 
  329   d->mEvalErrorString = QString();
 
  335     d->mRootNode = 
::parseExpression( d->mExp, d->mParserErrorString, d->mParserErrors );
 
  340     d->mEvalErrorString = tr( 
"No root node! Parsing failed?" );
 
  344   initGeomCalculator( context );
 
  345   d->mIsPrepared = 
true;
 
  346   return d->mRootNode->prepare( 
this, context );
 
  351   d->mEvalErrorString = QString();
 
  354     d->mEvalErrorString = tr( 
"No root node! Parsing failed?" );
 
  363   d->mEvalErrorString = QString();
 
  366     d->mEvalErrorString = tr( 
"No root node! Parsing failed?" );
 
  370   if ( ! d->mIsPrepared )
 
  374   return d->mRootNode->eval( 
this, context );
 
  379   return !d->mEvalErrorString.isNull();
 
  384   return d->mEvalErrorString;
 
  389   d->mEvalErrorString = 
str;
 
  397   return d->mRootNode->dump();
 
  402   if ( !d->mCalc && d->mDaCrs && d->mDaCrs->isValid() && d->mDaTransformContext )
 
  406     d->mCalc->setEllipsoid( d->mDaEllipsoid.isEmpty() ? 
geoNone() : d->mDaEllipsoid );
 
  407     d->mCalc->setSourceCrs( *d->mDaCrs.get(), *d->mDaTransformContext.get() );
 
  410   return d->mCalc.get();
 
  415   return d->mDistanceUnit;
 
  420   d->mDistanceUnit = unit;
 
  438   while ( index < action.size() )
 
  440     static const QRegularExpression sRegEx{ QStringLiteral( 
"\\[%(.*?)%\\]" ),  QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption };
 
  442     const QRegularExpressionMatch match = sRegEx.match( action, index );
 
  443     if ( !match.hasMatch() )
 
  446     const int pos = action.indexOf( sRegEx, index );
 
  447     const int start = index;
 
  448     index = pos + match.capturedLength( 0 );
 
  449     const QString toReplace = match.captured( 1 ).trimmed();
 
  456 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 2) 
  457       expr_action += action.midRef( start, index - start );
 
  459       expr_action += QStringView {action}.mid( start, index - start );
 
  470     QVariant result = exp.
evaluate( context );
 
  475 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 2) 
  476       expr_action += action.midRef( start, index - start );
 
  478       expr_action += QStringView {action}.mid( start, index - start );
 
  484     expr_action += action.mid( start, pos - start ) + result.toString();
 
  487 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 2) 
  488   expr_action += action.midRef( index );
 
  490   expr_action += QStringView {action}.mid( index ).toString();
 
  498   QSet<QString> variables;
 
  500   while ( index < text.size() )
 
  502     const thread_local QRegularExpression rx( 
"\\[%([^\\]]+)%\\]" );
 
  503     const QRegularExpressionMatch match = rx.match( text );
 
  504     if ( !match.hasMatch() )
 
  507     index = match.capturedStart() + match.capturedLength();
 
  508     QString to_replace = match.captured( 1 ).trimmed();
 
  523   double convertedValue = QLocale().toDouble( text, &ok );
 
  526     return convertedValue;
 
  536   QVariant result = expr.
evaluate( &context );
 
  537   convertedValue = result.toDouble( &ok );
 
  540     return fallbackValue;
 
  542   return convertedValue;
 
  547   QgsExpression::initFunctionHelp();
 
  549   if ( !sFunctionHelpTexts()->contains( name ) )
 
  550     return tr( 
"function help for %1 missing" ).arg( name );
 
  552   const Help &f = ( *sFunctionHelpTexts() )[ name ];
 
  555   if ( f.mType == tr( 
"group" ) )
 
  557     name = 
group( name );
 
  558     name = name.toLower();
 
  561   name = name.toHtmlEscaped();
 
  563   QString helpContents( QStringLiteral( 
"<h3>%1</h3>\n<div class=\"description\"><p>%2</p></div>" )
 
  564                         .arg( tr( 
"%1 %2" ).arg( f.mType, name ),
 
  567   for ( 
const HelpVariant &v : std::as_const( f.mVariants ) )
 
  569     if ( f.mVariants.size() > 1 )
 
  571       helpContents += QStringLiteral( 
"<h3>%1</h3>\n<div class=\"description\">%2</p></div>" ).arg( v.mName, v.mDescription );
 
  574     if ( f.mType != tr( 
"group" ) && f.mType != tr( 
"expression" ) )
 
  575       helpContents += QStringLiteral( 
"<h4>%1</h4>\n<div class=\"syntax\">\n" ).arg( tr( 
"Syntax" ) );
 
  577     if ( f.mType == tr( 
"operator" ) )
 
  579       if ( v.mArguments.size() == 1 )
 
  581         helpContents += QStringLiteral( 
"<code><span class=\"functionname\">%1</span> <span class=\"argument\">%2</span></code>" )
 
  582                         .arg( name, v.mArguments[0].mArg );
 
  584       else if ( v.mArguments.size() == 2 )
 
  586         helpContents += QStringLiteral( 
"<code><span class=\"argument\">%1</span> <span class=\"functionname\">%2</span> <span class=\"argument\">%3</span></code>" )
 
  587                         .arg( v.mArguments[0].mArg, name, v.mArguments[1].mArg );
 
  590     else if ( f.mType != tr( 
"group" ) && f.mType != tr( 
"expression" ) )
 
  592       helpContents += QStringLiteral( 
"<code><span class=\"functionname\">%1</span>" ).arg( name );
 
  594       bool hasOptionalArgs = 
false;
 
  596       if ( f.mType == tr( 
"function" ) && ( f.mName[0] != 
'$' || !v.mArguments.isEmpty() || v.mVariableLenArguments ) )
 
  601         for ( 
const HelpArg &a : std::as_const( v.mArguments ) )
 
  607               hasOptionalArgs = 
true;
 
  608               helpContents += QLatin1Char( 
'[' );
 
  611             helpContents += delim;
 
  612             helpContents += QStringLiteral( 
"<span class=\"argument\">%2%3</span>" ).arg(
 
  614                               a.mDefaultVal.isEmpty() ? QString() : 
'=' + a.mDefaultVal
 
  618               helpContents += QLatin1Char( 
']' );
 
  620           delim = QStringLiteral( 
"," );
 
  623         if ( v.mVariableLenArguments )
 
  625           helpContents += QChar( 0x2026 );
 
  631       helpContents += QLatin1String( 
"</code>" );
 
  633       if ( hasOptionalArgs )
 
  635         helpContents += QLatin1String( 
"<br/><br/>" ) + tr( 
"[ ] marks optional components" );
 
  639     if ( !v.mArguments.isEmpty() )
 
  641       helpContents += QStringLiteral( 
"<h4>%1</h4>\n<div class=\"arguments\">\n<table>" ).arg( tr( 
"Arguments" ) );
 
  643       for ( 
const HelpArg &a : std::as_const( v.mArguments ) )
 
  648         helpContents += QStringLiteral( 
"<tr><td class=\"argument\">%1</td><td>%2</td></tr>" ).arg( a.mArg, a.mDescription );
 
  651       helpContents += QLatin1String( 
"</table>\n</div>\n" );
 
  654     if ( !v.mExamples.isEmpty() )
 
  656       helpContents += QStringLiteral( 
"<h4>%1</h4>\n<div class=\"examples\">\n<ul>\n" ).arg( tr( 
"Examples" ) );
 
  658       for ( 
const HelpExample &e : std::as_const( v.mExamples ) )
 
  660         helpContents += 
"<li><code>" + e.mExpression + 
"</code> → <code>" + e.mReturns + 
"</code>";
 
  662         if ( !e.mNote.isEmpty() )
 
  663           helpContents += QStringLiteral( 
" (%1)" ).arg( e.mNote );
 
  665         helpContents += QLatin1String( 
"</li>\n" );
 
  668       helpContents += QLatin1String( 
"</ul>\n</div>\n" );
 
  671     if ( !v.mNotes.isEmpty() )
 
  673       helpContents += QStringLiteral( 
"<h4>%1</h4>\n<div class=\"notes\"><p>%2</p></div>\n" ).arg( tr( 
"Notes" ), v.mNotes );
 
  682   QStringList 
tags = QStringList();
 
  684   QgsExpression::initFunctionHelp();
 
  686   if ( sFunctionHelpTexts()->contains( name ) )
 
  688     const Help &f = ( *sFunctionHelpTexts() )[ name ];
 
  690     for ( 
const HelpVariant &v : std::as_const( f.mVariants ) )
 
  699 void QgsExpression::initVariableHelp()
 
  701   if ( !sVariableHelpTexts()->isEmpty() )
 
  705   sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_version" ), QCoreApplication::translate( 
"variable_help", 
"Current QGIS version string." ) );
 
  706   sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_version_no" ), QCoreApplication::translate( 
"variable_help", 
"Current QGIS version number." ) );
 
  707   sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_release_name" ), QCoreApplication::translate( 
"variable_help", 
"Current QGIS release name." ) );
 
  708   sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_short_version" ), QCoreApplication::translate( 
"variable_help", 
"Short QGIS version string." ) );
 
  709   sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_os_name" ), QCoreApplication::translate( 
"variable_help", 
"Operating system name, e.g., 'windows', 'linux' or 'osx'." ) );
 
  710   sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_platform" ), QCoreApplication::translate( 
"variable_help", 
"QGIS platform, e.g., 'desktop' or 'server'." ) );
 
  711   sVariableHelpTexts()->insert( QStringLiteral( 
"qgis_locale" ), QCoreApplication::translate( 
"variable_help", 
"Two letter identifier for current QGIS locale." ) );
 
  712   sVariableHelpTexts()->insert( QStringLiteral( 
"user_account_name" ), QCoreApplication::translate( 
"variable_help", 
"Current user's operating system account name." ) );
 
  713   sVariableHelpTexts()->insert( QStringLiteral( 
"user_full_name" ), QCoreApplication::translate( 
"variable_help", 
"Current user's operating system user name (if available)." ) );
 
  716   sVariableHelpTexts()->insert( QStringLiteral( 
"project_title" ), QCoreApplication::translate( 
"variable_help", 
"Title of current project." ) );
 
  717   sVariableHelpTexts()->insert( QStringLiteral( 
"project_path" ), QCoreApplication::translate( 
"variable_help", 
"Full path (including file name) of current project." ) );
 
  718   sVariableHelpTexts()->insert( QStringLiteral( 
"project_folder" ), QCoreApplication::translate( 
"variable_help", 
"Folder for current project." ) );
 
  719   sVariableHelpTexts()->insert( QStringLiteral( 
"project_filename" ), QCoreApplication::translate( 
"variable_help", 
"Filename of current project." ) );
 
  720   sVariableHelpTexts()->insert( QStringLiteral( 
"project_basename" ), QCoreApplication::translate( 
"variable_help", 
"Base name of current project's filename (without path and extension)." ) );
 
  721   sVariableHelpTexts()->insert( QStringLiteral( 
"project_home" ), QCoreApplication::translate( 
"variable_help", 
"Home path of current project." ) );
 
  722   sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs" ), QCoreApplication::translate( 
"variable_help", 
"Coordinate reference system of project (e.g., 'EPSG:4326')." ) );
 
  723   sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_definition" ), QCoreApplication::translate( 
"variable_help", 
"Coordinate reference system of project (full definition)." ) );
 
  724   sVariableHelpTexts()->insert( QStringLiteral( 
"project_units" ), QCoreApplication::translate( 
"variable_help", 
"Unit of the project's CRS." ) );
 
  725   sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_description" ), QCoreApplication::translate( 
"variable_help", 
"Name of the coordinate reference system of the project." ) );
 
  726   sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_acronym" ), QCoreApplication::translate( 
"variable_help", 
"Acronym of the coordinate reference system of the project." ) );
 
  727   sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_ellipsoid" ), QCoreApplication::translate( 
"variable_help", 
"Acronym of the ellipsoid of the coordinate reference system of the project." ) );
 
  728   sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_proj4" ), QCoreApplication::translate( 
"variable_help", 
"Proj4 definition of the coordinate reference system of the project." ) );
 
  729   sVariableHelpTexts()->insert( QStringLiteral( 
"project_crs_wkt" ), QCoreApplication::translate( 
"variable_help", 
"WKT definition of the coordinate reference system of the project." ) );
 
  730   sVariableHelpTexts()->insert( QStringLiteral( 
"project_author" ), QCoreApplication::translate( 
"variable_help", 
"Project author, taken from project metadata." ) );
 
  731   sVariableHelpTexts()->insert( QStringLiteral( 
"project_abstract" ), QCoreApplication::translate( 
"variable_help", 
"Project abstract, taken from project metadata." ) );
 
  732   sVariableHelpTexts()->insert( QStringLiteral( 
"project_creation_date" ), QCoreApplication::translate( 
"variable_help", 
"Project creation date, taken from project metadata." ) );
 
  733   sVariableHelpTexts()->insert( QStringLiteral( 
"project_identifier" ), QCoreApplication::translate( 
"variable_help", 
"Project identifier, taken from project metadata." ) );
 
  734   sVariableHelpTexts()->insert( QStringLiteral( 
"project_last_saved" ), QCoreApplication::translate( 
"variable_help", 
"Date/time when project was last saved." ) );
 
  735   sVariableHelpTexts()->insert( QStringLiteral( 
"project_keywords" ), QCoreApplication::translate( 
"variable_help", 
"Project keywords, taken from project metadata." ) );
 
  736   sVariableHelpTexts()->insert( QStringLiteral( 
"project_area_units" ), QCoreApplication::translate( 
"variable_help", 
"Area unit for current project, used when calculating areas of geometries." ) );
 
  737   sVariableHelpTexts()->insert( QStringLiteral( 
"project_distance_units" ), QCoreApplication::translate( 
"variable_help", 
"Distance unit for current project, used when calculating lengths of geometries." ) );
 
  738   sVariableHelpTexts()->insert( QStringLiteral( 
"project_ellipsoid" ), QCoreApplication::translate( 
"variable_help", 
"Name of ellipsoid of current project, used when calculating geodetic areas and lengths of geometries." ) );
 
  739   sVariableHelpTexts()->insert( QStringLiteral( 
"layer_ids" ), QCoreApplication::translate( 
"variable_help", 
"List of all map layer IDs from the current project." ) );
 
  740   sVariableHelpTexts()->insert( QStringLiteral( 
"layers" ), QCoreApplication::translate( 
"variable_help", 
"List of all map layers from the current project." ) );
 
  743   sVariableHelpTexts()->insert( QStringLiteral( 
"layer_name" ), QCoreApplication::translate( 
"variable_help", 
"Name of current layer." ) );
 
  744   sVariableHelpTexts()->insert( QStringLiteral( 
"layer_id" ), QCoreApplication::translate( 
"variable_help", 
"ID of current layer." ) );
 
  745   sVariableHelpTexts()->insert( QStringLiteral( 
"layer_crs" ), QCoreApplication::translate( 
"variable_help", 
"CRS Authority ID of current layer." ) );
 
  746   sVariableHelpTexts()->insert( QStringLiteral( 
"layer" ), QCoreApplication::translate( 
"variable_help", 
"The current layer." ) );
 
  749   sVariableHelpTexts()->insert( QStringLiteral( 
"layout_name" ), QCoreApplication::translate( 
"variable_help", 
"Name of composition." ) );
 
  750   sVariableHelpTexts()->insert( QStringLiteral( 
"layout_numpages" ), QCoreApplication::translate( 
"variable_help", 
"Number of pages in composition." ) );
 
  751   sVariableHelpTexts()->insert( QStringLiteral( 
"layout_page" ), QCoreApplication::translate( 
"variable_help", 
"Current page number in composition." ) );
 
  752   sVariableHelpTexts()->insert( QStringLiteral( 
"layout_pageheight" ), QCoreApplication::translate( 
"variable_help", 
"Composition page height in mm (or specified custom units)." ) );
 
  753   sVariableHelpTexts()->insert( QStringLiteral( 
"layout_pagewidth" ), QCoreApplication::translate( 
"variable_help", 
"Composition page width in mm (or specified custom units)." ) );
 
  754   sVariableHelpTexts()->insert( QStringLiteral( 
"layout_pageoffsets" ), QCoreApplication::translate( 
"variable_help", 
"Array of Y coordinate of the top of each page." ) );
 
  755   sVariableHelpTexts()->insert( QStringLiteral( 
"layout_dpi" ), QCoreApplication::translate( 
"variable_help", 
"Composition resolution (DPI)." ) );
 
  758   sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_layerid" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas coverage layer ID." ) );
 
  759   sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_layername" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas coverage layer name." ) );
 
  760   sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_totalfeatures" ), QCoreApplication::translate( 
"variable_help", 
"Total number of features in atlas." ) );
 
  761   sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_featurenumber" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas feature number." ) );
 
  762   sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_filename" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas file name." ) );
 
  763   sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_pagename" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas page name." ) );
 
  764   sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_feature" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas feature (as feature object)." ) );
 
  765   sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_featureid" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas feature ID." ) );
 
  766   sVariableHelpTexts()->insert( QStringLiteral( 
"atlas_geometry" ), QCoreApplication::translate( 
"variable_help", 
"Current atlas feature geometry." ) );
 
  769   sVariableHelpTexts()->insert( QStringLiteral( 
"item_id" ), QCoreApplication::translate( 
"variable_help", 
"Layout item user-assigned ID (not necessarily unique)." ) );
 
  770   sVariableHelpTexts()->insert( QStringLiteral( 
"item_uuid" ), QCoreApplication::translate( 
"variable_help", 
"layout item unique ID." ) );
 
  771   sVariableHelpTexts()->insert( QStringLiteral( 
"item_left" ), QCoreApplication::translate( 
"variable_help", 
"Left position of layout item (in mm)." ) );
 
  772   sVariableHelpTexts()->insert( QStringLiteral( 
"item_top" ), QCoreApplication::translate( 
"variable_help", 
"Top position of layout item (in mm)." ) );
 
  773   sVariableHelpTexts()->insert( QStringLiteral( 
"item_width" ), QCoreApplication::translate( 
"variable_help", 
"Width of layout item (in mm)." ) );
 
  774   sVariableHelpTexts()->insert( QStringLiteral( 
"item_height" ), QCoreApplication::translate( 
"variable_help", 
"Height of layout item (in mm)." ) );
 
  777   sVariableHelpTexts()->insert( QStringLiteral( 
"map_id" ), QCoreApplication::translate( 
"variable_help", 
"ID of current map destination. This will be 'canvas' for canvas renders, and the item ID for layout map renders." ) );
 
  778   sVariableHelpTexts()->insert( QStringLiteral( 
"map_rotation" ), QCoreApplication::translate( 
"variable_help", 
"Current rotation of map." ) );
 
  779   sVariableHelpTexts()->insert( QStringLiteral( 
"map_scale" ), QCoreApplication::translate( 
"variable_help", 
"Current scale of map." ) );
 
  780   sVariableHelpTexts()->insert( QStringLiteral( 
"map_extent" ), QCoreApplication::translate( 
"variable_help", 
"Geometry representing the current extent of the map." ) );
 
  781   sVariableHelpTexts()->insert( QStringLiteral( 
"map_extent_center" ), QCoreApplication::translate( 
"variable_help", 
"Center of map." ) );
 
  782   sVariableHelpTexts()->insert( QStringLiteral( 
"map_extent_width" ), QCoreApplication::translate( 
"variable_help", 
"Width of map." ) );
 
  783   sVariableHelpTexts()->insert( QStringLiteral( 
"map_extent_height" ), QCoreApplication::translate( 
"variable_help", 
"Height of map." ) );
 
  784   sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs" ), QCoreApplication::translate( 
"variable_help", 
"Coordinate reference system of map (e.g., 'EPSG:4326')." ) );
 
  785   sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_description" ), QCoreApplication::translate( 
"variable_help", 
"Name of the coordinate reference system of the map." ) );
 
  786   sVariableHelpTexts()->insert( QStringLiteral( 
"map_units" ), QCoreApplication::translate( 
"variable_help", 
"Units for map measurements." ) );
 
  787   sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_definition" ), QCoreApplication::translate( 
"variable_help", 
"Coordinate reference system of the map (full definition)." ) );
 
  788   sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_acronym" ), QCoreApplication::translate( 
"variable_help", 
"Acronym of the coordinate reference system of the map." ) );
 
  789   sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_projection" ), QCoreApplication::translate( 
"variable_help", 
"Projection method used by the coordinate reference system of the map." ) );
 
  790   sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_ellipsoid" ), QCoreApplication::translate( 
"variable_help", 
"Acronym of the ellipsoid of the coordinate reference system of the map." ) );
 
  791   sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_proj4" ), QCoreApplication::translate( 
"variable_help", 
"Proj4 definition of the coordinate reference system of the map." ) );
 
  792   sVariableHelpTexts()->insert( QStringLiteral( 
"map_crs_wkt" ), QCoreApplication::translate( 
"variable_help", 
"WKT definition of the coordinate reference system of the map." ) );
 
  793   sVariableHelpTexts()->insert( QStringLiteral( 
"map_layer_ids" ), QCoreApplication::translate( 
"variable_help", 
"List of map layer IDs visible in the map." ) );
 
  794   sVariableHelpTexts()->insert( QStringLiteral( 
"map_layers" ), QCoreApplication::translate( 
"variable_help", 
"List of map layers visible in the map." ) );
 
  796   sVariableHelpTexts()->insert( QStringLiteral( 
"map_start_time" ), QCoreApplication::translate( 
"variable_help", 
"Start of the map's temporal time range (as a datetime value)" ) );
 
  797   sVariableHelpTexts()->insert( QStringLiteral( 
"map_end_time" ), QCoreApplication::translate( 
"variable_help", 
"End of the map's temporal time range (as a datetime value)" ) );
 
  798   sVariableHelpTexts()->insert( QStringLiteral( 
"map_interval" ), QCoreApplication::translate( 
"variable_help", 
"Duration of the map's temporal time range (as an interval value)" ) );
 
  800   sVariableHelpTexts()->insert( QStringLiteral( 
"frame_rate" ), QCoreApplication::translate( 
"variable_help", 
"Number of frames per second during animation playback" ) );
 
  801   sVariableHelpTexts()->insert( QStringLiteral( 
"frame_number" ), QCoreApplication::translate( 
"variable_help", 
"Current frame number during animation playback" ) );
 
  802   sVariableHelpTexts()->insert( QStringLiteral( 
"frame_duration" ), QCoreApplication::translate( 
"variable_help", 
"Temporal duration of each animation frame (as an interval value)" ) );
 
  803   sVariableHelpTexts()->insert( QStringLiteral( 
"animation_start_time" ), QCoreApplication::translate( 
"variable_help", 
"Start of the animation's overall temporal time range (as a datetime value)" ) );
 
  804   sVariableHelpTexts()->insert( QStringLiteral( 
"animation_end_time" ), QCoreApplication::translate( 
"variable_help", 
"End of the animation's overall temporal time range (as a datetime value)" ) );
 
  805   sVariableHelpTexts()->insert( QStringLiteral( 
"animation_interval" ), QCoreApplication::translate( 
"variable_help", 
"Duration of the animation's overall temporal time range (as an interval value)" ) );
 
  808   sVariableHelpTexts()->insert( QStringLiteral( 
"zoom_level" ), QCoreApplication::translate( 
"variable_help", 
"Zoom level of the tile that is being rendered (derived from the current map scale). Normally in interval [0, 20]." ) );
 
  809   sVariableHelpTexts()->insert( QStringLiteral( 
"vector_tile_zoom" ), QCoreApplication::translate( 
"variable_help", 
"Exact zoom level of the tile 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 interpolated values between two integer zoom levels." ) );
 
  811   sVariableHelpTexts()->insert( QStringLiteral( 
"row_number" ), QCoreApplication::translate( 
"variable_help", 
"Stores the number of the current row." ) );
 
  812   sVariableHelpTexts()->insert( QStringLiteral( 
"grid_number" ), QCoreApplication::translate( 
"variable_help", 
"Current grid annotation value." ) );
 
  813   sVariableHelpTexts()->insert( QStringLiteral( 
"grid_axis" ), QCoreApplication::translate( 
"variable_help", 
"Current grid annotation axis (e.g., 'x' for longitude, 'y' for latitude)." ) );
 
  814   sVariableHelpTexts()->insert( QStringLiteral( 
"column_number" ), QCoreApplication::translate( 
"variable_help", 
"Stores the number of the current column." ) );
 
  817   sVariableHelpTexts()->insert( QStringLiteral( 
"canvas_cursor_point" ), QCoreApplication::translate( 
"variable_help", 
"Last cursor position on the canvas in the project's geographical coordinates." ) );
 
  820   sVariableHelpTexts()->insert( QStringLiteral( 
"legend_title" ), QCoreApplication::translate( 
"variable_help", 
"Title of the legend." ) );
 
  821   sVariableHelpTexts()->insert( QStringLiteral( 
"legend_column_count" ), QCoreApplication::translate( 
"variable_help", 
"Number of column in the legend." ) );
 
  822   sVariableHelpTexts()->insert( QStringLiteral( 
"legend_split_layers" ), QCoreApplication::translate( 
"variable_help", 
"Boolean indicating if layers can be split in the legend." ) );
 
  823   sVariableHelpTexts()->insert( QStringLiteral( 
"legend_wrap_string" ), QCoreApplication::translate( 
"variable_help", 
"Characters used to wrap the legend text." ) );
 
  824   sVariableHelpTexts()->insert( QStringLiteral( 
"legend_filter_by_map" ), QCoreApplication::translate( 
"variable_help", 
"Boolean indicating if the content of the legend is filtered by the map." ) );
 
  825   sVariableHelpTexts()->insert( QStringLiteral( 
"legend_filter_out_atlas" ), QCoreApplication::translate( 
"variable_help", 
"Boolean indicating if the Atlas is filtered out of the legend." ) );
 
  828   sVariableHelpTexts()->insert( QStringLiteral( 
"scale_value" ), QCoreApplication::translate( 
"variable_help", 
"Current scale bar distance value." ) );
 
  831   sVariableHelpTexts()->insert( QStringLiteral( 
"snapping_results" ), QCoreApplication::translate( 
"variable_help",
 
  832                                 "<p>An array with an item for each snapped point.</p>" 
  833                                 "<p>Each item is a map with the following keys:</p>" 
  835                                 "<dt>valid</dt><dd>Boolean that indicates if the snapping result is valid</dd>" 
  836                                 "<dt>layer</dt><dd>The layer on which the snapped feature is</dd>" 
  837                                 "<dt>feature_id</dt><dd>The feature id of the snapped feature</dd>" 
  838                                 "<dt>vertex_index</dt><dd>The index of the snapped vertex</dd>" 
  839                                 "<dt>distance</dt><dd>The distance between the mouse cursor and the snapped point at the time of snapping</dd>" 
  844   sVariableHelpTexts()->insert( QStringLiteral( 
"geometry_part_count" ), QCoreApplication::translate( 
"variable_help", 
"Number of parts in rendered feature's geometry." ) );
 
  845   sVariableHelpTexts()->insert( QStringLiteral( 
"geometry_part_num" ), QCoreApplication::translate( 
"variable_help", 
"Current geometry part number for feature being rendered." ) );
 
  846   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." ) );
 
  847   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." ) );
 
  848   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." ) );
 
  850   sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_color" ), QCoreApplication::translate( 
"symbol_color", 
"Color of symbol used to render the feature." ) );
 
  851   sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_angle" ), QCoreApplication::translate( 
"symbol_angle", 
"Angle of symbol used to render the feature (valid for marker symbols only)." ) );
 
  852   sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_layer_count" ), QCoreApplication::translate( 
"symbol_layer_count", 
"Total number of symbol layers in the symbol." ) );
 
  853   sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_layer_index" ), QCoreApplication::translate( 
"symbol_layer_index", 
"Current symbol layer index." ) );
 
  854   sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_marker_row" ), QCoreApplication::translate( 
"symbol_marker_row", 
"Row number for marker (valid for point pattern fills only)." ) );
 
  855   sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_marker_column" ), QCoreApplication::translate( 
"symbol_marker_column", 
"Column number for marker (valid for point pattern fills only)." ) );
 
  857   sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_label" ), QCoreApplication::translate( 
"symbol_label", 
"Label for the symbol (either a user defined label or the default autogenerated label)." ) );
 
  858   sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_id" ), QCoreApplication::translate( 
"symbol_id", 
"Internal ID of the symbol." ) );
 
  859   sVariableHelpTexts()->insert( QStringLiteral( 
"symbol_count" ), QCoreApplication::translate( 
"symbol_count", 
"Total number of features represented by the symbol." ) );
 
  862   sVariableHelpTexts()->insert( QStringLiteral( 
"cluster_color" ), QCoreApplication::translate( 
"cluster_color", 
"Color of symbols within a cluster, or NULL if symbols have mixed colors." ) );
 
  863   sVariableHelpTexts()->insert( QStringLiteral( 
"cluster_size" ), QCoreApplication::translate( 
"cluster_size", 
"Number of symbols contained within a cluster." ) );
 
  866   sVariableHelpTexts()->insert( QStringLiteral( 
"algorithm_id" ), QCoreApplication::translate( 
"algorithm_id", 
"Unique ID for algorithm." ) );
 
  867   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)." ) );
 
  868   sVariableHelpTexts()->insert( QStringLiteral( 
"model_folder" ), QCoreApplication::translate( 
"variable_help", 
"Folder containing current model (or project folder if model is embedded in a project)." ) );
 
  869   sVariableHelpTexts()->insert( QStringLiteral( 
"model_name" ), QCoreApplication::translate( 
"variable_help", 
"Name of current model." ) );
 
  870   sVariableHelpTexts()->insert( QStringLiteral( 
"model_group" ), QCoreApplication::translate( 
"variable_help", 
"Group for current model." ) );
 
  871   sVariableHelpTexts()->insert( QStringLiteral( 
"fullextent_minx" ), QCoreApplication::translate( 
"fullextent_minx", 
"Minimum x-value from full canvas extent (including all layers)." ) );
 
  872   sVariableHelpTexts()->insert( QStringLiteral( 
"fullextent_miny" ), QCoreApplication::translate( 
"fullextent_miny", 
"Minimum y-value from full canvas extent (including all layers)." ) );
 
  873   sVariableHelpTexts()->insert( QStringLiteral( 
"fullextent_maxx" ), QCoreApplication::translate( 
"fullextent_maxx", 
"Maximum x-value from full canvas extent (including all layers)." ) );
 
  874   sVariableHelpTexts()->insert( QStringLiteral( 
"fullextent_maxy" ), QCoreApplication::translate( 
"fullextent_maxy", 
"Maximum y-value from full canvas extent (including all layers)." ) );
 
  877   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)." ) );
 
  880   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." ) );
 
  881   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." ) );
 
  884   sVariableHelpTexts()->insert( QStringLiteral( 
"current_parent_geometry" ), QCoreApplication::translate( 
"current_parent_geometry",
 
  885                                 "Only usable in an embedded form context, " 
  886                                 "represents the geometry of the feature currently being edited in the parent form.\n" 
  887                                 "Can be used in a form/row context to filter the related features using a value " 
  888                                 "from the feature currently edited in the parent form, to make sure that the filter " 
  889                                 "still works with standalone forms it is recommended to wrap this variable in a " 
  891   sVariableHelpTexts()->insert( QStringLiteral( 
"current_parent_feature" ), QCoreApplication::translate( 
"current_parent_feature",
 
  892                                 "Only usable in an embedded form context, " 
  893                                 "represents the feature currently being edited in the parent form.\n" 
  894                                 "Can be used in a form/row context to filter the related features using a value " 
  895                                 "from the feature currently edited in the parent form, to make sure that the filter " 
  896                                 "still works with standalone forms it is recommended to wrap this variable in a " 
  900   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." ) );
 
  906   if ( sVariableHelpTexts()->contains( name ) )
 
  910   sVariableHelpTexts()->insert( name, description );
 
  916   QgsExpression::initVariableHelp();
 
  917   return sVariableHelpTexts()->value( variableName, QString() );
 
  922   QString text = !description.isEmpty() ? QStringLiteral( 
"<p>%1</p>" ).arg( description ) : QString();
 
  926     if ( !value.isValid() )
 
  928       valueString = QCoreApplication::translate( 
"variable_help", 
"not set" );
 
  934     text.append( QCoreApplication::translate( 
"variable_help", 
"<p>Current value: %1</p>" ).arg( valueString ) );
 
  941   if ( sGroups()->isEmpty() )
 
  943     sGroups()->insert( QStringLiteral( 
"Aggregates" ), tr( 
"Aggregates" ) );
 
  944     sGroups()->insert( QStringLiteral( 
"Arrays" ), tr( 
"Arrays" ) );
 
  945     sGroups()->insert( QStringLiteral( 
"Color" ), tr( 
"Color" ) );
 
  946     sGroups()->insert( QStringLiteral( 
"Conditionals" ), tr( 
"Conditionals" ) );
 
  947     sGroups()->insert( QStringLiteral( 
"Conversions" ), tr( 
"Conversions" ) );
 
  948     sGroups()->insert( QStringLiteral( 
"Date and Time" ), tr( 
"Date and Time" ) );
 
  949     sGroups()->insert( QStringLiteral( 
"Fields and Values" ), tr( 
"Fields and Values" ) );
 
  950     sGroups()->insert( QStringLiteral( 
"Files and Paths" ), tr( 
"Files and Paths" ) );
 
  951     sGroups()->insert( QStringLiteral( 
"Fuzzy Matching" ), tr( 
"Fuzzy Matching" ) );
 
  952     sGroups()->insert( QStringLiteral( 
"General" ), tr( 
"General" ) );
 
  953     sGroups()->insert( QStringLiteral( 
"GeometryGroup" ), tr( 
"Geometry" ) );
 
  954     sGroups()->insert( QStringLiteral( 
"Map Layers" ), tr( 
"Map Layers" ) );
 
  955     sGroups()->insert( QStringLiteral( 
"Maps" ), tr( 
"Maps" ) );
 
  956     sGroups()->insert( QStringLiteral( 
"Math" ), tr( 
"Math" ) );
 
  957     sGroups()->insert( QStringLiteral( 
"Operators" ), tr( 
"Operators" ) );
 
  958     sGroups()->insert( QStringLiteral( 
"Rasters" ), tr( 
"Rasters" ) );
 
  959     sGroups()->insert( QStringLiteral( 
"Record and Attributes" ), tr( 
"Record and Attributes" ) );
 
  960     sGroups()->insert( QStringLiteral( 
"String" ), tr( 
"String" ) );
 
  961     sGroups()->insert( QStringLiteral( 
"Variables" ), tr( 
"Variables" ) );
 
  962     sGroups()->insert( QStringLiteral( 
"Recent (%1)" ), tr( 
"Recent (%1)" ) );
 
  963     sGroups()->insert( QStringLiteral( 
"UserGroup" ), tr( 
"User expressions" ) );
 
  969   return sGroups()->value( name, name );
 
  974   const QString startToken = htmlOutput ? QStringLiteral( 
"<i><" ) : QStringLiteral( 
"<" );
 
  975   const QString endToken = htmlOutput ? QStringLiteral( 
"></i>" ) : QStringLiteral( 
">" );
 
  982       return startToken + tr( 
"empty geometry" ) + endToken;
 
  989     return startToken + tr( 
"map layer" ) + endToken;
 
  991   else if ( !value.isValid() )
 
  993     return htmlOutput ? tr( 
"<i>NULL</i>" ) : QString();
 
  999     return startToken + tr( 
"feature: %1" ).arg( feat.
id() ) + endToken;
 
 1004     if ( interval.
days() > 1 )
 
 1006       return startToken + tr( 
"interval: %1 days" ).arg( interval.
days() ) + endToken;
 
 1008     else if ( interval.
hours() > 1 )
 
 1010       return startToken + tr( 
"interval: %1 hours" ).arg( interval.
hours() ) + endToken;
 
 1012     else if ( interval.
minutes() > 1 )
 
 1014       return startToken + tr( 
"interval: %1 minutes" ).arg( interval.
minutes() ) + endToken;
 
 1018       return startToken + tr( 
"interval: %1 seconds" ).arg( interval.
seconds() ) + endToken;
 
 1023     return startToken + tr( 
"gradient ramp" ) + endToken;
 
 1025   else if ( value.type() == QVariant::Date )
 
 1027     const QDate dt = value.toDate();
 
 1028     return startToken + tr( 
"date: %1" ).arg( dt.toString( QStringLiteral( 
"yyyy-MM-dd" ) ) ) + endToken;
 
 1030   else if ( value.type() == QVariant::Time )
 
 1032     const QTime tm = value.toTime();
 
 1033     return startToken + tr( 
"time: %1" ).arg( tm.toString( QStringLiteral( 
"hh:mm:ss" ) ) ) + endToken;
 
 1035   else if ( value.type() == QVariant::DateTime )
 
 1037     const QDateTime dt = value.toDateTime();
 
 1038     return startToken + tr( 
"datetime: %1 (%2)" ).arg( dt.toString( QStringLiteral( 
"yyyy-MM-dd hh:mm:ss" ) ), dt.timeZoneAbbreviation() ) + endToken;
 
 1040   else if ( value.type() == QVariant::String )
 
 1042     const QString previewString = value.toString();
 
 1043     if ( previewString.length() > maximumPreviewLength + 3 )
 
 1045       return tr( 
"'%1…'" ).arg( previewString.left( maximumPreviewLength ) );
 
 1049       return '\'' + previewString + 
'\'';
 
 1052   else if ( value.type() == QVariant::Map )
 
 1054     QString mapStr = QStringLiteral( 
"{" );
 
 1055     const QVariantMap map = value.toMap();
 
 1057     for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
 
 1059       mapStr.append( separator );
 
 1060       if ( separator.isEmpty() )
 
 1061         separator = QStringLiteral( 
"," );
 
 1063       mapStr.append( QStringLiteral( 
" '%1': %2" ).arg( it.key(), 
formatPreviewString( it.value(), htmlOutput ) ) );
 
 1064       if ( mapStr.length() > maximumPreviewLength - 3 )
 
 1066         mapStr = tr( 
"%1…" ).arg( mapStr.left( maximumPreviewLength - 2 ) );
 
 1071       mapStr += QLatin1Char( 
' ' );
 
 1072     mapStr += QLatin1Char( 
'}' );
 
 1075   else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
 
 1077     QString listStr = QStringLiteral( 
"[" );
 
 1078     const QVariantList list = value.toList();
 
 1080     for ( 
const QVariant &arrayValue : list )
 
 1082       listStr.append( separator );
 
 1083       if ( separator.isEmpty() )
 
 1084         separator = QStringLiteral( 
"," );
 
 1086       listStr.append( 
" " );
 
 1088       if ( listStr.length() > maximumPreviewLength - 3 )
 
 1090         listStr = QString( tr( 
"%1…" ) ).arg( listStr.left( maximumPreviewLength - 2 ) );
 
 1094     if ( !list.empty() )
 
 1095       listStr += QLatin1Char( 
' ' );
 
 1096     listStr += QLatin1Char( 
']' );
 
 1099   else if ( value.type() == QVariant::Int ||
 
 1100             value.type() == QVariant::UInt ||
 
 1101             value.type() == QVariant::LongLong ||
 
 1102             value.type() == QVariant::ULongLong ||
 
 1103             value.type() == QVariant::Double ||
 
 1105             value.type() == 
static_cast<QVariant::Type
>( QMetaType::Float ) )
 
 1107     return QgsExpressionUtils::toLocalizedString( value );
 
 1111     QString 
str { value.toString() };
 
 1112     if ( 
str.length() > maximumPreviewLength - 3 )
 
 1114       str = tr( 
"%1…" ).arg( 
str.left( maximumPreviewLength - 2 ) );
 
 1124   if ( value.isNull() )
 
 1125     expr = QStringLiteral( 
"%1 IS NULL" ).arg( 
quotedColumnRef( fieldName ) );
 
 1145       if ( columnRef && literal )
 
 1148         value = literal->
value();
 
 1158   if ( expressions.empty() )
 
 1164   for ( 
const QString &
expression : expressions )
 
 1175       else if ( 
field != inField )
 
 1191         if ( inOp->isNotIn() )
 
 1200           inField = columnRef->
name();
 
 1203         else if ( columnRef->
name() != inField )
 
 1210           const QList<QgsExpressionNode *> 
nodes = nodeList->list();
 
 1228           QStringList orParts;
 
 1231             if ( leftOrOp->op( ) == QgsExpressionNodeBinaryOperator::BinaryOperator::boOr )
 
 1233               orParts.append( collectOrs( leftOrOp->opLeft(), leftOrOp->opRight() ) );
 
 1237               orParts.append( leftOrOp->dump() );
 
 1242             orParts.append( leftInOp->dump() );
 
 1251             if ( rightOrOp->op( ) == QgsExpressionNodeBinaryOperator::BinaryOperator::boOr )
 
 1253               orParts.append( collectOrs( rightOrOp->opLeft(), rightOrOp->opRight() ) );
 
 1257               orParts.append( rightOrOp->dump() );
 
 1262             orParts.append( rightInOp->dump() );
 
 1272         if ( orOp->op( ) == QgsExpressionNodeBinaryOperator::BinaryOperator::boOr )
 
 1275           const QStringList orParts = collectOrs( orOp->opLeft(), orOp->opRight() );
 
 1276           if ( orParts.isEmpty() )
 
 1282             QString orPartsResult;
 
 1287               if ( ! inExp.rootNode() )
 
 1294                 if ( inOpInner->node()->nodeType() != QgsExpressionNode::NodeType::ntColumnRef || inOpInner->node()->referencedColumns().size() < 1 )
 
 1299                 const QString innerInfield { inOpInner->node()->
referencedColumns().values().first() };
 
 1303                   inField = innerInfield;
 
 1307                 if ( innerInfield != inField )
 
 1313                   const auto constInnerValuesList { inOpInner->list()->list() };
 
 1314                   for ( 
const auto &innerInValueNode : std::as_const( constInnerValuesList ) )
 
 1316                     values.append( innerInValueNode->dump() );
 
 1343   result = QStringLiteral( 
"%1 IN (%2)" ).arg( 
quotedColumnRef( inField ), values.join( 
',' ) );
 
 1349   return d->mRootNode;
 
 1364   if ( attrIndex >= 0 )
 
 1371     const QString fieldName =  qgis::down_cast<const QgsExpressionNodeColumnRef *>( candidate.
rootNode() )->name();
 
 1379   if ( !d->mRootNode )
 
 1380     return QList<const QgsExpressionNode *>();
 
 1382   return d->mRootNode->nodes();
 
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
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 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.
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 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...
void setDistanceUnits(QgsUnitTypes::DistanceUnit unit)
Sets the desired distance units for calculations involving geomCalculator(), e.g.,...
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.
QgsUnitTypes::AreaUnit areaUnits() const
Returns the desired areal units for calculations involving geomCalculator(), e.g.,...
QgsExpression()
Create an empty expression.
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value)
Create an expression allowing to evaluate if a field is equal to a value.
QString dump() const
Returns an expression string, constructed from the internal abstract syntax tree.
static QString helpText(QString name)
Returns the help text for a specified function.
static bool isFieldEqualityExpression(const QString &expression, QString &field, QVariant &value)
Returns true if the given expression is a simple "field=value" type expression.
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.
QgsUnitTypes::DistanceUnit distanceUnits() const
Returns the desired distance units for calculations involving geomCalculator(), e....
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 setAreaUnits(QgsUnitTypes::AreaUnit unit)
Sets the desired areal units for calculations involving geomCalculator(), e.g., "$area".
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.
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 SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
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.
DistanceUnit
Units of distance.
@ DistanceUnknownUnit
Unknown distance unit.
static Q_INVOKABLE QgsUnitTypes::DistanceUnit stringToDistanceUnit(const QString &string, bool *ok=nullptr)
Converts a translated string to a distance unit.
static Q_INVOKABLE QgsUnitTypes::AreaUnit stringToAreaUnit(const QString &string, bool *ok=nullptr)
Converts a translated string to an areal unit.
@ AreaUnknownUnit
Unknown areal unit.
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(Type type) SIP_HOLDGIL
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)
HelpTextHash & functionHelpTexts()
#define QgsDebugMsgLevel(str, level)
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.