LCOV - code coverage report
Current view: top level - core/expression - qgsexpressioncontextutils.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 47 563 8.3 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :      qgsexpressioncontextutils.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 "qgsexpressioncontextutils.h"
      17                 :            : #include "qgsapplication.h"
      18                 :            : #include "qgsvectorlayer.h"
      19                 :            : #include "qgsproject.h"
      20                 :            : #include "qgsexpression.h"
      21                 :            : #include "qgsprocessingcontext.h"
      22                 :            : #include "qgsprocessingmodelalgorithm.h"
      23                 :            : #include "qgsprocessingalgorithm.h"
      24                 :            : #include "qgsmapsettings.h"
      25                 :            : #include "qgssymbollayerutils.h"
      26                 :            : #include "qgslayout.h"
      27                 :            : #include "qgslayoutitem.h"
      28                 :            : #include "qgsexpressionutils.h"
      29                 :            : #include "qgslayoutpagecollection.h"
      30                 :            : #include "qgslayoutatlas.h"
      31                 :            : #include "qgslayoutmultiframe.h"
      32                 :            : #include "qgsfeatureid.h"
      33                 :            : #include "qgslayoutitemmap.h"
      34                 :            : 
      35                 :          1 : QgsExpressionContextScope *QgsExpressionContextUtils::globalScope()
      36                 :            : {
      37                 :          1 :   QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Global" ) );
      38                 :            : 
      39                 :          1 :   QVariantMap customVariables = QgsApplication::customVariables();
      40                 :            : 
      41                 :          1 :   for ( QVariantMap::const_iterator it = customVariables.constBegin(); it != customVariables.constEnd(); ++it )
      42                 :            :   {
      43                 :          0 :     scope->setVariable( it.key(), it.value(), true );
      44                 :          0 :   }
      45                 :            : 
      46                 :            :   //add some extra global variables
      47                 :          2 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_version" ), Qgis::version(), true, true ) );
      48                 :          2 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_version_no" ), Qgis::versionInt(), true, true ) );
      49                 :          3 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_short_version" ), QStringLiteral( "%1.%2" ).arg( Qgis::versionInt() / 10000 ).arg( Qgis::versionInt() / 100 % 100 ), true, true ) );
      50                 :          2 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_release_name" ), Qgis::releaseName(), true, true ) );
      51                 :          2 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_platform" ), QgsApplication::platform(), true, true ) );
      52                 :          2 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_os_name" ), QgsApplication::osName(), true, true ) );
      53                 :          2 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_locale" ), QgsApplication::locale(), true, true ) );
      54                 :          2 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_account_name" ), QgsApplication::userLoginName(), true, true ) );
      55                 :          2 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_full_name" ), QgsApplication::userFullName(), true, true ) );
      56                 :            : 
      57                 :          1 :   return scope;
      58                 :          1 : }
      59                 :            : 
      60                 :          0 : void QgsExpressionContextUtils::setGlobalVariable( const QString &name, const QVariant &value )
      61                 :            : {
      62                 :          0 :   QgsApplication::setCustomVariable( name, value );
      63                 :          0 : }
      64                 :            : 
      65                 :          0 : void QgsExpressionContextUtils::setGlobalVariables( const QVariantMap &variables )
      66                 :            : {
      67                 :          0 :   QgsApplication::setCustomVariables( variables );
      68                 :          0 : }
      69                 :            : 
      70                 :          0 : void QgsExpressionContextUtils::removeGlobalVariable( const QString &name )
      71                 :            : {
      72                 :          0 :   QVariantMap vars = QgsApplication::customVariables();
      73                 :          0 :   if ( vars.remove( name ) )
      74                 :          0 :     QgsApplication::setCustomVariables( vars );
      75                 :          0 : }
      76                 :            : 
      77                 :            : /// @cond PRIVATE
      78                 :            : 
      79                 :          0 : class GetLayoutItemVariables : public QgsScopedExpressionFunction
      80                 :            : {
      81                 :            :   public:
      82                 :          0 :     GetLayoutItemVariables( const QgsLayout *c )
      83                 :          0 :       : QgsScopedExpressionFunction( QStringLiteral( "item_variables" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "id" ) ), QStringLiteral( "Layout" ) )
      84                 :          0 :       , mLayout( c )
      85                 :          0 :     {}
      86                 :            : 
      87                 :          0 :     QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) override
      88                 :            :     {
      89                 :          0 :       if ( !mLayout )
      90                 :          0 :         return QVariant();
      91                 :            : 
      92                 :          0 :       QString id = values.at( 0 ).toString();
      93                 :            : 
      94                 :          0 :       const QgsLayoutItem *item = mLayout->itemById( id );
      95                 :          0 :       if ( !item )
      96                 :          0 :         return QVariant();
      97                 :            : 
      98                 :          0 :       QgsExpressionContext c = item->createExpressionContext();
      99                 :            : 
     100                 :          0 :       return c.variablesToMap();
     101                 :          0 :     }
     102                 :            : 
     103                 :          0 :     QgsScopedExpressionFunction *clone() const override
     104                 :            :     {
     105                 :          0 :       return new GetLayoutItemVariables( mLayout );
     106                 :          0 :     }
     107                 :            : 
     108                 :            :   private:
     109                 :            : 
     110                 :            :     const QgsLayout *mLayout = nullptr;
     111                 :            : 
     112                 :            : };
     113                 :            : 
     114                 :            : 
     115                 :          0 : class GetLayoutMapLayerCredits : public QgsScopedExpressionFunction
     116                 :            : {
     117                 :            :   public:
     118                 :          0 :     GetLayoutMapLayerCredits( const QgsLayout *c )
     119                 :          0 :       : QgsScopedExpressionFunction( QStringLiteral( "map_credits" ),
     120                 :          0 :                                      QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "id" ) )
     121                 :          0 :                                      << QgsExpressionFunction::Parameter( QStringLiteral( "include_layer_names" ), true, false )
     122                 :          0 :                                      << QgsExpressionFunction::Parameter( QStringLiteral( "layer_name_separator" ), true, QStringLiteral( ": " ) ), QStringLiteral( "Layout" ) )
     123                 :          0 :       , mLayout( c )
     124                 :          0 :     {}
     125                 :            : 
     126                 :          0 :     QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) override
     127                 :            :     {
     128                 :          0 :       if ( !mLayout )
     129                 :          0 :         return QVariant();
     130                 :            : 
     131                 :          0 :       QString id = values.value( 0 ).toString();
     132                 :            : 
     133                 :          0 :       if ( QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( mLayout->itemById( id ) ) )
     134                 :            :       {
     135                 :          0 :         QgsExpressionContext c = map->createExpressionContext();
     136                 :          0 :         const QVariantList mapLayers = c.variable( QStringLiteral( "map_layers" ) ).toList();
     137                 :            : 
     138                 :          0 :         const bool includeLayerNames = values.value( 1 ).toBool();
     139                 :          0 :         const QString layerNameSeparator = values.value( 2 ).toString();
     140                 :            : 
     141                 :          0 :         QVariantList res;
     142                 :          0 :         for ( const QVariant &value : mapLayers )
     143                 :            :         {
     144                 :          0 :           if ( const QgsMapLayer *layer = qobject_cast< const QgsMapLayer * >( value.value< QObject * >() ) )
     145                 :            :           {
     146                 :          0 :             const QStringList credits = !layer->metadata().rights().isEmpty() ? layer->metadata().rights() : QStringList() << layer->attribution();
     147                 :          0 :             for ( const QString &credit : credits )
     148                 :            :             {
     149                 :          0 :               if ( credit.trimmed().isEmpty() )
     150                 :          0 :                 continue;
     151                 :            : 
     152                 :          0 :               const QString creditString = includeLayerNames ? layer->name() + layerNameSeparator + credit
     153                 :          0 :                                            : credit;
     154                 :            : 
     155                 :          0 :               if ( !res.contains( creditString ) )
     156                 :          0 :                 res << creditString;
     157                 :          0 :             }
     158                 :          0 :           }
     159                 :            :         }
     160                 :            : 
     161                 :          0 :         return res;
     162                 :          0 :       }
     163                 :          0 :       return QVariant();
     164                 :          0 :     }
     165                 :            : 
     166                 :          0 :     QgsScopedExpressionFunction *clone() const override
     167                 :            :     {
     168                 :          0 :       return new GetLayoutMapLayerCredits( mLayout );
     169                 :          0 :     }
     170                 :            : 
     171                 :            :   private:
     172                 :            : 
     173                 :            :     const QgsLayout *mLayout = nullptr;
     174                 :            : 
     175                 :            : };
     176                 :            : 
     177                 :          0 : class GetCurrentFormFieldValue : public QgsScopedExpressionFunction
     178                 :            : {
     179                 :            :   public:
     180                 :          0 :     GetCurrentFormFieldValue( )
     181                 :          0 :       : QgsScopedExpressionFunction( QStringLiteral( "current_value" ), QgsExpressionFunction::ParameterList() << QStringLiteral( "field_name" ), QStringLiteral( "Form" ) )
     182                 :          0 :     {}
     183                 :            : 
     184                 :          0 :     QVariant func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * ) override
     185                 :            :     {
     186                 :          0 :       QString fieldName( values.at( 0 ).toString() );
     187                 :          0 :       const QgsFeature feat( context->variable( QStringLiteral( "current_feature" ) ).value<QgsFeature>() );
     188                 :          0 :       if ( fieldName.isEmpty() || ! feat.isValid( ) )
     189                 :            :       {
     190                 :          0 :         return QVariant();
     191                 :            :       }
     192                 :          0 :       return feat.attribute( fieldName ) ;
     193                 :          0 :     }
     194                 :            : 
     195                 :          0 :     QgsScopedExpressionFunction *clone() const override
     196                 :            :     {
     197                 :          0 :       return new GetCurrentFormFieldValue( );
     198                 :          0 :     }
     199                 :            : 
     200                 :          0 :     bool isStatic( const QgsExpressionNodeFunction *, QgsExpression *, const QgsExpressionContext * ) const override
     201                 :            :     {
     202                 :          0 :       return false;
     203                 :            :     };
     204                 :            : 
     205                 :            : };
     206                 :            : 
     207                 :          0 : class GetCurrentParentFormFieldValue : public QgsScopedExpressionFunction
     208                 :            : {
     209                 :            :   public:
     210                 :          0 :     GetCurrentParentFormFieldValue( )
     211                 :          0 :       : QgsScopedExpressionFunction( QStringLiteral( "current_parent_value" ), QgsExpressionFunction::ParameterList() << QStringLiteral( "field_name" ), QStringLiteral( "Form" ) )
     212                 :          0 :     {}
     213                 :            : 
     214                 :          0 :     QVariant func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * ) override
     215                 :            :     {
     216                 :          0 :       QString fieldName( values.at( 0 ).toString() );
     217                 :          0 :       const QgsFeature feat( context->variable( QStringLiteral( "current_parent_feature" ) ).value<QgsFeature>() );
     218                 :          0 :       if ( fieldName.isEmpty() || ! feat.isValid( ) )
     219                 :            :       {
     220                 :          0 :         return QVariant();
     221                 :            :       }
     222                 :          0 :       return feat.attribute( fieldName ) ;
     223                 :          0 :     }
     224                 :            : 
     225                 :          0 :     QgsScopedExpressionFunction *clone() const override
     226                 :            :     {
     227                 :          0 :       return new GetCurrentParentFormFieldValue( );
     228                 :          0 :     }
     229                 :            : 
     230                 :          0 :     bool isStatic( const QgsExpressionNodeFunction *, QgsExpression *, const QgsExpressionContext * ) const override
     231                 :            :     {
     232                 :          0 :       return false;
     233                 :            :     };
     234                 :            : 
     235                 :            : };
     236                 :            : 
     237                 :            : 
     238                 :          0 : class GetProcessingParameterValue : public QgsScopedExpressionFunction
     239                 :            : {
     240                 :            :   public:
     241                 :          0 :     GetProcessingParameterValue( const QVariantMap &params )
     242                 :          0 :       : QgsScopedExpressionFunction( QStringLiteral( "parameter" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "name" ) ), QStringLiteral( "Processing" ) )
     243                 :          0 :       , mParams( params )
     244                 :          0 :     {}
     245                 :            : 
     246                 :          0 :     QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) override
     247                 :            :     {
     248                 :          0 :       return mParams.value( values.at( 0 ).toString() );
     249                 :          0 :     }
     250                 :            : 
     251                 :          0 :     QgsScopedExpressionFunction *clone() const override
     252                 :            :     {
     253                 :          0 :       return new GetProcessingParameterValue( mParams );
     254                 :          0 :     }
     255                 :            : 
     256                 :            :   private:
     257                 :            : 
     258                 :            :     const QVariantMap mParams;
     259                 :            : 
     260                 :            : };
     261                 :            : 
     262                 :            : ///@endcond
     263                 :            : 
     264                 :            : 
     265                 :          0 : QgsExpressionContextScope *QgsExpressionContextUtils::formScope( const QgsFeature &formFeature, const QString &formMode )
     266                 :            : {
     267                 :          0 :   QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Form" ) );
     268                 :          0 :   scope->addFunction( QStringLiteral( "current_value" ), new GetCurrentFormFieldValue( ) );
     269                 :          0 :   scope->setVariable( QStringLiteral( "current_geometry" ), formFeature.geometry( ), true );
     270                 :          0 :   scope->setVariable( QStringLiteral( "current_feature" ), formFeature, true );
     271                 :          0 :   scope->setVariable( QStringLiteral( "form_mode" ), formMode, true );
     272                 :          0 :   return scope;
     273                 :          0 : }
     274                 :            : 
     275                 :            : 
     276                 :          0 : QgsExpressionContextScope *QgsExpressionContextUtils::parentFormScope( const QgsFeature &parentFormFeature, const QString &parentFormMode )
     277                 :            : {
     278                 :          0 :   QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Parent Form" ) );
     279                 :          0 :   scope->addFunction( QStringLiteral( "current_parent_value" ), new GetCurrentParentFormFieldValue( ) );
     280                 :          0 :   scope->setVariable( QStringLiteral( "current_parent_geometry" ), parentFormFeature.geometry( ), true );
     281                 :          0 :   scope->setVariable( QStringLiteral( "current_parent_feature" ), parentFormFeature, true );
     282                 :          0 :   scope->setVariable( QStringLiteral( "parent_form_mode" ), parentFormMode, true );
     283                 :          0 :   return scope;
     284                 :          0 : }
     285                 :            : 
     286                 :          1 : QgsExpressionContextScope *QgsExpressionContextUtils::projectScope( const QgsProject *project )
     287                 :            : {
     288                 :          1 :   if ( !project )
     289                 :            :   {
     290                 :          0 :     QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Project" ) );
     291                 :          0 :     return scope;
     292                 :            :   }
     293                 :            :   else
     294                 :          1 :     return project->createExpressionContextScope();
     295                 :          1 : }
     296                 :            : 
     297                 :          0 : void QgsExpressionContextUtils::setProjectVariable( QgsProject *project, const QString &name, const QVariant &value )
     298                 :            : {
     299                 :          0 :   if ( !project )
     300                 :          0 :     return;
     301                 :            : 
     302                 :          0 :   QVariantMap vars = project->customVariables();
     303                 :            : 
     304                 :          0 :   vars.insert( name, value );
     305                 :            : 
     306                 :          0 :   project->setCustomVariables( vars );
     307                 :          0 : }
     308                 :            : 
     309                 :          0 : void QgsExpressionContextUtils::setProjectVariables( QgsProject *project, const QVariantMap &variables )
     310                 :            : {
     311                 :          0 :   if ( !project )
     312                 :          0 :     return;
     313                 :            : 
     314                 :          0 :   project->setCustomVariables( variables );
     315                 :          0 : }
     316                 :            : 
     317                 :          0 : void QgsExpressionContextUtils::removeProjectVariable( QgsProject *project, const QString &name )
     318                 :            : {
     319                 :          0 :   if ( !project )
     320                 :            :   {
     321                 :          0 :     return;
     322                 :            :   }
     323                 :            : 
     324                 :          0 :   QVariantMap vars = project->customVariables();
     325                 :          0 :   if ( vars.remove( name ) )
     326                 :          0 :     project->setCustomVariables( vars );
     327                 :          0 : }
     328                 :            : 
     329                 :        200 : QgsExpressionContextScope *QgsExpressionContextUtils::layerScope( const QgsMapLayer *layer )
     330                 :            : {
     331                 :        200 :   QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layer" ) );
     332                 :            : 
     333                 :        200 :   if ( !layer )
     334                 :          0 :     return scope;
     335                 :            : 
     336                 :            :   //add variables defined in layer properties
     337                 :        400 :   const QStringList variableNames = layer->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
     338                 :        400 :   const QStringList variableValues = layer->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
     339                 :            : 
     340                 :        200 :   int varIndex = 0;
     341                 :        200 :   for ( const QString &variableName : variableNames )
     342                 :            :   {
     343                 :          0 :     if ( varIndex >= variableValues.length() )
     344                 :            :     {
     345                 :          0 :       break;
     346                 :            :     }
     347                 :            : 
     348                 :          0 :     QVariant varValue = variableValues.at( varIndex );
     349                 :          0 :     varIndex++;
     350                 :          0 :     scope->setVariable( variableName, varValue, true );
     351                 :          0 :   }
     352                 :            : 
     353                 :        400 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_name" ), layer->name(), true, true ) );
     354                 :        400 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_id" ), layer->id(), true, true ) );
     355                 :        400 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "_layer_crs" ), QVariant::fromValue<QgsCoordinateReferenceSystem>( layer->crs() ), true, true ) );
     356                 :        400 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_crs" ), layer->crs().authid(), true, true ) );
     357                 :        400 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer" ), QVariant::fromValue<QgsWeakMapLayerPointer >( QgsWeakMapLayerPointer( const_cast<QgsMapLayer *>( layer ) ) ), true, true ) );
     358                 :            : 
     359                 :        200 :   const QgsVectorLayer *vLayer = qobject_cast< const QgsVectorLayer * >( layer );
     360                 :        200 :   if ( vLayer )
     361                 :            :   {
     362                 :        200 :     scope->setFields( vLayer->fields() );
     363                 :        200 :   }
     364                 :            : 
     365                 :            :   //TODO - add functions. Possibilities include:
     366                 :            :   //is_selected
     367                 :            :   //field summary stats
     368                 :            : 
     369                 :        200 :   return scope;
     370                 :        200 : }
     371                 :            : 
     372                 :          1 : QList<QgsExpressionContextScope *> QgsExpressionContextUtils::globalProjectLayerScopes( const QgsMapLayer *layer )
     373                 :            : {
     374                 :          1 :   QList<QgsExpressionContextScope *> scopes;
     375                 :          1 :   scopes << globalScope();
     376                 :            : 
     377                 :          1 :   QgsProject *project = QgsProject::instance();  // TODO: use project associated with layer
     378                 :          1 :   if ( project )
     379                 :          1 :     scopes << projectScope( project );
     380                 :            : 
     381                 :          1 :   if ( layer )
     382                 :          1 :     scopes << layerScope( layer );
     383                 :          1 :   return scopes;
     384                 :          1 : }
     385                 :            : 
     386                 :            : 
     387                 :          0 : void QgsExpressionContextUtils::setLayerVariable( QgsMapLayer *layer, const QString &name, const QVariant &value )
     388                 :            : {
     389                 :          0 :   if ( !layer )
     390                 :          0 :     return;
     391                 :            : 
     392                 :            :   //write variable to layer
     393                 :          0 :   QStringList variableNames = layer->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
     394                 :          0 :   QStringList variableValues = layer->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
     395                 :            : 
     396                 :          0 :   variableNames << name;
     397                 :          0 :   variableValues << value.toString();
     398                 :            : 
     399                 :          0 :   layer->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
     400                 :          0 :   layer->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
     401                 :          0 : }
     402                 :            : 
     403                 :          0 : void QgsExpressionContextUtils::setLayerVariables( QgsMapLayer *layer, const QVariantMap &variables )
     404                 :            : {
     405                 :          0 :   if ( !layer )
     406                 :          0 :     return;
     407                 :            : 
     408                 :          0 :   QStringList variableNames;
     409                 :          0 :   QStringList variableValues;
     410                 :            : 
     411                 :          0 :   QVariantMap::const_iterator it = variables.constBegin();
     412                 :          0 :   for ( ; it != variables.constEnd(); ++it )
     413                 :            :   {
     414                 :          0 :     variableNames << it.key();
     415                 :          0 :     variableValues << it.value().toString();
     416                 :          0 :   }
     417                 :            : 
     418                 :          0 :   layer->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
     419                 :          0 :   layer->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
     420                 :          0 : }
     421                 :            : 
     422                 :          0 : QgsExpressionContextScope *QgsExpressionContextUtils::mapSettingsScope( const QgsMapSettings &mapSettings )
     423                 :            : {
     424                 :            :   // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
     425                 :            :   // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
     426                 :            : 
     427                 :            :   // and because people don't read that ^^, I'm going to blast it all over this function
     428                 :            : 
     429                 :          0 :   QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Map Settings" ) );
     430                 :            : 
     431                 :            :   //add known map settings context variables
     432                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_id" ), "canvas", true ) );
     433                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_rotation" ), mapSettings.rotation(), true ) );
     434                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_scale" ), mapSettings.scale(), true ) );
     435                 :            : 
     436                 :            :   // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
     437                 :            :   // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
     438                 :            : 
     439                 :          0 :   QgsGeometry extent = QgsGeometry::fromRect( mapSettings.visibleExtent() );
     440                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent" ), QVariant::fromValue( extent ), true ) );
     441                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_width" ), mapSettings.visibleExtent().width(), true ) );
     442                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_height" ), mapSettings.visibleExtent().height(), true ) );
     443                 :            : 
     444                 :            :   // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
     445                 :            :   // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
     446                 :            : 
     447                 :          0 :   QgsGeometry centerPoint = QgsGeometry::fromPointXY( mapSettings.visibleExtent().center() );
     448                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_center" ), QVariant::fromValue( centerPoint ), true ) );
     449                 :            : 
     450                 :            :   // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
     451                 :            :   // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
     452                 :            : 
     453                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs" ), mapSettings.destinationCrs().authid(), true ) );
     454                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_definition" ), mapSettings.destinationCrs().toProj(), true ) );
     455                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_units" ), QgsUnitTypes::toString( mapSettings.mapUnits() ), true ) );
     456                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_description" ), mapSettings.destinationCrs().description(), true ) );
     457                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_acronym" ), mapSettings.destinationCrs().projectionAcronym(), true ) );
     458                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_ellipsoid" ), mapSettings.destinationCrs().ellipsoidAcronym(), true ) );
     459                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_proj4" ), mapSettings.destinationCrs().toProj(), true ) );
     460                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_wkt" ), mapSettings.destinationCrs().toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ), true ) );
     461                 :            : 
     462                 :            :   // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
     463                 :            :   // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
     464                 :            : 
     465                 :          0 :   QVariantList layersIds;
     466                 :          0 :   QVariantList layers;
     467                 :          0 :   const QList<QgsMapLayer *> layersInMap = mapSettings.layers();
     468                 :          0 :   layersIds.reserve( layersInMap.count() );
     469                 :          0 :   layers.reserve( layersInMap.count() );
     470                 :          0 :   for ( QgsMapLayer *layer : layersInMap )
     471                 :            :   {
     472                 :          0 :     layersIds << layer->id();
     473                 :          0 :     layers << QVariant::fromValue<QgsWeakMapLayerPointer>( QgsWeakMapLayerPointer( layer ) );
     474                 :            :   }
     475                 :            : 
     476                 :            :   // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
     477                 :            :   // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
     478                 :            : 
     479                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_layer_ids" ), layersIds, true ) );
     480                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_layers" ), layers, true ) );
     481                 :            : 
     482                 :            :   // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
     483                 :            :   // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
     484                 :            : 
     485                 :          0 :   scope->addFunction( QStringLiteral( "is_layer_visible" ), new GetLayerVisibility( mapSettings.layers(), mapSettings.scale() ) );
     486                 :            : 
     487                 :            :   // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
     488                 :            :   // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
     489                 :            : 
     490                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_start_time" ), mapSettings.isTemporal() ? mapSettings.temporalRange().begin() : QVariant(), true ) );
     491                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_end_time" ), mapSettings.isTemporal() ? mapSettings.temporalRange().end() : QVariant(), true ) );
     492                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_interval" ), mapSettings.isTemporal() ? ( mapSettings.temporalRange().end() - mapSettings.temporalRange().begin() ) : QVariant(), true ) );
     493                 :            : 
     494                 :            :   // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsLayoutItemMap::createExpressionContext()
     495                 :            :   // (rationale is described in QgsLayoutItemMap::createExpressionContext() )
     496                 :            : 
     497                 :          0 :   return scope;
     498                 :          0 : }
     499                 :            : 
     500                 :          0 : QgsExpressionContextScope *QgsExpressionContextUtils::mapToolCaptureScope( const QList<QgsPointLocator::Match> &matches )
     501                 :            : {
     502                 :          0 :   QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Map Tool Capture" ) );
     503                 :            : 
     504                 :          0 :   QVariantList matchList;
     505                 :            : 
     506                 :          0 :   for ( const QgsPointLocator::Match &match : matches )
     507                 :            :   {
     508                 :          0 :     QVariantMap matchMap;
     509                 :            : 
     510                 :          0 :     matchMap.insert( QStringLiteral( "valid" ), match.isValid() );
     511                 :          0 :     matchMap.insert( QStringLiteral( "layer" ), QVariant::fromValue<QgsWeakMapLayerPointer>( QgsWeakMapLayerPointer( match.layer() ) ) );
     512                 :          0 :     matchMap.insert( QStringLiteral( "feature_id" ), match.featureId() );
     513                 :          0 :     matchMap.insert( QStringLiteral( "vertex_index" ), match.vertexIndex() );
     514                 :          0 :     matchMap.insert( QStringLiteral( "distance" ), match.distance() );
     515                 :            : 
     516                 :          0 :     matchList.append( matchMap );
     517                 :          0 :   }
     518                 :            : 
     519                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "snapping_results" ), matchList ) );
     520                 :            : 
     521                 :          0 :   return scope;
     522                 :          0 : }
     523                 :            : 
     524                 :          0 : QgsExpressionContextScope *QgsExpressionContextUtils::updateSymbolScope( const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope )
     525                 :            : {
     526                 :          0 :   if ( !symbolScope )
     527                 :          0 :     return nullptr;
     528                 :            : 
     529                 :          0 :   symbolScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_SYMBOL_COLOR, symbol ? symbol->color() : QColor(), true ) );
     530                 :            : 
     531                 :          0 :   double angle = 0.0;
     532                 :          0 :   const QgsMarkerSymbol *markerSymbol = dynamic_cast< const QgsMarkerSymbol * >( symbol );
     533                 :          0 :   if ( markerSymbol )
     534                 :            :   {
     535                 :          0 :     angle = markerSymbol->angle();
     536                 :          0 :   }
     537                 :          0 :   symbolScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_SYMBOL_ANGLE, angle, true ) );
     538                 :            : 
     539                 :          0 :   return symbolScope;
     540                 :          0 : }
     541                 :            : 
     542                 :          0 : QgsExpressionContextScope *QgsExpressionContextUtils::layoutScope( const QgsLayout *layout )
     543                 :            : {
     544                 :          0 :   std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope( QObject::tr( "Layout" ) ) );
     545                 :          0 :   if ( !layout )
     546                 :          0 :     return scope.release();
     547                 :            : 
     548                 :            :   //add variables defined in layout properties
     549                 :          0 :   const QStringList variableNames = layout->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
     550                 :          0 :   const QStringList variableValues = layout->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
     551                 :            : 
     552                 :          0 :   int varIndex = 0;
     553                 :            : 
     554                 :          0 :   for ( const QString &variableName : variableNames )
     555                 :            :   {
     556                 :          0 :     if ( varIndex >= variableValues.length() )
     557                 :            :     {
     558                 :          0 :       break;
     559                 :            :     }
     560                 :            : 
     561                 :          0 :     QVariant varValue = variableValues.at( varIndex );
     562                 :          0 :     varIndex++;
     563                 :          0 :     scope->setVariable( variableName, varValue );
     564                 :          0 :   }
     565                 :            : 
     566                 :            :   //add known layout context variables
     567                 :          0 :   if ( const QgsMasterLayoutInterface *l = dynamic_cast< const QgsMasterLayoutInterface * >( layout ) )
     568                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_name" ), l->name(), true ) );
     569                 :            : 
     570                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_numpages" ), layout->pageCollection()->pageCount(), true ) );
     571                 :          0 :   if ( layout->pageCollection()->pageCount() > 0 )
     572                 :            :   {
     573                 :            :     // just take first page size
     574                 :          0 :     QSizeF s = layout->pageCollection()->page( 0 )->sizeWithUnits().toQSizeF();
     575                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), s.height(), true ) );
     576                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), s.width(), true ) );
     577                 :          0 :   }
     578                 :            : 
     579                 :          0 :   QVariantList offsets;
     580                 :          0 :   for ( int i = 0; i < layout->pageCollection()->pageCount(); i++ )
     581                 :            :   {
     582                 :          0 :     QPointF p = layout->pageCollection()->pagePositionToLayoutPosition( i, QgsLayoutPoint( 0, 0 ) );
     583                 :          0 :     offsets << p.y();
     584                 :          0 :   }
     585                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageoffsets" ), offsets, true ) );
     586                 :            : 
     587                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_dpi" ), layout->renderContext().dpi(), true ) );
     588                 :            : 
     589                 :          0 :   scope->addFunction( QStringLiteral( "item_variables" ), new GetLayoutItemVariables( layout ) );
     590                 :          0 :   scope->addFunction( QStringLiteral( "map_credits" ), new GetLayoutMapLayerCredits( layout ) );
     591                 :            : 
     592                 :          0 :   if ( layout->reportContext().layer() )
     593                 :            :   {
     594                 :          0 :     scope->setFields( layout->reportContext().layer()->fields() );
     595                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layerid" ), layout->reportContext().layer()->id(), true ) );
     596                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layername" ), layout->reportContext().layer()->name(), true ) );
     597                 :          0 :   }
     598                 :            : 
     599                 :          0 :   if ( layout->reportContext().feature().isValid() )
     600                 :            :   {
     601                 :          0 :     QgsFeature atlasFeature = layout->reportContext().feature();
     602                 :          0 :     scope->setFeature( atlasFeature );
     603                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( atlasFeature ), true ) );
     604                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), FID_IS_NULL( atlasFeature.id() ) ? QVariant() : atlasFeature.id(), true ) );
     605                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( atlasFeature.geometry() ), true ) );
     606                 :          0 :   }
     607                 :            : 
     608                 :          0 :   return scope.release();
     609                 :          0 : }
     610                 :            : 
     611                 :          0 : void QgsExpressionContextUtils::setLayoutVariable( QgsLayout *layout, const QString &name, const QVariant &value )
     612                 :            : {
     613                 :          0 :   if ( !layout )
     614                 :          0 :     return;
     615                 :            : 
     616                 :            :   //write variable to layout
     617                 :          0 :   QStringList variableNames = layout->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
     618                 :          0 :   QStringList variableValues = layout->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
     619                 :            : 
     620                 :          0 :   variableNames << name;
     621                 :          0 :   variableValues << value.toString();
     622                 :            : 
     623                 :          0 :   layout->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
     624                 :          0 :   layout->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
     625                 :          0 : }
     626                 :            : 
     627                 :          0 : void QgsExpressionContextUtils::setLayoutVariables( QgsLayout *layout, const QVariantMap &variables )
     628                 :            : {
     629                 :          0 :   if ( !layout )
     630                 :          0 :     return;
     631                 :            : 
     632                 :          0 :   QStringList variableNames;
     633                 :          0 :   QStringList variableValues;
     634                 :            : 
     635                 :          0 :   QVariantMap::const_iterator it = variables.constBegin();
     636                 :          0 :   for ( ; it != variables.constEnd(); ++it )
     637                 :            :   {
     638                 :          0 :     variableNames << it.key();
     639                 :          0 :     variableValues << it.value().toString();
     640                 :          0 :   }
     641                 :            : 
     642                 :          0 :   layout->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
     643                 :          0 :   layout->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
     644                 :          0 : }
     645                 :            : 
     646                 :          0 : QgsExpressionContextScope *QgsExpressionContextUtils::atlasScope( const QgsLayoutAtlas *atlas )
     647                 :            : {
     648                 :          0 :   QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Atlas" ) );
     649                 :          0 :   if ( !atlas )
     650                 :            :   {
     651                 :            :     //add some dummy atlas variables. This is done so that as in certain contexts we want to show
     652                 :            :     //users that these variables are available even if they have no current value
     653                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_pagename" ), QString(), true, true ) );
     654                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( QgsFeature() ), true, true ) );
     655                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), QVariant(), true, true ) );
     656                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( QgsGeometry() ), true, true ) );
     657                 :          0 :     return scope;
     658                 :            :   }
     659                 :            : 
     660                 :            :   //add known atlas variables
     661                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_totalfeatures" ), atlas->count(), true, true ) );
     662                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featurenumber" ), atlas->currentFeatureNumber() + 1, true, true ) );
     663                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_filename" ), atlas->currentFilename(), true, true ) );
     664                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_pagename" ), atlas->nameForPage( atlas->currentFeatureNumber() ), true, true ) );
     665                 :            : 
     666                 :          0 :   if ( atlas->enabled() && atlas->coverageLayer() )
     667                 :            :   {
     668                 :          0 :     scope->setFields( atlas->coverageLayer()->fields() );
     669                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layerid" ), atlas->coverageLayer()->id(), true ) );
     670                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layername" ), atlas->coverageLayer()->name(), true ) );
     671                 :          0 :   }
     672                 :            : 
     673                 :          0 :   if ( atlas->enabled() )
     674                 :            :   {
     675                 :          0 :     QgsFeature atlasFeature = atlas->layout()->reportContext().feature();
     676                 :          0 :     scope->setFeature( atlasFeature );
     677                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( atlasFeature ), true ) );
     678                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), FID_IS_NULL( atlasFeature.id() ) ? QVariant() : atlasFeature.id(), true ) );
     679                 :          0 :     scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( atlasFeature.geometry() ), true ) );
     680                 :          0 :   }
     681                 :            : 
     682                 :          0 :   return scope;
     683                 :          0 : }
     684                 :            : 
     685                 :          0 : QgsExpressionContextScope *QgsExpressionContextUtils::layoutItemScope( const QgsLayoutItem *item )
     686                 :            : {
     687                 :          0 :   QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layout Item" ) );
     688                 :          0 :   if ( !item )
     689                 :          0 :     return scope;
     690                 :            : 
     691                 :            :   //add variables defined in layout item properties
     692                 :          0 :   const QStringList variableNames = item->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
     693                 :          0 :   const QStringList variableValues = item->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
     694                 :            : 
     695                 :          0 :   int varIndex = 0;
     696                 :          0 :   for ( const QString &variableName : variableNames )
     697                 :            :   {
     698                 :          0 :     if ( varIndex >= variableValues.length() )
     699                 :            :     {
     700                 :          0 :       break;
     701                 :            :     }
     702                 :            : 
     703                 :          0 :     QVariant varValue = variableValues.at( varIndex );
     704                 :          0 :     varIndex++;
     705                 :          0 :     scope->setVariable( variableName, varValue );
     706                 :          0 :   }
     707                 :            : 
     708                 :            :   //add known layout item context variables
     709                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "item_id" ), item->id(), true ) );
     710                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "item_uuid" ), item->uuid(), true ) );
     711                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_page" ), item->page() + 1, true ) );
     712                 :            : 
     713                 :          0 :   if ( item->layout() )
     714                 :            :   {
     715                 :          0 :     const QgsLayoutItemPage *page = item->layout()->pageCollection()->page( item->page() );
     716                 :          0 :     if ( page )
     717                 :            :     {
     718                 :          0 :       const QSizeF s = page->sizeWithUnits().toQSizeF();
     719                 :          0 :       scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), s.height(), true ) );
     720                 :          0 :       scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), s.width(), true ) );
     721                 :          0 :     }
     722                 :            :     else
     723                 :            :     {
     724                 :          0 :       scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), QVariant(), true ) );
     725                 :          0 :       scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), QVariant(), true ) );
     726                 :            :     }
     727                 :          0 :   }
     728                 :            : 
     729                 :          0 :   return scope;
     730                 :          0 : }
     731                 :            : 
     732                 :          0 : void QgsExpressionContextUtils::setLayoutItemVariable( QgsLayoutItem *item, const QString &name, const QVariant &value )
     733                 :            : {
     734                 :          0 :   if ( !item )
     735                 :          0 :     return;
     736                 :            : 
     737                 :            :   //write variable to layout item
     738                 :          0 :   QStringList variableNames = item->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
     739                 :          0 :   QStringList variableValues = item->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
     740                 :            : 
     741                 :          0 :   variableNames << name;
     742                 :          0 :   variableValues << value.toString();
     743                 :            : 
     744                 :          0 :   item->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
     745                 :          0 :   item->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
     746                 :          0 : }
     747                 :            : 
     748                 :          0 : void QgsExpressionContextUtils::setLayoutItemVariables( QgsLayoutItem *item, const QVariantMap &variables )
     749                 :            : {
     750                 :          0 :   if ( !item )
     751                 :          0 :     return;
     752                 :            : 
     753                 :          0 :   QStringList variableNames;
     754                 :          0 :   QStringList variableValues;
     755                 :            : 
     756                 :          0 :   QVariantMap::const_iterator it = variables.constBegin();
     757                 :          0 :   for ( ; it != variables.constEnd(); ++it )
     758                 :            :   {
     759                 :          0 :     variableNames << it.key();
     760                 :          0 :     variableValues << it.value().toString();
     761                 :          0 :   }
     762                 :            : 
     763                 :          0 :   item->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
     764                 :          0 :   item->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
     765                 :          0 : }
     766                 :            : 
     767                 :          0 : QgsExpressionContextScope *QgsExpressionContextUtils::multiFrameScope( const QgsLayoutMultiFrame *frame )
     768                 :            : {
     769                 :          0 :   QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Multiframe Item" ) );
     770                 :          0 :   if ( !frame )
     771                 :          0 :     return scope;
     772                 :            : 
     773                 :            :   //add variables defined in layout item properties
     774                 :          0 :   const QStringList variableNames = frame->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
     775                 :          0 :   const QStringList variableValues = frame->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
     776                 :            : 
     777                 :          0 :   int varIndex = 0;
     778                 :          0 :   for ( const QString &variableName : variableNames )
     779                 :            :   {
     780                 :          0 :     if ( varIndex >= variableValues.length() )
     781                 :            :     {
     782                 :          0 :       break;
     783                 :            :     }
     784                 :            : 
     785                 :          0 :     QVariant varValue = variableValues.at( varIndex );
     786                 :          0 :     varIndex++;
     787                 :          0 :     scope->setVariable( variableName, varValue );
     788                 :          0 :   }
     789                 :            : 
     790                 :          0 :   return scope;
     791                 :          0 : }
     792                 :            : 
     793                 :          0 : void QgsExpressionContextUtils::setLayoutMultiFrameVariable( QgsLayoutMultiFrame *frame, const QString &name, const QVariant &value )
     794                 :            : {
     795                 :          0 :   if ( !frame )
     796                 :          0 :     return;
     797                 :            : 
     798                 :            :   //write variable to layout multiframe
     799                 :          0 :   QStringList variableNames = frame->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
     800                 :          0 :   QStringList variableValues = frame->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
     801                 :            : 
     802                 :          0 :   variableNames << name;
     803                 :          0 :   variableValues << value.toString();
     804                 :            : 
     805                 :          0 :   frame->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
     806                 :          0 :   frame->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
     807                 :          0 : }
     808                 :            : 
     809                 :          0 : void QgsExpressionContextUtils::setLayoutMultiFrameVariables( QgsLayoutMultiFrame *frame, const QVariantMap &variables )
     810                 :            : {
     811                 :          0 :   if ( !frame )
     812                 :          0 :     return;
     813                 :            : 
     814                 :          0 :   QStringList variableNames;
     815                 :          0 :   QStringList variableValues;
     816                 :            : 
     817                 :          0 :   QVariantMap::const_iterator it = variables.constBegin();
     818                 :          0 :   for ( ; it != variables.constEnd(); ++it )
     819                 :            :   {
     820                 :          0 :     variableNames << it.key();
     821                 :          0 :     variableValues << it.value().toString();
     822                 :          0 :   }
     823                 :            : 
     824                 :          0 :   frame->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
     825                 :          0 :   frame->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
     826                 :          0 : }
     827                 :            : 
     828                 :          0 : QgsExpressionContext QgsExpressionContextUtils::createFeatureBasedContext( const QgsFeature &feature, const QgsFields &fields )
     829                 :            : {
     830                 :          0 :   QgsExpressionContextScope *scope = new QgsExpressionContextScope();
     831                 :          0 :   scope->setFeature( feature );
     832                 :          0 :   scope->setFields( fields );
     833                 :          0 :   return QgsExpressionContext() << scope;
     834                 :          0 : }
     835                 :            : 
     836                 :          0 : QgsExpressionContextScope *QgsExpressionContextUtils::processingAlgorithmScope( const QgsProcessingAlgorithm *algorithm, const QVariantMap &parameters, QgsProcessingContext &context )
     837                 :            : {
     838                 :            :   // set aside for future use
     839                 :          0 :   Q_UNUSED( context )
     840                 :            : 
     841                 :          0 :   std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope( QObject::tr( "Algorithm" ) ) );
     842                 :          0 :   scope->addFunction( QStringLiteral( "parameter" ), new GetProcessingParameterValue( parameters ) );
     843                 :            : 
     844                 :          0 :   if ( !algorithm )
     845                 :          0 :     return scope.release();
     846                 :            : 
     847                 :            :   //add standard algorithm variables
     848                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "algorithm_id" ), algorithm->id(), true ) );
     849                 :            : 
     850                 :          0 :   return scope.release();
     851                 :          0 : }
     852                 :            : 
     853                 :          0 : QgsExpressionContextScope *QgsExpressionContextUtils::processingModelAlgorithmScope( const QgsProcessingModelAlgorithm *model, const QVariantMap &, QgsProcessingContext &context )
     854                 :            : {
     855                 :          0 :   std::unique_ptr< QgsExpressionContextScope > modelScope( new QgsExpressionContextScope( QObject::tr( "Model" ) ) );
     856                 :          0 :   QString modelPath;
     857                 :          0 :   if ( !model->sourceFilePath().isEmpty() )
     858                 :            :   {
     859                 :          0 :     modelPath = model->sourceFilePath();
     860                 :          0 :   }
     861                 :          0 :   else if ( context.project() )
     862                 :            :   {
     863                 :            :     // fallback to project path -- the model may be embedded in a project, OR an unsaved model. In either case the
     864                 :            :     // project path is a logical value to fall back to
     865                 :          0 :     modelPath = context.project()->projectStorage() ? context.project()->fileName() : context.project()->absoluteFilePath();
     866                 :          0 :   }
     867                 :            : 
     868                 :          0 :   const QString modelFolder = !modelPath.isEmpty() ? QFileInfo( modelPath ).path() : QString();
     869                 :          0 :   modelScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "model_path" ), QDir::toNativeSeparators( modelPath ), true ) );
     870                 :          0 :   modelScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "model_folder" ), QDir::toNativeSeparators( modelFolder ), true, true ) );
     871                 :          0 :   modelScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "model_name" ), model->displayName(), true ) );
     872                 :          0 :   modelScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "model_group" ), model->group(), true ) );
     873                 :            : 
     874                 :            :   // custom variables
     875                 :          0 :   const QVariantMap customVariables = model->variables();
     876                 :          0 :   for ( auto it = customVariables.constBegin(); it != customVariables.constEnd(); ++it )
     877                 :            :   {
     878                 :          0 :     modelScope->addVariable( QgsExpressionContextScope::StaticVariable( it.key(), it.value(), true ) );
     879                 :          0 :   }
     880                 :            : 
     881                 :          0 :   return modelScope.release();
     882                 :          0 : }
     883                 :            : 
     884                 :          0 : QgsExpressionContextScope *QgsExpressionContextUtils::notificationScope( const QString &message )
     885                 :            : {
     886                 :          0 :   std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope() );
     887                 :          0 :   scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "notification_message" ), message, true ) );
     888                 :          0 :   return scope.release();
     889                 :          0 : }
     890                 :            : 
     891                 :          0 : void QgsExpressionContextUtils::registerContextFunctions()
     892                 :            : {
     893                 :          0 :   QgsExpression::registerFunction( new GetNamedProjectColor( nullptr ) );
     894                 :          0 :   QgsExpression::registerFunction( new GetLayoutItemVariables( nullptr ) );
     895                 :          0 :   QgsExpression::registerFunction( new GetLayoutMapLayerCredits( nullptr ) );
     896                 :          0 :   QgsExpression::registerFunction( new GetLayerVisibility( QList<QgsMapLayer *>(), 0.0 ) );
     897                 :          0 :   QgsExpression::registerFunction( new GetProcessingParameterValue( QVariantMap() ) );
     898                 :          0 :   QgsExpression::registerFunction( new GetCurrentFormFieldValue( ) );
     899                 :          0 :   QgsExpression::registerFunction( new GetCurrentParentFormFieldValue( ) );
     900                 :          0 : }
     901                 :            : 
     902                 :          0 : bool QgsScopedExpressionFunction::usesGeometry( const QgsExpressionNodeFunction *node ) const
     903                 :            : {
     904                 :            :   Q_UNUSED( node )
     905                 :          0 :   return mUsesGeometry;
     906                 :            : }
     907                 :            : 
     908                 :          0 : QSet<QString> QgsScopedExpressionFunction::referencedColumns( const QgsExpressionNodeFunction *node ) const
     909                 :            : {
     910                 :            :   Q_UNUSED( node )
     911                 :          0 :   return mReferencedColumns;
     912                 :            : }
     913                 :            : 
     914                 :          0 : bool QgsScopedExpressionFunction::isStatic( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
     915                 :            : {
     916                 :          0 :   return allParamsStatic( node, parent, context );
     917                 :            : }
     918                 :            : 
     919                 :            : //
     920                 :            : // GetLayerVisibility
     921                 :            : //
     922                 :            : 
     923                 :          0 : QgsExpressionContextUtils::GetLayerVisibility::GetLayerVisibility( const QList<QgsMapLayer *> &layers, double scale )
     924                 :          0 :   : QgsScopedExpressionFunction( QStringLiteral( "is_layer_visible" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "id" ) ), QStringLiteral( "General" ) )
     925                 :          0 :   , mLayers( _qgis_listRawToQPointer( layers ) )
     926                 :          0 :   , mScale( scale )
     927                 :          0 : {
     928                 :          0 :   for ( const auto &layer : mLayers )
     929                 :            :   {
     930                 :          0 :     if ( layer->hasScaleBasedVisibility() )
     931                 :            :     {
     932                 :          0 :       mScaleBasedVisibilityDetails[ layer ] = qMakePair( layer->minimumScale(), layer->maximumScale() );
     933                 :          0 :     }
     934                 :            :   }
     935                 :          0 : }
     936                 :            : 
     937                 :          0 : QgsExpressionContextUtils::GetLayerVisibility::GetLayerVisibility()
     938                 :          0 :   : QgsScopedExpressionFunction( QStringLiteral( "is_layer_visible" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "id" ) ), QStringLiteral( "General" ) )
     939                 :          0 : {}
     940                 :            : 
     941                 :          0 : QVariant QgsExpressionContextUtils::GetLayerVisibility::func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
     942                 :            : {
     943                 :          0 :   if ( mLayers.isEmpty() )
     944                 :            :   {
     945                 :          0 :     return false;
     946                 :            :   }
     947                 :            : 
     948                 :          0 :   bool isVisible = false;
     949                 :          0 :   QgsMapLayer *layer = QgsExpressionUtils::getMapLayer( values.at( 0 ), parent );
     950                 :          0 :   if ( layer && mLayers.contains( layer ) )
     951                 :            :   {
     952                 :          0 :     isVisible = true;
     953                 :          0 :     if ( mScaleBasedVisibilityDetails.contains( layer ) && !qgsDoubleNear( mScale, 0.0 ) )
     954                 :            :     {
     955                 :          0 :       if ( ( !qgsDoubleNear( mScaleBasedVisibilityDetails[ layer ].first, 0.0 ) && mScale > mScaleBasedVisibilityDetails[ layer ].first ) ||
     956                 :          0 :            ( !qgsDoubleNear( mScaleBasedVisibilityDetails[ layer ].second, 0.0 ) && mScale < mScaleBasedVisibilityDetails[ layer ].second ) )
     957                 :            :       {
     958                 :          0 :         isVisible = false;
     959                 :          0 :       }
     960                 :          0 :     }
     961                 :          0 :   }
     962                 :            : 
     963                 :          0 :   return isVisible;
     964                 :          0 : }
     965                 :            : 
     966                 :          0 : QgsScopedExpressionFunction *QgsExpressionContextUtils::GetLayerVisibility::clone() const
     967                 :            : {
     968                 :          0 :   GetLayerVisibility *func = new GetLayerVisibility();
     969                 :          0 :   func->mLayers = mLayers;
     970                 :          0 :   func->mScale = mScale;
     971                 :          0 :   func->mScaleBasedVisibilityDetails = mScaleBasedVisibilityDetails;
     972                 :          0 :   return func;
     973                 :          0 : }

Generated by: LCOV version 1.14