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 ¶ms )
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 ¶meters, 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 : }
|