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