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