QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_ellipsoid" ), project->ellipsoid(), true, true ) );
811  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_distance_units" ), QgsUnitTypes::toString( project->distanceUnits() ), true, true ) );
812  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_area_units" ), QgsUnitTypes::toString( project->areaUnits() ), true, true ) );
813  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "_project_transform_context" ), QVariant::fromValue<QgsCoordinateTransformContext>( project->transformContext() ), true, true ) );
814 
815  // metadata
816  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_author" ), project->metadata().author(), true, true ) );
817  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_abstract" ), project->metadata().abstract(), true, true ) );
818  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_creation_date" ), project->metadata().creationDateTime(), true, true ) );
819  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_identifier" ), project->metadata().identifier(), true, true ) );
820 
821  // keywords
822  QVariantMap keywords;
823  QgsAbstractMetadataBase::KeywordMap metadataKeywords = project->metadata().keywords();
824  for ( auto it = metadataKeywords.constBegin(); it != metadataKeywords.constEnd(); ++it )
825  {
826  keywords.insert( it.key(), it.value() );
827  }
828  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_keywords" ), keywords, true, true ) );
829 
830  scope->addFunction( QStringLiteral( "project_color" ), new GetNamedProjectColor( project ) );
831  return scope;
832 }
833 
834 void QgsExpressionContextUtils::setProjectVariable( QgsProject *project, const QString &name, const QVariant &value )
835 {
836  if ( !project )
837  return;
838 
839  QVariantMap vars = project->customVariables();
840 
841  vars.insert( name, value );
842 
843  project->setCustomVariables( vars );
844 }
845 
846 void QgsExpressionContextUtils::setProjectVariables( QgsProject *project, const QVariantMap &variables )
847 {
848  if ( !project )
849  return;
850 
851  project->setCustomVariables( variables );
852 }
853 
855 {
856  if ( !project )
857  {
858  return;
859  }
860 
861  QVariantMap vars = project->customVariables();
862  if ( vars.remove( name ) )
863  project->setCustomVariables( vars );
864 }
865 
867 {
868  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layer" ) );
869 
870  if ( !layer )
871  return scope;
872 
873  //add variables defined in layer properties
874  QStringList variableNames = layer->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
875  QStringList variableValues = layer->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
876 
877  int varIndex = 0;
878  Q_FOREACH ( const QString &variableName, variableNames )
879  {
880  if ( varIndex >= variableValues.length() )
881  {
882  break;
883  }
884 
885  QVariant varValue = variableValues.at( varIndex );
886  varIndex++;
887  scope->setVariable( variableName, varValue, true );
888  }
889 
890  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_name" ), layer->name(), true, true ) );
891  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_id" ), layer->id(), true, true ) );
892  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "_layer_crs" ), QVariant::fromValue<QgsCoordinateReferenceSystem>( layer->crs() ), true, true ) );
893  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer" ), QVariant::fromValue<QgsWeakMapLayerPointer >( QgsWeakMapLayerPointer( const_cast<QgsMapLayer *>( layer ) ) ), true, true ) );
894 
895  const QgsVectorLayer *vLayer = qobject_cast< const QgsVectorLayer * >( layer );
896  if ( vLayer )
897  {
898  scope->setFields( vLayer->fields() );
899  }
900 
901  //TODO - add functions. Possibilities include:
902  //is_selected
903  //field summary stats
904 
905  return scope;
906 }
907 
908 QList<QgsExpressionContextScope *> QgsExpressionContextUtils::globalProjectLayerScopes( const QgsMapLayer *layer )
909 {
910  QList<QgsExpressionContextScope *> scopes;
911  scopes << globalScope();
912 
913  QgsProject *project = QgsProject::instance(); // TODO: use project associated with layer
914  if ( project )
915  scopes << projectScope( project );
916 
917  if ( layer )
918  scopes << layerScope( layer );
919  return scopes;
920 }
921 
922 
923 void QgsExpressionContextUtils::setLayerVariable( QgsMapLayer *layer, const QString &name, const QVariant &value )
924 {
925  if ( !layer )
926  return;
927 
928  //write variable to layer
929  QStringList variableNames = layer->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
930  QStringList variableValues = layer->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
931 
932  variableNames << name;
933  variableValues << value.toString();
934 
935  layer->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
936  layer->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
937 }
938 
939 void QgsExpressionContextUtils::setLayerVariables( QgsMapLayer *layer, const QVariantMap &variables )
940 {
941  if ( !layer )
942  return;
943 
944  QStringList variableNames;
945  QStringList variableValues;
946 
947  QVariantMap::const_iterator it = variables.constBegin();
948  for ( ; it != variables.constEnd(); ++it )
949  {
950  variableNames << it.key();
951  variableValues << it.value().toString();
952  }
953 
954  layer->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
955  layer->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
956 }
957 
959 {
960  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
961  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
962 
963  // and because people don't read that ^^, I'm going to blast it all over this function
964 
965  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Map Settings" ) );
966 
967  //add known map settings context variables
968  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_id" ), "canvas", true ) );
969  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_rotation" ), mapSettings.rotation(), true ) );
970  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_scale" ), mapSettings.scale(), true ) );
971 
972  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
973  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
974 
975  QgsGeometry extent = QgsGeometry::fromRect( mapSettings.visibleExtent() );
976  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent" ), QVariant::fromValue( extent ), true ) );
977  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_width" ), mapSettings.visibleExtent().width(), true ) );
978  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_height" ), mapSettings.visibleExtent().height(), true ) );
979 
980  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
981  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
982 
983  QgsGeometry centerPoint = QgsGeometry::fromPointXY( mapSettings.visibleExtent().center() );
984  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_center" ), QVariant::fromValue( centerPoint ), true ) );
985 
986  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
987  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
988 
989  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs" ), mapSettings.destinationCrs().authid(), true ) );
990  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_definition" ), mapSettings.destinationCrs().toProj4(), true ) );
991  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_units" ), QgsUnitTypes::toString( mapSettings.mapUnits() ), true ) );
992 
993  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
994  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
995 
996  QVariantList layersIds;
997  QVariantList layers;
998  const QList<QgsMapLayer *> layersInMap = mapSettings.layers();
999  layersIds.reserve( layersInMap.count() );
1000  layers.reserve( layersInMap.count() );
1001  for ( QgsMapLayer *layer : layersInMap )
1002  {
1003  layersIds << layer->id();
1004  layers << QVariant::fromValue<QgsWeakMapLayerPointer>( QgsWeakMapLayerPointer( layer ) );
1005  }
1006 
1007  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
1008  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
1009 
1010  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_layer_ids" ), layersIds, true ) );
1011  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_layers" ), layers, true ) );
1012 
1013  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
1014  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
1015 
1016  scope->addFunction( QStringLiteral( "is_layer_visible" ), new GetLayerVisibility( mapSettings.layers() ) );
1017 
1018  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
1019  // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
1020 
1021  return scope;
1022 }
1023 
1024 QgsExpressionContextScope *QgsExpressionContextUtils::mapToolCaptureScope( const QList<QgsPointLocator::Match> &matches )
1025 {
1026  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Map Tool Capture" ) );
1027 
1028  QVariantList matchList;
1029 
1030  for ( const QgsPointLocator::Match &match : matches )
1031  {
1032  QVariantMap matchMap;
1033 
1034  matchMap.insert( QStringLiteral( "valid" ), match.isValid() );
1035  matchMap.insert( QStringLiteral( "layer" ), QVariant::fromValue<QgsWeakMapLayerPointer>( QgsWeakMapLayerPointer( match.layer() ) ) );
1036  matchMap.insert( QStringLiteral( "feature_id" ), match.featureId() );
1037  matchMap.insert( QStringLiteral( "vertex_index" ), match.vertexIndex() );
1038  matchMap.insert( QStringLiteral( "distance" ), match.distance() );
1039 
1040  matchList.append( matchMap );
1041  }
1042 
1043  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "snapping_results" ), matchList ) );
1044 
1045  return scope;
1046 }
1047 
1049 {
1050  if ( !symbolScope )
1051  return nullptr;
1052 
1053  symbolScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_SYMBOL_COLOR, symbol ? symbol->color() : QColor(), true ) );
1054 
1055  double angle = 0.0;
1056  const QgsMarkerSymbol *markerSymbol = dynamic_cast< const QgsMarkerSymbol * >( symbol );
1057  if ( markerSymbol )
1058  {
1059  angle = markerSymbol->angle();
1060  }
1062 
1063  return symbolScope;
1064 }
1065 
1067 {
1068  std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope( QObject::tr( "Layout" ) ) );
1069  if ( !layout )
1070  return scope.release();
1071 
1072  //add variables defined in layout properties
1073  QStringList variableNames = layout->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
1074  QStringList variableValues = layout->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
1075 
1076  int varIndex = 0;
1077  Q_FOREACH ( const QString &variableName, variableNames )
1078  {
1079  if ( varIndex >= variableValues.length() )
1080  {
1081  break;
1082  }
1083 
1084  QVariant varValue = variableValues.at( varIndex );
1085  varIndex++;
1086  scope->setVariable( variableName, varValue );
1087  }
1088 
1089  //add known layout context variables
1090  if ( const QgsMasterLayoutInterface *l = dynamic_cast< const QgsMasterLayoutInterface * >( layout ) )
1091  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_name" ), l->name(), true ) );
1092 
1093  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_numpages" ), layout->pageCollection()->pageCount(), true ) );
1094  if ( layout->pageCollection()->pageCount() > 0 )
1095  {
1096  // just take first page size
1097  QSizeF s = layout->pageCollection()->page( 0 )->sizeWithUnits().toQSizeF();
1098  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), s.height(), true ) );
1099  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), s.width(), true ) );
1100  }
1101  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_dpi" ), layout->renderContext().dpi(), true ) );
1102 
1103  scope->addFunction( QStringLiteral( "item_variables" ), new GetLayoutItemVariables( layout ) );
1104 
1105  if ( layout->reportContext().layer() )
1106  {
1107  scope->setFields( layout->reportContext().layer()->fields() );
1108  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layerid" ), layout->reportContext().layer()->id(), true ) );
1109  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layername" ), layout->reportContext().layer()->name(), true ) );
1110  }
1111 
1112  if ( layout->reportContext().feature().isValid() )
1113  {
1114  QgsFeature atlasFeature = layout->reportContext().feature();
1115  scope->setFeature( atlasFeature );
1116  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( atlasFeature ), true ) );
1117  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), atlasFeature.id(), true ) );
1118  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( atlasFeature.geometry() ), true ) );
1119  }
1120 
1121  return scope.release();
1122 }
1123 
1124 void QgsExpressionContextUtils::setLayoutVariable( QgsLayout *layout, const QString &name, const QVariant &value )
1125 {
1126  if ( !layout )
1127  return;
1128 
1129  //write variable to layout
1130  QStringList variableNames = layout->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
1131  QStringList variableValues = layout->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
1132 
1133  variableNames << name;
1134  variableValues << value.toString();
1135 
1136  layout->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
1137  layout->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
1138 }
1139 
1140 void QgsExpressionContextUtils::setLayoutVariables( QgsLayout *layout, const QVariantMap &variables )
1141 {
1142  if ( !layout )
1143  return;
1144 
1145  QStringList variableNames;
1146  QStringList variableValues;
1147 
1148  QVariantMap::const_iterator it = variables.constBegin();
1149  for ( ; it != variables.constEnd(); ++it )
1150  {
1151  variableNames << it.key();
1152  variableValues << it.value().toString();
1153  }
1154 
1155  layout->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
1156  layout->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
1157 }
1158 
1160 {
1161  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Atlas" ) );
1162  if ( !atlas )
1163  {
1164  //add some dummy atlas variables. This is done so that as in certain contexts we want to show
1165  //users that these variables are available even if they have no current value
1166  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_pagename" ), QString(), true ) );
1167  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( QgsFeature() ), true ) );
1168  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), 0, true ) );
1169  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( QgsGeometry() ), true ) );
1170  return scope;
1171  }
1172 
1173  //add known atlas variables
1174  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_totalfeatures" ), atlas->count(), true ) );
1175  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featurenumber" ), atlas->currentFeatureNumber() + 1, true ) );
1176  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_filename" ), atlas->currentFilename(), true ) );
1177  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_pagename" ), atlas->nameForPage( atlas->currentFeatureNumber() ), true ) );
1178 
1179  if ( atlas->enabled() && atlas->coverageLayer() )
1180  {
1181  scope->setFields( atlas->coverageLayer()->fields() );
1182  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layerid" ), atlas->coverageLayer()->id(), true ) );
1183  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layername" ), atlas->coverageLayer()->name(), true ) );
1184  }
1185 
1186  if ( atlas->enabled() )
1187  {
1188  QgsFeature atlasFeature = atlas->layout()->reportContext().feature();
1189  scope->setFeature( atlasFeature );
1190  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( atlasFeature ), true ) );
1191  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), atlasFeature.id(), true ) );
1192  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( atlasFeature.geometry() ), true ) );
1193  }
1194 
1195  return scope;
1196 }
1197 
1199 {
1200  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layout Item" ) );
1201  if ( !item )
1202  return scope;
1203 
1204  //add variables defined in layout item properties
1205  const QStringList variableNames = item->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
1206  const QStringList variableValues = item->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
1207 
1208  int varIndex = 0;
1209  for ( const QString &variableName : variableNames )
1210  {
1211  if ( varIndex >= variableValues.length() )
1212  {
1213  break;
1214  }
1215 
1216  QVariant varValue = variableValues.at( varIndex );
1217  varIndex++;
1218  scope->setVariable( variableName, varValue );
1219  }
1220 
1221  //add known layout item context variables
1222  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "item_id" ), item->id(), true ) );
1223  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "item_uuid" ), item->uuid(), true ) );
1224  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_page" ), item->page() + 1, true ) );
1225 
1226  if ( item->layout() )
1227  {
1228  const QgsLayoutItemPage *page = item->layout()->pageCollection()->page( item->page() );
1229  if ( page )
1230  {
1231  const QSizeF s = page->sizeWithUnits().toQSizeF();
1232  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), s.height(), true ) );
1233  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), s.width(), true ) );
1234  }
1235  else
1236  {
1237  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), QVariant(), true ) );
1238  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), QVariant(), true ) );
1239  }
1240  }
1241 
1242  return scope;
1243 }
1244 
1245 void QgsExpressionContextUtils::setLayoutItemVariable( QgsLayoutItem *item, const QString &name, const QVariant &value )
1246 {
1247  if ( !item )
1248  return;
1249 
1250  //write variable to layout item
1251  QStringList variableNames = item->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
1252  QStringList variableValues = item->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
1253 
1254  variableNames << name;
1255  variableValues << value.toString();
1256 
1257  item->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
1258  item->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
1259 }
1260 
1261 void QgsExpressionContextUtils::setLayoutItemVariables( QgsLayoutItem *item, const QVariantMap &variables )
1262 {
1263  if ( !item )
1264  return;
1265 
1266  QStringList variableNames;
1267  QStringList variableValues;
1268 
1269  QVariantMap::const_iterator it = variables.constBegin();
1270  for ( ; it != variables.constEnd(); ++it )
1271  {
1272  variableNames << it.key();
1273  variableValues << it.value().toString();
1274  }
1275 
1276  item->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
1277  item->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
1278 }
1279 
1281 {
1283  scope->setFeature( feature );
1284  scope->setFields( fields );
1285  return QgsExpressionContext() << scope;
1286 }
1287 
1289 {
1290  // set aside for future use
1291  Q_UNUSED( context );
1292 
1293  std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope( QObject::tr( "Algorithm" ) ) );
1294  scope->addFunction( QStringLiteral( "parameter" ), new GetProcessingParameterValue( parameters ) );
1295 
1296  if ( !algorithm )
1297  return scope.release();
1298 
1299  //add standard algorithm variables
1300  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "algorithm_id" ), algorithm->id(), true ) );
1301 
1302  return scope.release();
1303 }
1304 
1306 {
1307  std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope() );
1308  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "notification_message" ), message, true ) );
1309  return scope.release();
1310 }
1311 
1313 {
1314  QgsExpression::registerFunction( new GetNamedProjectColor( nullptr ) );
1315  QgsExpression::registerFunction( new GetLayoutItemVariables( nullptr ) );
1316  QgsExpression::registerFunction( new GetLayerVisibility( QList<QgsMapLayer *>() ) );
1317  QgsExpression::registerFunction( new GetProcessingParameterValue( QVariantMap() ) );
1318  QgsExpression::registerFunction( new GetCurrentFormFieldValue( ) );
1319 }
1320 
1322 {
1323  Q_UNUSED( node )
1324  return mUsesGeometry;
1325 }
1326 
1328 {
1329  Q_UNUSED( node )
1330  return mReferencedColumns;
1331 }
1332 
1334 {
1335  return allParamsStatic( node, parent, context );
1336 }
1337 
1338 //
1339 // GetLayerVisibility
1340 //
1341 
1342 QgsExpressionContextUtils::GetLayerVisibility::GetLayerVisibility( const QList<QgsMapLayer *> &layers )
1343  : QgsScopedExpressionFunction( QStringLiteral( "is_layer_visible" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "id" ) ), QStringLiteral( "General" ) )
1344  , mLayers( _qgis_listRawToQPointer( layers ) )
1345 {}
1346 
1347 QVariant QgsExpressionContextUtils::GetLayerVisibility::func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1348 {
1349  if ( mLayers.isEmpty() )
1350  {
1351  return false;
1352  }
1353 
1354  QgsMapLayer *layer = QgsExpressionUtils::getMapLayer( values.at( 0 ), parent );
1355  if ( layer )
1356  {
1357  return mLayers.contains( layer );
1358  }
1359  else
1360  {
1361  return false;
1362  }
1363 }
1364 
1365 QgsScopedExpressionFunction *QgsExpressionContextUtils::GetLayerVisibility::clone() const
1366 {
1367  return new GetLayerVisibility( _qgis_listQPointerToRaw( mLayers ) );
1368 }
int pageCount() const
Returns the number of pages in the collection.
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.
QgsUnitTypes::DistanceUnit mapUnits() const
Gets units of map&#39;s geographical coordinates - used for scale calculation.
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.
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.
bool isHighlightedVariable(const QString &name) const
Returns true if the specified variable name is intended to be highlighted to the user.
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.
bool hasFunction(const QString &name) const
Checks whether a specified function is contained in the context.
Base class for all map layer types.
Definition: qgsmaplayer.h:63
double angle() const
Returns the marker angle for the whole symbol.
Definition: qgssymbol.cpp:1182
static void setLayoutItemVariables(QgsLayoutItem *item, const QVariantMap &variables)
Sets all layout item context variables for an item.
QString title() const
Returns the project&#39;s title.
Definition: qgsproject.cpp:431
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.
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.
double scale() const
Returns the calculated map scale.
static void setLayoutVariable(QgsLayout *layout, const QString &name, const QVariant &value)
Sets a layout context variable.
static void setCustomVariables(const QVariantMap &customVariables)
Custom expression variables for this application.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:61
bool hasVariable(const QString &name) const
Check whether a variable is specified by any scope within the context.
QgsExpressionContext & operator=(const QgsExpressionContext &other)
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:183
int currentFeatureNumber() const
Returns the current feature number, where a value of 0 corresponds to the first feature.
void addFunction(const QString &name, QgsScopedExpressionFunction *function)
Adds a function to the scope.
QgsExpressionContextScope(const QString &name=QString())
Constructor for QgsExpressionContextScope.
QString identifier() const
A reference, URI, URL or some other mechanism to identify the resource.
QgsExpressionFunction * function(const QString &name) const
Retrieves a function from the scope.
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...
QVariant cachedValue(const QString &key) const
Returns the matching cached value, if set.
int scopeCount() const
Returns the number of scopes contained in the context.
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
QgsAbstractMetadataBase::KeywordMap keywords() const
Returns the keywords map, which is a set of descriptive keywords associated with the resource...
QString id() const
Returns the unique ID for the algorithm, which is a combination of the algorithm provider&#39;s ID and th...
bool isStatic(const QString &name) const
Tests whether the variable with the specified name is static and can be cached.
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for the object.
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes takes output image size into accou...
Container of fields for a vector layer.
Definition: qgsfields.h:42
QStringList readListEntry(const QString &scope, const QString &key, const QStringList &def=QStringList(), bool *ok=nullptr) const
Key value accessors.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
bool hasVariable(const QString &name) const
Tests whether a variable with the specified name exists in the scope.
static QVariantMap customVariables()
Custom expression variables for this application.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the scope.
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.
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
bool hasFeature() const
Returns true if the context has a feature associated with it.
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)
QString ellipsoid
Definition: qgsproject.h:97
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...
int indexOfScope(QgsExpressionContextScope *scope) const
Returns the index of the specified scope if it exists within the context.
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
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.
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:732
static QString userFullName()
Returns the user&#39;s operating system login account full display name.
void clearCachedValues() const
Clears all cached values from the context.
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
QgsLayoutSize sizeWithUnits() const
Returns the item&#39;s current size, including units.
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 name() const
Returns the friendly display name of the context scope.
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
QList< QgsMapLayer * > layers() const
Gets list of layers for map rendering The layers are stored in the reverse order of how they are rend...
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.
QgsUnitTypes::AreaUnit areaUnits() const
Convenience function to query default area measurement units for project.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
bool hasFunction(const QString &name) const
Tests whether a function with the specified name exists in the scope.
QStringList variableNames() const
Returns a list of variables names set by all scopes in the context.
bool removeVariable(const QString &name)
Removes a variable from the context scope, if found.
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
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...
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.
QStringList filteredVariableNames() const
Returns a filtered and sorted list of variable names contained within the scope.
QgsProjectStorage * projectStorage() const
Returns pointer to project storage implementation that handles read/write of the project file...
Definition: qgsproject.cpp:562
QgsFeature feature() const
Returns the current feature for evaluating the layout.
QString nameForPage(int page) const
Returns the calculated name for a specified atlas page number.
bool enabled() const
Returns whether the atlas generation is enabled.
bool hasCachedValue(const QString &key) const
Returns true if the expression context contains a cached value with a matching key.
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
QString description(const QString &name) const
Returns the translated description for the variable with the specified name (if set).
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
Class used to render QgsLayout as an atlas, by iterating over the features from an associated vector ...
QgsFields fields() const
Convenience function for retrieving the fields for the context, if set.
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:229
static const QString EXPR_SYMBOL_COLOR
Inbuilt variable name for symbol color variable.
bool isReadOnly(const QString &name) const
Returns whether a variable is read only, and should not be modifiable by users.
QgsFeature feature() const
Convenience function for retrieving the feature for the context, if set.
static bool registerFunction(QgsExpressionFunction *function, bool transferOwnership=false)
Registers a function to the expression engine.
void setCachedValue(const QString &key, const QVariant &value) const
Sets a value to cache within the expression context.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
Reads and writes project states.
Definition: qgsproject.h:89
static void setCustomVariable(const QString &name, const QVariant &value)
Set a single custom expression variable.
virtual QString uuid() const
Returns the item identification string.
QString currentFilename() const
Returns the current feature filename.
QStringList functionNames() const
Retrieves a list of function names contained in the context.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
static const QString EXPR_FIELDS
Inbuilt variable name for fields storage.
QString abstract() const
Returns a free-form description of the resource.
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
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.
QDateTime creationDateTime() const
Returns the project&#39;s creation date/timestamp.
QVariant variable(const QString &name) const
Retrieves a variable&#39;s value from the scope.
void setCustomVariables(const QVariantMap &customVariables)
A map of custom project variables.
QString description(const QString &name) const
Returns a translated description string for the variable with specified name.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:49
QSizeF toQSizeF() const
Converts the layout size to a QSizeF.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
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.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from the layout.
Definition: qgslayout.cpp:412
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:96
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. ...
int page() const
Returns the page the item is currently on, with the first page returning 0.
QString baseName() const
Returns the base name of the project file without the path and without extension - derived from fileN...
Definition: qgsproject.cpp:603
QgsUnitTypes::DistanceUnit distanceUnits() const
Convenience function to query default distance measurement units for project.
QString author() const
Returns the project author string.
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...
static const QString QGIS_RELEASE_NAME
Release name.
Definition: qgis.h:68
QVariantMap variablesToMap() const
Returns a map of variable name to value representing all the expression variables contained by the co...
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...
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
QVariantMap customVariables() const
A map of custom project variables.
QStringList filteredVariableNames() const
Returns a filtered list of variables names set by all scopes in 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
This class represents a coordinate reference system (CRS).
bool isHighlightedFunction(const QString &name) const
Returns true if the specified function name is intended to be highlighted to the user.
QString authid() const
Returns the authority identifier for the CRS.
QgsExpressionFunction * function(const QString &name) const
Fetches a matching function from the context.
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
QStringList functionNames() const
Retrieves a list of names of functions contained in the scope.
static const QString EXPR_GEOMETRY_POINT_NUM
Inbuilt variable name for point 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
QString id() const
Returns the item&#39;s ID name.
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.
QgsGeometry geometry
Definition: qgsfeature.h:67
const QgsLayout * layout() const
Returns the layout the object is attached to.
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.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Interface for master layout type objects, such as print layouts and reports.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:201
static const QString EXPR_GEOMETRY_PART_NUM
Inbuilt variable name for geometry part number variable.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from the object.
bool isStatic
A static variable can be cached for the lifetime of a context.
QColor color() const
Returns the symbol&#39;s color.
Definition: qgssymbol.cpp:459
Represents a vector layer which manages a vector based data sets.
bool isReadOnly(const QString &name) const
Tests whether the specified variable is read only and should not be editable by users.
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.
double dpi() const
Returns the dpi for outputting the layout.
QgsVectorLayer * coverageLayer() const
Returns the coverage layer used for the atlas features.
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.
bool hasFeature() const
Returns true if the scope has a feature associated with it.
QgsVectorLayer * layer() const
Returns the vector layer associated with the layout&#39;s context.
Expression function for use within a QgsExpressionContextScope.
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:70
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)
QStringList variableNames() const
Returns a list of variable names contained within the scope.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:208
Item representing the paper in a layout.
QString toProj4() const
Returns a Proj4 string representation of this CRS.