QGIS API Documentation 3.28.14-Firenze (exported)
Loading...
Searching...
No Matches
qgsexpression.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsexpression.cpp
3 -------------------
4 begin : August 2011
5 copyright : (C) 2011 Martin Dobias
6 email : wonder.sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsexpression.h"
19#include "qgsfeaturerequest.h"
20#include "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 QString resultString;
487 if ( !QgsVariantUtils::isNull( result ) )
488 resultString = result.toString();
489
490 QgsDebugMsgLevel( "Expression result is: " + resultString, 3 );
491
492 expr_action += action.mid( start, pos - start ) + resultString;
493 }
494
495#if QT_VERSION < QT_VERSION_CHECK(5, 15, 2)
496 expr_action += action.midRef( index );
497#else
498 expr_action += QStringView {action} .mid( index ).toString();
499#endif
500
501 return expr_action;
502}
503
504QSet<QString> QgsExpression::referencedVariables( const QString &text )
505{
506 QSet<QString> variables;
507 int index = 0;
508 while ( index < text.size() )
509 {
510 const thread_local QRegularExpression rx( "\\[%([^\\]]+)%\\]" );
511 const QRegularExpressionMatch match = rx.match( text );
512 if ( !match.hasMatch() )
513 break;
514
515 index = match.capturedStart() + match.capturedLength();
516 QString to_replace = match.captured( 1 ).trimmed();
517
518 QgsExpression exp( to_replace );
519 variables.unite( exp.referencedVariables() );
520 }
521
522 return variables;
523}
524
525double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
526{
527 bool ok;
528 //first test if text is directly convertible to double
529 // use system locale: e.g. in German locale, user is presented with numbers "1,23" instead of "1.23" in C locale
530 // so we also want to allow user to rewrite it to "5,23" and it is still accepted
531 double convertedValue = QLocale().toDouble( text, &ok );
532 if ( ok )
533 {
534 return convertedValue;
535 }
536
537 //otherwise try to evaluate as expression
538 QgsExpression expr( text );
539
540 QgsExpressionContext context;
543
544 QVariant result = expr.evaluate( &context );
545 convertedValue = result.toDouble( &ok );
546 if ( expr.hasEvalError() || !ok )
547 {
548 return fallbackValue;
549 }
550 return convertedValue;
551}
552
553QString QgsExpression::helpText( QString name )
554{
555 QgsExpression::initFunctionHelp();
556
557 if ( !sFunctionHelpTexts()->contains( name ) )
558 return tr( "function help for %1 missing" ).arg( name );
559
560 const Help &f = ( *sFunctionHelpTexts() )[ name ];
561
562 name = f.mName;
563 if ( f.mType == tr( "group" ) )
564 {
565 name = group( name );
566 name = name.toLower();
567 }
568
569 name = name.toHtmlEscaped();
570
571 QString helpContents( QStringLiteral( "<h3>%1</h3>\n<div class=\"description\"><p>%2</p></div>" )
572 .arg( tr( "%1 %2" ).arg( f.mType, name ),
573 f.mDescription ) );
574
575 for ( const HelpVariant &v : std::as_const( f.mVariants ) )
576 {
577 if ( f.mVariants.size() > 1 )
578 {
579 helpContents += QStringLiteral( "<h3>%1</h3>\n<div class=\"description\">%2</p></div>" ).arg( v.mName, v.mDescription );
580 }
581
582 if ( f.mType != tr( "group" ) && f.mType != tr( "expression" ) )
583 helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"syntax\">\n" ).arg( tr( "Syntax" ) );
584
585 if ( f.mType == tr( "operator" ) )
586 {
587 if ( v.mArguments.size() == 1 )
588 {
589 helpContents += QStringLiteral( "<code><span class=\"functionname\">%1</span> <span class=\"argument\">%2</span></code>" )
590 .arg( name, v.mArguments[0].mArg );
591 }
592 else if ( v.mArguments.size() == 2 )
593 {
594 helpContents += QStringLiteral( "<code><span class=\"argument\">%1</span> <span class=\"functionname\">%2</span> <span class=\"argument\">%3</span></code>" )
595 .arg( v.mArguments[0].mArg, name, v.mArguments[1].mArg );
596 }
597 }
598 else if ( f.mType != tr( "group" ) && f.mType != tr( "expression" ) )
599 {
600 helpContents += QStringLiteral( "<code><span class=\"functionname\">%1</span>" ).arg( name );
601
602 bool hasOptionalArgs = false;
603
604 if ( f.mType == tr( "function" ) && ( f.mName[0] != '$' || !v.mArguments.isEmpty() || v.mVariableLenArguments ) )
605 {
606 helpContents += '(';
607
608 QString delim;
609 for ( const HelpArg &a : std::as_const( v.mArguments ) )
610 {
611 if ( !a.mDescOnly )
612 {
613 if ( a.mOptional )
614 {
615 hasOptionalArgs = true;
616 helpContents += QLatin1Char( '[' );
617 }
618
619 helpContents += delim;
620 helpContents += QStringLiteral( "<span class=\"argument\">%2%3</span>" ).arg(
621 a.mArg,
622 a.mDefaultVal.isEmpty() ? QString() : ":=" + a.mDefaultVal
623 );
624
625 if ( a.mOptional )
626 helpContents += QLatin1Char( ']' );
627 }
628 delim = QStringLiteral( "," );
629 }
630
631 if ( v.mVariableLenArguments )
632 {
633 helpContents += QChar( 0x2026 );
634 }
635
636 helpContents += ')';
637 }
638
639 helpContents += QLatin1String( "</code>" );
640
641 if ( hasOptionalArgs )
642 {
643 helpContents += QLatin1String( "<br/><br/>" ) + tr( "[ ] marks optional components" );
644 }
645 }
646
647 if ( !v.mArguments.isEmpty() )
648 {
649 helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"arguments\">\n<table>" ).arg( tr( "Arguments" ) );
650
651 for ( const HelpArg &a : std::as_const( v.mArguments ) )
652 {
653 if ( a.mSyntaxOnly )
654 continue;
655
656 helpContents += QStringLiteral( "<tr><td class=\"argument\">%1</td><td>%2</td></tr>" ).arg( a.mArg, a.mDescription );
657 }
658
659 helpContents += QLatin1String( "</table>\n</div>\n" );
660 }
661
662 if ( !v.mExamples.isEmpty() )
663 {
664 helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"examples\">\n<ul>\n" ).arg( tr( "Examples" ) );
665
666 for ( const HelpExample &e : std::as_const( v.mExamples ) )
667 {
668 helpContents += "<li><code>" + e.mExpression + "</code> &rarr; <code>" + e.mReturns + "</code>";
669
670 if ( !e.mNote.isEmpty() )
671 helpContents += QStringLiteral( " (%1)" ).arg( e.mNote );
672
673 helpContents += QLatin1String( "</li>\n" );
674 }
675
676 helpContents += QLatin1String( "</ul>\n</div>\n" );
677 }
678
679 if ( !v.mNotes.isEmpty() )
680 {
681 helpContents += QStringLiteral( "<h4>%1</h4>\n<div class=\"notes\"><p>%2</p></div>\n" ).arg( tr( "Notes" ), v.mNotes );
682 }
683 }
684
685 return helpContents;
686}
687
688QStringList QgsExpression::tags( const QString &name )
689{
690 QStringList tags = QStringList();
691
692 QgsExpression::initFunctionHelp();
693
694 if ( sFunctionHelpTexts()->contains( name ) )
695 {
696 const Help &f = ( *sFunctionHelpTexts() )[ name ];
697
698 for ( const HelpVariant &v : std::as_const( f.mVariants ) )
699 {
700 tags << v.mTags;
701 }
702 }
703
704 return tags;
705}
706
707void QgsExpression::initVariableHelp()
708{
709 if ( !sVariableHelpTexts()->isEmpty() )
710 return;
711
712 //global variables
713 sVariableHelpTexts()->insert( QStringLiteral( "qgis_version" ), QCoreApplication::translate( "variable_help", "Current QGIS version string." ) );
714 sVariableHelpTexts()->insert( QStringLiteral( "qgis_version_no" ), QCoreApplication::translate( "variable_help", "Current QGIS version number." ) );
715 sVariableHelpTexts()->insert( QStringLiteral( "qgis_release_name" ), QCoreApplication::translate( "variable_help", "Current QGIS release name." ) );
716 sVariableHelpTexts()->insert( QStringLiteral( "qgis_short_version" ), QCoreApplication::translate( "variable_help", "Short QGIS version string." ) );
717 sVariableHelpTexts()->insert( QStringLiteral( "qgis_os_name" ), QCoreApplication::translate( "variable_help", "Operating system name, e.g., 'windows', 'linux' or 'osx'." ) );
718 sVariableHelpTexts()->insert( QStringLiteral( "qgis_platform" ), QCoreApplication::translate( "variable_help", "QGIS platform, e.g., 'desktop' or 'server'." ) );
719 sVariableHelpTexts()->insert( QStringLiteral( "qgis_locale" ), QCoreApplication::translate( "variable_help", "Two letter identifier for current QGIS locale." ) );
720 sVariableHelpTexts()->insert( QStringLiteral( "user_account_name" ), QCoreApplication::translate( "variable_help", "Current user's operating system account name." ) );
721 sVariableHelpTexts()->insert( QStringLiteral( "user_full_name" ), QCoreApplication::translate( "variable_help", "Current user's operating system user name (if available)." ) );
722
723 //project variables
724 sVariableHelpTexts()->insert( QStringLiteral( "project_title" ), QCoreApplication::translate( "variable_help", "Title of current project." ) );
725 sVariableHelpTexts()->insert( QStringLiteral( "project_path" ), QCoreApplication::translate( "variable_help", "Full path (including file name) of current project." ) );
726 sVariableHelpTexts()->insert( QStringLiteral( "project_folder" ), QCoreApplication::translate( "variable_help", "Folder for current project." ) );
727 sVariableHelpTexts()->insert( QStringLiteral( "project_filename" ), QCoreApplication::translate( "variable_help", "Filename of current project." ) );
728 sVariableHelpTexts()->insert( QStringLiteral( "project_basename" ), QCoreApplication::translate( "variable_help", "Base name of current project's filename (without path and extension)." ) );
729 sVariableHelpTexts()->insert( QStringLiteral( "project_home" ), QCoreApplication::translate( "variable_help", "Home path of current project." ) );
730 sVariableHelpTexts()->insert( QStringLiteral( "project_crs" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of project (e.g., 'EPSG:4326')." ) );
731 sVariableHelpTexts()->insert( QStringLiteral( "project_crs_definition" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of project (full definition)." ) );
732 sVariableHelpTexts()->insert( QStringLiteral( "project_units" ), QCoreApplication::translate( "variable_help", "Unit of the project's CRS." ) );
733 sVariableHelpTexts()->insert( QStringLiteral( "project_crs_description" ), QCoreApplication::translate( "variable_help", "Name of the coordinate reference system of the project." ) );
734 sVariableHelpTexts()->insert( QStringLiteral( "project_crs_acronym" ), QCoreApplication::translate( "variable_help", "Acronym of the coordinate reference system of the project." ) );
735 sVariableHelpTexts()->insert( QStringLiteral( "project_crs_ellipsoid" ), QCoreApplication::translate( "variable_help", "Acronym of the ellipsoid of the coordinate reference system of the project." ) );
736 sVariableHelpTexts()->insert( QStringLiteral( "project_crs_proj4" ), QCoreApplication::translate( "variable_help", "Proj4 definition of the coordinate reference system of the project." ) );
737 sVariableHelpTexts()->insert( QStringLiteral( "project_crs_wkt" ), QCoreApplication::translate( "variable_help", "WKT definition of the coordinate reference system of the project." ) );
738 sVariableHelpTexts()->insert( QStringLiteral( "project_author" ), QCoreApplication::translate( "variable_help", "Project author, taken from project metadata." ) );
739 sVariableHelpTexts()->insert( QStringLiteral( "project_abstract" ), QCoreApplication::translate( "variable_help", "Project abstract, taken from project metadata." ) );
740 sVariableHelpTexts()->insert( QStringLiteral( "project_creation_date" ), QCoreApplication::translate( "variable_help", "Project creation date, taken from project metadata." ) );
741 sVariableHelpTexts()->insert( QStringLiteral( "project_identifier" ), QCoreApplication::translate( "variable_help", "Project identifier, taken from project metadata." ) );
742 sVariableHelpTexts()->insert( QStringLiteral( "project_last_saved" ), QCoreApplication::translate( "variable_help", "Date/time when project was last saved." ) );
743 sVariableHelpTexts()->insert( QStringLiteral( "project_keywords" ), QCoreApplication::translate( "variable_help", "Project keywords, taken from project metadata." ) );
744 sVariableHelpTexts()->insert( QStringLiteral( "project_area_units" ), QCoreApplication::translate( "variable_help", "Area unit for current project, used when calculating areas of geometries." ) );
745 sVariableHelpTexts()->insert( QStringLiteral( "project_distance_units" ), QCoreApplication::translate( "variable_help", "Distance unit for current project, used when calculating lengths of geometries." ) );
746 sVariableHelpTexts()->insert( QStringLiteral( "project_ellipsoid" ), QCoreApplication::translate( "variable_help", "Name of ellipsoid of current project, used when calculating geodetic areas and lengths of geometries." ) );
747 sVariableHelpTexts()->insert( QStringLiteral( "layer_ids" ), QCoreApplication::translate( "variable_help", "List of all map layer IDs from the current project." ) );
748 sVariableHelpTexts()->insert( QStringLiteral( "layers" ), QCoreApplication::translate( "variable_help", "List of all map layers from the current project." ) );
749
750 //layer variables
751 sVariableHelpTexts()->insert( QStringLiteral( "layer_name" ), QCoreApplication::translate( "variable_help", "Name of current layer." ) );
752 sVariableHelpTexts()->insert( QStringLiteral( "layer_id" ), QCoreApplication::translate( "variable_help", "ID of current layer." ) );
753 sVariableHelpTexts()->insert( QStringLiteral( "layer_crs" ), QCoreApplication::translate( "variable_help", "CRS Authority ID of current layer." ) );
754 sVariableHelpTexts()->insert( QStringLiteral( "layer" ), QCoreApplication::translate( "variable_help", "The current layer." ) );
755
756 //feature variables
757 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." ) );
758 sVariableHelpTexts()->insert( QStringLiteral( "id" ), QCoreApplication::translate( "variable_help", "The ID of the current feature being evaluated." ) );
759 sVariableHelpTexts()->insert( QStringLiteral( "geometry" ), QCoreApplication::translate( "variable_help", "The geometry of the current feature being evaluated." ) );
760
761 //composition variables
762 sVariableHelpTexts()->insert( QStringLiteral( "layout_name" ), QCoreApplication::translate( "variable_help", "Name of composition." ) );
763 sVariableHelpTexts()->insert( QStringLiteral( "layout_numpages" ), QCoreApplication::translate( "variable_help", "Number of pages in composition." ) );
764 sVariableHelpTexts()->insert( QStringLiteral( "layout_page" ), QCoreApplication::translate( "variable_help", "Current page number in composition." ) );
765 sVariableHelpTexts()->insert( QStringLiteral( "layout_pageheight" ), QCoreApplication::translate( "variable_help", "Composition page height in mm (or specified custom units)." ) );
766 sVariableHelpTexts()->insert( QStringLiteral( "layout_pagewidth" ), QCoreApplication::translate( "variable_help", "Composition page width in mm (or specified custom units)." ) );
767 sVariableHelpTexts()->insert( QStringLiteral( "layout_pageoffsets" ), QCoreApplication::translate( "variable_help", "Array of Y coordinate of the top of each page." ) );
768 sVariableHelpTexts()->insert( QStringLiteral( "layout_dpi" ), QCoreApplication::translate( "variable_help", "Composition resolution (DPI)." ) );
769
770 //atlas variables
771 sVariableHelpTexts()->insert( QStringLiteral( "atlas_layerid" ), QCoreApplication::translate( "variable_help", "Current atlas coverage layer ID." ) );
772 sVariableHelpTexts()->insert( QStringLiteral( "atlas_layername" ), QCoreApplication::translate( "variable_help", "Current atlas coverage layer name." ) );
773 sVariableHelpTexts()->insert( QStringLiteral( "atlas_totalfeatures" ), QCoreApplication::translate( "variable_help", "Total number of features in atlas." ) );
774 sVariableHelpTexts()->insert( QStringLiteral( "atlas_featurenumber" ), QCoreApplication::translate( "variable_help", "Current atlas feature number." ) );
775 sVariableHelpTexts()->insert( QStringLiteral( "atlas_filename" ), QCoreApplication::translate( "variable_help", "Current atlas file name." ) );
776 sVariableHelpTexts()->insert( QStringLiteral( "atlas_pagename" ), QCoreApplication::translate( "variable_help", "Current atlas page name." ) );
777 sVariableHelpTexts()->insert( QStringLiteral( "atlas_feature" ), QCoreApplication::translate( "variable_help", "Current atlas feature (as feature object)." ) );
778 sVariableHelpTexts()->insert( QStringLiteral( "atlas_featureid" ), QCoreApplication::translate( "variable_help", "Current atlas feature ID." ) );
779 sVariableHelpTexts()->insert( QStringLiteral( "atlas_geometry" ), QCoreApplication::translate( "variable_help", "Current atlas feature geometry." ) );
780
781 //layout item variables
782 sVariableHelpTexts()->insert( QStringLiteral( "item_id" ), QCoreApplication::translate( "variable_help", "Layout item user-assigned ID (not necessarily unique)." ) );
783 sVariableHelpTexts()->insert( QStringLiteral( "item_uuid" ), QCoreApplication::translate( "variable_help", "layout item unique ID." ) );
784 sVariableHelpTexts()->insert( QStringLiteral( "item_left" ), QCoreApplication::translate( "variable_help", "Left position of layout item (in mm)." ) );
785 sVariableHelpTexts()->insert( QStringLiteral( "item_top" ), QCoreApplication::translate( "variable_help", "Top position of layout item (in mm)." ) );
786 sVariableHelpTexts()->insert( QStringLiteral( "item_width" ), QCoreApplication::translate( "variable_help", "Width of layout item (in mm)." ) );
787 sVariableHelpTexts()->insert( QStringLiteral( "item_height" ), QCoreApplication::translate( "variable_help", "Height of layout item (in mm)." ) );
788
789 //map settings item variables
790 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." ) );
791 sVariableHelpTexts()->insert( QStringLiteral( "map_rotation" ), QCoreApplication::translate( "variable_help", "Current rotation of map." ) );
792 sVariableHelpTexts()->insert( QStringLiteral( "map_scale" ), QCoreApplication::translate( "variable_help", "Current scale of map." ) );
793 sVariableHelpTexts()->insert( QStringLiteral( "map_extent" ), QCoreApplication::translate( "variable_help", "Geometry representing the current extent of the map." ) );
794 sVariableHelpTexts()->insert( QStringLiteral( "map_extent_center" ), QCoreApplication::translate( "variable_help", "Center of map." ) );
795 sVariableHelpTexts()->insert( QStringLiteral( "map_extent_width" ), QCoreApplication::translate( "variable_help", "Width of map." ) );
796 sVariableHelpTexts()->insert( QStringLiteral( "map_extent_height" ), QCoreApplication::translate( "variable_help", "Height of map." ) );
797 sVariableHelpTexts()->insert( QStringLiteral( "map_crs" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of map (e.g., 'EPSG:4326')." ) );
798 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_description" ), QCoreApplication::translate( "variable_help", "Name of the coordinate reference system of the map." ) );
799 sVariableHelpTexts()->insert( QStringLiteral( "map_units" ), QCoreApplication::translate( "variable_help", "Units for map measurements." ) );
800 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_definition" ), QCoreApplication::translate( "variable_help", "Coordinate reference system of the map (full definition)." ) );
801 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_acronym" ), QCoreApplication::translate( "variable_help", "Acronym of the coordinate reference system of the map." ) );
802 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_projection" ), QCoreApplication::translate( "variable_help", "Projection method used by the coordinate reference system of the map." ) );
803 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_ellipsoid" ), QCoreApplication::translate( "variable_help", "Acronym of the ellipsoid of the coordinate reference system of the map." ) );
804 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_proj4" ), QCoreApplication::translate( "variable_help", "Proj4 definition of the coordinate reference system of the map." ) );
805 sVariableHelpTexts()->insert( QStringLiteral( "map_crs_wkt" ), QCoreApplication::translate( "variable_help", "WKT definition of the coordinate reference system of the map." ) );
806 sVariableHelpTexts()->insert( QStringLiteral( "map_layer_ids" ), QCoreApplication::translate( "variable_help", "List of map layer IDs visible in the map." ) );
807 sVariableHelpTexts()->insert( QStringLiteral( "map_layers" ), QCoreApplication::translate( "variable_help", "List of map layers visible in the map." ) );
808
809 sVariableHelpTexts()->insert( QStringLiteral( "map_start_time" ), QCoreApplication::translate( "variable_help", "Start of the map's temporal time range (as a datetime value)" ) );
810 sVariableHelpTexts()->insert( QStringLiteral( "map_end_time" ), QCoreApplication::translate( "variable_help", "End of the map's temporal time range (as a datetime value)" ) );
811 sVariableHelpTexts()->insert( QStringLiteral( "map_interval" ), QCoreApplication::translate( "variable_help", "Duration of the map's temporal time range (as an interval value)" ) );
812
813 sVariableHelpTexts()->insert( QStringLiteral( "frame_rate" ), QCoreApplication::translate( "variable_help", "Number of frames per second during animation playback" ) );
814 sVariableHelpTexts()->insert( QStringLiteral( "frame_number" ), QCoreApplication::translate( "variable_help", "Current frame number during animation playback" ) );
815 sVariableHelpTexts()->insert( QStringLiteral( "frame_duration" ), QCoreApplication::translate( "variable_help", "Temporal duration of each animation frame (as an interval value)" ) );
816 sVariableHelpTexts()->insert( QStringLiteral( "frame_timestep" ), QCoreApplication::translate( "variable_help", "Frame time step during animation playback" ) );
817 sVariableHelpTexts()->insert( QStringLiteral( "frame_timestep_unit" ), QCoreApplication::translate( "variable_help", "Unit value of the frame time step during animation playback" ) );
818 sVariableHelpTexts()->insert( QStringLiteral( "frame_timestep_units" ), QCoreApplication::translate( "variable_help", "String representation of the frame time step unit during animation playback" ) );
819 sVariableHelpTexts()->insert( QStringLiteral( "animation_start_time" ), QCoreApplication::translate( "variable_help", "Start of the animation's overall temporal time range (as a datetime value)" ) );
820 sVariableHelpTexts()->insert( QStringLiteral( "animation_end_time" ), QCoreApplication::translate( "variable_help", "End of the animation's overall temporal time range (as a datetime value)" ) );
821 sVariableHelpTexts()->insert( QStringLiteral( "animation_interval" ), QCoreApplication::translate( "variable_help", "Duration of the animation's overall temporal time range (as an interval value)" ) );
822
823 // vector tile layer variables
824 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]." ) );
825 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." ) );
826
827 sVariableHelpTexts()->insert( QStringLiteral( "row_number" ), QCoreApplication::translate( "variable_help", "Stores the number of the current row." ) );
828 sVariableHelpTexts()->insert( QStringLiteral( "grid_number" ), QCoreApplication::translate( "variable_help", "Current grid annotation value." ) );
829 sVariableHelpTexts()->insert( QStringLiteral( "grid_axis" ), QCoreApplication::translate( "variable_help", "Current grid annotation axis (e.g., 'x' for longitude, 'y' for latitude)." ) );
830 sVariableHelpTexts()->insert( QStringLiteral( "column_number" ), QCoreApplication::translate( "variable_help", "Stores the number of the current column." ) );
831
832 // map canvas item variables
833 sVariableHelpTexts()->insert( QStringLiteral( "canvas_cursor_point" ), QCoreApplication::translate( "variable_help", "Last cursor position on the canvas in the project's geographical coordinates." ) );
834
835 // legend canvas item variables
836 sVariableHelpTexts()->insert( QStringLiteral( "legend_title" ), QCoreApplication::translate( "variable_help", "Title of the legend." ) );
837 sVariableHelpTexts()->insert( QStringLiteral( "legend_column_count" ), QCoreApplication::translate( "variable_help", "Number of column in the legend." ) );
838 sVariableHelpTexts()->insert( QStringLiteral( "legend_split_layers" ), QCoreApplication::translate( "variable_help", "Boolean indicating if layers can be split in the legend." ) );
839 sVariableHelpTexts()->insert( QStringLiteral( "legend_wrap_string" ), QCoreApplication::translate( "variable_help", "Characters used to wrap the legend text." ) );
840 sVariableHelpTexts()->insert( QStringLiteral( "legend_filter_by_map" ), QCoreApplication::translate( "variable_help", "Boolean indicating if the content of the legend is filtered by the map." ) );
841 sVariableHelpTexts()->insert( QStringLiteral( "legend_filter_out_atlas" ), QCoreApplication::translate( "variable_help", "Boolean indicating if the Atlas is filtered out of the legend." ) );
842
843 // scalebar rendering
844 sVariableHelpTexts()->insert( QStringLiteral( "scale_value" ), QCoreApplication::translate( "variable_help", "Current scale bar distance value." ) );
845
846 // map tool capture variables
847 sVariableHelpTexts()->insert( QStringLiteral( "snapping_results" ), QCoreApplication::translate( "variable_help",
848 "<p>An array with an item for each snapped point.</p>"
849 "<p>Each item is a map with the following keys:</p>"
850 "<dl>"
851 "<dt>valid</dt><dd>Boolean that indicates if the snapping result is valid</dd>"
852 "<dt>layer</dt><dd>The layer on which the snapped feature is</dd>"
853 "<dt>feature_id</dt><dd>The feature id of the snapped feature</dd>"
854 "<dt>vertex_index</dt><dd>The index of the snapped vertex</dd>"
855 "<dt>distance</dt><dd>The distance between the mouse cursor and the snapped point at the time of snapping</dd>"
856 "</dl>" ) );
857
858
859 //symbol variables
860 sVariableHelpTexts()->insert( QStringLiteral( "geometry_part_count" ), QCoreApplication::translate( "variable_help", "Number of parts in rendered feature's geometry." ) );
861 sVariableHelpTexts()->insert( QStringLiteral( "geometry_part_num" ), QCoreApplication::translate( "variable_help", "Current geometry part number for feature being rendered." ) );
862 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." ) );
863 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." ) );
864 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." ) );
865
866 sVariableHelpTexts()->insert( QStringLiteral( "symbol_color" ), QCoreApplication::translate( "symbol_color", "Color of symbol used to render the feature." ) );
867 sVariableHelpTexts()->insert( QStringLiteral( "symbol_angle" ), QCoreApplication::translate( "symbol_angle", "Angle of symbol used to render the feature (valid for marker symbols only)." ) );
868 sVariableHelpTexts()->insert( QStringLiteral( "symbol_layer_count" ), QCoreApplication::translate( "symbol_layer_count", "Total number of symbol layers in the symbol." ) );
869 sVariableHelpTexts()->insert( QStringLiteral( "symbol_layer_index" ), QCoreApplication::translate( "symbol_layer_index", "Current symbol layer index." ) );
870 sVariableHelpTexts()->insert( QStringLiteral( "symbol_marker_row" ), QCoreApplication::translate( "symbol_marker_row", "Row number for marker (valid for point pattern fills only)." ) );
871 sVariableHelpTexts()->insert( QStringLiteral( "symbol_marker_column" ), QCoreApplication::translate( "symbol_marker_column", "Column number for marker (valid for point pattern fills only)." ) );
872 sVariableHelpTexts()->insert( QStringLiteral( "symbol_frame" ), QCoreApplication::translate( "symbol_frame", "Frame number (for animated symbols only)." ) );
873
874 sVariableHelpTexts()->insert( QStringLiteral( "symbol_label" ), QCoreApplication::translate( "symbol_label", "Label for the symbol (either a user defined label or the default autogenerated label)." ) );
875 sVariableHelpTexts()->insert( QStringLiteral( "symbol_id" ), QCoreApplication::translate( "symbol_id", "Internal ID of the symbol." ) );
876 sVariableHelpTexts()->insert( QStringLiteral( "symbol_count" ), QCoreApplication::translate( "symbol_count", "Total number of features represented by the symbol." ) );
877
878 //cluster variables
879 sVariableHelpTexts()->insert( QStringLiteral( "cluster_color" ), QCoreApplication::translate( "cluster_color", "Color of symbols within a cluster, or NULL if symbols have mixed colors." ) );
880 sVariableHelpTexts()->insert( QStringLiteral( "cluster_size" ), QCoreApplication::translate( "cluster_size", "Number of symbols contained within a cluster." ) );
881
882 //processing variables
883 sVariableHelpTexts()->insert( QStringLiteral( "algorithm_id" ), QCoreApplication::translate( "algorithm_id", "Unique ID for algorithm." ) );
884 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)." ) );
885 sVariableHelpTexts()->insert( QStringLiteral( "model_folder" ), QCoreApplication::translate( "variable_help", "Folder containing current model (or project folder if model is embedded in a project)." ) );
886 sVariableHelpTexts()->insert( QStringLiteral( "model_name" ), QCoreApplication::translate( "variable_help", "Name of current model." ) );
887 sVariableHelpTexts()->insert( QStringLiteral( "model_group" ), QCoreApplication::translate( "variable_help", "Group for current model." ) );
888 sVariableHelpTexts()->insert( QStringLiteral( "fullextent_minx" ), QCoreApplication::translate( "fullextent_minx", "Minimum x-value from full canvas extent (including all layers)." ) );
889 sVariableHelpTexts()->insert( QStringLiteral( "fullextent_miny" ), QCoreApplication::translate( "fullextent_miny", "Minimum y-value from full canvas extent (including all layers)." ) );
890 sVariableHelpTexts()->insert( QStringLiteral( "fullextent_maxx" ), QCoreApplication::translate( "fullextent_maxx", "Maximum x-value from full canvas extent (including all layers)." ) );
891 sVariableHelpTexts()->insert( QStringLiteral( "fullextent_maxy" ), QCoreApplication::translate( "fullextent_maxy", "Maximum y-value from full canvas extent (including all layers)." ) );
892
893 //provider notification
894 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)." ) );
895
896 //form context variable
897 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." ) );
898 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." ) );
899
900 //parent form context variable
901 sVariableHelpTexts()->insert( QStringLiteral( "current_parent_geometry" ), QCoreApplication::translate( "current_parent_geometry",
902 "Only usable in an embedded form context, "
903 "represents the geometry of the feature currently being edited in the parent form.\n"
904 "Can be used in a form/row context to filter the related features using a value "
905 "from the feature currently edited in the parent form, to make sure that the filter "
906 "still works with standalone forms it is recommended to wrap this variable in a "
907 "'coalesce()'." ) );
908 sVariableHelpTexts()->insert( QStringLiteral( "current_parent_feature" ), QCoreApplication::translate( "current_parent_feature",
909 "Only usable in an embedded form context, "
910 "represents the feature currently being edited in the parent form.\n"
911 "Can be used in a form/row context to filter the related features using a value "
912 "from the feature currently edited in the parent form, to make sure that the filter "
913 "still works with standalone forms it is recommended to wrap this variable in a "
914 "'coalesce()'." ) );
915
916 //form variable
917 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." ) );
918
919 // plots
920 sVariableHelpTexts()->insert( QStringLiteral( "plot_axis" ), QCoreApplication::translate( "plot_axis", "The associated plot axis, e.g. 'x' or 'y'." ) );
921 sVariableHelpTexts()->insert( QStringLiteral( "plot_axis_value" ), QCoreApplication::translate( "plot_axis_value", "The current value for the plot axis." ) );
922}
923
924
925bool QgsExpression::addVariableHelpText( const QString name, const QString &description )
926{
927 if ( sVariableHelpTexts()->contains( name ) )
928 {
929 return false;
930 }
931 sVariableHelpTexts()->insert( name, description );
932 return true;
933}
934
935QString QgsExpression::variableHelpText( const QString &variableName )
936{
937 QgsExpression::initVariableHelp();
938 return sVariableHelpTexts()->value( variableName, QString() );
939}
940
941QString QgsExpression::formatVariableHelp( const QString &description, bool showValue, const QVariant &value )
942{
943 QString text = !description.isEmpty() ? QStringLiteral( "<p>%1</p>" ).arg( description ) : QString();
944 if ( showValue )
945 {
946 QString valueString;
947 if ( !value.isValid() )
948 {
949 valueString = QCoreApplication::translate( "variable_help", "not set" );
950 }
951 else
952 {
953 valueString = QStringLiteral( "<b>%1</b>" ).arg( formatPreviewString( value ) );
954 }
955 text.append( QCoreApplication::translate( "variable_help", "<p>Current value: %1</p>" ).arg( valueString ) );
956 }
957 return text;
958}
959
960QString QgsExpression::group( const QString &name )
961{
962 if ( sGroups()->isEmpty() )
963 {
964 sGroups()->insert( QStringLiteral( "Aggregates" ), tr( "Aggregates" ) );
965 sGroups()->insert( QStringLiteral( "Arrays" ), tr( "Arrays" ) );
966 sGroups()->insert( QStringLiteral( "Color" ), tr( "Color" ) );
967 sGroups()->insert( QStringLiteral( "Conditionals" ), tr( "Conditionals" ) );
968 sGroups()->insert( QStringLiteral( "Conversions" ), tr( "Conversions" ) );
969 sGroups()->insert( QStringLiteral( "Date and Time" ), tr( "Date and Time" ) );
970 sGroups()->insert( QStringLiteral( "Fields and Values" ), tr( "Fields and Values" ) );
971 sGroups()->insert( QStringLiteral( "Files and Paths" ), tr( "Files and Paths" ) );
972 sGroups()->insert( QStringLiteral( "Fuzzy Matching" ), tr( "Fuzzy Matching" ) );
973 sGroups()->insert( QStringLiteral( "General" ), tr( "General" ) );
974 sGroups()->insert( QStringLiteral( "GeometryGroup" ), tr( "Geometry" ) );
975 sGroups()->insert( QStringLiteral( "Map Layers" ), tr( "Map Layers" ) );
976 sGroups()->insert( QStringLiteral( "Maps" ), tr( "Maps" ) );
977 sGroups()->insert( QStringLiteral( "Math" ), tr( "Math" ) );
978 sGroups()->insert( QStringLiteral( "Operators" ), tr( "Operators" ) );
979 sGroups()->insert( QStringLiteral( "Rasters" ), tr( "Rasters" ) );
980 sGroups()->insert( QStringLiteral( "Record and Attributes" ), tr( "Record and Attributes" ) );
981 sGroups()->insert( QStringLiteral( "String" ), tr( "String" ) );
982 sGroups()->insert( QStringLiteral( "Variables" ), tr( "Variables" ) );
983 sGroups()->insert( QStringLiteral( "Recent (%1)" ), tr( "Recent (%1)" ) );
984 sGroups()->insert( QStringLiteral( "UserGroup" ), tr( "User expressions" ) );
985 }
986
987 //return the translated name for this group. If group does not
988 //have a translated name in the gGroups hash, return the name
989 //unchanged
990 return sGroups()->value( name, name );
991}
992
993QString QgsExpression::formatPreviewString( const QVariant &value, const bool htmlOutput, int maximumPreviewLength )
994{
995 const QString startToken = htmlOutput ? QStringLiteral( "<i>&lt;" ) : QStringLiteral( "<" );
996 const QString endToken = htmlOutput ? QStringLiteral( "&gt;</i>" ) : QStringLiteral( ">" );
997
998 if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
999 {
1000 //result is a geometry
1001 QgsGeometry geom = value.value<QgsGeometry>();
1002 if ( geom.isNull() )
1003 return startToken + tr( "empty geometry" ) + endToken;
1004 else
1005 return startToken + tr( "geometry: %1" ).arg( QgsWkbTypes::displayString( geom.constGet()->wkbType() ) )
1006 + endToken;
1007 }
1008 else if ( value.value< QgsWeakMapLayerPointer >().data() )
1009 {
1010 return startToken + tr( "map layer" ) + endToken;
1011 }
1012 else if ( !value.isValid() )
1013 {
1014 return htmlOutput ? tr( "<i>NULL</i>" ) : QString();
1015 }
1016 else if ( value.userType() == QMetaType::type( "QgsFeature" ) )
1017 {
1018 //result is a feature
1019 QgsFeature feat = value.value<QgsFeature>();
1020 return startToken + tr( "feature: %1" ).arg( feat.id() ) + endToken;
1021 }
1022 else if ( value.userType() == QMetaType::type( "QgsInterval" ) )
1023 {
1024 QgsInterval interval = value.value<QgsInterval>();
1025 if ( interval.days() > 1 )
1026 {
1027 return startToken + tr( "interval: %1 days" ).arg( interval.days() ) + endToken;
1028 }
1029 else if ( interval.hours() > 1 )
1030 {
1031 return startToken + tr( "interval: %1 hours" ).arg( interval.hours() ) + endToken;
1032 }
1033 else if ( interval.minutes() > 1 )
1034 {
1035 return startToken + tr( "interval: %1 minutes" ).arg( interval.minutes() ) + endToken;
1036 }
1037 else
1038 {
1039 return startToken + tr( "interval: %1 seconds" ).arg( interval.seconds() ) + endToken;
1040 }
1041 }
1042 else if ( value.userType() == QMetaType::type( "QgsGradientColorRamp" ) )
1043 {
1044 return startToken + tr( "gradient ramp" ) + endToken;
1045 }
1046 else if ( value.type() == QVariant::Date )
1047 {
1048 const QDate dt = value.toDate();
1049 return startToken + tr( "date: %1" ).arg( dt.toString( QStringLiteral( "yyyy-MM-dd" ) ) ) + endToken;
1050 }
1051 else if ( value.type() == QVariant::Time )
1052 {
1053 const QTime tm = value.toTime();
1054 return startToken + tr( "time: %1" ).arg( tm.toString( QStringLiteral( "hh:mm:ss" ) ) ) + endToken;
1055 }
1056 else if ( value.type() == QVariant::DateTime )
1057 {
1058 const QDateTime dt = value.toDateTime();
1059 return startToken + tr( "datetime: %1 (%2)" ).arg( dt.toString( QStringLiteral( "yyyy-MM-dd hh:mm:ss" ) ), dt.timeZoneAbbreviation() ) + endToken;
1060 }
1061 else if ( value.type() == QVariant::String )
1062 {
1063 const QString previewString = value.toString();
1064 if ( previewString.length() > maximumPreviewLength + 3 )
1065 {
1066 return tr( "'%1…'" ).arg( previewString.left( maximumPreviewLength ) );
1067 }
1068 else
1069 {
1070 return '\'' + previewString + '\'';
1071 }
1072 }
1073 else if ( value.type() == QVariant::Map )
1074 {
1075 QString mapStr = QStringLiteral( "{" );
1076 const QVariantMap map = value.toMap();
1077 QString separator;
1078 for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
1079 {
1080 mapStr.append( separator );
1081 if ( separator.isEmpty() )
1082 separator = QStringLiteral( "," );
1083
1084 mapStr.append( QStringLiteral( " '%1': %2" ).arg( it.key(), formatPreviewString( it.value(), htmlOutput ) ) );
1085 if ( mapStr.length() > maximumPreviewLength - 3 )
1086 {
1087 mapStr = tr( "%1…" ).arg( mapStr.left( maximumPreviewLength - 2 ) );
1088 break;
1089 }
1090 }
1091 if ( !map.empty() )
1092 mapStr += QLatin1Char( ' ' );
1093 mapStr += QLatin1Char( '}' );
1094 return mapStr;
1095 }
1096 else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
1097 {
1098 QString listStr = QStringLiteral( "[" );
1099 const QVariantList list = value.toList();
1100 QString separator;
1101 for ( const QVariant &arrayValue : list )
1102 {
1103 listStr.append( separator );
1104 if ( separator.isEmpty() )
1105 separator = QStringLiteral( "," );
1106
1107 listStr.append( " " );
1108 listStr.append( formatPreviewString( arrayValue, htmlOutput ) );
1109 if ( listStr.length() > maximumPreviewLength - 3 )
1110 {
1111 listStr = QString( tr( "%1…" ) ).arg( listStr.left( maximumPreviewLength - 2 ) );
1112 break;
1113 }
1114 }
1115 if ( !list.empty() )
1116 listStr += QLatin1Char( ' ' );
1117 listStr += QLatin1Char( ']' );
1118 return listStr;
1119 }
1120 else if ( value.type() == QVariant::Int ||
1121 value.type() == QVariant::UInt ||
1122 value.type() == QVariant::LongLong ||
1123 value.type() == QVariant::ULongLong ||
1124 value.type() == QVariant::Double ||
1125 // Qt madness with QMetaType::Float :/
1126 value.type() == static_cast<QVariant::Type>( QMetaType::Float ) )
1127 {
1128 return QgsExpressionUtils::toLocalizedString( value );
1129 }
1130 else
1131 {
1132 QString str { value.toString() };
1133 if ( str.length() > maximumPreviewLength - 3 )
1134 {
1135 str = tr( "%1…" ).arg( str.left( maximumPreviewLength - 2 ) );
1136 }
1137 return str;
1138 }
1139}
1140
1141QString QgsExpression::createFieldEqualityExpression( const QString &fieldName, const QVariant &value, QVariant::Type fieldType )
1142{
1143 QString expr;
1144
1145 if ( QgsVariantUtils::isNull( value ) )
1146 expr = QStringLiteral( "%1 IS NULL" ).arg( quotedColumnRef( fieldName ) );
1147 else if ( fieldType == QVariant::Type::Invalid )
1148 expr = QStringLiteral( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value ) );
1149 else
1150 expr = QStringLiteral( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value, fieldType ) );
1151
1152 return expr;
1153}
1154
1155bool QgsExpression::isFieldEqualityExpression( const QString &expression, QString &field, QVariant &value )
1156{
1158
1159 if ( !e.rootNode() )
1160 return false;
1161
1162 if ( const QgsExpressionNodeBinaryOperator *binOp = dynamic_cast<const QgsExpressionNodeBinaryOperator *>( e.rootNode() ) )
1163 {
1164 if ( binOp->op() == QgsExpressionNodeBinaryOperator::boEQ )
1165 {
1166 const QgsExpressionNodeColumnRef *columnRef = dynamic_cast<const QgsExpressionNodeColumnRef *>( binOp->opLeft() );
1167 const QgsExpressionNodeLiteral *literal = dynamic_cast<const QgsExpressionNodeLiteral *>( binOp->opRight() );
1168 if ( columnRef && literal )
1169 {
1170 field = columnRef->name();
1171 value = literal->value();
1172 return true;
1173 }
1174 }
1175 }
1176 return false;
1177}
1178
1179bool QgsExpression::attemptReduceToInClause( const QStringList &expressions, QString &result )
1180{
1181 if ( expressions.empty() )
1182 return false;
1183
1184 QString inField;
1185 bool first = true;
1186 QStringList values;
1187 for ( const QString &expression : expressions )
1188 {
1189 QString field;
1190 QVariant value;
1192 {
1193 if ( first )
1194 {
1195 inField = field;
1196 first = false;
1197 }
1198 else if ( field != inField )
1199 {
1200 return false;
1201 }
1202 values << QgsExpression::quotedValue( value );
1203 }
1204 else
1205 {
1206 // we also allow reducing similar 'field IN (...)' expressions!
1208
1209 if ( !e.rootNode() )
1210 return false;
1211
1212 if ( const QgsExpressionNodeInOperator *inOp = dynamic_cast<const QgsExpressionNodeInOperator *>( e.rootNode() ) )
1213 {
1214 if ( inOp->isNotIn() )
1215 return false;
1216
1217 const QgsExpressionNodeColumnRef *columnRef = dynamic_cast<const QgsExpressionNodeColumnRef *>( inOp->node() );
1218 if ( !columnRef )
1219 return false;
1220
1221 if ( first )
1222 {
1223 inField = columnRef->name();
1224 first = false;
1225 }
1226 else if ( columnRef->name() != inField )
1227 {
1228 return false;
1229 }
1230
1231 if ( QgsExpressionNode::NodeList *nodeList = inOp->list() )
1232 {
1233 const QList<QgsExpressionNode *> nodes = nodeList->list();
1234 for ( const QgsExpressionNode *node : nodes )
1235 {
1236 const QgsExpressionNodeLiteral *literal = dynamic_cast<const QgsExpressionNodeLiteral *>( node );
1237 if ( !literal )
1238 return false;
1239
1240 values << QgsExpression::quotedValue( literal->value() );
1241 }
1242 }
1243 }
1244 // Collect ORs
1245 else if ( const QgsExpressionNodeBinaryOperator *orOp = dynamic_cast<const QgsExpressionNodeBinaryOperator *>( e.rootNode() ) )
1246 {
1247
1248 // OR Collector function: returns a possibly empty list of the left and right operands of an OR expression
1249 std::function<QStringList( QgsExpressionNode *, QgsExpressionNode * )> collectOrs = [ &collectOrs ]( QgsExpressionNode * opLeft, QgsExpressionNode * opRight ) -> QStringList
1250 {
1251 QStringList orParts;
1252 if ( const QgsExpressionNodeBinaryOperator *leftOrOp = dynamic_cast<const QgsExpressionNodeBinaryOperator *>( opLeft ) )
1253 {
1255 {
1256 orParts.append( collectOrs( leftOrOp->opLeft(), leftOrOp->opRight() ) );
1257 }
1258 else
1259 {
1260 orParts.append( leftOrOp->dump() );
1261 }
1262 }
1263 else if ( const QgsExpressionNodeInOperator *leftInOp = dynamic_cast<const QgsExpressionNodeInOperator *>( opLeft ) )
1264 {
1265 orParts.append( leftInOp->dump() );
1266 }
1267 else
1268 {
1269 return {};
1270 }
1271
1272 if ( const QgsExpressionNodeBinaryOperator *rightOrOp = dynamic_cast<const QgsExpressionNodeBinaryOperator *>( opRight ) )
1273 {
1275 {
1276 orParts.append( collectOrs( rightOrOp->opLeft(), rightOrOp->opRight() ) );
1277 }
1278 else
1279 {
1280 orParts.append( rightOrOp->dump() );
1281 }
1282 }
1283 else if ( const QgsExpressionNodeInOperator *rightInOp = dynamic_cast<const QgsExpressionNodeInOperator *>( opRight ) )
1284 {
1285 orParts.append( rightInOp->dump() );
1286 }
1287 else
1288 {
1289 return {};
1290 }
1291
1292 return orParts;
1293 };
1294
1296 {
1297 // Try to collect all OR conditions
1298 const QStringList orParts = collectOrs( orOp->opLeft(), orOp->opRight() );
1299 if ( orParts.isEmpty() )
1300 {
1301 return false;
1302 }
1303 else
1304 {
1305 QString orPartsResult;
1306 if ( attemptReduceToInClause( orParts, orPartsResult ) )
1307 {
1308 // Need to check if the IN field is correct,
1309 QgsExpression inExp { orPartsResult };
1310 if ( ! inExp.rootNode() )
1311 {
1312 return false;
1313 }
1314
1315 if ( const QgsExpressionNodeInOperator *inOpInner = dynamic_cast<const QgsExpressionNodeInOperator *>( inExp.rootNode() ) )
1316 {
1317 if ( inOpInner->node()->nodeType() != QgsExpressionNode::NodeType::ntColumnRef || inOpInner->node()->referencedColumns().size() < 1 )
1318 {
1319 return false;
1320 }
1321
1322 const QString innerInfield { inOpInner->node()->referencedColumns().values().first() };
1323
1324 if ( first )
1325 {
1326 inField = innerInfield;
1327 first = false;
1328 }
1329
1330 if ( innerInfield != inField )
1331 {
1332 return false;
1333 }
1334 else
1335 {
1336 const auto constInnerValuesList { inOpInner->list()->list() };
1337 for ( const auto &innerInValueNode : std::as_const( constInnerValuesList ) )
1338 {
1339 values.append( innerInValueNode->dump() );
1340 }
1341 }
1342
1343 }
1344 else
1345 {
1346 return false;
1347 }
1348 }
1349 else
1350 {
1351 return false;
1352 }
1353 }
1354 }
1355 else
1356 {
1357 return false;
1358 }
1359 }
1360 else
1361 {
1362 return false;
1363 }
1364 }
1365 }
1366 result = QStringLiteral( "%1 IN (%2)" ).arg( quotedColumnRef( inField ), values.join( ',' ) );
1367 return true;
1368}
1369
1371{
1372 return d->mRootNode;
1373}
1374
1376{
1377 return d->mRootNode && d->mRootNode->nodeType() == QgsExpressionNode::ntColumnRef;
1378}
1379
1380int QgsExpression::expressionToLayerFieldIndex( const QString &expression, const QgsVectorLayer *layer )
1381{
1382 if ( !layer )
1383 return -1;
1384
1385 // easy check first -- lookup field directly.
1386 int attrIndex = layer->fields().lookupField( expression.trimmed() );
1387 if ( attrIndex >= 0 )
1388 return attrIndex;
1389
1390 // may still be a simple field expression, just one which is enclosed in "" or similar
1391 QgsExpression candidate( expression );
1392 if ( candidate.isField() )
1393 {
1394 const QString fieldName = qgis::down_cast<const QgsExpressionNodeColumnRef *>( candidate.rootNode() )->name();
1395 return layer->fields().lookupField( fieldName );
1396 }
1397 return -1;
1398}
1399
1400QString QgsExpression::quoteFieldExpression( const QString &expression, const QgsVectorLayer *layer )
1401{
1402 if ( !layer )
1403 return expression;
1404
1405 const int fieldIndex = QgsExpression::expressionToLayerFieldIndex( expression, layer );
1406 if ( !expression.contains( '\"' ) && fieldIndex != -1 )
1407 {
1408 // retrieve actual field name from layer, so that we correctly remove any unwanted leading/trailing whitespace
1409 return QgsExpression::quotedColumnRef( layer->fields().at( fieldIndex ).name() );
1410 }
1411 else
1412 {
1413 return expression;
1414 }
1415}
1416
1417QList<const QgsExpressionNode *> QgsExpression::nodes() const
1418{
1419 if ( !d->mRootNode )
1420 return QList<const QgsExpressionNode *>();
1421
1422 return d->mRootNode->nodes();
1423}
1424
1425
1426
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
A 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
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.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
A representation of the interval between two datetime values.
Definition qgsinterval.h:42
double days() const
Returns the interval duration in days.
double seconds() const
Returns the interval duration in seconds.
double hours() const
Returns the interval duration in hours.
double minutes() const
Returns the interval duration in minutes.
static QgsProject * instance()
Returns the QgsProject singleton instance.
DistanceUnit
Units of distance.
@ DistanceUnknownUnit
Unknown distance unit.
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.
@ AreaUnknownUnit
Unknown areal unit.
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
static QString displayString(Type type)
Returns a non-translated display string type for a WKB type, e.g., the geometry name used in WKT geom...
#define str(x)
Definition qgis.cpp: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:476
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
#define QgsDebugMsg(str)
Definition qgslogger.h:38
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.