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