QGIS API Documentation 3.41.0-Master (3440c17df1d)
Loading...
Searching...
No Matches
qgsexpression.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsexpression.cpp
3 -------------------
4 begin : August 2011
5 copyright : (C) 2011 Martin Dobias
6 email : wonder.sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsexpression.h"
19#include "qgsfeaturerequest.h"
20#include "qgslogger.h"
22#include "qgsgeometry.h"
23#include "qgsproject.h"
25#include "qgsexpressionutils.h"
26#include "qgsexpression_p.h"
27#include "qgsvariantutils.h"
28#include "qgsunittypes.h"
29#include "qgscolorrampimpl.h"
30
31#include <QRegularExpression>
32
33// from parser
34extern QgsExpressionNode *parseExpression( const QString &str, QString &parserErrorMsg, QList<QgsExpression::ParserError> &parserErrors );
35
36Q_GLOBAL_STATIC( QgsStringMap, sVariableHelpTexts )
38
39HelpTextHash QgsExpression::sFunctionHelpTexts;
40QRecursiveMutex QgsExpression::sFunctionsMutex;
41QMap< QString, int> QgsExpression::sFunctionIndexMap;
42
44HelpTextHash &QgsExpression::functionHelpTexts()
45{
46 return sFunctionHelpTexts;
47}
49
50bool QgsExpression::checkExpression( const QString &text, const QgsExpressionContext *context, QString &errorMessage )
51{
52 QgsExpression exp( text );
53 exp.prepare( context );
54 errorMessage = exp.parserErrorString();
55 return !exp.hasParserError();
56}
57
58void QgsExpression::setExpression( const QString &expression )
59{
60 detach();
61 d->mRootNode = ::parseExpression( expression, d->mParserErrorString, d->mParserErrors );
62 d->mEvalErrorString = QString();
63 d->mExp = expression;
64 d->mIsPrepared = false;
65}
66
68{
69 if ( !d->mExp.isNull() )
70 return d->mExp;
71 else
72 return dump();
73}
74
75QString QgsExpression::quotedColumnRef( QString name )
76{
77 return QStringLiteral( "\"%1\"" ).arg( name.replace( '\"', QLatin1String( "\"\"" ) ) );
78}
79
80QString QgsExpression::quotedString( QString text )
81{
82 text.replace( '\'', QLatin1String( "''" ) );
83 text.replace( '\\', QLatin1String( "\\\\" ) );
84 text.replace( '\n', QLatin1String( "\\n" ) );
85 text.replace( '\t', QLatin1String( "\\t" ) );
86 return QStringLiteral( "'%1'" ).arg( text );
87}
88
89QString QgsExpression::quotedValue( const QVariant &value )
90{
91 return quotedValue( value, static_cast<QMetaType::Type>( value.userType() ) );
92}
93
94QString QgsExpression::quotedValue( const QVariant &value, QMetaType::Type type )
95{
96 if ( QgsVariantUtils::isNull( value ) )
97 return QStringLiteral( "NULL" );
98
99 switch ( type )
100 {
101 case QMetaType::Type::Int:
102 case QMetaType::Type::LongLong:
103 case QMetaType::Type::Double:
104 return value.toString();
105
106 case QMetaType::Type::Bool:
107 return value.toBool() ? QStringLiteral( "TRUE" ) : QStringLiteral( "FALSE" );
108
109 case QMetaType::Type::QVariantList:
110 case QMetaType::Type::QStringList:
111 {
112 QStringList quotedValues;
113 const QVariantList values = value.toList();
114 quotedValues.reserve( values.count() );
115 for ( const QVariant &v : values )
116 {
117 quotedValues += quotedValue( v );
118 }
119 return QStringLiteral( "array( %1 )" ).arg( quotedValues.join( QLatin1String( ", " ) ) );
120 }
121
122 default:
123 case QMetaType::Type::QString:
124 return quotedString( value.toString() );
125 }
126
127}
128
129QString QgsExpression::quotedValue( const QVariant &value, QVariant::Type type )
130{
132}
133
134bool QgsExpression::isFunctionName( const QString &name )
135{
136 return functionIndex( name ) != -1;
137}
138
139int QgsExpression::functionIndex( const QString &name )
140{
141 QMutexLocker locker( &sFunctionsMutex );
142
143 auto it = sFunctionIndexMap.constFind( name );
144 if ( it != sFunctionIndexMap.constEnd() )
145 return *it;
146
147 const QList<QgsExpressionFunction *> &functions = QgsExpression::Functions();
148 int i = 0;
149 for ( const QgsExpressionFunction *function : functions )
150 {
151 if ( QString::compare( name, function->name(), Qt::CaseInsensitive ) == 0 )
152 {
153 sFunctionIndexMap.insert( name, i );
154 return i;
155 }
156 const QStringList aliases = function->aliases();
157 for ( const QString &alias : aliases )
158 {
159 if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
160 {
161 sFunctionIndexMap.insert( name, i );
162 return i;
163 }
164 }
165 i++;
166 }
167 return -1;
168}
169
171{
172 return Functions().size();
173}
174
175
176QgsExpression::QgsExpression( const QString &expr )
177 : d( new QgsExpressionPrivate )
178{
179 d->mRootNode = ::parseExpression( expr, d->mParserErrorString, d->mParserErrors );
180 d->mExp = expr;
181 Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
182}
183
185 : d( other.d )
186{
187 d->ref.ref();
188}
189
191{
192 if ( this != &other )
193 {
194 if ( !d->ref.deref() )
195 {
196 delete d;
197 }
198
199 d = other.d;
200 d->ref.ref();
201 }
202 return *this;
203}
204
205QgsExpression::operator QString() const
206{
207 return d->mExp;
208}
209
211 : d( new QgsExpressionPrivate )
212{
213}
214
216{
217 Q_ASSERT( d );
218 if ( !d->ref.deref() )
219 delete d;
220}
221
222bool QgsExpression::operator==( const QgsExpression &other ) const
223{
224 return ( d == other.d || d->mExp == other.d->mExp );
225}
226
228{
229 return d->mRootNode;
230}
231
233{
234 return d->mParserErrors.count() > 0;
235}
236
238{
239 return d->mParserErrorString.replace( "syntax error, unexpected end of file",
240 tr( "Incomplete expression. You might not have finished the full expression." ) );
241}
242
243QList<QgsExpression::ParserError> QgsExpression::parserErrors() const
244{
245 return d->mParserErrors;
246}
247
249{
250 if ( !d->mRootNode )
251 return QSet<QString>();
252
253 return d->mRootNode->referencedColumns();
254}
255
257{
258 if ( !d->mRootNode )
259 return QSet<QString>();
260
261 return d->mRootNode->referencedVariables();
262}
263
265{
266 if ( !d->mRootNode )
267 return QSet<QString>();
268
269 return d->mRootNode->referencedFunctions();
270}
271
273{
274 if ( !d->mRootNode )
275 return QSet<int>();
276
277 const QSet<QString> referencedFields = d->mRootNode->referencedColumns();
278 QSet<int> referencedIndexes;
279
280 for ( const QString &fieldName : referencedFields )
281 {
282 if ( fieldName == QgsFeatureRequest::ALL_ATTRIBUTES )
283 {
284 const QgsAttributeList attributesList = fields.allAttributesList();
285 referencedIndexes = QSet<int>( attributesList.begin(), attributesList.end() );
286 break;
287 }
288 const int idx = fields.lookupField( fieldName );
289 if ( idx >= 0 )
290 {
291 referencedIndexes << idx;
292 }
293 }
294
295 return referencedIndexes;
296}
297
299{
300 if ( !d->mRootNode )
301 return false;
302 return d->mRootNode->needsGeometry();
303}
304
305void QgsExpression::initGeomCalculator( const QgsExpressionContext *context )
306{
307 // Set the geometry calculator from the context if it has not been set by setGeomCalculator()
308 if ( context && ! d->mCalc )
309 {
310 // actually don't do it right away, cos it's expensive to create and only a very small number of expression
311 // functions actually require it. Let's lazily construct it when needed
312 d->mDaEllipsoid = context->variable( QStringLiteral( "project_ellipsoid" ) ).toString();
313 d->mDaCrs = std::make_unique<QgsCoordinateReferenceSystem>( context->variable( QStringLiteral( "_layer_crs" ) ).value<QgsCoordinateReferenceSystem>() );
314 d->mDaTransformContext = std::make_unique<QgsCoordinateTransformContext>( context->variable( QStringLiteral( "_project_transform_context" ) ).value<QgsCoordinateTransformContext>() );
315 }
316
317 // Set the distance units from the context if it has not been set by setDistanceUnits()
318 if ( context && distanceUnits() == Qgis::DistanceUnit::Unknown )
319 {
320 QString distanceUnitsStr = context->variable( QStringLiteral( "project_distance_units" ) ).toString();
321 if ( ! distanceUnitsStr.isEmpty() )
323 }
324
325 // Set the area units from the context if it has not been set by setAreaUnits()
326 if ( context && areaUnits() == Qgis::AreaUnit::Unknown )
327 {
328 QString areaUnitsStr = context->variable( QStringLiteral( "project_area_units" ) ).toString();
329 if ( ! areaUnitsStr.isEmpty() )
331 }
332}
333
334void QgsExpression::detach()
335{
336 Q_ASSERT( d );
337
338 if ( d->ref > 1 )
339 {
340 ( void )d->ref.deref();
341
342 d = new QgsExpressionPrivate( *d );
343 }
344}
345
347{
348 detach();
349 if ( calc )
350 d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea( *calc ) );
351 else
352 d->mCalc.reset();
353}
354
356{
357 detach();
358 d->mEvalErrorString = QString();
359 if ( !d->mRootNode )
360 {
361 //re-parse expression. Creation of QgsExpressionContexts may have added extra
362 //known functions since this expression was created, so we have another try
363 //at re-parsing it now that the context must have been created
364 d->mRootNode = ::parseExpression( d->mExp, d->mParserErrorString, d->mParserErrors );
365 }
366
367 if ( !d->mRootNode )
368 {
369 d->mEvalErrorString = tr( "No root node! Parsing failed?" );
370 return false;
371 }
372
373 initGeomCalculator( context );
374 d->mIsPrepared = true;
375 return d->mRootNode->prepare( this, context );
376}
377
379{
380 d->mEvalErrorString = QString();
381 if ( !d->mRootNode )
382 {
383 d->mEvalErrorString = tr( "No root node! Parsing failed?" );
384 return QVariant();
385 }
386
387 return d->mRootNode->eval( this, static_cast<const QgsExpressionContext *>( nullptr ) );
388}
389
391{
392 d->mEvalErrorString = QString();
393 if ( !d->mRootNode )
394 {
395 d->mEvalErrorString = tr( "No root node! Parsing failed?" );
396 return QVariant();
397 }
398
399 if ( ! d->mIsPrepared )
400 {
401 prepare( context );
402 }
403 return d->mRootNode->eval( this, context );
404}
405
407{
408 return !d->mEvalErrorString.isNull();
409}
410
412{
413 return d->mEvalErrorString;
414}
415
417{
418 d->mEvalErrorString = str;
419}
420
421QString QgsExpression::dump() const
422{
423 if ( !d->mRootNode )
424 return QString();
425
426 return d->mRootNode->dump();
427}
428
430{
431 if ( !d->mCalc && d->mDaCrs && d->mDaCrs->isValid() && d->mDaTransformContext )
432 {
433 // calculator IS required, so initialize it now...
434 d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea() );
435 d->mCalc->setEllipsoid( d->mDaEllipsoid.isEmpty() ? geoNone() : d->mDaEllipsoid );
436 d->mCalc->setSourceCrs( *d->mDaCrs.get(), *d->mDaTransformContext.get() );
437 }
438
439 return d->mCalc.get();
440}
441
443{
444 return d->mDistanceUnit;
445}
446
448{
449 d->mDistanceUnit = unit;
450}
451
453{
454 return d->mAreaUnit;
455}
456
458{
459 d->mAreaUnit = unit;
460}
461
462QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea )
463{
464 QString expr_action;
465
466 int index = 0;
467 while ( index < action.size() )
468 {
469 static const QRegularExpression sRegEx{ QStringLiteral( "\\[%(.*?)%\\]" ), QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption };
470
471 const QRegularExpressionMatch match = sRegEx.match( action, index );
472 if ( !match.hasMatch() )
473 break;
474
475 const int pos = action.indexOf( sRegEx, index );
476 const int start = index;
477 index = pos + match.capturedLength( 0 );
478 const QString toReplace = match.captured( 1 ).trimmed();
479 QgsDebugMsgLevel( "Found expression: " + toReplace, 3 );
480
481 QgsExpression exp( toReplace );
482 if ( exp.hasParserError() )
483 {
484 QgsDebugError( "Expression parser error: " + exp.parserErrorString() );
485 expr_action += QStringView {action} .mid( start, index - start );
486 continue;
487 }
488
489 if ( distanceArea )
490 {
491 //if QgsDistanceArea specified for area/distance conversion, use it
492 exp.setGeomCalculator( distanceArea );
493 }
494
495 QVariant result = exp.evaluate( context );
496
497 if ( exp.hasEvalError() )
498 {
499 QgsDebugError( "Expression parser eval error: " + exp.evalErrorString() );
500 expr_action += QStringView {action} .mid( start, index - start );
501 continue;
502 }
503
504 QString resultString;
505 if ( !QgsVariantUtils::isNull( result ) )
506 resultString = result.toString();
507
508 QgsDebugMsgLevel( "Expression result is: " + resultString, 3 );
509
510 expr_action += action.mid( start, pos - start ) + resultString;
511 }
512
513 expr_action += QStringView {action} .mid( index ).toString();
514 return expr_action;
515}
516
517QSet<QString> QgsExpression::referencedVariables( const QString &text )
518{
519 QSet<QString> variables;
520 int index = 0;
521 while ( index < text.size() )
522 {
523 const thread_local QRegularExpression rx( "\\[%([^\\]]+)%\\]" );
524 const QRegularExpressionMatch match = rx.match( text );
525 if ( !match.hasMatch() )
526 break;
527
528 index = match.capturedStart() + match.capturedLength();
529 QString to_replace = match.captured( 1 ).trimmed();
530
531 QgsExpression exp( to_replace );
532 variables.unite( exp.referencedVariables() );
533 }
534
535 return variables;
536}
537
538double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
539{
540 bool ok;
541 //first test if text is directly convertible to double
542 // use system locale: e.g. in German locale, user is presented with numbers "1,23" instead of "1.23" in C locale
543 // so we also want to allow user to rewrite it to "5,23" and it is still accepted
544 double convertedValue = QLocale().toDouble( text, &ok );
545 if ( ok )
546 {
547 return convertedValue;
548 }
549
550 //otherwise try to evaluate as expression
551 QgsExpression expr( text );
552
553 QgsExpressionContext context;
556
557 QVariant result = expr.evaluate( &context );
558 convertedValue = result.toDouble( &ok );
559 if ( expr.hasEvalError() || !ok )
560 {
561 return fallbackValue;
562 }
563 return convertedValue;
564}
565
566QString QgsExpression::helpText( QString name )
567{
568 QgsExpression::initFunctionHelp();
569
570 if ( !sFunctionHelpTexts.contains( name ) )
571 return tr( "function help for %1 missing" ).arg( name );
572
573 const Help &f = sFunctionHelpTexts[ name ];
574
575 name = f.mName;
576 if ( f.mType == tr( "group" ) )
577 {
578 name = group( name );
579 name = name.toLower();
580 }
581
582 name = name.toHtmlEscaped();
583
584 QString helpContents( QStringLiteral( "<h3>%1</h3>\n<div class=\"description\"><p>%2</p></div>" )
585 .arg( tr( "%1 %2" ).arg( f.mType, name ),
586 f.mDescription ) );
587
588 for ( const HelpVariant &v : std::as_const( f.mVariants ) )
589 {
590 if ( f.mVariants.size() > 1 )
591 {
592 helpContents += QStringLiteral( "<h3>%1</h3>\n<div class=\"description\">%2</p></div>" ).arg( v.mName, v.mDescription );
593 }
594
595 if ( f.mType != tr( "group" ) && f.mType != tr( "expression" ) )
596 helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"syntax\">\n" ).arg( tr( "Syntax" ) );
597
598 if ( f.mType == tr( "operator" ) )
599 {
600 if ( v.mArguments.size() == 1 )
601 {
602 helpContents += QStringLiteral( "<code><span class=\"functionname\">%1</span> <span class=\"argument\">%2</span></code>" )
603 .arg( name, v.mArguments[0].mArg );
604 }
605 else if ( v.mArguments.size() == 2 )
606 {
607 helpContents += QStringLiteral( "<code><span class=\"argument\">%1</span> <span class=\"functionname\">%2</span> <span class=\"argument\">%3</span></code>" )
608 .arg( v.mArguments[0].mArg, name, v.mArguments[1].mArg );
609 }
610 }
611 else if ( f.mType != tr( "group" ) && f.mType != tr( "expression" ) )
612 {
613 helpContents += QStringLiteral( "<code><span class=\"functionname\">%1</span>" ).arg( name );
614
615 bool hasOptionalArgs = false;
616
617 if ( f.mType == tr( "function" ) && ( f.mName[0] != '$' || !v.mArguments.isEmpty() || v.mVariableLenArguments ) )
618 {
619 helpContents += '(';
620
621 QString delim;
622 for ( const HelpArg &a : std::as_const( v.mArguments ) )
623 {
624 if ( !a.mDescOnly )
625 {
626 if ( a.mOptional )
627 {
628 hasOptionalArgs = true;
629 helpContents += QLatin1Char( '[' );
630 }
631
632 helpContents += delim;
633 helpContents += QStringLiteral( "<span class=\"argument\">%2%3</span>" ).arg(
634 a.mArg,
635 a.mDefaultVal.isEmpty() ? QString() : ":=" + a.mDefaultVal
636 );
637
638 if ( a.mOptional )
639 helpContents += QLatin1Char( ']' );
640 }
641 delim = QStringLiteral( "," );
642 }
643
644 if ( v.mVariableLenArguments )
645 {
646 helpContents += QChar( 0x2026 );
647 }
648
649 helpContents += ')';
650 }
651
652 helpContents += QLatin1String( "</code>" );
653
654 if ( hasOptionalArgs )
655 {
656 helpContents += QLatin1String( "<br/><br/>" ) + tr( "[ ] marks optional components" );
657 }
658 }
659
660 if ( !v.mArguments.isEmpty() )
661 {
662 helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"arguments\">\n<table>" ).arg( tr( "Arguments" ) );
663
664 for ( const HelpArg &a : std::as_const( v.mArguments ) )
665 {
666 if ( a.mSyntaxOnly )
667 continue;
668
669 helpContents += QStringLiteral( "<tr><td class=\"argument\">%1</td><td>%2</td></tr>" ).arg( a.mArg, a.mDescription );
670 }
671
672 helpContents += QLatin1String( "</table>\n</div>\n" );
673 }
674
675 if ( !v.mExamples.isEmpty() )
676 {
677 helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"examples\">\n<ul>\n" ).arg( tr( "Examples" ) );
678
679 for ( const HelpExample &e : std::as_const( v.mExamples ) )
680 {
681 helpContents += "<li><code>" + e.mExpression + "</code> &rarr; <code>" + e.mReturns + "</code>";
682
683 if ( !e.mNote.isEmpty() )
684 helpContents += QStringLiteral( " (%1)" ).arg( e.mNote );
685
686 helpContents += QLatin1String( "</li>\n" );
687 }
688
689 helpContents += QLatin1String( "</ul>\n</div>\n" );
690 }
691
692 if ( !v.mNotes.isEmpty() )
693 {
694 helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"notes\"><p>%2</p></div>\n" ).arg( tr( "Notes" ), v.mNotes );
695 }
696 }
697
698 return helpContents;
699}
700
701QStringList QgsExpression::tags( const QString &name )
702{
703 QStringList tags = QStringList();
704
705 QgsExpression::initFunctionHelp();
706
707 if ( sFunctionHelpTexts.contains( name ) )
708 {
709 const Help &f = sFunctionHelpTexts[ name ];
710
711 for ( const HelpVariant &v : std::as_const( f.mVariants ) )
712 {
713 tags << v.mTags;
714 }
715 }
716
717 return tags;
718}
719
720void QgsExpression::initVariableHelp()
721{
722 if ( !sVariableHelpTexts()->isEmpty() )
723 return;
724
725 //global variables
726 sVariableHelpTexts()->insert( QStringLiteral( "qgis_version" ), QCoreApplication::translate( "variable_help", "Current QGIS version string." ) );
727 sVariableHelpTexts()->insert( QStringLiteral( "qgis_version_no" ), QCoreApplication::translate( "variable_help", "Current QGIS version number." ) );
728 sVariableHelpTexts()->insert( QStringLiteral( "qgis_release_name" ), QCoreApplication::translate( "variable_help", "Current QGIS release name." ) );
729 sVariableHelpTexts()->insert( QStringLiteral( "qgis_short_version" ), QCoreApplication::translate( "variable_help", "Short QGIS version string." ) );
730 sVariableHelpTexts()->insert( QStringLiteral( "qgis_os_name" ), QCoreApplication::translate( "variable_help", "Operating system name, e.g., 'windows', 'linux' or 'osx'." ) );
731 sVariableHelpTexts()->insert( QStringLiteral( "qgis_platform" ), QCoreApplication::translate( "variable_help", "QGIS platform, e.g., 'desktop' or 'server'." ) );
732 sVariableHelpTexts()->insert( QStringLiteral( "qgis_locale" ), QCoreApplication::translate( "variable_help", "Two letter identifier for current QGIS locale." ) );
733 sVariableHelpTexts()->insert( QStringLiteral( "user_account_name" ), QCoreApplication::translate( "variable_help", "Current user's operating system account name." ) );
734 sVariableHelpTexts()->insert( QStringLiteral( "user_full_name" ), QCoreApplication::translate( "variable_help", "Current user's operating system user name (if available)." ) );
735
736 //project variables
737 sVariableHelpTexts()->insert( QStringLiteral( "project_title" ), QCoreApplication::translate( "variable_help", "Title of current project." ) );
738 sVariableHelpTexts()->insert( QStringLiteral( "project_path" ), QCoreApplication::translate( "variable_help", "Full path (including file name) of current project." ) );
739 sVariableHelpTexts()->insert( QStringLiteral( "project_folder" ), QCoreApplication::translate( "variable_help", "Folder for current project." ) );
740 sVariableHelpTexts()->insert( QStringLiteral( "project_filename" ), QCoreApplication::translate( "variable_help", "Filename of current project." ) );
741 sVariableHelpTexts()->insert( QStringLiteral( "project_basename" ), QCoreApplication::translate( "variable_help", "Base name of current project's filename (without path and extension)." ) );
742 sVariableHelpTexts()->insert( QStringLiteral( "project_home" ), QCoreApplication::translate( "variable_help", "Home path of current project." ) );
743 sVariableHelpTexts()->insert( QStringLiteral( "project_crs" ), QCoreApplication::translate( "variable_help", "Identifier for the coordinate reference system of project (e.g., 'EPSG:4326')." ) );
744 sVariableHelpTexts()->insert( QStringLiteral( "project_crs_definition" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of project (full definition)." ) );
745 sVariableHelpTexts()->insert( QStringLiteral( "project_units" ), QCoreApplication::translate( "variable_help", "Unit of the project's CRS." ) );
746 sVariableHelpTexts()->insert( QStringLiteral( "project_crs_description" ), QCoreApplication::translate( "variable_help", "Name of the coordinate reference system of the project." ) );
747 sVariableHelpTexts()->insert( QStringLiteral( "project_crs_acronym" ), QCoreApplication::translate( "variable_help", "Acronym of the coordinate reference system of the project." ) );
748 sVariableHelpTexts()->insert( QStringLiteral( "project_crs_ellipsoid" ), QCoreApplication::translate( "variable_help", "Acronym of the ellipsoid of the coordinate reference system of the project." ) );
749 sVariableHelpTexts()->insert( QStringLiteral( "project_crs_proj4" ), QCoreApplication::translate( "variable_help", "Proj4 definition of the coordinate reference system of the project." ) );
750 sVariableHelpTexts()->insert( QStringLiteral( "project_crs_wkt" ), QCoreApplication::translate( "variable_help", "WKT definition of the coordinate reference system of the project." ) );
751
752 sVariableHelpTexts()->insert( QStringLiteral( "project_vertical_crs" ), QCoreApplication::translate( "variable_help", "Identifier for the vertical coordinate reference system of the project (e.g., 'EPSG:5703')." ) );
753 sVariableHelpTexts()->insert( QStringLiteral( "project_vertical_crs_definition" ), QCoreApplication::translate( "variable_help", "Vertical coordinate reference system of project (full definition)." ) );
754 sVariableHelpTexts()->insert( QStringLiteral( "project_vertical_crs_description" ), QCoreApplication::translate( "variable_help", "Name of the vertical coordinate reference system of the project." ) );
755 sVariableHelpTexts()->insert( QStringLiteral( "project_vertical_crs_wkt" ), QCoreApplication::translate( "variable_help", "WKT definition of the vertical coordinate reference system of the project." ) );
756
757 sVariableHelpTexts()->insert( QStringLiteral( "project_author" ), QCoreApplication::translate( "variable_help", "Project author, taken from project metadata." ) );
758 sVariableHelpTexts()->insert( QStringLiteral( "project_abstract" ), QCoreApplication::translate( "variable_help", "Project abstract, taken from project metadata." ) );
759 sVariableHelpTexts()->insert( QStringLiteral( "project_creation_date" ), QCoreApplication::translate( "variable_help", "Project creation date, taken from project metadata." ) );
760 sVariableHelpTexts()->insert( QStringLiteral( "project_identifier" ), QCoreApplication::translate( "variable_help", "Project identifier, taken from project metadata." ) );
761 sVariableHelpTexts()->insert( QStringLiteral( "project_last_saved" ), QCoreApplication::translate( "variable_help", "Date/time when project was last saved." ) );
762 sVariableHelpTexts()->insert( QStringLiteral( "project_keywords" ), QCoreApplication::translate( "variable_help", "Project keywords, taken from project metadata." ) );
763 sVariableHelpTexts()->insert( QStringLiteral( "project_area_units" ), QCoreApplication::translate( "variable_help", "Area unit for current project, used when calculating areas of geometries." ) );
764 sVariableHelpTexts()->insert( QStringLiteral( "project_distance_units" ), QCoreApplication::translate( "variable_help", "Distance unit for current project, used when calculating lengths of geometries." ) );
765 sVariableHelpTexts()->insert( QStringLiteral( "project_ellipsoid" ), QCoreApplication::translate( "variable_help", "Name of ellipsoid of current project, used when calculating geodetic areas and lengths of geometries." ) );
766 sVariableHelpTexts()->insert( QStringLiteral( "layer_ids" ), QCoreApplication::translate( "variable_help", "List of all map layer IDs from the current project." ) );
767 sVariableHelpTexts()->insert( QStringLiteral( "layers" ), QCoreApplication::translate( "variable_help", "List of all map layers from the current project." ) );
768
769 //layer variables
770 sVariableHelpTexts()->insert( QStringLiteral( "layer_name" ), QCoreApplication::translate( "variable_help", "Name of current layer." ) );
771 sVariableHelpTexts()->insert( QStringLiteral( "layer_id" ), QCoreApplication::translate( "variable_help", "ID of current layer." ) );
772 sVariableHelpTexts()->insert( QStringLiteral( "layer_crs" ), QCoreApplication::translate( "variable_help", "CRS Authority ID of current layer." ) );
773 sVariableHelpTexts()->insert( QStringLiteral( "layer" ), QCoreApplication::translate( "variable_help", "The current layer." ) );
774 sVariableHelpTexts()->insert( QStringLiteral( "layer_crs_ellipsoid" ), QCoreApplication::translate( "variable_help", "Ellipsoid acronym of current layer CRS." ) );
775
776 sVariableHelpTexts()->insert( QStringLiteral( "layer_vertical_crs" ), QCoreApplication::translate( "variable_help", "Identifier for the vertical coordinate reference system of the layer (e.g., 'EPSG:5703')." ) );
777 sVariableHelpTexts()->insert( QStringLiteral( "layer_vertical_crs_definition" ), QCoreApplication::translate( "variable_help", "Vertical coordinate reference system of layer (full definition)." ) );
778 sVariableHelpTexts()->insert( QStringLiteral( "layer_vertical_crs_description" ), QCoreApplication::translate( "variable_help", "Name of the vertical coordinate reference system of the layer." ) );
779 sVariableHelpTexts()->insert( QStringLiteral( "layer_vertical_crs_wkt" ), QCoreApplication::translate( "variable_help", "WKT definition of the vertical coordinate reference system of the layer." ) );
780
781 //feature variables
782 sVariableHelpTexts()->insert( QStringLiteral( "feature" ), QCoreApplication::translate( "variable_help", "The current feature being evaluated. This can be used with the 'attribute' function to evaluate attribute values from the current feature." ) );
783 sVariableHelpTexts()->insert( QStringLiteral( "id" ), QCoreApplication::translate( "variable_help", "The ID of the current feature being evaluated." ) );
784 sVariableHelpTexts()->insert( QStringLiteral( "geometry" ), QCoreApplication::translate( "variable_help", "The geometry of the current feature being evaluated." ) );
785
786 //composition variables
787 sVariableHelpTexts()->insert( QStringLiteral( "layout_name" ), QCoreApplication::translate( "variable_help", "Name of composition." ) );
788 sVariableHelpTexts()->insert( QStringLiteral( "layout_numpages" ), QCoreApplication::translate( "variable_help", "Number of pages in composition." ) );
789 sVariableHelpTexts()->insert( QStringLiteral( "layout_page" ), QCoreApplication::translate( "variable_help", "Current page number in composition." ) );
790 sVariableHelpTexts()->insert( QStringLiteral( "layout_pageheight" ), QCoreApplication::translate( "variable_help", "Composition page height in mm (or specified custom units)." ) );
791 sVariableHelpTexts()->insert( QStringLiteral( "layout_pagewidth" ), QCoreApplication::translate( "variable_help", "Composition page width in mm (or specified custom units)." ) );
792 sVariableHelpTexts()->insert( QStringLiteral( "layout_pageoffsets" ), QCoreApplication::translate( "variable_help", "Array of Y coordinate of the top of each page." ) );
793 sVariableHelpTexts()->insert( QStringLiteral( "layout_dpi" ), QCoreApplication::translate( "variable_help", "Composition resolution (DPI)." ) );
794
795 //atlas variables
796 sVariableHelpTexts()->insert( QStringLiteral( "atlas_layerid" ), QCoreApplication::translate( "variable_help", "Current atlas coverage layer ID." ) );
797 sVariableHelpTexts()->insert( QStringLiteral( "atlas_layername" ), QCoreApplication::translate( "variable_help", "Current atlas coverage layer name." ) );
798 sVariableHelpTexts()->insert( QStringLiteral( "atlas_totalfeatures" ), QCoreApplication::translate( "variable_help", "Total number of features in atlas." ) );
799 sVariableHelpTexts()->insert( QStringLiteral( "atlas_featurenumber" ), QCoreApplication::translate( "variable_help", "Current atlas feature number." ) );
800 sVariableHelpTexts()->insert( QStringLiteral( "atlas_filename" ), QCoreApplication::translate( "variable_help", "Current atlas file name." ) );
801 sVariableHelpTexts()->insert( QStringLiteral( "atlas_pagename" ), QCoreApplication::translate( "variable_help", "Current atlas page name." ) );
802 sVariableHelpTexts()->insert( QStringLiteral( "atlas_feature" ), QCoreApplication::translate( "variable_help", "Current atlas feature (as feature object)." ) );
803 sVariableHelpTexts()->insert( QStringLiteral( "atlas_featureid" ), QCoreApplication::translate( "variable_help", "Current atlas feature ID." ) );
804 sVariableHelpTexts()->insert( QStringLiteral( "atlas_geometry" ), QCoreApplication::translate( "variable_help", "Current atlas feature geometry." ) );
805
806 //layout item variables
807 sVariableHelpTexts()->insert( QStringLiteral( "item_id" ), QCoreApplication::translate( "variable_help", "Layout item user-assigned ID (not necessarily unique)." ) );
808 sVariableHelpTexts()->insert( QStringLiteral( "item_uuid" ), QCoreApplication::translate( "variable_help", "layout item unique ID." ) );
809 sVariableHelpTexts()->insert( QStringLiteral( "item_left" ), QCoreApplication::translate( "variable_help", "Left position of layout item (in mm)." ) );
810 sVariableHelpTexts()->insert( QStringLiteral( "item_top" ), QCoreApplication::translate( "variable_help", "Top position of layout item (in mm)." ) );
811 sVariableHelpTexts()->insert( QStringLiteral( "item_width" ), QCoreApplication::translate( "variable_help", "Width of layout item (in mm)." ) );
812 sVariableHelpTexts()->insert( QStringLiteral( "item_height" ), QCoreApplication::translate( "variable_help", "Height of layout item (in mm)." ) );
813
814 //map settings item variables
815 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." ) );
816 sVariableHelpTexts()->insert( QStringLiteral( "map_rotation" ), QCoreApplication::translate( "variable_help", "Current rotation of map." ) );
817 sVariableHelpTexts()->insert( QStringLiteral( "map_scale" ), QCoreApplication::translate( "variable_help", "Current scale of map." ) );
818 sVariableHelpTexts()->insert( QStringLiteral( "map_extent" ), QCoreApplication::translate( "variable_help", "Geometry representing the current extent of the map." ) );
819 sVariableHelpTexts()->insert( QStringLiteral( "map_extent_center" ), QCoreApplication::translate( "variable_help", "Center of map." ) );
820 sVariableHelpTexts()->insert( QStringLiteral( "map_extent_width" ), QCoreApplication::translate( "variable_help", "Width of map." ) );
821 sVariableHelpTexts()->insert( QStringLiteral( "map_extent_height" ), QCoreApplication::translate( "variable_help", "Height of map." ) );
822 sVariableHelpTexts()->insert( QStringLiteral( "map_crs" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of map (e.g., 'EPSG:4326')." ) );
823 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_description" ), QCoreApplication::translate( "variable_help", "Name of the coordinate reference system of the map." ) );
824 sVariableHelpTexts()->insert( QStringLiteral( "map_units" ), QCoreApplication::translate( "variable_help", "Units for map measurements." ) );
825 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_definition" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of the map (full definition)." ) );
826 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_acronym" ), QCoreApplication::translate( "variable_help", "Acronym of the coordinate reference system of the map." ) );
827 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_projection" ), QCoreApplication::translate( "variable_help", "Projection method used by the coordinate reference system of the map." ) );
828 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_ellipsoid" ), QCoreApplication::translate( "variable_help", "Acronym of the ellipsoid of the coordinate reference system of the map." ) );
829 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_proj4" ), QCoreApplication::translate( "variable_help", "Proj4 definition of the coordinate reference system of the map." ) );
830 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_wkt" ), QCoreApplication::translate( "variable_help", "WKT definition of the coordinate reference system of the map." ) );
831 sVariableHelpTexts()->insert( QStringLiteral( "map_layer_ids" ), QCoreApplication::translate( "variable_help", "List of map layer IDs visible in the map." ) );
832 sVariableHelpTexts()->insert( QStringLiteral( "map_layers" ), QCoreApplication::translate( "variable_help", "List of map layers visible in the map." ) );
833
834 sVariableHelpTexts()->insert( QStringLiteral( "map_start_time" ), QCoreApplication::translate( "variable_help", "Start of the map's temporal time range (as a datetime value)" ) );
835 sVariableHelpTexts()->insert( QStringLiteral( "map_end_time" ), QCoreApplication::translate( "variable_help", "End of the map's temporal time range (as a datetime value)" ) );
836 sVariableHelpTexts()->insert( QStringLiteral( "map_interval" ), QCoreApplication::translate( "variable_help", "Duration of the map's temporal time range (as an interval value)" ) );
837 sVariableHelpTexts()->insert( QStringLiteral( "map_z_range_lower" ), QCoreApplication::translate( "variable_help", "Lower elevation of the map's elevation range" ) );
838 sVariableHelpTexts()->insert( QStringLiteral( "map_z_range_upper" ), QCoreApplication::translate( "variable_help", "Upper elevation of the map's elevation range" ) );
839
840 sVariableHelpTexts()->insert( QStringLiteral( "frame_rate" ), QCoreApplication::translate( "variable_help", "Number of frames per second during animation playback" ) );
841 sVariableHelpTexts()->insert( QStringLiteral( "frame_number" ), QCoreApplication::translate( "variable_help", "Current frame number during animation playback" ) );
842 sVariableHelpTexts()->insert( QStringLiteral( "frame_duration" ), QCoreApplication::translate( "variable_help", "Temporal duration of each animation frame (as an interval value)" ) );
843 sVariableHelpTexts()->insert( QStringLiteral( "frame_timestep" ), QCoreApplication::translate( "variable_help", "Frame time step during animation playback" ) );
844 sVariableHelpTexts()->insert( QStringLiteral( "frame_timestep_unit" ), QCoreApplication::translate( "variable_help", "Unit value of the frame time step during animation playback" ) );
845 sVariableHelpTexts()->insert( QStringLiteral( "frame_timestep_units" ), QCoreApplication::translate( "variable_help", "String representation of the frame time step unit during animation playback" ) );
846 sVariableHelpTexts()->insert( QStringLiteral( "animation_start_time" ), QCoreApplication::translate( "variable_help", "Start of the animation's overall temporal time range (as a datetime value)" ) );
847 sVariableHelpTexts()->insert( QStringLiteral( "animation_end_time" ), QCoreApplication::translate( "variable_help", "End of the animation's overall temporal time range (as a datetime value)" ) );
848 sVariableHelpTexts()->insert( QStringLiteral( "animation_interval" ), QCoreApplication::translate( "variable_help", "Duration of the animation's overall temporal time range (as an interval value)" ) );
849
850 // vector tile layer variables
851 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]." ) );
852 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." ) );
853
854 sVariableHelpTexts()->insert( QStringLiteral( "row_number" ), QCoreApplication::translate( "variable_help", "Stores the number of the current row." ) );
855 sVariableHelpTexts()->insert( QStringLiteral( "grid_number" ), QCoreApplication::translate( "variable_help", "Current grid annotation value." ) );
856 sVariableHelpTexts()->insert( QStringLiteral( "grid_axis" ), QCoreApplication::translate( "variable_help", "Current grid annotation axis (e.g., 'x' for longitude, 'y' for latitude)." ) );
857 sVariableHelpTexts()->insert( QStringLiteral( "column_number" ), QCoreApplication::translate( "variable_help", "Stores the number of the current column." ) );
858
859 // map canvas item variables
860 sVariableHelpTexts()->insert( QStringLiteral( "canvas_cursor_point" ), QCoreApplication::translate( "variable_help", "Last cursor position on the canvas in the project's geographical coordinates." ) );
861 sVariableHelpTexts()->insert( QStringLiteral( "layer_cursor_point" ), QCoreApplication::translate( "variable_help", "Last cursor position on the canvas in the current layers's geographical coordinates. QGIS Server: When used in a maptip expression for a raster layer, this variable holds the GetFeatureInfo position." ) );
862
863 // legend canvas item variables
864 sVariableHelpTexts()->insert( QStringLiteral( "legend_title" ), QCoreApplication::translate( "variable_help", "Title of the legend." ) );
865 sVariableHelpTexts()->insert( QStringLiteral( "legend_column_count" ), QCoreApplication::translate( "variable_help", "Number of column in the legend." ) );
866 sVariableHelpTexts()->insert( QStringLiteral( "legend_split_layers" ), QCoreApplication::translate( "variable_help", "Boolean indicating if layers can be split in the legend." ) );
867 sVariableHelpTexts()->insert( QStringLiteral( "legend_wrap_string" ), QCoreApplication::translate( "variable_help", "Characters used to wrap the legend text." ) );
868 sVariableHelpTexts()->insert( QStringLiteral( "legend_filter_by_map" ), QCoreApplication::translate( "variable_help", "Boolean indicating if the content of the legend is filtered by the map." ) );
869 sVariableHelpTexts()->insert( QStringLiteral( "legend_filter_out_atlas" ), QCoreApplication::translate( "variable_help", "Boolean indicating if the Atlas is filtered out of the legend." ) );
870
871 // scalebar rendering
872 sVariableHelpTexts()->insert( QStringLiteral( "scale_value" ), QCoreApplication::translate( "variable_help", "Current scale bar distance value." ) );
873
874 // map tool capture variables
875 sVariableHelpTexts()->insert( QStringLiteral( "snapping_results" ), QCoreApplication::translate( "variable_help",
876 "<p>An array with an item for each snapped point.</p>"
877 "<p>Each item is a map with the following keys:</p>"
878 "<dl>"
879 "<dt>valid</dt><dd>Boolean that indicates if the snapping result is valid</dd>"
880 "<dt>layer</dt><dd>The layer on which the snapped feature is</dd>"
881 "<dt>feature_id</dt><dd>The feature id of the snapped feature</dd>"
882 "<dt>vertex_index</dt><dd>The index of the snapped vertex</dd>"
883 "<dt>distance</dt><dd>The distance between the mouse cursor and the snapped point at the time of snapping</dd>"
884 "</dl>" ) );
885
886
887 //symbol variables
888 sVariableHelpTexts()->insert( QStringLiteral( "geometry_part_count" ), QCoreApplication::translate( "variable_help", "Number of parts in rendered feature's geometry." ) );
889 sVariableHelpTexts()->insert( QStringLiteral( "geometry_part_num" ), QCoreApplication::translate( "variable_help", "Current geometry part number for feature being rendered." ) );
890 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." ) );
891 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." ) );
892 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." ) );
893
894 sVariableHelpTexts()->insert( QStringLiteral( "symbol_color" ), QCoreApplication::translate( "symbol_color", "Color of symbol used to render the feature." ) );
895 sVariableHelpTexts()->insert( QStringLiteral( "symbol_angle" ), QCoreApplication::translate( "symbol_angle", "Angle of symbol used to render the feature (valid for marker symbols only)." ) );
896 sVariableHelpTexts()->insert( QStringLiteral( "symbol_layer_count" ), QCoreApplication::translate( "symbol_layer_count", "Total number of symbol layers in the symbol." ) );
897 sVariableHelpTexts()->insert( QStringLiteral( "symbol_layer_index" ), QCoreApplication::translate( "symbol_layer_index", "Current symbol layer index." ) );
898 sVariableHelpTexts()->insert( QStringLiteral( "symbol_marker_row" ), QCoreApplication::translate( "symbol_marker_row", "Row number for marker (valid for point pattern fills only)." ) );
899 sVariableHelpTexts()->insert( QStringLiteral( "symbol_marker_column" ), QCoreApplication::translate( "symbol_marker_column", "Column number for marker (valid for point pattern fills only)." ) );
900 sVariableHelpTexts()->insert( QStringLiteral( "symbol_frame" ), QCoreApplication::translate( "symbol_frame", "Frame number (for animated symbols only)." ) );
901
902 sVariableHelpTexts()->insert( QStringLiteral( "symbol_label" ), QCoreApplication::translate( "symbol_label", "Label for the symbol (either a user defined label or the default autogenerated label)." ) );
903 sVariableHelpTexts()->insert( QStringLiteral( "symbol_id" ), QCoreApplication::translate( "symbol_id", "Internal ID of the symbol." ) );
904 sVariableHelpTexts()->insert( QStringLiteral( "symbol_count" ), QCoreApplication::translate( "symbol_count", "Total number of features represented by the symbol." ) );
905
906 //cluster variables
907 sVariableHelpTexts()->insert( QStringLiteral( "cluster_color" ), QCoreApplication::translate( "cluster_color", "Color of symbols within a cluster, or NULL if symbols have mixed colors." ) );
908 sVariableHelpTexts()->insert( QStringLiteral( "cluster_size" ), QCoreApplication::translate( "cluster_size", "Number of symbols contained within a cluster." ) );
909
910 //processing variables
911 sVariableHelpTexts()->insert( QStringLiteral( "algorithm_id" ), QCoreApplication::translate( "algorithm_id", "Unique ID for algorithm." ) );
912 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)." ) );
913 sVariableHelpTexts()->insert( QStringLiteral( "model_folder" ), QCoreApplication::translate( "variable_help", "Folder containing current model (or project folder if model is embedded in a project)." ) );
914 sVariableHelpTexts()->insert( QStringLiteral( "model_name" ), QCoreApplication::translate( "variable_help", "Name of current model." ) );
915 sVariableHelpTexts()->insert( QStringLiteral( "model_group" ), QCoreApplication::translate( "variable_help", "Group for current model." ) );
916 sVariableHelpTexts()->insert( QStringLiteral( "fullextent_minx" ), QCoreApplication::translate( "fullextent_minx", "Minimum x-value from full canvas extent (including all layers)." ) );
917 sVariableHelpTexts()->insert( QStringLiteral( "fullextent_miny" ), QCoreApplication::translate( "fullextent_miny", "Minimum y-value from full canvas extent (including all layers)." ) );
918 sVariableHelpTexts()->insert( QStringLiteral( "fullextent_maxx" ), QCoreApplication::translate( "fullextent_maxx", "Maximum x-value from full canvas extent (including all layers)." ) );
919 sVariableHelpTexts()->insert( QStringLiteral( "fullextent_maxy" ), QCoreApplication::translate( "fullextent_maxy", "Maximum y-value from full canvas extent (including all layers)." ) );
920
921 //provider notification
922 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)." ) );
923
924 //form context variable
925 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." ) );
926 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." ) );
927
928 //parent form context variable
929 sVariableHelpTexts()->insert( QStringLiteral( "current_parent_geometry" ), QCoreApplication::translate( "current_parent_geometry",
930 "Only usable in an embedded form context, "
931 "represents the geometry of the feature currently being edited in the parent form.\n"
932 "Can be used in a form/row context to filter the related features using a value "
933 "from the feature currently edited in the parent form, to make sure that the filter "
934 "still works with standalone forms it is recommended to wrap this variable in a "
935 "'coalesce()'." ) );
936 sVariableHelpTexts()->insert( QStringLiteral( "current_parent_feature" ), QCoreApplication::translate( "current_parent_feature",
937 "Only usable in an embedded form context, "
938 "represents the feature currently being edited in the parent form.\n"
939 "Can be used in a form/row context to filter the related features using a value "
940 "from the feature currently edited in the parent form, to make sure that the filter "
941 "still works with standalone forms it is recommended to wrap this variable in a "
942 "'coalesce()'." ) );
943
944 //form variable
945 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." ) );
946
947 // plots
948 sVariableHelpTexts()->insert( QStringLiteral( "plot_axis" ), QCoreApplication::translate( "plot_axis", "The associated plot axis, e.g. 'x' or 'y'." ) );
949 sVariableHelpTexts()->insert( QStringLiteral( "plot_axis_value" ), QCoreApplication::translate( "plot_axis_value", "The current value for the plot axis." ) );
950}
951
952
953bool QgsExpression::addVariableHelpText( const QString name, const QString &description )
954{
955 if ( sVariableHelpTexts()->contains( name ) )
956 {
957 return false;
958 }
959 sVariableHelpTexts()->insert( name, description );
960 return true;
961}
962
963QString QgsExpression::variableHelpText( const QString &variableName )
964{
965 QgsExpression::initVariableHelp();
966 return sVariableHelpTexts()->value( variableName, QString() );
967}
968
969QString QgsExpression::formatVariableHelp( const QString &description, bool showValue, const QVariant &value )
970{
971 QString text = !description.isEmpty() ? QStringLiteral( "<p>%1</p>" ).arg( description ) : QString();
972 if ( showValue )
973 {
974 QString valueString;
975 if ( !value.isValid() )
976 {
977 valueString = QCoreApplication::translate( "variable_help", "not set" );
978 }
979 else
980 {
981 valueString = QStringLiteral( "<b>%1</b>" ).arg( formatPreviewString( value ) );
982 }
983 text.append( QCoreApplication::translate( "variable_help", "<p>Current value: %1</p>" ).arg( valueString ) );
984 }
985 return text;
986}
987
988QString QgsExpression::group( const QString &name )
989{
990 if ( sGroups()->isEmpty() )
991 {
992 sGroups()->insert( QStringLiteral( "Aggregates" ), tr( "Aggregates" ) );
993 sGroups()->insert( QStringLiteral( "Arrays" ), tr( "Arrays" ) );
994 sGroups()->insert( QStringLiteral( "Color" ), tr( "Color" ) );
995 sGroups()->insert( QStringLiteral( "Conditionals" ), tr( "Conditionals" ) );
996 sGroups()->insert( QStringLiteral( "Conversions" ), tr( "Conversions" ) );
997 sGroups()->insert( QStringLiteral( "Date and Time" ), tr( "Date and Time" ) );
998 sGroups()->insert( QStringLiteral( "Fields and Values" ), tr( "Fields and Values" ) );
999 sGroups()->insert( QStringLiteral( "Files and Paths" ), tr( "Files and Paths" ) );
1000 sGroups()->insert( QStringLiteral( "Fuzzy Matching" ), tr( "Fuzzy Matching" ) );
1001 sGroups()->insert( QStringLiteral( "General" ), tr( "General" ) );
1002 sGroups()->insert( QStringLiteral( "GeometryGroup" ), tr( "Geometry" ) );
1003 sGroups()->insert( QStringLiteral( "Map Layers" ), tr( "Map Layers" ) );
1004 sGroups()->insert( QStringLiteral( "Maps" ), tr( "Maps" ) );
1005 sGroups()->insert( QStringLiteral( "Math" ), tr( "Math" ) );
1006 sGroups()->insert( QStringLiteral( "Operators" ), tr( "Operators" ) );
1007 sGroups()->insert( QStringLiteral( "Rasters" ), tr( "Rasters" ) );
1008 sGroups()->insert( QStringLiteral( "Record and Attributes" ), tr( "Record and Attributes" ) );
1009 sGroups()->insert( QStringLiteral( "String" ), tr( "String" ) );
1010 sGroups()->insert( QStringLiteral( "Variables" ), tr( "Variables" ) );
1011 sGroups()->insert( QStringLiteral( "Recent (%1)" ), tr( "Recent (%1)" ) );
1012 sGroups()->insert( QStringLiteral( "UserGroup" ), tr( "User expressions" ) );
1013 }
1014
1015 //return the translated name for this group. If group does not
1016 //have a translated name in the gGroups hash, return the name
1017 //unchanged
1018 return sGroups()->value( name, name );
1019}
1020
1021QString QgsExpression::formatPreviewString( const QVariant &value, const bool htmlOutput, int maximumPreviewLength )
1022{
1023 const QString startToken = htmlOutput ? QStringLiteral( "<i>&lt;" ) : QStringLiteral( "<" );
1024 const QString endToken = htmlOutput ? QStringLiteral( "&gt;</i>" ) : QStringLiteral( ">" );
1025
1026 QgsGeometry geom = QgsExpressionUtils::getGeometry( value, nullptr );
1027 if ( !geom.isNull() )
1028 {
1029 //result is a geometry
1030 if ( geom.isNull() )
1031 return startToken + tr( "empty geometry" ) + endToken;
1032 else
1033 return startToken + tr( "geometry: %1" ).arg( QgsWkbTypes::displayString( geom.constGet()->wkbType() ) )
1034 + endToken;
1035 }
1036 else if ( value.value< QgsWeakMapLayerPointer >().data() )
1037 {
1038 return startToken + tr( "map layer" ) + endToken;
1039 }
1040 else if ( !value.isValid() )
1041 {
1042 return htmlOutput ? tr( "<i>NULL</i>" ) : QString();
1043 }
1044 else if ( value.userType() == qMetaTypeId< QgsFeature>() )
1045 {
1046 //result is a feature
1047 QgsFeature feat = value.value<QgsFeature>();
1048 return startToken + tr( "feature: %1" ).arg( feat.id() ) + endToken;
1049 }
1050 else if ( value.userType() == qMetaTypeId< QgsInterval>() )
1051 {
1052 QgsInterval interval = value.value<QgsInterval>();
1053 if ( interval.days() > 1 )
1054 {
1055 return startToken + tr( "interval: %1 days" ).arg( interval.days() ) + endToken;
1056 }
1057 else if ( interval.hours() > 1 )
1058 {
1059 return startToken + tr( "interval: %1 hours" ).arg( interval.hours() ) + endToken;
1060 }
1061 else if ( interval.minutes() > 1 )
1062 {
1063 return startToken + tr( "interval: %1 minutes" ).arg( interval.minutes() ) + endToken;
1064 }
1065 else
1066 {
1067 return startToken + tr( "interval: %1 seconds" ).arg( interval.seconds() ) + endToken;
1068 }
1069 }
1070 else if ( value.userType() == qMetaTypeId< QgsGradientColorRamp>() )
1071 {
1072 return startToken + tr( "gradient ramp" ) + endToken;
1073 }
1074 else if ( value.userType() == QMetaType::Type::QDate )
1075 {
1076 const QDate dt = value.toDate();
1077 return startToken + tr( "date: %1" ).arg( dt.toString( QStringLiteral( "yyyy-MM-dd" ) ) ) + endToken;
1078 }
1079 else if ( value.userType() == QMetaType::Type::QTime )
1080 {
1081 const QTime tm = value.toTime();
1082 return startToken + tr( "time: %1" ).arg( tm.toString( QStringLiteral( "hh:mm:ss" ) ) ) + endToken;
1083 }
1084 else if ( value.userType() == QMetaType::Type::QDateTime )
1085 {
1086 const QDateTime dt = value.toDateTime();
1087 return startToken + tr( "datetime: %1 (%2)" ).arg( dt.toString( QStringLiteral( "yyyy-MM-dd hh:mm:ss" ) ), dt.timeZoneAbbreviation() ) + endToken;
1088 }
1089 else if ( value.userType() == QMetaType::Type::QString )
1090 {
1091 const QString previewString = value.toString();
1092 if ( previewString.length() > maximumPreviewLength + 3 )
1093 {
1094 return tr( "'%1…'" ).arg( previewString.left( maximumPreviewLength ) );
1095 }
1096 else
1097 {
1098 return '\'' + previewString + '\'';
1099 }
1100 }
1101 else if ( value.userType() == QMetaType::Type::QVariantMap )
1102 {
1103 QString mapStr = QStringLiteral( "{" );
1104 const QVariantMap map = value.toMap();
1105 QString separator;
1106 for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
1107 {
1108 mapStr.append( separator );
1109 if ( separator.isEmpty() )
1110 separator = QStringLiteral( "," );
1111
1112 mapStr.append( QStringLiteral( " '%1': %2" ).arg( it.key(), formatPreviewString( it.value(), htmlOutput ) ) );
1113 if ( mapStr.length() > maximumPreviewLength - 3 )
1114 {
1115 mapStr = tr( "%1…" ).arg( mapStr.left( maximumPreviewLength - 2 ) );
1116 break;
1117 }
1118 }
1119 if ( !map.empty() )
1120 mapStr += QLatin1Char( ' ' );
1121 mapStr += QLatin1Char( '}' );
1122 return mapStr;
1123 }
1124 else if ( value.userType() == QMetaType::Type::QVariantList || value.userType() == QMetaType::Type::QStringList )
1125 {
1126 QString listStr = QStringLiteral( "[" );
1127 const QVariantList list = value.toList();
1128 QString separator;
1129 for ( const QVariant &arrayValue : list )
1130 {
1131 listStr.append( separator );
1132 if ( separator.isEmpty() )
1133 separator = QStringLiteral( "," );
1134
1135 listStr.append( " " );
1136 listStr.append( formatPreviewString( arrayValue, htmlOutput ) );
1137 if ( listStr.length() > maximumPreviewLength - 3 )
1138 {
1139 listStr = QString( tr( "%1…" ) ).arg( listStr.left( maximumPreviewLength - 2 ) );
1140 break;
1141 }
1142 }
1143 if ( !list.empty() )
1144 listStr += QLatin1Char( ' ' );
1145 listStr += QLatin1Char( ']' );
1146 return listStr;
1147 }
1148 else if ( value.type() == QVariant::Color )
1149 {
1150 const QColor color = value.value<QColor>();
1151
1152 if ( !color.isValid() )
1153 {
1154 return tr( "<i>Invalid</i>" );
1155 }
1156
1157 switch ( color.spec() )
1158 {
1159 case QColor::Spec::Cmyk:
1160 return QStringLiteral( "CMYKA: %1,%2,%3,%4,%5" )
1161 .arg( color.cyanF(), 0, 'f', 2 ).arg( color.magentaF(), 0, 'f', 2 )
1162 .arg( color.yellowF(), 0, 'f', 2 ).arg( color.blackF(), 0, 'f', 2 )
1163 .arg( color.alphaF(), 0, 'f', 2 );
1164
1165 case QColor::Spec::Hsv:
1166 return QStringLiteral( "HSVA: %1,%2,%3,%4" )
1167 .arg( color.hsvHueF(), 0, 'f', 2 ).arg( color.hsvSaturationF(), 0, 'f', 2 )
1168 .arg( color.valueF(), 0, 'f', 2 ).arg( color.alphaF(), 0, 'f', 2 );
1169
1170 case QColor::Spec::Hsl:
1171 return QStringLiteral( "HSLA: %1,%2,%3,%4" )
1172 .arg( color.hslHueF(), 0, 'f', 2 ).arg( color.hslSaturationF(), 0, 'f', 2 )
1173 .arg( color.lightnessF(), 0, 'f', 2 ).arg( color.alphaF(), 0, 'f', 2 );
1174
1175 case QColor::Spec::Rgb:
1176 case QColor::Spec::ExtendedRgb:
1177 return QStringLiteral( "RGBA: %1,%2,%3,%4" )
1178 .arg( color.redF(), 0, 'f', 2 ).arg( color.greenF(), 0, 'f', 2 )
1179 .arg( color.blueF(), 0, 'f', 2 ).arg( color.alphaF(), 0, 'f', 2 );
1180
1181 case QColor::Spec::Invalid:
1182 return tr( "<i>Invalid</i>" );
1183 }
1184 QgsDebugError( QStringLiteral( "Unknown color format: %1" ).arg( color.spec() ) );
1185 return tr( "<i>Unknown color format: %1</i>" ).arg( color.spec() );
1186 }
1187 else if ( value.userType() == QMetaType::Type::Int ||
1188 value.userType() == QMetaType::Type::UInt ||
1189 value.userType() == QMetaType::Type::LongLong ||
1190 value.userType() == QMetaType::Type::ULongLong ||
1191 value.userType() == QMetaType::Type::Double ||
1192 // Qt madness with QMetaType::Float :/
1193 value.userType() == static_cast<QMetaType::Type>( QMetaType::Float ) )
1194 {
1195 return QgsExpressionUtils::toLocalizedString( value );
1196 }
1197 else
1198 {
1199 QString str { value.toString() };
1200 if ( str.length() > maximumPreviewLength - 3 )
1201 {
1202 str = tr( "%1…" ).arg( str.left( maximumPreviewLength - 2 ) );
1203 }
1204 return str;
1205 }
1206}
1207
1208QString QgsExpression::createFieldEqualityExpression( const QString &fieldName, const QVariant &value, QMetaType::Type fieldType )
1209{
1210 QString expr;
1211
1212 if ( QgsVariantUtils::isNull( value ) )
1213 expr = QStringLiteral( "%1 IS NULL" ).arg( quotedColumnRef( fieldName ) );
1214 else if ( fieldType == QMetaType::Type::UnknownType )
1215 expr = QStringLiteral( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value ) );
1216 else
1217 expr = QStringLiteral( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value, fieldType ) );
1218
1219 return expr;
1220}
1221
1222QString QgsExpression::createFieldEqualityExpression( const QString &fieldName, const QVariant &value, QVariant::Type fieldType )
1223{
1224 return createFieldEqualityExpression( fieldName, value, QgsVariantUtils::variantTypeToMetaType( fieldType ) );
1225}
1226
1227bool QgsExpression::isFieldEqualityExpression( const QString &expression, QString &field, QVariant &value )
1228{
1230
1231 if ( !e.rootNode() )
1232 return false;
1233
1234 if ( const QgsExpressionNodeBinaryOperator *binOp = dynamic_cast<const QgsExpressionNodeBinaryOperator *>( e.rootNode() ) )
1235 {
1236 if ( binOp->op() == QgsExpressionNodeBinaryOperator::boEQ )
1237 {
1238 const QgsExpressionNodeColumnRef *columnRef = dynamic_cast<const QgsExpressionNodeColumnRef *>( binOp->opLeft() );
1239 const QgsExpressionNodeLiteral *literal = dynamic_cast<const QgsExpressionNodeLiteral *>( binOp->opRight() );
1240 if ( columnRef && literal )
1241 {
1242 field = columnRef->name();
1243 value = literal->value();
1244 return true;
1245 }
1246 }
1247 }
1248 return false;
1249}
1250
1251bool QgsExpression::attemptReduceToInClause( const QStringList &expressions, QString &result )
1252{
1253 if ( expressions.empty() )
1254 return false;
1255
1256 QString inField;
1257 bool first = true;
1258 QStringList values;
1259 for ( const QString &expression : expressions )
1260 {
1261 QString field;
1262 QVariant value;
1264 {
1265 if ( first )
1266 {
1267 inField = field;
1268 first = false;
1269 }
1270 else if ( field != inField )
1271 {
1272 return false;
1273 }
1274 values << QgsExpression::quotedValue( value );
1275 }
1276 else
1277 {
1278 // we also allow reducing similar 'field IN (...)' expressions!
1280
1281 if ( !e.rootNode() )
1282 return false;
1283
1284 if ( const QgsExpressionNodeInOperator *inOp = dynamic_cast<const QgsExpressionNodeInOperator *>( e.rootNode() ) )
1285 {
1286 if ( inOp->isNotIn() )
1287 return false;
1288
1289 const QgsExpressionNodeColumnRef *columnRef = dynamic_cast<const QgsExpressionNodeColumnRef *>( inOp->node() );
1290 if ( !columnRef )
1291 return false;
1292
1293 if ( first )
1294 {
1295 inField = columnRef->name();
1296 first = false;
1297 }
1298 else if ( columnRef->name() != inField )
1299 {
1300 return false;
1301 }
1302
1303 if ( QgsExpressionNode::NodeList *nodeList = inOp->list() )
1304 {
1305 const QList<QgsExpressionNode *> nodes = nodeList->list();
1306 for ( const QgsExpressionNode *node : nodes )
1307 {
1308 const QgsExpressionNodeLiteral *literal = dynamic_cast<const QgsExpressionNodeLiteral *>( node );
1309 if ( !literal )
1310 return false;
1311
1312 values << QgsExpression::quotedValue( literal->value() );
1313 }
1314 }
1315 }
1316 // Collect ORs
1317 else if ( const QgsExpressionNodeBinaryOperator *orOp = dynamic_cast<const QgsExpressionNodeBinaryOperator *>( e.rootNode() ) )
1318 {
1319
1320 // OR Collector function: returns a possibly empty list of the left and right operands of an OR expression
1321 std::function<QStringList( QgsExpressionNode *, QgsExpressionNode * )> collectOrs = [ &collectOrs ]( QgsExpressionNode * opLeft, QgsExpressionNode * opRight ) -> QStringList
1322 {
1323 QStringList orParts;
1324 if ( const QgsExpressionNodeBinaryOperator *leftOrOp = dynamic_cast<const QgsExpressionNodeBinaryOperator *>( opLeft ) )
1325 {
1327 {
1328 orParts.append( collectOrs( leftOrOp->opLeft(), leftOrOp->opRight() ) );
1329 }
1330 else
1331 {
1332 orParts.append( leftOrOp->dump() );
1333 }
1334 }
1335 else if ( const QgsExpressionNodeInOperator *leftInOp = dynamic_cast<const QgsExpressionNodeInOperator *>( opLeft ) )
1336 {
1337 orParts.append( leftInOp->dump() );
1338 }
1339 else
1340 {
1341 return {};
1342 }
1343
1344 if ( const QgsExpressionNodeBinaryOperator *rightOrOp = dynamic_cast<const QgsExpressionNodeBinaryOperator *>( opRight ) )
1345 {
1347 {
1348 orParts.append( collectOrs( rightOrOp->opLeft(), rightOrOp->opRight() ) );
1349 }
1350 else
1351 {
1352 orParts.append( rightOrOp->dump() );
1353 }
1354 }
1355 else if ( const QgsExpressionNodeInOperator *rightInOp = dynamic_cast<const QgsExpressionNodeInOperator *>( opRight ) )
1356 {
1357 orParts.append( rightInOp->dump() );
1358 }
1359 else
1360 {
1361 return {};
1362 }
1363
1364 return orParts;
1365 };
1366
1368 {
1369 // Try to collect all OR conditions
1370 const QStringList orParts = collectOrs( orOp->opLeft(), orOp->opRight() );
1371 if ( orParts.isEmpty() )
1372 {
1373 return false;
1374 }
1375 else
1376 {
1377 QString orPartsResult;
1378 if ( attemptReduceToInClause( orParts, orPartsResult ) )
1379 {
1380 // Need to check if the IN field is correct,
1381 QgsExpression inExp { orPartsResult };
1382 if ( ! inExp.rootNode() )
1383 {
1384 return false;
1385 }
1386
1387 if ( const QgsExpressionNodeInOperator *inOpInner = dynamic_cast<const QgsExpressionNodeInOperator *>( inExp.rootNode() ) )
1388 {
1389 if ( inOpInner->node()->nodeType() != QgsExpressionNode::NodeType::ntColumnRef || inOpInner->node()->referencedColumns().size() < 1 )
1390 {
1391 return false;
1392 }
1393
1394 const QString innerInfield { inOpInner->node()->referencedColumns().values().first() };
1395
1396 if ( first )
1397 {
1398 inField = innerInfield;
1399 first = false;
1400 }
1401
1402 if ( innerInfield != inField )
1403 {
1404 return false;
1405 }
1406 else
1407 {
1408 const auto constInnerValuesList { inOpInner->list()->list() };
1409 for ( const auto &innerInValueNode : std::as_const( constInnerValuesList ) )
1410 {
1411 values.append( innerInValueNode->dump() );
1412 }
1413 }
1414
1415 }
1416 else
1417 {
1418 return false;
1419 }
1420 }
1421 else
1422 {
1423 return false;
1424 }
1425 }
1426 }
1427 else
1428 {
1429 return false;
1430 }
1431 }
1432 else
1433 {
1434 return false;
1435 }
1436 }
1437 }
1438 result = QStringLiteral( "%1 IN (%2)" ).arg( quotedColumnRef( inField ), values.join( ',' ) );
1439 return true;
1440}
1441
1443{
1444 return d->mRootNode;
1445}
1446
1448{
1449 return d->mRootNode && d->mRootNode->nodeType() == QgsExpressionNode::ntColumnRef;
1450}
1451
1452int QgsExpression::expressionToLayerFieldIndex( const QString &expression, const QgsVectorLayer *layer )
1453{
1454 if ( !layer )
1455 return -1;
1456
1457 // easy check first -- lookup field directly.
1458 int attrIndex = layer->fields().lookupField( expression.trimmed() );
1459 if ( attrIndex >= 0 )
1460 return attrIndex;
1461
1462 // may still be a simple field expression, just one which is enclosed in "" or similar
1463 QgsExpression candidate( expression );
1464 if ( candidate.isField() )
1465 {
1466 const QString fieldName = qgis::down_cast<const QgsExpressionNodeColumnRef *>( candidate.rootNode() )->name();
1467 return layer->fields().lookupField( fieldName );
1468 }
1469 return -1;
1470}
1471
1472QString QgsExpression::quoteFieldExpression( const QString &expression, const QgsVectorLayer *layer )
1473{
1474 if ( !layer )
1475 return expression;
1476
1477 const int fieldIndex = QgsExpression::expressionToLayerFieldIndex( expression, layer );
1478 if ( !expression.contains( '\"' ) && fieldIndex != -1 )
1479 {
1480 // retrieve actual field name from layer, so that we correctly remove any unwanted leading/trailing whitespace
1481 return QgsExpression::quotedColumnRef( layer->fields().at( fieldIndex ).name() );
1482 }
1483 else
1484 {
1485 return expression;
1486 }
1487}
1488
1489QList<const QgsExpressionNode *> QgsExpression::nodes() const
1490{
1491 if ( !d->mRootNode )
1492 return QList<const QgsExpressionNode *>();
1493
1494 return d->mRootNode->nodes();
1495}
DistanceUnit
Units of distance.
Definition qgis.h:4677
@ Unknown
Unknown distance unit.
AreaUnit
Units of area.
Definition qgis.h:4754
@ Unknown
Unknown areal unit.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
A abstract base class for defining QgsExpression functions.
A binary expression operator, which operates on two values.
An expression node which takes it value from a feature's field.
QString name() const
The name of the column.
An expression node for value IN or NOT IN clauses.
An expression node for literal values.
QVariant value() const
The value of the literal.
A list of expression nodes.
QList< QgsExpressionNode * > list()
Gets a list of all the nodes.
Abstract base class for all nodes that can appear in an expression.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
static const QList< QgsExpressionFunction * > & Functions()
QgsExpression & operator=(const QgsExpression &other)
Create a copy of this expression.
QString expression() const
Returns the original, unmodified expression string.
Qgis::DistanceUnit distanceUnits() const
Returns the desired distance units for calculations involving geomCalculator(), e....
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
void setExpression(const QString &expression)
Set the expression string, will reset the whole internal structure.
static int functionIndex(const QString &name)
Returns index of the function in Functions array.
static double evaluateToDouble(const QString &text, double fallbackValue)
Attempts to evaluate a text string as an expression to a resultant double value.
static QString quoteFieldExpression(const QString &expression, const QgsVectorLayer *layer)
Validate if the expression is a field in the layer and ensure it is quoted.
static int functionCount()
Returns the number of functions defined in the parser.
QList< const QgsExpressionNode * > nodes() const
Returns a list of all nodes which are used in this expression.
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
QSet< QString > referencedVariables() const
Returns a list of all variables which are used in this expression.
static bool isFunctionName(const QString &name)
tells whether the identifier is a name of existing function
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
static QString variableHelpText(const QString &variableName)
Returns the help text for a specified variable.
QList< QgsExpression::ParserError > parserErrors() const
Returns parser error details including location of error.
QString evalErrorString() const
Returns evaluation error.
bool operator==(const QgsExpression &other) const
Compares two expressions.
QString parserErrorString() const
Returns parser error.
static QString formatPreviewString(const QVariant &value, bool htmlOutput=true, int maximumPreviewLength=60)
Formats an expression result for friendly display to the user.
static QString replaceExpressionText(const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea=nullptr)
This function replaces each expression between [% and %] in the string with the result of its evaluat...
static QStringList tags(const QString &name)
Returns a string list of search tags for a specified function.
bool isField() const
Checks whether an expression consists only of a single field reference.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
QgsExpression()
Create an empty expression.
QString dump() const
Returns an expression string, constructed from the internal abstract syntax tree.
static PRIVATE QString helpText(QString name)
Returns the help text for a specified function.
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QMetaType::Type fieldType=QMetaType::Type::UnknownType)
Create an expression allowing to evaluate if a field is equal to a value.
void setDistanceUnits(Qgis::DistanceUnit unit)
Sets the desired distance units for calculations involving geomCalculator(), e.g.,...
void setAreaUnits(Qgis::AreaUnit unit)
Sets the desired areal units for calculations involving geomCalculator(), e.g., "$area".
static bool isFieldEqualityExpression(const QString &expression, QString &field, QVariant &value)
Returns true if the given expression is a simple "field=value" type expression.
Qgis::AreaUnit areaUnits() const
Returns the desired areal units for calculations involving geomCalculator(), e.g.,...
QSet< QString > referencedFunctions() const
Returns a list of the names of all functions which are used in this expression.
static QString group(const QString &group)
Returns the translated name for a function group.
void setEvalErrorString(const QString &str)
Sets evaluation error (used internally by evaluation functions)
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
void setGeomCalculator(const QgsDistanceArea *calc)
Sets the geometry calculator used for distance and area calculations in expressions.
const QgsExpressionNode * rootNode() const
Returns the root node of the expression.
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
static QString formatVariableHelp(const QString &description, bool showValue=true, const QVariant &value=QVariant())
Returns formatted help text for a variable.
static int expressionToLayerFieldIndex(const QString &expression, const QgsVectorLayer *layer)
Attempts to resolve an expression to a field index from the given layer.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QVariant evaluate()
Evaluate the feature and return the result.
static bool attemptReduceToInClause(const QStringList &expressions, QString &result)
Attempts to reduce a list of expressions to a single "field IN (val1, val2, ... )" type expression.
bool isValid() const
Checks if this expression is valid.
static bool addVariableHelpText(const QString name, const QString &description)
Adds a help string for a custom variable.
QgsDistanceArea * geomCalculator()
Returns calculator used for distance and area calculations (used by $length, $area and $perimeter fun...
QSet< int > referencedAttributeIndexes(const QgsFields &fields) const
Returns a list of field name indexes obtained from the provided fields.
static bool checkExpression(const QString &text, const QgsExpressionContext *context, QString &errorMessage)
Tests whether a string is a valid expression.
static const QString ALL_ATTRIBUTES
A special attribute that if set matches all attributes.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsFeatureId id
Definition qgsfeature.h:66
QString name
Definition qgsfield.h:62
Container of fields for a vector layer.
Definition qgsfields.h:46
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
A representation of the interval between two datetime values.
Definition qgsinterval.h:46
double days() const
Returns the interval duration in days.
double seconds() const
Returns the interval duration in seconds.
double hours() const
Returns the interval duration in hours.
double minutes() const
Returns the interval duration in minutes.
static QgsProject * instance()
Returns the QgsProject singleton instance.
static Q_INVOKABLE Qgis::DistanceUnit stringToDistanceUnit(const QString &string, bool *ok=nullptr)
Converts a translated string to a distance unit.
static Q_INVOKABLE Qgis::AreaUnit stringToAreaUnit(const QString &string, bool *ok=nullptr)
Converts a translated string to an areal unit.
static QMetaType::Type variantTypeToMetaType(QVariant::Type variantType)
Converts a QVariant::Type to a QMetaType::Type.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based data sets.
static QString displayString(Qgis::WkbType type)
Returns a non-translated display string type for a WKB type, e.g., the geometry name used in WKT geom...
#define str(x)
Definition qgis.cpp:39
CONSTLATIN1STRING geoNone()
Constant that holds the string representation for "No ellips/No CRS".
Definition qgis.h:6453
QMap< QString, QString > QgsStringMap
Definition qgis.h:6496
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
QgsExpressionNode * parseExpression(const QString &str, QString &parserErrorMsg, QList< QgsExpression::ParserError > &parserErrors)
QList< int > QgsAttributeList
Definition qgsfield.h:27
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
#define QgsDebugError(str)
Definition qgslogger.h:38
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.