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