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