QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
830 // legend canvas item variables
831 sVariableHelpTexts()->insert( QStringLiteral( "legend_title" ), QCoreApplication::translate( "variable_help", "Title of the legend." ) );
832 sVariableHelpTexts()->insert( QStringLiteral( "legend_column_count" ), QCoreApplication::translate( "variable_help", "Number of column in the legend." ) );
833 sVariableHelpTexts()->insert( QStringLiteral( "legend_split_layers" ), QCoreApplication::translate( "variable_help", "Boolean indicating if layers can be split in the legend." ) );
834 sVariableHelpTexts()->insert( QStringLiteral( "legend_wrap_string" ), QCoreApplication::translate( "variable_help", "Characters used to wrap the legend text." ) );
835 sVariableHelpTexts()->insert( QStringLiteral( "legend_filter_by_map" ), QCoreApplication::translate( "variable_help", "Boolean indicating if the content of the legend is filtered by the map." ) );
836 sVariableHelpTexts()->insert( QStringLiteral( "legend_filter_out_atlas" ), QCoreApplication::translate( "variable_help", "Boolean indicating if the Atlas is filtered out of the legend." ) );
837
838 // scalebar rendering
839 sVariableHelpTexts()->insert( QStringLiteral( "scale_value" ), QCoreApplication::translate( "variable_help", "Current scale bar distance value." ) );
840
841 // map tool capture variables
842 sVariableHelpTexts()->insert( QStringLiteral( "snapping_results" ), QCoreApplication::translate( "variable_help",
843 "<p>An array with an item for each snapped point.</p>"
844 "<p>Each item is a map with the following keys:</p>"
845 "<dl>"
846 "<dt>valid</dt><dd>Boolean that indicates if the snapping result is valid</dd>"
847 "<dt>layer</dt><dd>The layer on which the snapped feature is</dd>"
848 "<dt>feature_id</dt><dd>The feature id of the snapped feature</dd>"
849 "<dt>vertex_index</dt><dd>The index of the snapped vertex</dd>"
850 "<dt>distance</dt><dd>The distance between the mouse cursor and the snapped point at the time of snapping</dd>"
851 "</dl>" ) );
852
853
854 //symbol variables
855 sVariableHelpTexts()->insert( QStringLiteral( "geometry_part_count" ), QCoreApplication::translate( "variable_help", "Number of parts in rendered feature's geometry." ) );
856 sVariableHelpTexts()->insert( QStringLiteral( "geometry_part_num" ), QCoreApplication::translate( "variable_help", "Current geometry part number for feature being rendered." ) );
857 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." ) );
858 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." ) );
859 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." ) );
860
861 sVariableHelpTexts()->insert( QStringLiteral( "symbol_color" ), QCoreApplication::translate( "symbol_color", "Color of symbol used to render the feature." ) );
862 sVariableHelpTexts()->insert( QStringLiteral( "symbol_angle" ), QCoreApplication::translate( "symbol_angle", "Angle of symbol used to render the feature (valid for marker symbols only)." ) );
863 sVariableHelpTexts()->insert( QStringLiteral( "symbol_layer_count" ), QCoreApplication::translate( "symbol_layer_count", "Total number of symbol layers in the symbol." ) );
864 sVariableHelpTexts()->insert( QStringLiteral( "symbol_layer_index" ), QCoreApplication::translate( "symbol_layer_index", "Current symbol layer index." ) );
865 sVariableHelpTexts()->insert( QStringLiteral( "symbol_marker_row" ), QCoreApplication::translate( "symbol_marker_row", "Row number for marker (valid for point pattern fills only)." ) );
866 sVariableHelpTexts()->insert( QStringLiteral( "symbol_marker_column" ), QCoreApplication::translate( "symbol_marker_column", "Column number for marker (valid for point pattern fills only)." ) );
867 sVariableHelpTexts()->insert( QStringLiteral( "symbol_frame" ), QCoreApplication::translate( "symbol_frame", "Frame number (for animated symbols only)." ) );
868
869 sVariableHelpTexts()->insert( QStringLiteral( "symbol_label" ), QCoreApplication::translate( "symbol_label", "Label for the symbol (either a user defined label or the default autogenerated label)." ) );
870 sVariableHelpTexts()->insert( QStringLiteral( "symbol_id" ), QCoreApplication::translate( "symbol_id", "Internal ID of the symbol." ) );
871 sVariableHelpTexts()->insert( QStringLiteral( "symbol_count" ), QCoreApplication::translate( "symbol_count", "Total number of features represented by the symbol." ) );
872
873 //cluster variables
874 sVariableHelpTexts()->insert( QStringLiteral( "cluster_color" ), QCoreApplication::translate( "cluster_color", "Color of symbols within a cluster, or NULL if symbols have mixed colors." ) );
875 sVariableHelpTexts()->insert( QStringLiteral( "cluster_size" ), QCoreApplication::translate( "cluster_size", "Number of symbols contained within a cluster." ) );
876
877 //processing variables
878 sVariableHelpTexts()->insert( QStringLiteral( "algorithm_id" ), QCoreApplication::translate( "algorithm_id", "Unique ID for algorithm." ) );
879 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)." ) );
880 sVariableHelpTexts()->insert( QStringLiteral( "model_folder" ), QCoreApplication::translate( "variable_help", "Folder containing current model (or project folder if model is embedded in a project)." ) );
881 sVariableHelpTexts()->insert( QStringLiteral( "model_name" ), QCoreApplication::translate( "variable_help", "Name of current model." ) );
882 sVariableHelpTexts()->insert( QStringLiteral( "model_group" ), QCoreApplication::translate( "variable_help", "Group for current model." ) );
883 sVariableHelpTexts()->insert( QStringLiteral( "fullextent_minx" ), QCoreApplication::translate( "fullextent_minx", "Minimum x-value from full canvas extent (including all layers)." ) );
884 sVariableHelpTexts()->insert( QStringLiteral( "fullextent_miny" ), QCoreApplication::translate( "fullextent_miny", "Minimum y-value from full canvas extent (including all layers)." ) );
885 sVariableHelpTexts()->insert( QStringLiteral( "fullextent_maxx" ), QCoreApplication::translate( "fullextent_maxx", "Maximum x-value from full canvas extent (including all layers)." ) );
886 sVariableHelpTexts()->insert( QStringLiteral( "fullextent_maxy" ), QCoreApplication::translate( "fullextent_maxy", "Maximum y-value from full canvas extent (including all layers)." ) );
887
888 //provider notification
889 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)." ) );
890
891 //form context variable
892 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." ) );
893 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." ) );
894
895 //parent form context variable
896 sVariableHelpTexts()->insert( QStringLiteral( "current_parent_geometry" ), QCoreApplication::translate( "current_parent_geometry",
897 "Only usable in an embedded form context, "
898 "represents the geometry of the feature currently being edited in the parent form.\n"
899 "Can be used in a form/row context to filter the related features using a value "
900 "from the feature currently edited in the parent form, to make sure that the filter "
901 "still works with standalone forms it is recommended to wrap this variable in a "
902 "'coalesce()'." ) );
903 sVariableHelpTexts()->insert( QStringLiteral( "current_parent_feature" ), QCoreApplication::translate( "current_parent_feature",
904 "Only usable in an embedded form context, "
905 "represents the feature currently being edited in the parent form.\n"
906 "Can be used in a form/row context to filter the related features using a value "
907 "from the feature currently edited in the parent form, to make sure that the filter "
908 "still works with standalone forms it is recommended to wrap this variable in a "
909 "'coalesce()'." ) );
910
911 //form variable
912 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." ) );
913
914 // plots
915 sVariableHelpTexts()->insert( QStringLiteral( "plot_axis" ), QCoreApplication::translate( "plot_axis", "The associated plot axis, e.g. 'x' or 'y'." ) );
916 sVariableHelpTexts()->insert( QStringLiteral( "plot_axis_value" ), QCoreApplication::translate( "plot_axis_value", "The current value for the plot axis." ) );
917}
918
919
920bool QgsExpression::addVariableHelpText( const QString name, const QString &description )
921{
922 if ( sVariableHelpTexts()->contains( name ) )
923 {
924 return false;
925 }
926 sVariableHelpTexts()->insert( name, description );
927 return true;
928}
929
930QString QgsExpression::variableHelpText( const QString &variableName )
931{
932 QgsExpression::initVariableHelp();
933 return sVariableHelpTexts()->value( variableName, QString() );
934}
935
936QString QgsExpression::formatVariableHelp( const QString &description, bool showValue, const QVariant &value )
937{
938 QString text = !description.isEmpty() ? QStringLiteral( "<p>%1</p>" ).arg( description ) : QString();
939 if ( showValue )
940 {
941 QString valueString;
942 if ( !value.isValid() )
943 {
944 valueString = QCoreApplication::translate( "variable_help", "not set" );
945 }
946 else
947 {
948 valueString = QStringLiteral( "<b>%1</b>" ).arg( formatPreviewString( value ) );
949 }
950 text.append( QCoreApplication::translate( "variable_help", "<p>Current value: %1</p>" ).arg( valueString ) );
951 }
952 return text;
953}
954
955QString QgsExpression::group( const QString &name )
956{
957 if ( sGroups()->isEmpty() )
958 {
959 sGroups()->insert( QStringLiteral( "Aggregates" ), tr( "Aggregates" ) );
960 sGroups()->insert( QStringLiteral( "Arrays" ), tr( "Arrays" ) );
961 sGroups()->insert( QStringLiteral( "Color" ), tr( "Color" ) );
962 sGroups()->insert( QStringLiteral( "Conditionals" ), tr( "Conditionals" ) );
963 sGroups()->insert( QStringLiteral( "Conversions" ), tr( "Conversions" ) );
964 sGroups()->insert( QStringLiteral( "Date and Time" ), tr( "Date and Time" ) );
965 sGroups()->insert( QStringLiteral( "Fields and Values" ), tr( "Fields and Values" ) );
966 sGroups()->insert( QStringLiteral( "Files and Paths" ), tr( "Files and Paths" ) );
967 sGroups()->insert( QStringLiteral( "Fuzzy Matching" ), tr( "Fuzzy Matching" ) );
968 sGroups()->insert( QStringLiteral( "General" ), tr( "General" ) );
969 sGroups()->insert( QStringLiteral( "GeometryGroup" ), tr( "Geometry" ) );
970 sGroups()->insert( QStringLiteral( "Map Layers" ), tr( "Map Layers" ) );
971 sGroups()->insert( QStringLiteral( "Maps" ), tr( "Maps" ) );
972 sGroups()->insert( QStringLiteral( "Math" ), tr( "Math" ) );
973 sGroups()->insert( QStringLiteral( "Operators" ), tr( "Operators" ) );
974 sGroups()->insert( QStringLiteral( "Rasters" ), tr( "Rasters" ) );
975 sGroups()->insert( QStringLiteral( "Record and Attributes" ), tr( "Record and Attributes" ) );
976 sGroups()->insert( QStringLiteral( "String" ), tr( "String" ) );
977 sGroups()->insert( QStringLiteral( "Variables" ), tr( "Variables" ) );
978 sGroups()->insert( QStringLiteral( "Recent (%1)" ), tr( "Recent (%1)" ) );
979 sGroups()->insert( QStringLiteral( "UserGroup" ), tr( "User expressions" ) );
980 }
981
982 //return the translated name for this group. If group does not
983 //have a translated name in the gGroups hash, return the name
984 //unchanged
985 return sGroups()->value( name, name );
986}
987
988QString QgsExpression::formatPreviewString( const QVariant &value, const bool htmlOutput, int maximumPreviewLength )
989{
990 const QString startToken = htmlOutput ? QStringLiteral( "<i>&lt;" ) : QStringLiteral( "<" );
991 const QString endToken = htmlOutput ? QStringLiteral( "&gt;</i>" ) : QStringLiteral( ">" );
992
993 if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
994 {
995 //result is a geometry
996 QgsGeometry geom = value.value<QgsGeometry>();
997 if ( geom.isNull() )
998 return startToken + tr( "empty geometry" ) + endToken;
999 else
1000 return startToken + tr( "geometry: %1" ).arg( QgsWkbTypes::displayString( geom.constGet()->wkbType() ) )
1001 + endToken;
1002 }
1003 else if ( value.value< QgsWeakMapLayerPointer >().data() )
1004 {
1005 return startToken + tr( "map layer" ) + endToken;
1006 }
1007 else if ( !value.isValid() )
1008 {
1009 return htmlOutput ? tr( "<i>NULL</i>" ) : QString();
1010 }
1011 else if ( value.userType() == QMetaType::type( "QgsFeature" ) )
1012 {
1013 //result is a feature
1014 QgsFeature feat = value.value<QgsFeature>();
1015 return startToken + tr( "feature: %1" ).arg( feat.id() ) + endToken;
1016 }
1017 else if ( value.userType() == QMetaType::type( "QgsInterval" ) )
1018 {
1019 QgsInterval interval = value.value<QgsInterval>();
1020 if ( interval.days() > 1 )
1021 {
1022 return startToken + tr( "interval: %1 days" ).arg( interval.days() ) + endToken;
1023 }
1024 else if ( interval.hours() > 1 )
1025 {
1026 return startToken + tr( "interval: %1 hours" ).arg( interval.hours() ) + endToken;
1027 }
1028 else if ( interval.minutes() > 1 )
1029 {
1030 return startToken + tr( "interval: %1 minutes" ).arg( interval.minutes() ) + endToken;
1031 }
1032 else
1033 {
1034 return startToken + tr( "interval: %1 seconds" ).arg( interval.seconds() ) + endToken;
1035 }
1036 }
1037 else if ( value.userType() == QMetaType::type( "QgsGradientColorRamp" ) )
1038 {
1039 return startToken + tr( "gradient ramp" ) + endToken;
1040 }
1041 else if ( value.type() == QVariant::Date )
1042 {
1043 const QDate dt = value.toDate();
1044 return startToken + tr( "date: %1" ).arg( dt.toString( QStringLiteral( "yyyy-MM-dd" ) ) ) + endToken;
1045 }
1046 else if ( value.type() == QVariant::Time )
1047 {
1048 const QTime tm = value.toTime();
1049 return startToken + tr( "time: %1" ).arg( tm.toString( QStringLiteral( "hh:mm:ss" ) ) ) + endToken;
1050 }
1051 else if ( value.type() == QVariant::DateTime )
1052 {
1053 const QDateTime dt = value.toDateTime();
1054 return startToken + tr( "datetime: %1 (%2)" ).arg( dt.toString( QStringLiteral( "yyyy-MM-dd hh:mm:ss" ) ), dt.timeZoneAbbreviation() ) + endToken;
1055 }
1056 else if ( value.type() == QVariant::String )
1057 {
1058 const QString previewString = value.toString();
1059 if ( previewString.length() > maximumPreviewLength + 3 )
1060 {
1061 return tr( "'%1…'" ).arg( previewString.left( maximumPreviewLength ) );
1062 }
1063 else
1064 {
1065 return '\'' + previewString + '\'';
1066 }
1067 }
1068 else if ( value.type() == QVariant::Map )
1069 {
1070 QString mapStr = QStringLiteral( "{" );
1071 const QVariantMap map = value.toMap();
1072 QString separator;
1073 for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
1074 {
1075 mapStr.append( separator );
1076 if ( separator.isEmpty() )
1077 separator = QStringLiteral( "," );
1078
1079 mapStr.append( QStringLiteral( " '%1': %2" ).arg( it.key(), formatPreviewString( it.value(), htmlOutput ) ) );
1080 if ( mapStr.length() > maximumPreviewLength - 3 )
1081 {
1082 mapStr = tr( "%1…" ).arg( mapStr.left( maximumPreviewLength - 2 ) );
1083 break;
1084 }
1085 }
1086 if ( !map.empty() )
1087 mapStr += QLatin1Char( ' ' );
1088 mapStr += QLatin1Char( '}' );
1089 return mapStr;
1090 }
1091 else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
1092 {
1093 QString listStr = QStringLiteral( "[" );
1094 const QVariantList list = value.toList();
1095 QString separator;
1096 for ( const QVariant &arrayValue : list )
1097 {
1098 listStr.append( separator );
1099 if ( separator.isEmpty() )
1100 separator = QStringLiteral( "," );
1101
1102 listStr.append( " " );
1103 listStr.append( formatPreviewString( arrayValue, htmlOutput ) );
1104 if ( listStr.length() > maximumPreviewLength - 3 )
1105 {
1106 listStr = QString( tr( "%1…" ) ).arg( listStr.left( maximumPreviewLength - 2 ) );
1107 break;
1108 }
1109 }
1110 if ( !list.empty() )
1111 listStr += QLatin1Char( ' ' );
1112 listStr += QLatin1Char( ']' );
1113 return listStr;
1114 }
1115 else if ( value.type() == QVariant::Int ||
1116 value.type() == QVariant::UInt ||
1117 value.type() == QVariant::LongLong ||
1118 value.type() == QVariant::ULongLong ||
1119 value.type() == QVariant::Double ||
1120 // Qt madness with QMetaType::Float :/
1121 value.type() == static_cast<QVariant::Type>( QMetaType::Float ) )
1122 {
1123 return QgsExpressionUtils::toLocalizedString( value );
1124 }
1125 else
1126 {
1127 QString str { value.toString() };
1128 if ( str.length() > maximumPreviewLength - 3 )
1129 {
1130 str = tr( "%1…" ).arg( str.left( maximumPreviewLength - 2 ) );
1131 }
1132 return str;
1133 }
1134}
1135
1136QString QgsExpression::createFieldEqualityExpression( const QString &fieldName, const QVariant &value, QVariant::Type fieldType )
1137{
1138 QString expr;
1139
1140 if ( QgsVariantUtils::isNull( value ) )
1141 expr = QStringLiteral( "%1 IS NULL" ).arg( quotedColumnRef( fieldName ) );
1142 else if ( fieldType == QVariant::Type::Invalid )
1143 expr = QStringLiteral( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value ) );
1144 else
1145 expr = QStringLiteral( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value, fieldType ) );
1146
1147 return expr;
1148}
1149
1150bool QgsExpression::isFieldEqualityExpression( const QString &expression, QString &field, QVariant &value )
1151{
1153
1154 if ( !e.rootNode() )
1155 return false;
1156
1157 if ( const QgsExpressionNodeBinaryOperator *binOp = dynamic_cast<const QgsExpressionNodeBinaryOperator *>( e.rootNode() ) )
1158 {
1159 if ( binOp->op() == QgsExpressionNodeBinaryOperator::boEQ )
1160 {
1161 const QgsExpressionNodeColumnRef *columnRef = dynamic_cast<const QgsExpressionNodeColumnRef *>( binOp->opLeft() );
1162 const QgsExpressionNodeLiteral *literal = dynamic_cast<const QgsExpressionNodeLiteral *>( binOp->opRight() );
1163 if ( columnRef && literal )
1164 {
1165 field = columnRef->name();
1166 value = literal->value();
1167 return true;
1168 }
1169 }
1170 }
1171 return false;
1172}
1173
1174bool QgsExpression::attemptReduceToInClause( const QStringList &expressions, QString &result )
1175{
1176 if ( expressions.empty() )
1177 return false;
1178
1179 QString inField;
1180 bool first = true;
1181 QStringList values;
1182 for ( const QString &expression : expressions )
1183 {
1184 QString field;
1185 QVariant value;
1187 {
1188 if ( first )
1189 {
1190 inField = field;
1191 first = false;
1192 }
1193 else if ( field != inField )
1194 {
1195 return false;
1196 }
1197 values << QgsExpression::quotedValue( value );
1198 }
1199 else
1200 {
1201 // we also allow reducing similar 'field IN (...)' expressions!
1203
1204 if ( !e.rootNode() )
1205 return false;
1206
1207 if ( const QgsExpressionNodeInOperator *inOp = dynamic_cast<const QgsExpressionNodeInOperator *>( e.rootNode() ) )
1208 {
1209 if ( inOp->isNotIn() )
1210 return false;
1211
1212 const QgsExpressionNodeColumnRef *columnRef = dynamic_cast<const QgsExpressionNodeColumnRef *>( inOp->node() );
1213 if ( !columnRef )
1214 return false;
1215
1216 if ( first )
1217 {
1218 inField = columnRef->name();
1219 first = false;
1220 }
1221 else if ( columnRef->name() != inField )
1222 {
1223 return false;
1224 }
1225
1226 if ( QgsExpressionNode::NodeList *nodeList = inOp->list() )
1227 {
1228 const QList<QgsExpressionNode *> nodes = nodeList->list();
1229 for ( const QgsExpressionNode *node : nodes )
1230 {
1231 const QgsExpressionNodeLiteral *literal = dynamic_cast<const QgsExpressionNodeLiteral *>( node );
1232 if ( !literal )
1233 return false;
1234
1235 values << QgsExpression::quotedValue( literal->value() );
1236 }
1237 }
1238 }
1239 // Collect ORs
1240 else if ( const QgsExpressionNodeBinaryOperator *orOp = dynamic_cast<const QgsExpressionNodeBinaryOperator *>( e.rootNode() ) )
1241 {
1242
1243 // OR Collector function: returns a possibly empty list of the left and right operands of an OR expression
1244 std::function<QStringList( QgsExpressionNode *, QgsExpressionNode * )> collectOrs = [ &collectOrs ]( QgsExpressionNode * opLeft, QgsExpressionNode * opRight ) -> QStringList
1245 {
1246 QStringList orParts;
1247 if ( const QgsExpressionNodeBinaryOperator *leftOrOp = dynamic_cast<const QgsExpressionNodeBinaryOperator *>( opLeft ) )
1248 {
1249 if ( leftOrOp->op( ) == QgsExpressionNodeBinaryOperator::BinaryOperator::boOr )
1250 {
1251 orParts.append( collectOrs( leftOrOp->opLeft(), leftOrOp->opRight() ) );
1252 }
1253 else
1254 {
1255 orParts.append( leftOrOp->dump() );
1256 }
1257 }
1258 else if ( const QgsExpressionNodeInOperator *leftInOp = dynamic_cast<const QgsExpressionNodeInOperator *>( opLeft ) )
1259 {
1260 orParts.append( leftInOp->dump() );
1261 }
1262 else
1263 {
1264 return {};
1265 }
1266
1267 if ( const QgsExpressionNodeBinaryOperator *rightOrOp = dynamic_cast<const QgsExpressionNodeBinaryOperator *>( opRight ) )
1268 {
1269 if ( rightOrOp->op( ) == QgsExpressionNodeBinaryOperator::BinaryOperator::boOr )
1270 {
1271 orParts.append( collectOrs( rightOrOp->opLeft(), rightOrOp->opRight() ) );
1272 }
1273 else
1274 {
1275 orParts.append( rightOrOp->dump() );
1276 }
1277 }
1278 else if ( const QgsExpressionNodeInOperator *rightInOp = dynamic_cast<const QgsExpressionNodeInOperator *>( opRight ) )
1279 {
1280 orParts.append( rightInOp->dump() );
1281 }
1282 else
1283 {
1284 return {};
1285 }
1286
1287 return orParts;
1288 };
1289
1290 if ( orOp->op( ) == QgsExpressionNodeBinaryOperator::BinaryOperator::boOr )
1291 {
1292 // Try to collect all OR conditions
1293 const QStringList orParts = collectOrs( orOp->opLeft(), orOp->opRight() );
1294 if ( orParts.isEmpty() )
1295 {
1296 return false;
1297 }
1298 else
1299 {
1300 QString orPartsResult;
1301 if ( attemptReduceToInClause( orParts, orPartsResult ) )
1302 {
1303 // Need to check if the IN field is correct,
1304 QgsExpression inExp { orPartsResult };
1305 if ( ! inExp.rootNode() )
1306 {
1307 return false;
1308 }
1309
1310 if ( const QgsExpressionNodeInOperator *inOpInner = dynamic_cast<const QgsExpressionNodeInOperator *>( inExp.rootNode() ) )
1311 {
1312 if ( inOpInner->node()->nodeType() != QgsExpressionNode::NodeType::ntColumnRef || inOpInner->node()->referencedColumns().size() < 1 )
1313 {
1314 return false;
1315 }
1316
1317 const QString innerInfield { inOpInner->node()->referencedColumns().values().first() };
1318
1319 if ( first )
1320 {
1321 inField = innerInfield;
1322 first = false;
1323 }
1324
1325 if ( innerInfield != inField )
1326 {
1327 return false;
1328 }
1329 else
1330 {
1331 const auto constInnerValuesList { inOpInner->list()->list() };
1332 for ( const auto &innerInValueNode : std::as_const( constInnerValuesList ) )
1333 {
1334 values.append( innerInValueNode->dump() );
1335 }
1336 }
1337
1338 }
1339 else
1340 {
1341 return false;
1342 }
1343 }
1344 else
1345 {
1346 return false;
1347 }
1348 }
1349 }
1350 else
1351 {
1352 return false;
1353 }
1354 }
1355 else
1356 {
1357 return false;
1358 }
1359 }
1360 }
1361 result = QStringLiteral( "%1 IN (%2)" ).arg( quotedColumnRef( inField ), values.join( ',' ) );
1362 return true;
1363}
1364
1366{
1367 return d->mRootNode;
1368}
1369
1371{
1372 return d->mRootNode && d->mRootNode->nodeType() == QgsExpressionNode::ntColumnRef;
1373}
1374
1375int QgsExpression::expressionToLayerFieldIndex( const QString &expression, const QgsVectorLayer *layer )
1376{
1377 if ( !layer )
1378 return -1;
1379
1380 // easy check first -- lookup field directly.
1381 int attrIndex = layer->fields().lookupField( expression.trimmed() );
1382 if ( attrIndex >= 0 )
1383 return attrIndex;
1384
1385 // may still be a simple field expression, just one which is enclosed in "" or similar
1386 QgsExpression candidate( expression );
1387 if ( candidate.isField() )
1388 {
1389 const QString fieldName = qgis::down_cast<const QgsExpressionNodeColumnRef *>( candidate.rootNode() )->name();
1390 return layer->fields().lookupField( fieldName );
1391 }
1392 return -1;
1393}
1394
1395QString QgsExpression::quoteFieldExpression( const QString &expression, const QgsVectorLayer *layer )
1396{
1397 if ( !layer )
1398 return expression;
1399
1400 const int fieldIndex = QgsExpression::expressionToLayerFieldIndex( expression, layer );
1401 if ( !expression.contains( '\"' ) && fieldIndex != -1 )
1402 {
1403 // retrieve actual field name from layer, so that we correctly remove any unwanted leading/trailing whitespace
1404 return QgsExpression::quotedColumnRef( layer->fields().at( fieldIndex ).name() );
1405 }
1406 else
1407 {
1408 return expression;
1409 }
1410}
1411
1412QList<const QgsExpressionNode *> QgsExpression::nodes() const
1413{
1414 if ( !d->mRootNode )
1415 return QList<const QgsExpressionNode *>();
1416
1417 return d->mRootNode->nodes();
1418}
1419
1420
1421
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:42
double days() const
Returns the interval duration in days.
double seconds() const
Returns the interval duration in seconds.
Definition: qgsinterval.h:236
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:477
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:2979
QMap< QString, QString > QgsStringMap
Definition: qgis.h:3022
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:2147