QGIS API Documentation  3.4.3-Madeira (2f64a3c)
qgsexpressioncontext.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsexpressioncontext.cpp
3  ------------------------
4  Date : April 2015
5  Copyright : (C) 2015 by Nyall Dawson
6  Email : nyall dot dawson 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 "qgsexpressioncontext.h"
17 
18 #include "qgslogger.h"
19 #include "qgsexpression.h"
20 #include "qgsexpressionfunction.h"
21 #include "qgsfields.h"
22 #include "qgsvectorlayer.h"
23 #include "qgsproject.h"
24 #include "qgssymbollayerutils.h"
25 #include "qgsgeometry.h"
26 #include "qgsapplication.h"
27 #include "qgsmapsettings.h"
28 #include "qgsmaplayerlistutils.h"
29 #include "qgsprocessingcontext.h"
30 #include "qgsprocessingalgorithm.h"
31 #include "qgslayoutatlas.h"
32 #include "qgslayout.h"
34 #include "qgslayoutreportcontext.h"
35 #include "qgsexpressionutils.h"
36 
37 #include <QSettings>
38 #include <QDir>
39 
40 
41 const QString QgsExpressionContext::EXPR_FIELDS( QStringLiteral( "_fields_" ) );
42 const QString QgsExpressionContext::EXPR_ORIGINAL_VALUE( QStringLiteral( "value" ) );
43 const QString QgsExpressionContext::EXPR_SYMBOL_COLOR( QStringLiteral( "symbol_color" ) );
44 const QString QgsExpressionContext::EXPR_SYMBOL_ANGLE( QStringLiteral( "symbol_angle" ) );
45 const QString QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT( QStringLiteral( "geometry_part_count" ) );
46 const QString QgsExpressionContext::EXPR_GEOMETRY_PART_NUM( QStringLiteral( "geometry_part_num" ) );
47 const QString QgsExpressionContext::EXPR_GEOMETRY_POINT_COUNT( QStringLiteral( "geometry_point_count" ) );
48 const QString QgsExpressionContext::EXPR_GEOMETRY_POINT_NUM( QStringLiteral( "geometry_point_num" ) );
49 const QString QgsExpressionContext::EXPR_CLUSTER_SIZE( QStringLiteral( "cluster_size" ) );
50 const QString QgsExpressionContext::EXPR_CLUSTER_COLOR( QStringLiteral( "cluster_color" ) );
51 
52 //
53 // QgsExpressionContextScope
54 //
55 
57  : mName( name )
58 {
59 
60 }
61 
63  : mName( other.mName )
64  , mVariables( other.mVariables )
65  , mHasFeature( other.mHasFeature )
66  , mFeature( other.mFeature )
67 {
68  QHash<QString, QgsScopedExpressionFunction * >::const_iterator it = other.mFunctions.constBegin();
69  for ( ; it != other.mFunctions.constEnd(); ++it )
70  {
71  mFunctions.insert( it.key(), it.value()->clone() );
72  }
73 }
74 
76 {
77  mName = other.mName;
78  mVariables = other.mVariables;
79  mHasFeature = other.mHasFeature;
80  mFeature = other.mFeature;
81 
82  qDeleteAll( mFunctions );
83  mFunctions.clear();
84  QHash<QString, QgsScopedExpressionFunction * >::const_iterator it = other.mFunctions.constBegin();
85  for ( ; it != other.mFunctions.constEnd(); ++it )
86  {
87  mFunctions.insert( it.key(), it.value()->clone() );
88  }
89 
90  return *this;
91 }
92 
94 {
95  qDeleteAll( mFunctions );
96 }
97 
98 void QgsExpressionContextScope::setVariable( const QString &name, const QVariant &value, bool isStatic )
99 {
100  if ( mVariables.contains( name ) )
101  {
102  StaticVariable existing = mVariables.value( name );
103  existing.value = value;
104  existing.isStatic = isStatic;
105  addVariable( existing );
106  }
107  else
108  {
109  addVariable( QgsExpressionContextScope::StaticVariable( name, value, false, isStatic ) );
110  }
111 }
112 
114 {
115  mVariables.insert( variable.name, variable );
116 }
117 
119 {
120  return mVariables.remove( name ) > 0;
121 }
122 
123 bool QgsExpressionContextScope::hasVariable( const QString &name ) const
124 {
125  return mVariables.contains( name );
126 }
127 
128 QVariant QgsExpressionContextScope::variable( const QString &name ) const
129 {
130  return hasVariable( name ) ? mVariables.value( name ).value : QVariant();
131 }
132 
134 {
135  QStringList names = mVariables.keys();
136  return names;
137 }
138 
139 bool QgsExpressionContextScope::variableNameSort( const QString &a, const QString &b )
140 {
141  return QString::localeAwareCompare( a, b ) < 0;
142 }
143 
145 class QgsExpressionContextVariableCompare
146 {
147  public:
148  explicit QgsExpressionContextVariableCompare( const QgsExpressionContextScope &scope )
149  : mScope( scope )
150  { }
151 
152  bool operator()( const QString &a, const QString &b ) const
153  {
154  bool aReadOnly = mScope.isReadOnly( a );
155  bool bReadOnly = mScope.isReadOnly( b );
156  if ( aReadOnly != bReadOnly )
157  return aReadOnly;
158  return QString::localeAwareCompare( a, b ) < 0;
159  }
160 
161  private:
162  const QgsExpressionContextScope &mScope;
163 };
165 
167 {
168  QStringList allVariables = mVariables.keys();
169  QStringList filtered;
170  Q_FOREACH ( const QString &variable, allVariables )
171  {
172  if ( variable.startsWith( '_' ) )
173  continue;
174 
175  filtered << variable;
176  }
177  QgsExpressionContextVariableCompare cmp( *this );
178  std::sort( filtered.begin(), filtered.end(), cmp );
179 
180  return filtered;
181 }
182 
183 bool QgsExpressionContextScope::isReadOnly( const QString &name ) const
184 {
185  return hasVariable( name ) ? mVariables.value( name ).readOnly : false;
186 }
187 
188 bool QgsExpressionContextScope::isStatic( const QString &name ) const
189 {
190  return hasVariable( name ) ? mVariables.value( name ).isStatic : false;
191 }
192 
193 QString QgsExpressionContextScope::description( const QString &name ) const
194 {
195  return hasVariable( name ) ? mVariables.value( name ).description : QString();
196 }
197 
198 bool QgsExpressionContextScope::hasFunction( const QString &name ) const
199 {
200  return mFunctions.contains( name );
201 }
202 
204 {
205  return mFunctions.contains( name ) ? mFunctions.value( name ) : nullptr;
206 }
207 
209 {
210  return mFunctions.keys();
211 }
212 
214 {
215  mFunctions.insert( name, function );
216 }
217 
218 
220 {
221  addVariable( StaticVariable( QgsExpressionContext::EXPR_FIELDS, QVariant::fromValue( fields ), true ) );
222 }
223 
224 
225 //
226 // QgsExpressionContext
227 //
228 
229 QgsExpressionContext::QgsExpressionContext( const QList<QgsExpressionContextScope *> &scopes )
230  : mStack( scopes )
231 {
232 }
233 
235 {
236  Q_FOREACH ( const QgsExpressionContextScope *scope, other.mStack )
237  {
238  mStack << new QgsExpressionContextScope( *scope );
239  }
240  mHighlightedVariables = other.mHighlightedVariables;
241  mHighlightedFunctions = other.mHighlightedFunctions;
242  mCachedValues = other.mCachedValues;
243 }
244 
246 {
247  if ( this != &other )
248  {
249  qDeleteAll( mStack );
250  // move the stack over
251  mStack = other.mStack;
252  other.mStack.clear();
253 
254  mHighlightedVariables = other.mHighlightedVariables;
255  mHighlightedFunctions = other.mHighlightedFunctions;
256  mCachedValues = other.mCachedValues;
257  }
258  return *this;
259 }
260 
262 {
263  qDeleteAll( mStack );
264  mStack.clear();
265  Q_FOREACH ( const QgsExpressionContextScope *scope, other.mStack )
266  {
267  mStack << new QgsExpressionContextScope( *scope );
268  }
269  mHighlightedVariables = other.mHighlightedVariables;
270  mHighlightedFunctions = other.mHighlightedFunctions;
271  mCachedValues = other.mCachedValues;
272  return *this;
273 }
274 
276 {
277  qDeleteAll( mStack );
278  mStack.clear();
279 }
280 
281 bool QgsExpressionContext::hasVariable( const QString &name ) const
282 {
283  Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
284  {
285  if ( scope->hasVariable( name ) )
286  return true;
287  }
288  return false;
289 }
290 
291 QVariant QgsExpressionContext::variable( const QString &name ) const
292 {
294  return scope ? scope->variable( name ) : QVariant();
295 }
296 
298 {
299  QStringList names = variableNames();
300  QVariantMap m;
301  Q_FOREACH ( const QString &name, names )
302  {
303  m.insert( name, variable( name ) );
304  }
305  return m;
306 }
307 
308 bool QgsExpressionContext::isHighlightedVariable( const QString &name ) const
309 {
310  return mHighlightedVariables.contains( name );
311 }
312 
314 {
315  mHighlightedVariables = variableNames;
316 }
317 
318 bool QgsExpressionContext::isHighlightedFunction( const QString &name ) const
319 {
320  return mHighlightedFunctions.contains( name );
321 }
322 
323 void QgsExpressionContext::setHighlightedFunctions( const QStringList &names )
324 {
325  mHighlightedFunctions = names;
326 }
327 
329 {
330  //iterate through stack backwards, so that higher priority variables take precedence
331  QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd();
332  while ( it != mStack.constBegin() )
333  {
334  --it;
335  if ( ( *it )->hasVariable( name ) )
336  return ( *it );
337  }
338  return nullptr;
339 }
340 
342 {
343  //iterate through stack backwards, so that higher priority variables take precedence
344  QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd();
345  while ( it != mStack.constBegin() )
346  {
347  --it;
348  if ( ( *it )->hasVariable( name ) )
349  return ( *it );
350  }
351  return nullptr;
352 }
353 
355 {
356  if ( index < 0 || index >= mStack.count() )
357  return nullptr;
358 
359  return mStack.at( index );
360 }
361 
363 {
364  if ( mStack.count() < 1 )
365  return nullptr;
366 
367  return mStack.last();
368 }
369 
371 {
372  if ( !scope )
373  return -1;
374 
375  return mStack.indexOf( scope );
376 }
377 
378 int QgsExpressionContext::indexOfScope( const QString &scopeName ) const
379 {
380  int index = 0;
381  Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
382  {
383  if ( scope->name() == scopeName )
384  return index;
385 
386  index++;
387  }
388  return -1;
389 }
390 
392 {
393  QStringList names;
394  Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
395  {
396  names << scope->variableNames();
397  }
398  return names.toSet().toList();
399 }
400 
402 {
403  QStringList allVariables = variableNames();
404  QStringList filtered;
405  Q_FOREACH ( const QString &variable, allVariables )
406  {
407  if ( variable.startsWith( '_' ) )
408  continue;
409 
410  filtered << variable;
411  }
412 
413  filtered.sort();
414  return filtered;
415 }
416 
417 bool QgsExpressionContext::isReadOnly( const QString &name ) const
418 {
419  Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
420  {
421  if ( scope->isReadOnly( name ) )
422  return true;
423  }
424  return false;
425 }
426 
427 QString QgsExpressionContext::description( const QString &name ) const
428 {
430  return ( scope && !scope->description( name ).isEmpty() ) ? scope->description( name ) : QgsExpression::variableHelpText( name );
431 }
432 
433 bool QgsExpressionContext::hasFunction( const QString &name ) const
434 {
435  Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
436  {
437  if ( scope->hasFunction( name ) )
438  return true;
439  }
440  return false;
441 }
442 
444 {
445  QStringList result;
446  Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
447  {
448  result << scope->functionNames();
449  }
450  result = result.toSet().toList();
451  result.sort();
452  return result;
453 }
454 
456 {
457  //iterate through stack backwards, so that higher priority variables take precedence
458  QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd();
459  while ( it != mStack.constBegin() )
460  {
461  --it;
462  if ( ( *it )->hasFunction( name ) )
463  return ( *it )->function( name );
464  }
465  return nullptr;
466 }
467 
469 {
470  return mStack.count();
471 }
472 
474 {
475  mStack.append( scope );
476 }
477 
478 void QgsExpressionContext::appendScopes( const QList<QgsExpressionContextScope *> &scopes )
479 {
480  mStack.append( scopes );
481 }
482 
484 {
485  if ( !mStack.isEmpty() )
486  return mStack.takeLast();
487 
488  return nullptr;
489 }
490 
491 QList<QgsExpressionContextScope *> QgsExpressionContext::takeScopes()
492 {
493  QList<QgsExpressionContextScope *> stack = mStack;
494  mStack.clear();
495  return stack;
496 }
497 
499 {
500  mStack.append( scope );
501  return *this;
502 }
503 
505 {
506  if ( mStack.isEmpty() )
507  mStack.append( new QgsExpressionContextScope() );
508 
509  mStack.last()->setFeature( feature );
510 }
511 
513 {
514  Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
515  {
516  if ( scope->hasFeature() )
517  return true;
518  }
519  return false;
520 }
521 
523 {
524  //iterate through stack backwards, so that higher priority variables take precedence
525  QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd();
526  while ( it != mStack.constBegin() )
527  {
528  --it;
529  if ( ( *it )->hasFeature() )
530  return ( *it )->feature();
531  }
532  return QgsFeature();
533 }
534 
536 {
537  if ( mStack.isEmpty() )
538  mStack.append( new QgsExpressionContextScope() );
539 
540  mStack.last()->setFields( fields );
541 }
542 
544 {
545  return qvariant_cast<QgsFields>( variable( QgsExpressionContext::EXPR_FIELDS ) );
546 }
547 
549 {
550  if ( mStack.isEmpty() )
551  mStack.append( new QgsExpressionContextScope() );
552 
554  value, true ) );
555 }
556 
557 void QgsExpressionContext::setCachedValue( const QString &key, const QVariant &value ) const
558 {
559  mCachedValues.insert( key, value );
560 }
561 
562 bool QgsExpressionContext::hasCachedValue( const QString &key ) const
563 {
564  return mCachedValues.contains( key );
565 }
566 
567 QVariant QgsExpressionContext::cachedValue( const QString &key ) const
568 {
569  return mCachedValues.value( key, QVariant() );
570 }
571 
573 {
574  mCachedValues.clear();
575 }
576 
577 
578 //
579 // QgsExpressionContextUtils
580 //
581 
583 {
584  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Global" ) );
585 
586  QVariantMap customVariables = QgsApplication::customVariables();
587 
588  for ( QVariantMap::const_iterator it = customVariables.constBegin(); it != customVariables.constEnd(); ++it )
589  {
590  scope->setVariable( it.key(), it.value(), true );
591  }
592 
593  //add some extra global variables
594  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_version" ), Qgis::QGIS_VERSION, true, true ) );
595  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_version_no" ), Qgis::QGIS_VERSION_INT, true, true ) );
596  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_short_version" ), QStringLiteral( "%1.%2" ).arg( Qgis::QGIS_VERSION_INT / 10000 ).arg( Qgis::QGIS_VERSION_INT / 100 % 100 ), true, true ) );
597  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_release_name" ), Qgis::QGIS_RELEASE_NAME, true, true ) );
598  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_platform" ), QgsApplication::platform(), true, true ) );
599  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_os_name" ), QgsApplication::osName(), true, true ) );
600  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_locale" ), QgsApplication::locale(), true, true ) );
601  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_account_name" ), QgsApplication::userLoginName(), true, true ) );
602  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_full_name" ), QgsApplication::userFullName(), true, true ) );
603 
604  return scope;
605 }
606 
607 void QgsExpressionContextUtils::setGlobalVariable( const QString &name, const QVariant &value )
608 {
609  QgsApplication::setCustomVariable( name, value );
610 }
611 
612 void QgsExpressionContextUtils::setGlobalVariables( const QVariantMap &variables )
613 {
615 }
616 
618 {
619  QVariantMap vars = QgsApplication::customVariables();
620  if ( vars.remove( name ) )
622 }
623 
624 
626 
627 class GetNamedProjectColor : public QgsScopedExpressionFunction
628 {
629  public:
630  GetNamedProjectColor( const QgsProject *project )
631  : QgsScopedExpressionFunction( QStringLiteral( "project_color" ), 1, QStringLiteral( "Color" ) )
632  , mProject( project )
633  {
634  if ( !project )
635  return;
636 
637  //build up color list from project. Do this in advance for speed
638  QStringList colorStrings = project->readListEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Colors" ) );
639  QStringList colorLabels = project->readListEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Labels" ) );
640 
641  //generate list from custom colors
642  int colorIndex = 0;
643  for ( QStringList::iterator it = colorStrings.begin();
644  it != colorStrings.end(); ++it )
645  {
646  QColor color = QgsSymbolLayerUtils::decodeColor( *it );
647  QString label;
648  if ( colorLabels.length() > colorIndex )
649  {
650  label = colorLabels.at( colorIndex );
651  }
652 
653  mColors.insert( label.toLower(), color );
654  colorIndex++;
655  }
656  }
657 
658  QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) override
659  {
660  QString colorName = values.at( 0 ).toString().toLower();
661  if ( mColors.contains( colorName ) )
662  {
663  return QStringLiteral( "%1,%2,%3" ).arg( mColors.value( colorName ).red() ).arg( mColors.value( colorName ).green() ).arg( mColors.value( colorName ).blue() );
664  }
665  else
666  return QVariant();
667  }
668 
669  QgsScopedExpressionFunction *clone() const override
670  {
671  return new GetNamedProjectColor( mProject );
672  }
673 
674  private:
675 
676  const QgsProject *mProject = nullptr;
677  QHash< QString, QColor > mColors;
678 
679 };
680 
681 class GetLayoutItemVariables : public QgsScopedExpressionFunction
682 {
683  public:
684  GetLayoutItemVariables( const QgsLayout *c )
685  : QgsScopedExpressionFunction( QStringLiteral( "item_variables" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "id" ) ), QStringLiteral( "Layout" ) )
686  , mLayout( c )
687  {}
688 
689  QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) override
690  {
691  if ( !mLayout )
692  return QVariant();
693 
694  QString id = values.at( 0 ).toString();
695 
696  const QgsLayoutItem *item = mLayout->itemById( id );
697  if ( !item )
698  return QVariant();
699 
701 
702  return c.variablesToMap();
703  }
704 
705  QgsScopedExpressionFunction *clone() const override
706  {
707  return new GetLayoutItemVariables( mLayout );
708  }
709 
710  private:
711 
712  const QgsLayout *mLayout = nullptr;
713 
714 };
715 
716 class GetCurrentFormFieldValue : public QgsScopedExpressionFunction
717 {
718  public:
719  GetCurrentFormFieldValue( )
720  : QgsScopedExpressionFunction( QStringLiteral( "current_value" ), QgsExpressionFunction::ParameterList() << QStringLiteral( "field_name" ), QStringLiteral( "Form" ) )
721  {}
722 
723  QVariant func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * ) override
724  {
725  QString fieldName( values.at( 0 ).toString() );
726  const QgsFeature feat( context->variable( QStringLiteral( "current_feature" ) ).value<QgsFeature>() );
727  if ( fieldName.isEmpty() || ! feat.isValid( ) )
728  {
729  return QVariant();
730  }
731  return feat.attribute( fieldName ) ;
732  }
733 
734  QgsScopedExpressionFunction *clone() const override
735  {
736  return new GetCurrentFormFieldValue( );
737  }
738 
739 };
740 
741 
742 class GetProcessingParameterValue : public QgsScopedExpressionFunction
743 {
744  public:
745  GetProcessingParameterValue( const QVariantMap &params )
746  : QgsScopedExpressionFunction( QStringLiteral( "parameter" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "name" ) ), QStringLiteral( "Processing" ) )
747  , mParams( params )
748  {}
749 
750  QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) override
751  {
752  return mParams.value( values.at( 0 ).toString() );
753  }
754 
755  QgsScopedExpressionFunction *clone() const override
756  {
757  return new GetProcessingParameterValue( mParams );
758  }
759 
760  private:
761 
762  const QVariantMap mParams;
763 
764 };
765 
767 
768 
769 QgsExpressionContextScope *QgsExpressionContextUtils::formScope( const QgsFeature &formFeature, const QString &formMode )
770 {
771  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Form" ) );
772  scope->addFunction( QStringLiteral( "current_value" ), new GetCurrentFormFieldValue( ) );
773  scope->setVariable( QStringLiteral( "current_geometry" ), formFeature.geometry( ), true );
774  scope->setVariable( QStringLiteral( "current_feature" ), formFeature, true );
775  scope->setVariable( QStringLiteral( "form_mode" ), formMode, true );
776  return scope;
777 }
778 
780 {
781  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Project" ) );
782 
783  if ( !project )
784  return scope;
785 
786  const QVariantMap vars = project->customVariables();
787 
788  QVariantMap::const_iterator it = vars.constBegin();
789 
790  for ( ; it != vars.constEnd(); ++it )
791  {
792  scope->setVariable( it.key(), it.value(), true );
793  }
794 
795  QString projectPath = project->projectStorage() ? project->fileName() : project->absoluteFilePath();
796  QString projectFolder = QFileInfo( projectPath ).path();
797  QString projectFilename = QFileInfo( projectPath ).fileName();
798  QString projectBasename = project->baseName();
799 
800  //add other known project variables
801  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_title" ), project->title(), true, true ) );
802  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_path" ), QDir::toNativeSeparators( projectPath ), true, true ) );
803  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_folder" ), QDir::toNativeSeparators( projectFolder ), true, true ) );
804  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_filename" ), projectFilename, true, true ) );
805  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_basename" ), projectBasename, true, true ) );
806  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_home" ), QDir::toNativeSeparators( project->homePath() ), true, true ) );
807  QgsCoordinateReferenceSystem projectCrs = project->crs();
808  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs" ), projectCrs.authid(), true, true ) );
809  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_definition" ), projectCrs.toProj4(), true, true ) );
810 
811  // metadata
812  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_author" ), project->metadata().author(), true, true ) );
813  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_abstract" ), project->metadata().abstract(), true, true ) );
814  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_creation_date" ), project->metadata().creationDateTime(), true, true ) );
815  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_identifier" ), project->metadata().identifier(), true, true ) );
816 
817  // keywords
818  QVariantMap keywords;
819  QgsAbstractMetadataBase::KeywordMap metadataKeywords = project->metadata().keywords();
820  for ( auto it = metadataKeywords.constBegin(); it != metadataKeywords.constEnd(); ++it )
821  {
822  keywords.insert( it.key(), it.value() );
823  }
824  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_keywords" ), keywords, true, true ) );
825 
826  scope->addFunction( QStringLiteral( "project_color" ), new GetNamedProjectColor( project ) );
827  return scope;
828 }
829 
830 void QgsExpressionContextUtils::setProjectVariable( QgsProject *project, const QString &name, const QVariant &value )
831 {
832  if ( !project )
833  return;
834 
835  QVariantMap vars = project->customVariables();
836 
837  vars.insert( name, value );
838 
839  project->setCustomVariables( vars );
840 }
841 
842 void QgsExpressionContextUtils::setProjectVariables( QgsProject *project, const QVariantMap &variables )
843 {
844  if ( !project )
845  return;
846 
847  project->setCustomVariables( variables );
848 }
849 
851 {
852  if ( !project )
853  {
854  return;
855  }
856 
857  QVariantMap vars = project->customVariables();
858  if ( vars.remove( name ) )
859  project->setCustomVariables( vars );
860 }
861 
863 {
864  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layer" ) );
865 
866  if ( !layer )
867  return scope;
868 
869  //add variables defined in layer properties
870  QStringList variableNames = layer->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
871  QStringList variableValues = layer->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
872 
873  int varIndex = 0;
874  Q_FOREACH ( const QString &variableName, variableNames )
875  {
876  if ( varIndex >= variableValues.length() )
877  {
878  break;
879  }
880 
881  QVariant varValue = variableValues.at( varIndex );
882  varIndex++;
883  scope->setVariable( variableName, varValue, true );
884  }
885 
886  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_name" ), layer->name(), true, true ) );
887  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_id" ), layer->id(), true, true ) );
888  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer" ), QVariant::fromValue<QgsWeakMapLayerPointer >( QgsWeakMapLayerPointer( const_cast<QgsMapLayer *>( layer ) ) ), true, true ) );
889 
890  const QgsVectorLayer *vLayer = qobject_cast< const QgsVectorLayer * >( layer );
891  if ( vLayer )
892  {
893  scope->setFields( vLayer->fields() );
894  }
895 
896  //TODO - add functions. Possibilities include:
897  //is_selected
898  //field summary stats
899 
900  return scope;
901 }
902 
903 QList<QgsExpressionContextScope *> QgsExpressionContextUtils::globalProjectLayerScopes( const QgsMapLayer *layer )
904 {
905  QList<QgsExpressionContextScope *> scopes;
906  scopes << globalScope();
907 
908  QgsProject *project = QgsProject::instance(); // TODO: use project associated with layer
909  if ( project )
910  scopes << projectScope( project );
911 
912  if ( layer )
913  scopes << layerScope( layer );
914  return scopes;
915 }
916 
917 
918 void QgsExpressionContextUtils::setLayerVariable( QgsMapLayer *layer, const QString &name, const QVariant &value )
919 {
920  if ( !layer )
921  return;
922 
923  //write variable to layer
924  QStringList variableNames = layer->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
925  QStringList variableValues = layer->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
926 
927  variableNames << name;
928  variableValues << value.toString();
929 
930  layer->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
931  layer->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
932 }
933 
934 void QgsExpressionContextUtils::setLayerVariables( QgsMapLayer *layer, const QVariantMap &variables )
935 {
936  if ( !layer )
937  return;
938 
939  QStringList variableNames;
940  QStringList variableValues;
941 
942  QVariantMap::const_iterator it = variables.constBegin();
943  for ( ; it != variables.constEnd(); ++it )
944  {
945  variableNames << it.key();
946  variableValues << it.value().toString();
947  }
948 
949  layer->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
950  layer->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
951 }
952 
954 {
955  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
956  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
957 
958  // and because people don't read that ^^, I'm going to blast it all over this function
959 
960  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Map Settings" ) );
961 
962  //add known map settings context variables
963  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_id" ), "canvas", true ) );
964  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_rotation" ), mapSettings.rotation(), true ) );
965  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_scale" ), mapSettings.scale(), true ) );
966 
967  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
968  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
969 
970  QgsGeometry extent = QgsGeometry::fromRect( mapSettings.visibleExtent() );
971  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent" ), QVariant::fromValue( extent ), true ) );
972  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_width" ), mapSettings.visibleExtent().width(), true ) );
973  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_height" ), mapSettings.visibleExtent().height(), true ) );
974 
975  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
976  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
977 
978  QgsGeometry centerPoint = QgsGeometry::fromPointXY( mapSettings.visibleExtent().center() );
979  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_center" ), QVariant::fromValue( centerPoint ), true ) );
980 
981  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
982  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
983 
984  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs" ), mapSettings.destinationCrs().authid(), true ) );
985  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_definition" ), mapSettings.destinationCrs().toProj4(), true ) );
986  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_units" ), QgsUnitTypes::toString( mapSettings.mapUnits() ), true ) );
987 
988  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
989  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
990 
991  QVariantList layersIds;
992  QVariantList layers;
993  const QList<QgsMapLayer *> layersInMap = mapSettings.layers();
994  layersIds.reserve( layersInMap.count() );
995  layers.reserve( layersInMap.count() );
996  for ( QgsMapLayer *layer : layersInMap )
997  {
998  layersIds << layer->id();
999  layers << QVariant::fromValue<QgsWeakMapLayerPointer>( QgsWeakMapLayerPointer( layer ) );
1000  }
1001 
1002  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
1003  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
1004 
1005  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_layer_ids" ), layersIds, true ) );
1006  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_layers" ), layers, true ) );
1007 
1008  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
1009  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
1010 
1011  scope->addFunction( QStringLiteral( "is_layer_visible" ), new GetLayerVisibility( mapSettings.layers() ) );
1012 
1013  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
1014  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
1015 
1016  return scope;
1017 }
1018 
1019 QgsExpressionContextScope *QgsExpressionContextUtils::mapToolCaptureScope( const QList<QgsPointLocator::Match> &matches )
1020 {
1021  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Map Tool Capture" ) );
1022 
1023  QVariantList matchList;
1024 
1025  for ( const QgsPointLocator::Match &match : matches )
1026  {
1027  QVariantMap matchMap;
1028 
1029  matchMap.insert( QStringLiteral( "valid" ), match.isValid() );
1030  matchMap.insert( QStringLiteral( "layer" ), QVariant::fromValue<QgsWeakMapLayerPointer>( QgsWeakMapLayerPointer( match.layer() ) ) );
1031  matchMap.insert( QStringLiteral( "feature_id" ), match.featureId() );
1032  matchMap.insert( QStringLiteral( "vertex_index" ), match.vertexIndex() );
1033  matchMap.insert( QStringLiteral( "distance" ), match.distance() );
1034 
1035  matchList.append( matchMap );
1036  }
1037 
1038  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "snapping_results" ), matchList ) );
1039 
1040  return scope;
1041 }
1042 
1044 {
1045  if ( !symbolScope )
1046  return nullptr;
1047 
1048  symbolScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_SYMBOL_COLOR, symbol ? symbol->color() : QColor(), true ) );
1049 
1050  double angle = 0.0;
1051  const QgsMarkerSymbol *markerSymbol = dynamic_cast< const QgsMarkerSymbol * >( symbol );
1052  if ( markerSymbol )
1053  {
1054  angle = markerSymbol->angle();
1055  }
1057 
1058  return symbolScope;
1059 }
1060 
1062 {
1063  std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope( QObject::tr( "Layout" ) ) );
1064  if ( !layout )
1065  return scope.release();
1066 
1067  //add variables defined in layout properties
1068  QStringList variableNames = layout->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
1069  QStringList variableValues = layout->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
1070 
1071  int varIndex = 0;
1072  Q_FOREACH ( const QString &variableName, variableNames )
1073  {
1074  if ( varIndex >= variableValues.length() )
1075  {
1076  break;
1077  }
1078 
1079  QVariant varValue = variableValues.at( varIndex );
1080  varIndex++;
1081  scope->setVariable( variableName, varValue );
1082  }
1083 
1084  //add known layout context variables
1085  if ( const QgsMasterLayoutInterface *l = dynamic_cast< const QgsMasterLayoutInterface * >( layout ) )
1086  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_name" ), l->name(), true ) );
1087 
1088  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_numpages" ), layout->pageCollection()->pageCount(), true ) );
1089  if ( layout->pageCollection()->pageCount() > 0 )
1090  {
1091  // just take first page size
1092  QSizeF s = layout->pageCollection()->page( 0 )->sizeWithUnits().toQSizeF();
1093  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), s.height(), true ) );
1094  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), s.width(), true ) );
1095  }
1096  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_dpi" ), layout->renderContext().dpi(), true ) );
1097 
1098  scope->addFunction( QStringLiteral( "item_variables" ), new GetLayoutItemVariables( layout ) );
1099 
1100  if ( layout->reportContext().layer() )
1101  {
1102  scope->setFields( layout->reportContext().layer()->fields() );
1103  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layerid" ), layout->reportContext().layer()->id(), true ) );
1104  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layername" ), layout->reportContext().layer()->name(), true ) );
1105  }
1106 
1107  if ( layout->reportContext().feature().isValid() )
1108  {
1109  QgsFeature atlasFeature = layout->reportContext().feature();
1110  scope->setFeature( atlasFeature );
1111  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( atlasFeature ), true ) );
1112  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), atlasFeature.id(), true ) );
1113  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( atlasFeature.geometry() ), true ) );
1114  }
1115 
1116  return scope.release();
1117 }
1118 
1119 void QgsExpressionContextUtils::setLayoutVariable( QgsLayout *layout, const QString &name, const QVariant &value )
1120 {
1121  if ( !layout )
1122  return;
1123 
1124  //write variable to layout
1125  QStringList variableNames = layout->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
1126  QStringList variableValues = layout->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
1127 
1128  variableNames << name;
1129  variableValues << value.toString();
1130 
1131  layout->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
1132  layout->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
1133 }
1134 
1135 void QgsExpressionContextUtils::setLayoutVariables( QgsLayout *layout, const QVariantMap &variables )
1136 {
1137  if ( !layout )
1138  return;
1139 
1140  QStringList variableNames;
1141  QStringList variableValues;
1142 
1143  QVariantMap::const_iterator it = variables.constBegin();
1144  for ( ; it != variables.constEnd(); ++it )
1145  {
1146  variableNames << it.key();
1147  variableValues << it.value().toString();
1148  }
1149 
1150  layout->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
1151  layout->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
1152 }
1153 
1155 {
1156  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Atlas" ) );
1157  if ( !atlas )
1158  {
1159  //add some dummy atlas variables. This is done so that as in certain contexts we want to show
1160  //users that these variables are available even if they have no current value
1161  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_pagename" ), QString(), true ) );
1162  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( QgsFeature() ), true ) );
1163  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), 0, true ) );
1164  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( QgsGeometry() ), true ) );
1165  return scope;
1166  }
1167 
1168  //add known atlas variables
1169  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_totalfeatures" ), atlas->count(), true ) );
1170  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featurenumber" ), atlas->currentFeatureNumber() + 1, true ) );
1171  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_filename" ), atlas->currentFilename(), true ) );
1172  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_pagename" ), atlas->nameForPage( atlas->currentFeatureNumber() ), true ) );
1173 
1174  if ( atlas->enabled() && atlas->coverageLayer() )
1175  {
1176  scope->setFields( atlas->coverageLayer()->fields() );
1177  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layerid" ), atlas->coverageLayer()->id(), true ) );
1178  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layername" ), atlas->coverageLayer()->name(), true ) );
1179  }
1180 
1181  if ( atlas->enabled() )
1182  {
1183  QgsFeature atlasFeature = atlas->layout()->reportContext().feature();
1184  scope->setFeature( atlasFeature );
1185  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( atlasFeature ), true ) );
1186  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), atlasFeature.id(), true ) );
1187  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( atlasFeature.geometry() ), true ) );
1188  }
1189 
1190  return scope;
1191 }
1192 
1194 {
1195  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layout Item" ) );
1196  if ( !item )
1197  return scope;
1198 
1199  //add variables defined in layout item properties
1200  const QStringList variableNames = item->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
1201  const QStringList variableValues = item->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
1202 
1203  int varIndex = 0;
1204  for ( const QString &variableName : variableNames )
1205  {
1206  if ( varIndex >= variableValues.length() )
1207  {
1208  break;
1209  }
1210 
1211  QVariant varValue = variableValues.at( varIndex );
1212  varIndex++;
1213  scope->setVariable( variableName, varValue );
1214  }
1215 
1216  //add known layout item context variables
1217  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "item_id" ), item->id(), true ) );
1218  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "item_uuid" ), item->uuid(), true ) );
1219  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_page" ), item->page() + 1, true ) );
1220 
1221  if ( item->layout() )
1222  {
1223  const QgsLayoutItemPage *page = item->layout()->pageCollection()->page( item->page() );
1224  if ( page )
1225  {
1226  const QSizeF s = page->sizeWithUnits().toQSizeF();
1227  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), s.height(), true ) );
1228  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), s.width(), true ) );
1229  }
1230  else
1231  {
1232  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), QVariant(), true ) );
1233  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), QVariant(), true ) );
1234  }
1235  }
1236 
1237  return scope;
1238 }
1239 
1240 void QgsExpressionContextUtils::setLayoutItemVariable( QgsLayoutItem *item, const QString &name, const QVariant &value )
1241 {
1242  if ( !item )
1243  return;
1244 
1245  //write variable to layout item
1246  QStringList variableNames = item->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
1247  QStringList variableValues = item->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
1248 
1249  variableNames << name;
1250  variableValues << value.toString();
1251 
1252  item->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
1253  item->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
1254 }
1255 
1256 void QgsExpressionContextUtils::setLayoutItemVariables( QgsLayoutItem *item, const QVariantMap &variables )
1257 {
1258  if ( !item )
1259  return;
1260 
1261  QStringList variableNames;
1262  QStringList variableValues;
1263 
1264  QVariantMap::const_iterator it = variables.constBegin();
1265  for ( ; it != variables.constEnd(); ++it )
1266  {
1267  variableNames << it.key();
1268  variableValues << it.value().toString();
1269  }
1270 
1271  item->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
1272  item->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
1273 }
1274 
1276 {
1278  scope->setFeature( feature );
1279  scope->setFields( fields );
1280  return QgsExpressionContext() << scope;
1281 }
1282 
1284 {
1285  // set aside for future use
1286  Q_UNUSED( context );
1287 
1288  std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope( QObject::tr( "Algorithm" ) ) );
1289  scope->addFunction( QStringLiteral( "parameter" ), new GetProcessingParameterValue( parameters ) );
1290 
1291  if ( !algorithm )
1292  return scope.release();
1293 
1294  //add standard algorithm variables
1295  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "algorithm_id" ), algorithm->id(), true ) );
1296 
1297  return scope.release();
1298 }
1299 
1301 {
1302  std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope() );
1303  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "notification_message" ), message, true ) );
1304  return scope.release();
1305 }
1306 
1308 {
1309  QgsExpression::registerFunction( new GetNamedProjectColor( nullptr ) );
1310  QgsExpression::registerFunction( new GetLayoutItemVariables( nullptr ) );
1311  QgsExpression::registerFunction( new GetLayerVisibility( QList<QgsMapLayer *>() ) );
1312  QgsExpression::registerFunction( new GetProcessingParameterValue( QVariantMap() ) );
1313  QgsExpression::registerFunction( new GetCurrentFormFieldValue( ) );
1314 }
1315 
1317 {
1318  Q_UNUSED( node )
1319  return mUsesGeometry;
1320 }
1321 
1323 {
1324  Q_UNUSED( node )
1325  return mReferencedColumns;
1326 }
1327 
1329 {
1330  return allParamsStatic( node, parent, context );
1331 }
1332 
1333 //
1334 // GetLayerVisibility
1335 //
1336 
1337 QgsExpressionContextUtils::GetLayerVisibility::GetLayerVisibility( const QList<QgsMapLayer *> &layers )
1338  : QgsScopedExpressionFunction( QStringLiteral( "is_layer_visible" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "id" ) ), QStringLiteral( "General" ) )
1339  , mLayers( _qgis_listRawToQPointer( layers ) )
1340 {}
1341 
1342 QVariant QgsExpressionContextUtils::GetLayerVisibility::func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1343 {
1344  if ( mLayers.isEmpty() )
1345  {
1346  return false;
1347  }
1348 
1349  QgsMapLayer *layer = QgsExpressionUtils::getMapLayer( values.at( 0 ), parent );
1350  if ( layer )
1351  {
1352  return mLayers.contains( layer );
1353  }
1354  else
1355  {
1356  return false;
1357  }
1358 }
1359 
1360 QgsScopedExpressionFunction *QgsExpressionContextUtils::GetLayerVisibility::clone() const
1361 {
1362  return new GetLayerVisibility( _qgis_listQPointerToRaw( mLayers ) );
1363 }
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:183
bool hasVariable(const QString &name) const
Tests whether a variable with the specified name exists in the scope.
static const QString EXPR_ORIGINAL_VALUE
Inbuilt variable name for value original value variable.
Class for parsing and evaluation of expressions (formerly called "search strings").
static QString locale()
Returns the QGIS locale.
QgsFeatureId id
Definition: qgsfeature.h:64
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbol to an expression context.
QVariant cachedValue(const QString &key) const
Returns the matching cached value, if set.
QString description(const QString &name) const
Returns the translated description for the variable with the specified name (if set).
static QgsExpressionContextScope * processingAlgorithmScope(const QgsProcessingAlgorithm *algorithm, const QVariantMap &parameters, QgsProcessingContext &context)
Creates a new scope which contains variables and functions relating to a processing algorithm...
static const QString EXPR_CLUSTER_COLOR
Inbuilt variable name for cluster color variable.
static void setLayoutItemVariable(QgsLayoutItem *item, const QString &name, const QVariant &value)
Sets a layout item context variable, with the given name and value.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Single variable definition for use within a QgsExpressionContextScope.
static void setGlobalVariable(const QString &name, const QVariant &value)
Sets a global context variable.
Base class for all map layer types.
Definition: qgsmaplayer.h:63
void setCachedValue(const QString &key, const QVariant &value) const
Sets a value to cache within the expression context.
bool isHighlightedFunction(const QString &name) const
Returns true if the specified function name is intended to be highlighted to the user.
static void setLayoutItemVariables(QgsLayoutItem *item, const QVariantMap &variables)
Sets all layout item context variables for an item.
static const QString QGIS_VERSION
Version string.
Definition: qgis.h:64
QgsExpressionContextScope * scope(int index)
Returns the scope at the specified index within the context.
static void setLayerVariables(QgsMapLayer *layer, const QVariantMap &variables)
Sets all layer context variables.
QString id() const
Returns the unique ID for the algorithm, which is a combination of the algorithm provider&#39;s ID and th...
QgsAbstractMetadataBase::KeywordMap keywords() const
Returns the keywords map, which is a set of descriptive keywords associated with the resource...
bool isReadOnly(const QString &name) const
Returns whether a variable is read only, and should not be modifiable by users.
Base class for graphical items within a QgsLayout.
static const QString EXPR_GEOMETRY_POINT_COUNT
Inbuilt variable name for point count variable.
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
static void setLayoutVariable(QgsLayout *layout, const QString &name, const QVariant &value)
Sets a layout context variable.
QStringList filteredVariableNames() const
Returns a filtered list of variables names set by all scopes in the context.
static void setCustomVariables(const QVariantMap &customVariables)
Custom expression variables for this application.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:61
QgsExpressionContext & operator=(const QgsExpressionContext &other)
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
bool hasFunction(const QString &name) const
Checks whether a specified function is contained in the context.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from the layout.
Definition: qgslayout.cpp:412
void addFunction(const QString &name, QgsScopedExpressionFunction *function)
Adds a function to the scope.
QgsExpressionContextScope(const QString &name=QString())
Constructor for QgsExpressionContextScope.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
static void removeProjectVariable(QgsProject *project, const QString &name)
Remove project context variable.
QgsExpressionContextScope * activeScopeForVariable(const QString &name)
Returns the currently active scope from the context for a specified variable name.
static QgsExpressionContext createFeatureBasedContext(const QgsFeature &feature, const QgsFields &fields)
Helper function for creating an expression context which contains just a feature and fields collectio...
QStringList variableNames() const
Returns a list of variable names contained within the scope.
bool hasCachedValue(const QString &key) const
Returns true if the expression context contains a cached value with a matching key.
QgsLayoutSize sizeWithUnits() const
Returns the item&#39;s current size, including units.
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for the object.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from the object.
QString toProj4() const
Returns a Proj4 string representation of this CRS.
bool isReadOnly(const QString &name) const
Tests whether the specified variable is read only and should not be editable by users.
QString author() const
Returns the project author string.
Container of fields for a vector layer.
Definition: qgsfields.h:42
bool hasVariable(const QString &name) const
Check whether a variable is specified by any scope within the context.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
static QVariantMap customVariables()
Custom expression variables for this application.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the scope.
QgsFields fields() const
Convenience function for retrieving the fields for the context, if set.
static QgsExpressionContextScope * mapToolCaptureScope(const QList< QgsPointLocator::Match > &matches)
Sets the expression context variables which are available for expressions triggered by a map tool cap...
static QString variableHelpText(const QString &variableName)
Returns the help text for a specified variable.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
QList< QgsMapLayer * > layers() const
Gets list of layers for map rendering The layers are stored in the reverse order of how they are rend...
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
QgsExpressionContextScope & operator=(const QgsExpressionContextScope &other)
QList< QgsExpressionContextScope * > takeScopes()
Returns all scopes from this context and remove them, leaving this context without any context...
static QgsExpressionContextScope * formScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current attribute form/table feat...
bool usesGeometry(const QgsExpressionNodeFunction *node) const override
Does this function use a geometry object.
static void setLayoutVariables(QgsLayout *layout, const QVariantMap &variables)
Sets all layout context variables.
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.
Definition: qgsmaplayer.h:1482
static const int QGIS_VERSION_INT
Version number used for comparing versions using the "Check QGIS Version" function.
Definition: qgis.h:66
Abstract base class for processing algorithms.
QList< QgsExpressionFunction::Parameter > ParameterList
List of parameters, used for function definition.
QgsLayoutRenderContext & renderContext()
Returns a reference to the layout&#39;s render context, which stores information relating to the current ...
Definition: qgslayout.cpp:356
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes takes output image size into accou...
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
QgsExpressionContext & operator<<(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
static QString userFullName()
Returns the user&#39;s operating system login account full display name.
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
QString description(const QString &name) const
Returns a translated description string for the variable with specified name.
bool hasFeature() const
Returns true if the context has a feature associated with it.
QgsUnitTypes::DistanceUnit mapUnits() const
Gets units of map&#39;s geographical coordinates - used for scale calculation.
QgsLayout * layout() override
Returns the layout associated with the iterator.
void setHighlightedFunctions(const QStringList &names)
Sets the list of function names intended to be highlighted to the user.
The QgsMapSettings class contains configuration for rendering of the map.
void setVariable(const QString &name, const QVariant &value, bool isStatic=false)
Convenience method for setting a variable in the context scope by name name and value.
QString homePath
Definition: qgsproject.h:94
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QSizeF toQSizeF() const
Converts the layout size to a QSizeF.
static QgsExpressionContextScope * layoutItemScope(const QgsLayoutItem *item)
Creates a new scope which contains variables and functions relating to a QgsLayoutItem.
bool isStatic(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const override
Will be called during prepare to determine if the function is static.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
bool removeVariable(const QString &name)
Removes a variable from the context scope, if found.
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
QgsVectorLayer * layer() const
Returns the vector layer associated with the layout&#39;s context.
bool hasFunction(const QString &name) const
Tests whether a function with the specified name exists in the scope.
static const QString EXPR_SYMBOL_ANGLE
Inbuilt variable name for symbol angle variable.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
const QgsLayout * layout() const
Returns the layout the object is attached to.
QgsLayoutItemPage * page(int pageNumber)
Returns a specific page (by pageNumber) from the collection.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
int scopeCount() const
Returns the number of scopes contained in the context.
bool isHighlightedVariable(const QString &name) const
Returns true if the specified variable name is intended to be highlighted to the user.
QgsLayoutPageCollection * pageCollection()
Returns a pointer to the layout&#39;s page collection, which stores and manages page items in the layout...
Definition: qgslayout.cpp:456
static void setProjectVariables(QgsProject *project, const QVariantMap &variables)
Sets all project context variables.
QgsProjectMetadata metadata
Definition: qgsproject.h:102
double scale() const
Returns the calculated map scale.
double dpi() const
Returns the dpi for outputting the layout.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:201
static QgsExpressionContextScope * notificationScope(const QString &message=QString())
Creates a new scope which contains variables and functions relating to provider notifications.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static void removeGlobalVariable(const QString &name)
Remove a global context variable.
QgsCoordinateReferenceSystem crs
Definition: qgsproject.h:95
QVariantMap variablesToMap() const
Returns a map of variable name to value representing all the expression variables contained by the co...
Class used to render QgsLayout as an atlas, by iterating over the features from an associated vector ...
QVariant variable(const QString &name) const
Retrieves a variable&#39;s value from the scope.
static const QString EXPR_SYMBOL_COLOR
Inbuilt variable name for symbol color variable.
QDateTime creationDateTime() const
Returns the project&#39;s creation date/timestamp.
static bool registerFunction(QgsExpressionFunction *function, bool transferOwnership=false)
Registers a function to the expression engine.
QStringList readListEntry(const QString &scope, const QString &key, const QStringList &def=QStringList(), bool *ok=nullptr) const
Key value accessors.
Reads and writes project states.
Definition: qgsproject.h:89
static void setCustomVariable(const QString &name, const QVariant &value)
Set a single custom expression variable.
QColor color() const
Returns the symbol&#39;s color.
Definition: qgssymbol.cpp:459
QString currentFilename() const
Returns the current feature filename.
int page() const
Returns the page the item is currently on, with the first page returning 0.
QString id() const
Returns the item&#39;s ID name.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
QgsExpressionFunction * function(const QString &name) const
Retrieves a function from the scope.
static const QString EXPR_FIELDS
Inbuilt variable name for fields storage.
QStringList variableNames() const
Returns a list of variables names set by all scopes in the context.
int count() override
Returns the number of features to iterate over.
Single scope for storing variables and functions for use within a QgsExpressionContext.
An expression node for expression functions.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the scope.
QStringList functionNames() const
Retrieves a list of names of functions contained in the scope.
void setCustomVariables(const QVariantMap &customVariables)
A map of custom project variables.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:49
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
QgsProjectStorage * projectStorage() const
Returns pointer to project storage implementation that handles read/write of the project file...
Definition: qgsproject.cpp:562
QString abstract() const
Returns a free-form description of the resource.
static void setLayerVariable(QgsMapLayer *layer, const QString &name, const QVariant &value)
Sets a layer context variable.
static QString userLoginName()
Returns the user&#39;s operating system login account name.
static QString osName()
Returns a string name of the operating system QGIS is running on.
int pageCount() const
Returns the number of pages in the collection.
int currentFeatureNumber() const
Returns the current feature number, where a value of 0 corresponds to the first feature.
QgsLayoutReportContext & reportContext()
Returns a reference to the layout&#39;s report context, which stores information relating to the current ...
Definition: qgslayout.cpp:366
static void setProjectVariable(QgsProject *project, const QString &name, const QVariant &value)
Sets a project context variable.
A abstract base class for defining QgsExpression functions.
static void registerContextFunctions()
Registers all known core functions provided by QgsExpressionContextScope objects. ...
static QgsExpressionContextScope * atlasScope(QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object...
QStringList functionNames() const
Retrieves a list of function names contained in the context.
static const QString QGIS_RELEASE_NAME
Release name.
Definition: qgis.h:68
QgsExpressionContext()=default
Constructor for QgsExpressionContext.
static QgsExpressionContextScope * layoutScope(const QgsLayout *layout)
Creates a new scope which contains variables and functions relating to a QgsLayout layout...
void clearCachedValues() const
Clears all cached values from the context.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
QMap< QString, QStringList > KeywordMap
Map of vocabulary string to keyword list.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:411
virtual QString uuid() const
Returns the item identification string.
This class represents a coordinate reference system (CRS).
bool isStatic(const QString &name) const
Tests whether the variable with the specified name is static and can be cached.
QString nameForPage(int page) const
Returns the calculated name for a specified atlas page number.
static QString platform()
Returns the QGIS platform name, e.g., "desktop" or "server".
static const QString EXPR_CLUSTER_SIZE
Inbuilt variable name for cluster size variable.
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for the layout.
Definition: qgslayout.cpp:404
bool enabled() const
Returns whether the atlas generation is enabled.
bool hasFeature() const
Returns true if the scope has a feature associated with it.
QgsFeature feature() const
Convenience function for retrieving the feature for the context, if set.
static const QString EXPR_GEOMETRY_POINT_NUM
Inbuilt variable name for point number variable.
QgsVectorLayer * coverageLayer() const
Returns the coverage layer used for the atlas features.
QgsFeature feature() const
Returns the current feature for evaluating the layout.
void setHighlightedVariables(const QStringList &variableNames)
Sets the list of variable names within the context intended to be highlighted to the user...
QString name
Definition: qgsmaplayer.h:67
Represents a single parameter passed to a function.
void appendScopes(const QList< QgsExpressionContextScope *> &scopes)
Appends a list of scopes to the end of the context.
QgsGeometry geometry
Definition: qgsfeature.h:67
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QString title() const
Returns the project&#39;s title.
Definition: qgsproject.cpp:431
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:229
QVariantMap customVariables() const
A map of custom project variables.
QString name() const
Returns the friendly display name of the context scope.
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
QString baseName() const
Returns the base name of the project file without the path and without extension - derived from fileN...
Definition: qgsproject.cpp:603
Interface for master layout type objects, such as print layouts and reports.
static const QString EXPR_GEOMETRY_PART_NUM
Inbuilt variable name for geometry part number variable.
QString absoluteFilePath() const
Returns full absolute path to the project file if the project is stored in a file system - derived fr...
Definition: qgsproject.cpp:592
bool isStatic
A static variable can be cached for the lifetime of a context.
Represents a vector layer which manages a vector based data sets.
int indexOfScope(QgsExpressionContextScope *scope) const
Returns the index of the specified scope if it exists within the context.
static const QString EXPR_GEOMETRY_PART_COUNT
Inbuilt variable name for geometry part count variable.
Contains information about the context in which a processing algorithm is executed.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
QStringList filteredVariableNames() const
Returns a filtered and sorted list of variable names contained within the scope.
QList< QgsExpressionContextScope *> scopes()
Returns a list of scopes contained within the stack.
QString fileName
Definition: qgsproject.h:93
static void setGlobalVariables(const QVariantMap &variables)
Sets all global context variables.
QgsExpressionFunction * function(const QString &name) const
Fetches a matching function from the context.
Expression function for use within a QgsExpressionContextScope.
double angle() const
Returns the marker angle for the whole symbol.
Definition: qgssymbol.cpp:1188
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
QString authid() const
Returns the authority identifier for the CRS.
QString identifier() const
A reference, URI, URL or some other mechanism to identify the resource.
QSet< QString > referencedColumns(const QgsExpressionNodeFunction *node) const override
Returns a set of field names which are required for this function.
static QColor decodeColor(const QString &str)
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:208
Item representing the paper in a layout.