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" );
103 case QVariant::StringList:
105 QStringList quotedValues;
106 const QVariantList values = value.toList();
107 quotedValues.reserve( values.count() );
108 for (
const QVariant &v : values )
112 return QStringLiteral(
"array( %1 )" ).arg( quotedValues.join( QLatin1String(
", " ) ) );
116 case QVariant::String:
130 for (
int i = 0; i < count; i++ )
135 for (
const QString &alias : aliases )
137 if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
151 : d( new QgsExpressionPrivate )
153 d->mRootNode =
::parseExpression( expr, d->mParserErrorString, d->mParserErrors );
155 Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
166 if (
this != &other )
168 if ( !d->ref.deref() )
179 QgsExpression::operator QString()
const
185 : d( new QgsExpressionPrivate )
192 if ( !d->ref.deref() )
198 return ( d == other.d || d->mExp == other.d->mExp );
208 return d->mParserErrors.count() > 0;
213 return d->mParserErrorString;
218 return d->mParserErrors;
224 return QSet<QString>();
226 return d->mRootNode->referencedColumns();
232 return QSet<QString>();
234 return d->mRootNode->referencedVariables();
240 return QSet<QString>();
242 return d->mRootNode->referencedFunctions();
250 const QSet<QString> referencedFields = d->mRootNode->referencedColumns();
251 QSet<int> referencedIndexes;
253 for (
const QString &fieldName : referencedFields )
263 referencedIndexes << idx;
267 return referencedIndexes;
274 return d->mRootNode->needsGeometry();
280 if ( context && ! d->mCalc )
284 d->mDaEllipsoid = context->
variable( QStringLiteral(
"project_ellipsoid" ) ).toString();
285 d->mDaCrs = std::make_unique<QgsCoordinateReferenceSystem>( context->
variable( QStringLiteral(
"_layer_crs" ) ).value<QgsCoordinateReferenceSystem>() );
286 d->mDaTransformContext = std::make_unique<QgsCoordinateTransformContext>( context->
variable( QStringLiteral(
"_project_transform_context" ) ).value<QgsCoordinateTransformContext>() );
292 QString distanceUnitsStr = context->
variable( QStringLiteral(
"project_distance_units" ) ).toString();
293 if ( ! distanceUnitsStr.isEmpty() )
300 QString areaUnitsStr = context->
variable( QStringLiteral(
"project_area_units" ) ).toString();
301 if ( ! areaUnitsStr.isEmpty() )
306 void QgsExpression::detach()
312 ( void )d->ref.deref();
314 d =
new QgsExpressionPrivate( *d );
322 d->mCalc = std::shared_ptr<QgsDistanceArea>(
new QgsDistanceArea( *calc ) );
330 d->mEvalErrorString = QString();
336 d->mRootNode =
::parseExpression( d->mExp, d->mParserErrorString, d->mParserErrors );
341 d->mEvalErrorString = tr(
"No root node! Parsing failed?" );
345 initGeomCalculator( context );
346 d->mIsPrepared =
true;
347 return d->mRootNode->prepare(
this, context );
352 d->mEvalErrorString = QString();
355 d->mEvalErrorString = tr(
"No root node! Parsing failed?" );
364 d->mEvalErrorString = QString();
367 d->mEvalErrorString = tr(
"No root node! Parsing failed?" );
371 if ( ! d->mIsPrepared )
375 return d->mRootNode->eval(
this, context );
380 return !d->mEvalErrorString.isNull();
385 return d->mEvalErrorString;
390 d->mEvalErrorString =
str;
398 return d->mRootNode->dump();
403 if ( !d->mCalc && d->mDaCrs && d->mDaCrs->isValid() && d->mDaTransformContext )
407 d->mCalc->setEllipsoid( d->mDaEllipsoid.isEmpty() ?
geoNone() : d->mDaEllipsoid );
408 d->mCalc->setSourceCrs( *d->mDaCrs.get(), *d->mDaTransformContext.get() );
411 return d->mCalc.get();
416 return d->mDistanceUnit;
421 d->mDistanceUnit = unit;
439 while ( index < action.size() )
441 static const QRegularExpression sRegEx{ QStringLiteral(
"\\[%(.*?)%\\]" ), QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption };
443 const QRegularExpressionMatch match = sRegEx.match( action, index );
444 if ( !match.hasMatch() )
447 const int pos = action.indexOf( sRegEx, index );
448 const int start = index;
449 index = pos + match.capturedLength( 0 );
450 const QString toReplace = match.captured( 1 ).trimmed();
457 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 2)
458 expr_action += action.midRef( start, index - start );
460 expr_action += QStringView {action}.mid( start, index - start );
471 QVariant result = exp.
evaluate( context );
476 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 2)
477 expr_action += action.midRef( start, index - start );
479 expr_action += QStringView {action}.mid( start, index - start );
485 expr_action += action.mid( start, pos - start ) + result.toString();
488 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 2)
489 expr_action += action.midRef( index );
491 expr_action += QStringView {action}.mid( index ).toString();
499 QSet<QString> variables;
501 while ( index < text.size() )
503 const thread_local QRegularExpression rx(
"\\[%([^\\]]+)%\\]" );
504 const QRegularExpressionMatch match = rx.match( text );
505 if ( !match.hasMatch() )
508 index = match.capturedStart() + match.capturedLength();
509 QString to_replace = match.captured( 1 ).trimmed();
524 double convertedValue = QLocale().toDouble( text, &ok );
527 return convertedValue;
537 QVariant result = expr.
evaluate( &context );
538 convertedValue = result.toDouble( &ok );
541 return fallbackValue;
543 return convertedValue;
548 QgsExpression::initFunctionHelp();
550 if ( !sFunctionHelpTexts()->contains( name ) )
551 return tr(
"function help for %1 missing" ).arg( name );
553 const Help &f = ( *sFunctionHelpTexts() )[ name ];
556 if ( f.mType == tr(
"group" ) )
558 name =
group( name );
559 name = name.toLower();
562 name = name.toHtmlEscaped();
564 QString helpContents( QStringLiteral(
"<h3>%1</h3>\n<div class=\"description\"><p>%2</p></div>" )
565 .arg( tr(
"%1 %2" ).arg( f.mType, name ),
568 for (
const HelpVariant &v : std::as_const( f.mVariants ) )
570 if ( f.mVariants.size() > 1 )
572 helpContents += QStringLiteral(
"<h3>%1</h3>\n<div class=\"description\">%2</p></div>" ).arg( v.mName, v.mDescription );
575 if ( f.mType != tr(
"group" ) && f.mType != tr(
"expression" ) )
576 helpContents += QStringLiteral(
"<h4>%1</h4>\n<div class=\"syntax\">\n" ).arg( tr(
"Syntax" ) );
578 if ( f.mType == tr(
"operator" ) )
580 if ( v.mArguments.size() == 1 )
582 helpContents += QStringLiteral(
"<code><span class=\"functionname\">%1</span> <span class=\"argument\">%2</span></code>" )
583 .arg( name, v.mArguments[0].mArg );
585 else if ( v.mArguments.size() == 2 )
587 helpContents += QStringLiteral(
"<code><span class=\"argument\">%1</span> <span class=\"functionname\">%2</span> <span class=\"argument\">%3</span></code>" )
588 .arg( v.mArguments[0].mArg, name, v.mArguments[1].mArg );
591 else if ( f.mType != tr(
"group" ) && f.mType != tr(
"expression" ) )
593 helpContents += QStringLiteral(
"<code><span class=\"functionname\">%1</span>" ).arg( name );
595 bool hasOptionalArgs =
false;
597 if ( f.mType == tr(
"function" ) && ( f.mName[0] !=
'$' || !v.mArguments.isEmpty() || v.mVariableLenArguments ) )
602 for (
const HelpArg &a : std::as_const( v.mArguments ) )
608 hasOptionalArgs =
true;
609 helpContents += QLatin1Char(
'[' );
612 helpContents += delim;
613 helpContents += QStringLiteral(
"<span class=\"argument\">%2%3</span>" ).arg(
615 a.mDefaultVal.isEmpty() ? QString() :
'=' + a.mDefaultVal
619 helpContents += QLatin1Char(
']' );
621 delim = QStringLiteral(
"," );
624 if ( v.mVariableLenArguments )
626 helpContents += QChar( 0x2026 );
632 helpContents += QLatin1String(
"</code>" );
634 if ( hasOptionalArgs )
636 helpContents += QLatin1String(
"<br/><br/>" ) + tr(
"[ ] marks optional components" );
640 if ( !v.mArguments.isEmpty() )
642 helpContents += QStringLiteral(
"<h4>%1</h4>\n<div class=\"arguments\">\n<table>" ).arg( tr(
"Arguments" ) );
644 for (
const HelpArg &a : std::as_const( v.mArguments ) )
649 helpContents += QStringLiteral(
"<tr><td class=\"argument\">%1</td><td>%2</td></tr>" ).arg( a.mArg, a.mDescription );
652 helpContents += QLatin1String(
"</table>\n</div>\n" );
655 if ( !v.mExamples.isEmpty() )
657 helpContents += QStringLiteral(
"<h4>%1</h4>\n<div class=\"examples\">\n<ul>\n" ).arg( tr(
"Examples" ) );
659 for (
const HelpExample &e : std::as_const( v.mExamples ) )
661 helpContents +=
"<li><code>" + e.mExpression +
"</code> → <code>" + e.mReturns +
"</code>";
663 if ( !e.mNote.isEmpty() )
664 helpContents += QStringLiteral(
" (%1)" ).arg( e.mNote );
666 helpContents += QLatin1String(
"</li>\n" );
669 helpContents += QLatin1String(
"</ul>\n</div>\n" );
672 if ( !v.mNotes.isEmpty() )
674 helpContents += QStringLiteral(
"<h4>%1</h4>\n<div class=\"notes\"><p>%2</p></div>\n" ).arg( tr(
"Notes" ), v.mNotes );
683 QStringList
tags = QStringList();
685 QgsExpression::initFunctionHelp();
687 if ( sFunctionHelpTexts()->contains( name ) )
689 const Help &f = ( *sFunctionHelpTexts() )[ name ];
691 for (
const HelpVariant &v : std::as_const( f.mVariants ) )
700 void QgsExpression::initVariableHelp()
702 if ( !sVariableHelpTexts()->isEmpty() )
706 sVariableHelpTexts()->insert( QStringLiteral(
"qgis_version" ), QCoreApplication::translate(
"variable_help",
"Current QGIS version string." ) );
707 sVariableHelpTexts()->insert( QStringLiteral(
"qgis_version_no" ), QCoreApplication::translate(
"variable_help",
"Current QGIS version number." ) );
708 sVariableHelpTexts()->insert( QStringLiteral(
"qgis_release_name" ), QCoreApplication::translate(
"variable_help",
"Current QGIS release name." ) );
709 sVariableHelpTexts()->insert( QStringLiteral(
"qgis_short_version" ), QCoreApplication::translate(
"variable_help",
"Short QGIS version string." ) );
710 sVariableHelpTexts()->insert( QStringLiteral(
"qgis_os_name" ), QCoreApplication::translate(
"variable_help",
"Operating system name, e.g., 'windows', 'linux' or 'osx'." ) );
711 sVariableHelpTexts()->insert( QStringLiteral(
"qgis_platform" ), QCoreApplication::translate(
"variable_help",
"QGIS platform, e.g., 'desktop' or 'server'." ) );
712 sVariableHelpTexts()->insert( QStringLiteral(
"qgis_locale" ), QCoreApplication::translate(
"variable_help",
"Two letter identifier for current QGIS locale." ) );
713 sVariableHelpTexts()->insert( QStringLiteral(
"user_account_name" ), QCoreApplication::translate(
"variable_help",
"Current user's operating system account name." ) );
714 sVariableHelpTexts()->insert( QStringLiteral(
"user_full_name" ), QCoreApplication::translate(
"variable_help",
"Current user's operating system user name (if available)." ) );
717 sVariableHelpTexts()->insert( QStringLiteral(
"project_title" ), QCoreApplication::translate(
"variable_help",
"Title of current project." ) );
718 sVariableHelpTexts()->insert( QStringLiteral(
"project_path" ), QCoreApplication::translate(
"variable_help",
"Full path (including file name) of current project." ) );
719 sVariableHelpTexts()->insert( QStringLiteral(
"project_folder" ), QCoreApplication::translate(
"variable_help",
"Folder for current project." ) );
720 sVariableHelpTexts()->insert( QStringLiteral(
"project_filename" ), QCoreApplication::translate(
"variable_help",
"Filename of current project." ) );
721 sVariableHelpTexts()->insert( QStringLiteral(
"project_basename" ), QCoreApplication::translate(
"variable_help",
"Base name of current project's filename (without path and extension)." ) );
722 sVariableHelpTexts()->insert( QStringLiteral(
"project_home" ), QCoreApplication::translate(
"variable_help",
"Home path of current project." ) );
723 sVariableHelpTexts()->insert( QStringLiteral(
"project_crs" ), QCoreApplication::translate(
"variable_help",
"Coordinate reference system of project (e.g., 'EPSG:4326')." ) );
724 sVariableHelpTexts()->insert( QStringLiteral(
"project_crs_definition" ), QCoreApplication::translate(
"variable_help",
"Coordinate reference system of project (full definition)." ) );
725 sVariableHelpTexts()->insert( QStringLiteral(
"project_units" ), QCoreApplication::translate(
"variable_help",
"Unit of the project's CRS." ) );
726 sVariableHelpTexts()->insert( QStringLiteral(
"project_crs_description" ), QCoreApplication::translate(
"variable_help",
"Name of the coordinate reference system of the project." ) );
727 sVariableHelpTexts()->insert( QStringLiteral(
"project_crs_acronym" ), QCoreApplication::translate(
"variable_help",
"Acronym of the coordinate reference system of the project." ) );
728 sVariableHelpTexts()->insert( QStringLiteral(
"project_crs_ellipsoid" ), QCoreApplication::translate(
"variable_help",
"Acronym of the ellipsoid of the coordinate reference system of the project." ) );
729 sVariableHelpTexts()->insert( QStringLiteral(
"project_crs_proj4" ), QCoreApplication::translate(
"variable_help",
"Proj4 definition of the coordinate reference system of the project." ) );
730 sVariableHelpTexts()->insert( QStringLiteral(
"project_crs_wkt" ), QCoreApplication::translate(
"variable_help",
"WKT definition of the coordinate reference system of the project." ) );
731 sVariableHelpTexts()->insert( QStringLiteral(
"project_author" ), QCoreApplication::translate(
"variable_help",
"Project author, taken from project metadata." ) );
732 sVariableHelpTexts()->insert( QStringLiteral(
"project_abstract" ), QCoreApplication::translate(
"variable_help",
"Project abstract, taken from project metadata." ) );
733 sVariableHelpTexts()->insert( QStringLiteral(
"project_creation_date" ), QCoreApplication::translate(
"variable_help",
"Project creation date, taken from project metadata." ) );
734 sVariableHelpTexts()->insert( QStringLiteral(
"project_identifier" ), QCoreApplication::translate(
"variable_help",
"Project identifier, taken from project metadata." ) );
735 sVariableHelpTexts()->insert( QStringLiteral(
"project_last_saved" ), QCoreApplication::translate(
"variable_help",
"Date/time when project was last saved." ) );
736 sVariableHelpTexts()->insert( QStringLiteral(
"project_keywords" ), QCoreApplication::translate(
"variable_help",
"Project keywords, taken from project metadata." ) );
737 sVariableHelpTexts()->insert( QStringLiteral(
"project_area_units" ), QCoreApplication::translate(
"variable_help",
"Area unit for current project, used when calculating areas of geometries." ) );
738 sVariableHelpTexts()->insert( QStringLiteral(
"project_distance_units" ), QCoreApplication::translate(
"variable_help",
"Distance unit for current project, used when calculating lengths of geometries." ) );
739 sVariableHelpTexts()->insert( QStringLiteral(
"project_ellipsoid" ), QCoreApplication::translate(
"variable_help",
"Name of ellipsoid of current project, used when calculating geodetic areas and lengths of geometries." ) );
740 sVariableHelpTexts()->insert( QStringLiteral(
"layer_ids" ), QCoreApplication::translate(
"variable_help",
"List of all map layer IDs from the current project." ) );
741 sVariableHelpTexts()->insert( QStringLiteral(
"layers" ), QCoreApplication::translate(
"variable_help",
"List of all map layers from the current project." ) );
744 sVariableHelpTexts()->insert( QStringLiteral(
"layer_name" ), QCoreApplication::translate(
"variable_help",
"Name of current layer." ) );
745 sVariableHelpTexts()->insert( QStringLiteral(
"layer_id" ), QCoreApplication::translate(
"variable_help",
"ID of current layer." ) );
746 sVariableHelpTexts()->insert( QStringLiteral(
"layer_crs" ), QCoreApplication::translate(
"variable_help",
"CRS Authority ID of current layer." ) );
747 sVariableHelpTexts()->insert( QStringLiteral(
"layer" ), QCoreApplication::translate(
"variable_help",
"The current layer." ) );
750 sVariableHelpTexts()->insert( QStringLiteral(
"layout_name" ), QCoreApplication::translate(
"variable_help",
"Name of composition." ) );
751 sVariableHelpTexts()->insert( QStringLiteral(
"layout_numpages" ), QCoreApplication::translate(
"variable_help",
"Number of pages in composition." ) );
752 sVariableHelpTexts()->insert( QStringLiteral(
"layout_page" ), QCoreApplication::translate(
"variable_help",
"Current page number in composition." ) );
753 sVariableHelpTexts()->insert( QStringLiteral(
"layout_pageheight" ), QCoreApplication::translate(
"variable_help",
"Composition page height in mm (or specified custom units)." ) );
754 sVariableHelpTexts()->insert( QStringLiteral(
"layout_pagewidth" ), QCoreApplication::translate(
"variable_help",
"Composition page width in mm (or specified custom units)." ) );
755 sVariableHelpTexts()->insert( QStringLiteral(
"layout_pageoffsets" ), QCoreApplication::translate(
"variable_help",
"Array of Y coordinate of the top of each page." ) );
756 sVariableHelpTexts()->insert( QStringLiteral(
"layout_dpi" ), QCoreApplication::translate(
"variable_help",
"Composition resolution (DPI)." ) );
759 sVariableHelpTexts()->insert( QStringLiteral(
"atlas_layerid" ), QCoreApplication::translate(
"variable_help",
"Current atlas coverage layer ID." ) );
760 sVariableHelpTexts()->insert( QStringLiteral(
"atlas_layername" ), QCoreApplication::translate(
"variable_help",
"Current atlas coverage layer name." ) );
761 sVariableHelpTexts()->insert( QStringLiteral(
"atlas_totalfeatures" ), QCoreApplication::translate(
"variable_help",
"Total number of features in atlas." ) );
762 sVariableHelpTexts()->insert( QStringLiteral(
"atlas_featurenumber" ), QCoreApplication::translate(
"variable_help",
"Current atlas feature number." ) );
763 sVariableHelpTexts()->insert( QStringLiteral(
"atlas_filename" ), QCoreApplication::translate(
"variable_help",
"Current atlas file name." ) );
764 sVariableHelpTexts()->insert( QStringLiteral(
"atlas_pagename" ), QCoreApplication::translate(
"variable_help",
"Current atlas page name." ) );
765 sVariableHelpTexts()->insert( QStringLiteral(
"atlas_feature" ), QCoreApplication::translate(
"variable_help",
"Current atlas feature (as feature object)." ) );
766 sVariableHelpTexts()->insert( QStringLiteral(
"atlas_featureid" ), QCoreApplication::translate(
"variable_help",
"Current atlas feature ID." ) );
767 sVariableHelpTexts()->insert( QStringLiteral(
"atlas_geometry" ), QCoreApplication::translate(
"variable_help",
"Current atlas feature geometry." ) );
770 sVariableHelpTexts()->insert( QStringLiteral(
"item_id" ), QCoreApplication::translate(
"variable_help",
"Layout item user-assigned ID (not necessarily unique)." ) );
771 sVariableHelpTexts()->insert( QStringLiteral(
"item_uuid" ), QCoreApplication::translate(
"variable_help",
"layout item unique ID." ) );
772 sVariableHelpTexts()->insert( QStringLiteral(
"item_left" ), QCoreApplication::translate(
"variable_help",
"Left position of layout item (in mm)." ) );
773 sVariableHelpTexts()->insert( QStringLiteral(
"item_top" ), QCoreApplication::translate(
"variable_help",
"Top position of layout item (in mm)." ) );
774 sVariableHelpTexts()->insert( QStringLiteral(
"item_width" ), QCoreApplication::translate(
"variable_help",
"Width of layout item (in mm)." ) );
775 sVariableHelpTexts()->insert( QStringLiteral(
"item_height" ), QCoreApplication::translate(
"variable_help",
"Height of layout item (in mm)." ) );
778 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." ) );
779 sVariableHelpTexts()->insert( QStringLiteral(
"map_rotation" ), QCoreApplication::translate(
"variable_help",
"Current rotation of map." ) );
780 sVariableHelpTexts()->insert( QStringLiteral(
"map_scale" ), QCoreApplication::translate(
"variable_help",
"Current scale of map." ) );
781 sVariableHelpTexts()->insert( QStringLiteral(
"map_extent" ), QCoreApplication::translate(
"variable_help",
"Geometry representing the current extent of the map." ) );
782 sVariableHelpTexts()->insert( QStringLiteral(
"map_extent_center" ), QCoreApplication::translate(
"variable_help",
"Center of map." ) );
783 sVariableHelpTexts()->insert( QStringLiteral(
"map_extent_width" ), QCoreApplication::translate(
"variable_help",
"Width of map." ) );
784 sVariableHelpTexts()->insert( QStringLiteral(
"map_extent_height" ), QCoreApplication::translate(
"variable_help",
"Height of map." ) );
785 sVariableHelpTexts()->insert( QStringLiteral(
"map_crs" ), QCoreApplication::translate(
"variable_help",
"Coordinate reference system of map (e.g., 'EPSG:4326')." ) );
786 sVariableHelpTexts()->insert( QStringLiteral(
"map_crs_description" ), QCoreApplication::translate(
"variable_help",
"Name of the coordinate reference system of the map." ) );
787 sVariableHelpTexts()->insert( QStringLiteral(
"map_units" ), QCoreApplication::translate(
"variable_help",
"Units for map measurements." ) );
788 sVariableHelpTexts()->insert( QStringLiteral(
"map_crs_definition" ), QCoreApplication::translate(
"variable_help",
"Coordinate reference system of the map (full definition)." ) );
789 sVariableHelpTexts()->insert( QStringLiteral(
"map_crs_acronym" ), QCoreApplication::translate(
"variable_help",
"Acronym of the coordinate reference system of the map." ) );
790 sVariableHelpTexts()->insert( QStringLiteral(
"map_crs_projection" ), QCoreApplication::translate(
"variable_help",
"Projection method used by the coordinate reference system of the map." ) );
791 sVariableHelpTexts()->insert( QStringLiteral(
"map_crs_ellipsoid" ), QCoreApplication::translate(
"variable_help",
"Acronym of the ellipsoid of the coordinate reference system of the map." ) );
792 sVariableHelpTexts()->insert( QStringLiteral(
"map_crs_proj4" ), QCoreApplication::translate(
"variable_help",
"Proj4 definition of the coordinate reference system of the map." ) );
793 sVariableHelpTexts()->insert( QStringLiteral(
"map_crs_wkt" ), QCoreApplication::translate(
"variable_help",
"WKT definition of the coordinate reference system of the map." ) );
794 sVariableHelpTexts()->insert( QStringLiteral(
"map_layer_ids" ), QCoreApplication::translate(
"variable_help",
"List of map layer IDs visible in the map." ) );
795 sVariableHelpTexts()->insert( QStringLiteral(
"map_layers" ), QCoreApplication::translate(
"variable_help",
"List of map layers visible in the map." ) );
797 sVariableHelpTexts()->insert( QStringLiteral(
"map_start_time" ), QCoreApplication::translate(
"variable_help",
"Start of the map's temporal time range (as a datetime value)" ) );
798 sVariableHelpTexts()->insert( QStringLiteral(
"map_end_time" ), QCoreApplication::translate(
"variable_help",
"End of the map's temporal time range (as a datetime value)" ) );
799 sVariableHelpTexts()->insert( QStringLiteral(
"map_interval" ), QCoreApplication::translate(
"variable_help",
"Duration of the map's temporal time range (as an interval value)" ) );
801 sVariableHelpTexts()->insert( QStringLiteral(
"frame_rate" ), QCoreApplication::translate(
"variable_help",
"Number of frames per second during animation playback" ) );
802 sVariableHelpTexts()->insert( QStringLiteral(
"frame_number" ), QCoreApplication::translate(
"variable_help",
"Current frame number during animation playback" ) );
803 sVariableHelpTexts()->insert( QStringLiteral(
"frame_duration" ), QCoreApplication::translate(
"variable_help",
"Temporal duration of each animation frame (as an interval value)" ) );
804 sVariableHelpTexts()->insert( QStringLiteral(
"animation_start_time" ), QCoreApplication::translate(
"variable_help",
"Start of the animation's overall temporal time range (as a datetime value)" ) );
805 sVariableHelpTexts()->insert( QStringLiteral(
"animation_end_time" ), QCoreApplication::translate(
"variable_help",
"End of the animation's overall temporal time range (as a datetime value)" ) );
806 sVariableHelpTexts()->insert( QStringLiteral(
"animation_interval" ), QCoreApplication::translate(
"variable_help",
"Duration of the animation's overall temporal time range (as an interval value)" ) );
809 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]." ) );
810 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." ) );
812 sVariableHelpTexts()->insert( QStringLiteral(
"row_number" ), QCoreApplication::translate(
"variable_help",
"Stores the number of the current row." ) );
813 sVariableHelpTexts()->insert( QStringLiteral(
"grid_number" ), QCoreApplication::translate(
"variable_help",
"Current grid annotation value." ) );
814 sVariableHelpTexts()->insert( QStringLiteral(
"grid_axis" ), QCoreApplication::translate(
"variable_help",
"Current grid annotation axis (e.g., 'x' for longitude, 'y' for latitude)." ) );
815 sVariableHelpTexts()->insert( QStringLiteral(
"column_number" ), QCoreApplication::translate(
"variable_help",
"Stores the number of the current column." ) );
818 sVariableHelpTexts()->insert( QStringLiteral(
"canvas_cursor_point" ), QCoreApplication::translate(
"variable_help",
"Last cursor position on the canvas in the project's geographical coordinates." ) );
821 sVariableHelpTexts()->insert( QStringLiteral(
"legend_title" ), QCoreApplication::translate(
"variable_help",
"Title of the legend." ) );
822 sVariableHelpTexts()->insert( QStringLiteral(
"legend_column_count" ), QCoreApplication::translate(
"variable_help",
"Number of column in the legend." ) );
823 sVariableHelpTexts()->insert( QStringLiteral(
"legend_split_layers" ), QCoreApplication::translate(
"variable_help",
"Boolean indicating if layers can be split in the legend." ) );
824 sVariableHelpTexts()->insert( QStringLiteral(
"legend_wrap_string" ), QCoreApplication::translate(
"variable_help",
"Characters used to wrap the legend text." ) );
825 sVariableHelpTexts()->insert( QStringLiteral(
"legend_filter_by_map" ), QCoreApplication::translate(
"variable_help",
"Boolean indicating if the content of the legend is filtered by the map." ) );
826 sVariableHelpTexts()->insert( QStringLiteral(
"legend_filter_out_atlas" ), QCoreApplication::translate(
"variable_help",
"Boolean indicating if the Atlas is filtered out of the legend." ) );
829 sVariableHelpTexts()->insert( QStringLiteral(
"scale_value" ), QCoreApplication::translate(
"variable_help",
"Current scale bar distance value." ) );
832 sVariableHelpTexts()->insert( QStringLiteral(
"snapping_results" ), QCoreApplication::translate(
"variable_help",
833 "<p>An array with an item for each snapped point.</p>"
834 "<p>Each item is a map with the following keys:</p>"
836 "<dt>valid</dt><dd>Boolean that indicates if the snapping result is valid</dd>"
837 "<dt>layer</dt><dd>The layer on which the snapped feature is</dd>"
838 "<dt>feature_id</dt><dd>The feature id of the snapped feature</dd>"
839 "<dt>vertex_index</dt><dd>The index of the snapped vertex</dd>"
840 "<dt>distance</dt><dd>The distance between the mouse cursor and the snapped point at the time of snapping</dd>"
845 sVariableHelpTexts()->insert( QStringLiteral(
"geometry_part_count" ), QCoreApplication::translate(
"variable_help",
"Number of parts in rendered feature's geometry." ) );
846 sVariableHelpTexts()->insert( QStringLiteral(
"geometry_part_num" ), QCoreApplication::translate(
"variable_help",
"Current geometry part number for feature being rendered." ) );
847 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." ) );
848 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." ) );
849 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." ) );
851 sVariableHelpTexts()->insert( QStringLiteral(
"symbol_color" ), QCoreApplication::translate(
"symbol_color",
"Color of symbol used to render the feature." ) );
852 sVariableHelpTexts()->insert( QStringLiteral(
"symbol_angle" ), QCoreApplication::translate(
"symbol_angle",
"Angle of symbol used to render the feature (valid for marker symbols only)." ) );
853 sVariableHelpTexts()->insert( QStringLiteral(
"symbol_layer_count" ), QCoreApplication::translate(
"symbol_layer_count",
"Total number of symbol layers in the symbol." ) );
854 sVariableHelpTexts()->insert( QStringLiteral(
"symbol_layer_index" ), QCoreApplication::translate(
"symbol_layer_index",
"Current symbol layer index." ) );
855 sVariableHelpTexts()->insert( QStringLiteral(
"symbol_marker_row" ), QCoreApplication::translate(
"symbol_marker_row",
"Row number for marker (valid for point pattern fills only)." ) );
856 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_frame" ), QCoreApplication::translate(
"symbol_frame",
"Frame number (for animated symbols only)." ) );
859 sVariableHelpTexts()->insert( QStringLiteral(
"symbol_label" ), QCoreApplication::translate(
"symbol_label",
"Label for the symbol (either a user defined label or the default autogenerated label)." ) );
860 sVariableHelpTexts()->insert( QStringLiteral(
"symbol_id" ), QCoreApplication::translate(
"symbol_id",
"Internal ID of the symbol." ) );
861 sVariableHelpTexts()->insert( QStringLiteral(
"symbol_count" ), QCoreApplication::translate(
"symbol_count",
"Total number of features represented by the symbol." ) );
864 sVariableHelpTexts()->insert( QStringLiteral(
"cluster_color" ), QCoreApplication::translate(
"cluster_color",
"Color of symbols within a cluster, or NULL if symbols have mixed colors." ) );
865 sVariableHelpTexts()->insert( QStringLiteral(
"cluster_size" ), QCoreApplication::translate(
"cluster_size",
"Number of symbols contained within a cluster." ) );
868 sVariableHelpTexts()->insert( QStringLiteral(
"algorithm_id" ), QCoreApplication::translate(
"algorithm_id",
"Unique ID for algorithm." ) );
869 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)." ) );
870 sVariableHelpTexts()->insert( QStringLiteral(
"model_folder" ), QCoreApplication::translate(
"variable_help",
"Folder containing current model (or project folder if model is embedded in a project)." ) );
871 sVariableHelpTexts()->insert( QStringLiteral(
"model_name" ), QCoreApplication::translate(
"variable_help",
"Name of current model." ) );
872 sVariableHelpTexts()->insert( QStringLiteral(
"model_group" ), QCoreApplication::translate(
"variable_help",
"Group for current model." ) );
873 sVariableHelpTexts()->insert( QStringLiteral(
"fullextent_minx" ), QCoreApplication::translate(
"fullextent_minx",
"Minimum x-value from full canvas extent (including all layers)." ) );
874 sVariableHelpTexts()->insert( QStringLiteral(
"fullextent_miny" ), QCoreApplication::translate(
"fullextent_miny",
"Minimum y-value from full canvas extent (including all layers)." ) );
875 sVariableHelpTexts()->insert( QStringLiteral(
"fullextent_maxx" ), QCoreApplication::translate(
"fullextent_maxx",
"Maximum x-value from full canvas extent (including all layers)." ) );
876 sVariableHelpTexts()->insert( QStringLiteral(
"fullextent_maxy" ), QCoreApplication::translate(
"fullextent_maxy",
"Maximum y-value from full canvas extent (including all layers)." ) );
879 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)." ) );
882 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." ) );
883 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." ) );
886 sVariableHelpTexts()->insert( QStringLiteral(
"current_parent_geometry" ), QCoreApplication::translate(
"current_parent_geometry",
887 "Only usable in an embedded form context, "
888 "represents the geometry of the feature currently being edited in the parent form.\n"
889 "Can be used in a form/row context to filter the related features using a value "
890 "from the feature currently edited in the parent form, to make sure that the filter "
891 "still works with standalone forms it is recommended to wrap this variable in a "
893 sVariableHelpTexts()->insert( QStringLiteral(
"current_parent_feature" ), QCoreApplication::translate(
"current_parent_feature",
894 "Only usable in an embedded form context, "
895 "represents the feature currently being edited in the parent form.\n"
896 "Can be used in a form/row context to filter the related features using a value "
897 "from the feature currently edited in the parent form, to make sure that the filter "
898 "still works with standalone forms it is recommended to wrap this variable in a "
902 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." ) );
905 sVariableHelpTexts()->insert( QStringLiteral(
"plot_axis" ), QCoreApplication::translate(
"plot_axis",
"The associated plot axis, e.g. 'x' or 'y'." ) );
906 sVariableHelpTexts()->insert( QStringLiteral(
"plot_axis_value" ), QCoreApplication::translate(
"plot_axis_value",
"The current value for the plot axis." ) );
912 if ( sVariableHelpTexts()->contains( name ) )
916 sVariableHelpTexts()->insert( name, description );
922 QgsExpression::initVariableHelp();
923 return sVariableHelpTexts()->value( variableName, QString() );
928 QString text = !description.isEmpty() ? QStringLiteral(
"<p>%1</p>" ).arg( description ) : QString();
932 if ( !value.isValid() )
934 valueString = QCoreApplication::translate(
"variable_help",
"not set" );
940 text.append( QCoreApplication::translate(
"variable_help",
"<p>Current value: %1</p>" ).arg( valueString ) );
947 if ( sGroups()->isEmpty() )
949 sGroups()->insert( QStringLiteral(
"Aggregates" ), tr(
"Aggregates" ) );
950 sGroups()->insert( QStringLiteral(
"Arrays" ), tr(
"Arrays" ) );
951 sGroups()->insert( QStringLiteral(
"Color" ), tr(
"Color" ) );
952 sGroups()->insert( QStringLiteral(
"Conditionals" ), tr(
"Conditionals" ) );
953 sGroups()->insert( QStringLiteral(
"Conversions" ), tr(
"Conversions" ) );
954 sGroups()->insert( QStringLiteral(
"Date and Time" ), tr(
"Date and Time" ) );
955 sGroups()->insert( QStringLiteral(
"Fields and Values" ), tr(
"Fields and Values" ) );
956 sGroups()->insert( QStringLiteral(
"Files and Paths" ), tr(
"Files and Paths" ) );
957 sGroups()->insert( QStringLiteral(
"Fuzzy Matching" ), tr(
"Fuzzy Matching" ) );
958 sGroups()->insert( QStringLiteral(
"General" ), tr(
"General" ) );
959 sGroups()->insert( QStringLiteral(
"GeometryGroup" ), tr(
"Geometry" ) );
960 sGroups()->insert( QStringLiteral(
"Map Layers" ), tr(
"Map Layers" ) );
961 sGroups()->insert( QStringLiteral(
"Maps" ), tr(
"Maps" ) );
962 sGroups()->insert( QStringLiteral(
"Math" ), tr(
"Math" ) );
963 sGroups()->insert( QStringLiteral(
"Operators" ), tr(
"Operators" ) );
964 sGroups()->insert( QStringLiteral(
"Rasters" ), tr(
"Rasters" ) );
965 sGroups()->insert( QStringLiteral(
"Record and Attributes" ), tr(
"Record and Attributes" ) );
966 sGroups()->insert( QStringLiteral(
"String" ), tr(
"String" ) );
967 sGroups()->insert( QStringLiteral(
"Variables" ), tr(
"Variables" ) );
968 sGroups()->insert( QStringLiteral(
"Recent (%1)" ), tr(
"Recent (%1)" ) );
969 sGroups()->insert( QStringLiteral(
"UserGroup" ), tr(
"User expressions" ) );
975 return sGroups()->value( name, name );
980 const QString startToken = htmlOutput ? QStringLiteral(
"<i><" ) : QStringLiteral(
"<" );
981 const QString endToken = htmlOutput ? QStringLiteral(
"></i>" ) : QStringLiteral(
">" );
988 return startToken + tr(
"empty geometry" ) + endToken;
995 return startToken + tr(
"map layer" ) + endToken;
997 else if ( !value.isValid() )
999 return htmlOutput ? tr(
"<i>NULL</i>" ) : QString();
1005 return startToken + tr(
"feature: %1" ).arg( feat.
id() ) + endToken;
1010 if ( interval.
days() > 1 )
1012 return startToken + tr(
"interval: %1 days" ).arg( interval.
days() ) + endToken;
1014 else if ( interval.
hours() > 1 )
1016 return startToken + tr(
"interval: %1 hours" ).arg( interval.
hours() ) + endToken;
1018 else if ( interval.
minutes() > 1 )
1020 return startToken + tr(
"interval: %1 minutes" ).arg( interval.
minutes() ) + endToken;
1024 return startToken + tr(
"interval: %1 seconds" ).arg( interval.
seconds() ) + endToken;
1029 return startToken + tr(
"gradient ramp" ) + endToken;
1031 else if ( value.type() == QVariant::Date )
1033 const QDate dt = value.toDate();
1034 return startToken + tr(
"date: %1" ).arg( dt.toString( QStringLiteral(
"yyyy-MM-dd" ) ) ) + endToken;
1036 else if ( value.type() == QVariant::Time )
1038 const QTime tm = value.toTime();
1039 return startToken + tr(
"time: %1" ).arg( tm.toString( QStringLiteral(
"hh:mm:ss" ) ) ) + endToken;
1041 else if ( value.type() == QVariant::DateTime )
1043 const QDateTime dt = value.toDateTime();
1044 return startToken + tr(
"datetime: %1 (%2)" ).arg( dt.toString( QStringLiteral(
"yyyy-MM-dd hh:mm:ss" ) ), dt.timeZoneAbbreviation() ) + endToken;
1046 else if ( value.type() == QVariant::String )
1048 const QString previewString = value.toString();
1049 if ( previewString.length() > maximumPreviewLength + 3 )
1051 return tr(
"'%1…'" ).arg( previewString.left( maximumPreviewLength ) );
1055 return '\'' + previewString +
'\'';
1058 else if ( value.type() == QVariant::Map )
1060 QString mapStr = QStringLiteral(
"{" );
1061 const QVariantMap map = value.toMap();
1063 for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
1065 mapStr.append( separator );
1066 if ( separator.isEmpty() )
1067 separator = QStringLiteral(
"," );
1069 mapStr.append( QStringLiteral(
" '%1': %2" ).arg( it.key(),
formatPreviewString( it.value(), htmlOutput ) ) );
1070 if ( mapStr.length() > maximumPreviewLength - 3 )
1072 mapStr = tr(
"%1…" ).arg( mapStr.left( maximumPreviewLength - 2 ) );
1077 mapStr += QLatin1Char(
' ' );
1078 mapStr += QLatin1Char(
'}' );
1081 else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
1083 QString listStr = QStringLiteral(
"[" );
1084 const QVariantList list = value.toList();
1086 for (
const QVariant &arrayValue : list )
1088 listStr.append( separator );
1089 if ( separator.isEmpty() )
1090 separator = QStringLiteral(
"," );
1092 listStr.append(
" " );
1094 if ( listStr.length() > maximumPreviewLength - 3 )
1096 listStr = QString( tr(
"%1…" ) ).arg( listStr.left( maximumPreviewLength - 2 ) );
1100 if ( !list.empty() )
1101 listStr += QLatin1Char(
' ' );
1102 listStr += QLatin1Char(
']' );
1105 else if ( value.type() == QVariant::Int ||
1106 value.type() == QVariant::UInt ||
1107 value.type() == QVariant::LongLong ||
1108 value.type() == QVariant::ULongLong ||
1109 value.type() == QVariant::Double ||
1111 value.type() ==
static_cast<QVariant::Type
>( QMetaType::Float ) )
1113 return QgsExpressionUtils::toLocalizedString( value );
1117 QString
str { value.toString() };
1118 if (
str.length() > maximumPreviewLength - 3 )
1120 str = tr(
"%1…" ).arg(
str.left( maximumPreviewLength - 2 ) );
1130 if ( value.isNull() )
1131 expr = QStringLiteral(
"%1 IS NULL" ).arg(
quotedColumnRef( fieldName ) );
1132 else if ( fieldType == QVariant::Type::Invalid )
1153 if ( columnRef && literal )
1156 value = literal->
value();
1166 if ( expressions.empty() )
1172 for (
const QString &
expression : expressions )
1183 else if (
field != inField )
1199 if ( inOp->isNotIn() )
1208 inField = columnRef->
name();
1211 else if ( columnRef->
name() != inField )
1218 const QList<QgsExpressionNode *>
nodes = nodeList->list();
1236 QStringList orParts;
1239 if ( leftOrOp->op( ) == QgsExpressionNodeBinaryOperator::BinaryOperator::boOr )
1241 orParts.append( collectOrs( leftOrOp->opLeft(), leftOrOp->opRight() ) );
1245 orParts.append( leftOrOp->dump() );
1250 orParts.append( leftInOp->dump() );
1259 if ( rightOrOp->op( ) == QgsExpressionNodeBinaryOperator::BinaryOperator::boOr )
1261 orParts.append( collectOrs( rightOrOp->opLeft(), rightOrOp->opRight() ) );
1265 orParts.append( rightOrOp->dump() );
1270 orParts.append( rightInOp->dump() );
1280 if ( orOp->op( ) == QgsExpressionNodeBinaryOperator::BinaryOperator::boOr )
1283 const QStringList orParts = collectOrs( orOp->opLeft(), orOp->opRight() );
1284 if ( orParts.isEmpty() )
1290 QString orPartsResult;
1295 if ( ! inExp.rootNode() )
1302 if ( inOpInner->node()->nodeType() != QgsExpressionNode::NodeType::ntColumnRef || inOpInner->node()->referencedColumns().size() < 1 )
1307 const QString innerInfield { inOpInner->node()->
referencedColumns().values().first() };
1311 inField = innerInfield;
1315 if ( innerInfield != inField )
1321 const auto constInnerValuesList { inOpInner->list()->list() };
1322 for (
const auto &innerInValueNode : std::as_const( constInnerValuesList ) )
1324 values.append( innerInValueNode->dump() );
1351 result = QStringLiteral(
"%1 IN (%2)" ).arg(
quotedColumnRef( inField ), values.join(
',' ) );
1357 return d->mRootNode;
1372 if ( attrIndex >= 0 )
1379 const QString fieldName = qgis::down_cast<const QgsExpressionNodeColumnRef *>( candidate.
rootNode() )->name();
1391 if ( !
expression.contains(
'\"' ) && fieldIndex != -1 )
1404 if ( !d->mRootNode )
1405 return QList<const QgsExpressionNode *>();
1407 return d->mRootNode->nodes();