Skip to content

Commit a0e35a3

Browse files
committedAug 22, 2015
Switch some composer expressions to contexts
1 parent f9a7820 commit a0e35a3

15 files changed

+470
-26
lines changed
 

‎python/core/composer/qgscomposeritem.sip

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,12 @@ class QgsComposerItem : QgsComposerObject, QGraphicsRectItem
630630
*/
631631
void setCurrentExportLayer( const int layerIdx = -1 );
632632

633+
/** Creates an expression context relating to the item's current state. The context includes
634+
* scopes for global, project, composition, atlas and item properties.
635+
* @note added in QGIS 2.12
636+
*/
637+
QgsExpressionContext* createExpressionContext() const /Factory/;
638+
633639
public slots:
634640
/** Sets the item rotation
635641
* @deprecated Use setItemRotation( double rotation ) instead

‎python/core/qgsexpressioncontext.sip

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,56 @@ class QgsExpressionContextUtils
404404
*/
405405
static void setLayerVariables( QgsMapLayer* layer, const QgsStringMap variables );
406406

407+
/** Creates a new scope which contains variables and functions relating to a QgsComposition.
408+
* For instance, number of pages and page sizes.
409+
* @param composition source composition
410+
*/
411+
static QgsExpressionContextScope* compositionScope( const QgsComposition *composition ) /Factory/;
412+
413+
/** Sets a composition context variable. This variable will be contained within scopes retrieved via
414+
* compositionScope().
415+
* @param composition target composition
416+
* @param name variable name
417+
* @param value variable value
418+
* @see setCompositionVariables()
419+
* @see compositionScope()
420+
*/
421+
static void setCompositionVariable( QgsComposition* composition, const QString& name, const QVariant& value );
422+
423+
/** Sets all composition context variables. Existing composition variables will be removed and replaced
424+
* with the variables specified.
425+
* @param composition target composition
426+
* @param variables new set of layer variables
427+
* @see setCompositionVariable()
428+
* @see compositionScope()
429+
*/
430+
static void setCompositionVariables( QgsComposition* composition, const QgsStringMap variables );
431+
432+
/** Creates a new scope which contains variables and functions relating to a QgsComposerItem.
433+
* For instance, item size and position.
434+
* @param composerItem source composer item
435+
*/
436+
static QgsExpressionContextScope* composerItemScope( const QgsComposerItem *composerItem ) /Factory/;
437+
438+
/** Sets a composer item context variable. This variable will be contained within scopes retrieved via
439+
* composerItemScope().
440+
* @param composerItem target composer item
441+
* @param name variable name
442+
* @param value variable value
443+
* @see setComposerItemVariables()
444+
* @see composerItemScope()
445+
*/
446+
static void setComposerItemVariable( QgsComposerItem* composerItem, const QString& name, const QVariant& value );
447+
448+
/** Sets all composition context variables. Existing compositoin variables will be removed and replaced
449+
* with the variables specified.
450+
* @param composerItem target composer item
451+
* @param variables new set of layer variables
452+
* @see setComposerItemVariable()
453+
* @see composerItemScope()
454+
*/
455+
static void setComposerItemVariables( QgsComposerItem* composerItem, const QgsStringMap variables );
456+
407457
/** Registers all known core functions provided by QgsExpressionContextScope objects.
408458
*/
409459
static void registerContextFunctions();

‎src/app/composer/qgscomposeritemwidget.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "qgscomposition.h"
2323
#include "qgspoint.h"
2424
#include "qgsdatadefinedbutton.h"
25+
#include "qgsexpressioncontext.h"
2526
#include <QColorDialog>
2627
#include <QPen>
2728

@@ -140,6 +141,13 @@ QgsComposerItemWidget::QgsComposerItemWidget( QWidget* parent, QgsComposerItem*
140141

141142
connect( mTransparencySlider, SIGNAL( valueChanged( int ) ), mTransparencySpnBx, SLOT( setValue( int ) ) );
142143

144+
QgsExpressionContext* context = mItem->createExpressionContext();
145+
mVariableEditor->setContext( context );
146+
mVariableEditor->setEditableScopeIndex( context->scopeCount() - 1 );
147+
delete context;
148+
149+
connect( mVariableEditor, SIGNAL( scopeChanged() ), this, SLOT( variablesChanged() ) );
150+
143151
//connect atlas signals to data defined buttons
144152
QgsAtlasComposition* atlas = atlasComposition();
145153
if ( atlas )
@@ -260,6 +268,11 @@ void QgsComposerItemWidget::changeItemPosition()
260268
mItem->endCommand();
261269
}
262270

271+
void QgsComposerItemWidget::variablesChanged()
272+
{
273+
QgsExpressionContextUtils::setComposerItemVariables( mItem, mVariableEditor->variablesInActiveScope() );
274+
}
275+
263276
QgsComposerItem::ItemPositionMode QgsComposerItemWidget::positionMode() const
264277
{
265278
if ( mUpperLeftCheckBox->checkState() == Qt::Checked )

‎src/app/composer/qgscomposeritemwidget.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ class QgsComposerItemWidget: public QgsComposerItemBaseWidget, private Ui::QgsCo
139139
// void changeItemTransparency( int value );
140140
void changeItemPosition();
141141

142+
private slots:
143+
144+
void variablesChanged();
145+
146+
142147
};
143148

144149
#endif //QGSCOMPOSERITEMWIDGET_H

‎src/app/composer/qgscompositionwidget.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "qgsstylev2.h"
2323
#include "qgssymbolv2selectordialog.h"
2424
#include "qgssymbollayerv2utils.h"
25+
#include "qgsexpressioncontext.h"
2526
#include <QColorDialog>
2627
#include <QWidget>
2728
#include <QPrinter> //for screen resolution
@@ -44,6 +45,14 @@ QgsCompositionWidget::QgsCompositionWidget( QWidget* parent, QgsComposition* c )
4445
//read with/height from composition and find suitable entries to display
4546
displayCompositionWidthHeight();
4647

48+
mVariableEditor->context()->appendScope( QgsExpressionContextUtils::globalScope() );
49+
mVariableEditor->context()->appendScope( QgsExpressionContextUtils::projectScope() );
50+
mVariableEditor->context()->appendScope( QgsExpressionContextUtils::compositionScope( mComposition ) );
51+
mVariableEditor->reloadContext();
52+
mVariableEditor->setEditableScopeIndex( 2 );
53+
54+
connect( mVariableEditor, SIGNAL( scopeChanged() ), this, SLOT( variablesChanged() ) );
55+
4756
if ( mComposition )
4857
{
4958
mNumPagesSpinBox->setValue( mComposition->numPages() );
@@ -170,6 +179,11 @@ void QgsCompositionWidget::populateDataDefinedButtons()
170179
mPaperOrientationDDBtn->blockSignals( false );
171180
}
172181

182+
void QgsCompositionWidget::variablesChanged()
183+
{
184+
QgsExpressionContextUtils::setCompositionVariables( mComposition, mVariableEditor->variablesInActiveScope() );
185+
}
186+
173187
void QgsCompositionWidget::setDataDefinedProperty( const QgsDataDefinedButton* ddBtn, QgsComposerObject::DataDefinedProperty property )
174188
{
175189
if ( !mComposition )

‎src/app/composer/qgscompositionwidget.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ class QgsCompositionWidget: public QWidget, private Ui::QgsCompositionWidgetBase
8383
/** Initializes data defined buttons to current atlas coverage layer*/
8484
void populateDataDefinedButtons();
8585

86+
void variablesChanged();
87+
8688
private:
8789
QgsComposition* mComposition;
8890
QMap<QString, QgsCompositionPaper> mPaperMap;

‎src/core/composer/qgsatlascomposition.cpp

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "qgsmaplayerregistry.h"
2828
#include "qgsproject.h"
2929
#include "qgsmessagelog.h"
30+
#include "qgsexpressioncontext.h"
3031

3132
QgsAtlasComposition::QgsAtlasComposition( QgsComposition* composition )
3233
: mComposition( composition )
@@ -218,6 +219,8 @@ int QgsAtlasComposition::updateFeatures()
218219
return 0;
219220
}
220221

222+
QgsExpressionContext expressionContext = createExpressionContext();
223+
221224
updateFilenameExpression();
222225

223226
// select all features with all attributes
@@ -248,7 +251,7 @@ int QgsAtlasComposition::updateFeatures()
248251
{
249252
nameExpression.reset( 0 );
250253
}
251-
nameExpression->prepare( mCoverageLayer->pendingFields() );
254+
nameExpression->prepare( &expressionContext );
252255
}
253256

254257
// We cannot use nextFeature() directly since the feature pointer is rewinded by the rendering process
@@ -260,10 +263,12 @@ int QgsAtlasComposition::updateFeatures()
260263

261264
while ( fit.nextFeature( feat ) )
262265
{
266+
expressionContext.setFeature( feat );
267+
263268
QString pageName;
264269
if ( !nameExpression.isNull() )
265270
{
266-
QVariant result = nameExpression->evaluate( &feat, mCoverageLayer->fields() );
271+
QVariant result = nameExpression->evaluate( &expressionContext );
267272
if ( nameExpression->hasEvalError() )
268273
{
269274
QgsMessageLog::logMessage( tr( "Atlas name eval error: %1" ).arg( nameExpression->evalErrorString() ), tr( "Composer" ) );
@@ -446,13 +451,15 @@ bool QgsAtlasComposition::prepareForFeature( const int featureI, const bool upda
446451
// retrieve the next feature, based on its id
447452
mCoverageLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeatureIds[ featureI ].first ) ).nextFeature( mCurrentFeature );
448453

454+
QgsExpressionContext expressionContext = createExpressionContext();
455+
449456
QgsExpression::setSpecialColumn( "$atlasfeatureid", mCurrentFeature.id() );
450457
QgsExpression::setSpecialColumn( "$atlasgeometry", QVariant::fromValue( *mCurrentFeature.constGeometry() ) );
451458
QgsExpression::setSpecialColumn( "$atlasfeature", QVariant::fromValue( mCurrentFeature ) );
452459
QgsExpression::setSpecialColumn( "$feature", QVariant(( int )featureI + 1 ) );
453460

454461
// generate filename for current feature
455-
if ( !evalFeatureFilename() )
462+
if ( !evalFeatureFilename( expressionContext ) )
456463
{
457464
//error evaluating filename
458465
return false;
@@ -820,14 +827,31 @@ bool QgsAtlasComposition::setFilenamePattern( const QString& pattern )
820827
return updateFilenameExpression();
821828
}
822829

830+
QgsExpressionContext QgsAtlasComposition::createExpressionContext()
831+
{
832+
QgsExpressionContext expressionContext;
833+
expressionContext << QgsExpressionContextUtils::globalScope()
834+
<< QgsExpressionContextUtils::projectScope();
835+
if ( mComposition )
836+
expressionContext << QgsExpressionContextUtils::compositionScope( mComposition );
837+
838+
expressionContext << new QgsExpressionContextScope( "Atlas" );
839+
if ( mCoverageLayer )
840+
expressionContext.lastScope()->setFields( mCoverageLayer->fields() );
841+
if ( mComposition->atlasMode() != QgsComposition::AtlasOff )
842+
expressionContext.lastScope()->setFeature( mCurrentFeature );
843+
844+
return expressionContext;
845+
}
846+
823847
bool QgsAtlasComposition::updateFilenameExpression()
824848
{
825849
if ( !mCoverageLayer )
826850
{
827851
return false;
828852
}
829853

830-
const QgsFields& fields = mCoverageLayer->fields();
854+
QgsExpressionContext expressionContext = createExpressionContext();
831855

832856
if ( mFilenamePattern.size() > 0 )
833857
{
@@ -841,23 +865,23 @@ bool QgsAtlasComposition::updateFilenameExpression()
841865
}
842866

843867
// prepare the filename expression
844-
mFilenameExpr->prepare( fields );
868+
mFilenameExpr->prepare( &expressionContext );
845869
}
846870

847871
//if atlas preview is currently enabled, regenerate filename for current feature
848872
if ( mComposition->atlasMode() == QgsComposition::PreviewAtlas )
849873
{
850-
evalFeatureFilename();
874+
evalFeatureFilename( expressionContext );
851875
}
852876
return true;
853877
}
854878

855-
bool QgsAtlasComposition::evalFeatureFilename()
879+
bool QgsAtlasComposition::evalFeatureFilename( const QgsExpressionContext &context )
856880
{
857881
//generate filename for current atlas feature
858882
if ( mFilenamePattern.size() > 0 && !mFilenameExpr.isNull() )
859883
{
860-
QVariant filenameRes = mFilenameExpr->evaluate( &mCurrentFeature, mCoverageLayer->fields() );
884+
QVariant filenameRes = mFilenameExpr->evaluate( &context );
861885
if ( mFilenameExpr->hasEvalError() )
862886
{
863887
QgsMessageLog::logMessage( tr( "Atlas filename evaluation error: %1" ).arg( mFilenameExpr->evalErrorString() ), tr( "Composer" ) );

‎src/core/composer/qgsatlascomposition.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class QgsComposerMap;
2929
class QgsComposition;
3030
class QgsVectorLayer;
3131
class QgsExpression;
32+
class QgsExpressionContext;
3233

3334
/** \ingroup MapComposer
3435
* Class used to render an Atlas, iterating over geometry features.
@@ -338,7 +339,7 @@ class CORE_EXPORT QgsAtlasComposition : public QObject
338339
/** Evaluates filename for current feature
339340
* @returns true if feature filename was successfully evaluated
340341
*/
341-
bool evalFeatureFilename();
342+
bool evalFeatureFilename( const QgsExpressionContext &context );
342343

343344
QgsComposition* mComposition;
344345

@@ -396,6 +397,8 @@ class CORE_EXPORT QgsAtlasComposition : public QObject
396397
//computes the extent of the current feature, in the crs of the specified map
397398
void computeExtent( QgsComposerMap *map );
398399

400+
QgsExpressionContext createExpressionContext();
401+
399402
//list of predefined scales
400403
QVector<qreal> mPredefinedScales;
401404
};

‎src/core/composer/qgscomposeritem.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "qgslogger.h"
4141
#include "qgssymbollayerv2utils.h" //for pointOnLineWithDistance
4242
#include "qgsmaprenderer.h" //for getCompositionMode
43+
#include "qgsexpressioncontext.h"
4344

4445
#include <cmath>
4546

@@ -846,6 +847,24 @@ bool QgsComposerItem::shouldDrawItem() const
846847
return !mEvaluatedExcludeFromExports;
847848
}
848849

850+
QgsExpressionContext* QgsComposerItem::createExpressionContext() const
851+
{
852+
QgsExpressionContext* context = new QgsExpressionContext();
853+
context->appendScope( QgsExpressionContextUtils::globalScope() );
854+
context->appendScope( QgsExpressionContextUtils::projectScope() );
855+
if ( mComposition )
856+
{
857+
context->appendScope( QgsExpressionContextUtils::compositionScope( mComposition ) );
858+
if ( mComposition->atlasComposition().enabled() )
859+
{
860+
context->appendScope( QgsExpressionContextUtils::atlasScope( &mComposition->atlasComposition() ) );
861+
}
862+
}
863+
864+
context->appendScope( QgsExpressionContextUtils::composerItemScope( this ) );
865+
return context;
866+
}
867+
849868
void QgsComposerItem::drawBackground( QPainter* p )
850869
{
851870
if ( mBackground && p )

‎src/core/composer/qgscomposeritem.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class QGraphicsLineItem;
3131
class QgsComposerItemGroup;
3232
class QgsDataDefined;
3333
class QgsComposition;
34+
class QgsExpressionContext;
3435

3536
/** \ingroup MapComposer
3637
* A item that forms part of a map composition.
@@ -582,6 +583,12 @@ class CORE_EXPORT QgsComposerItem: public QgsComposerObject, public QGraphicsRec
582583
*/
583584
virtual void setCurrentExportLayer( const int layerIdx = -1 ) { mCurrentExportLayer = layerIdx; }
584585

586+
/** Creates an expression context relating to the item's current state. The context includes
587+
* scopes for global, project, composition, atlas and item properties.
588+
* @note added in QGIS 2.12
589+
*/
590+
QgsExpressionContext* createExpressionContext() const;
591+
585592
public slots:
586593
/** Sets the item rotation
587594
* @deprecated Use setItemRotation( double rotation ) instead

‎src/core/composer/qgscomposerlabel.cpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "qgsproject.h"
2626
#include "qgsdistancearea.h"
2727
#include "qgsfontutils.h"
28+
#include "qgsexpressioncontext.h"
2829

2930
#include "qgswebview.h"
3031
#include "qgswebframe.h"
@@ -269,19 +270,16 @@ void QgsComposerLabel::refreshExpressionContext()
269270
if ( !mComposition )
270271
return;
271272

273+
QgsVectorLayer* layer = 0;
272274
if ( mComposition->atlasComposition().enabled() )
273275
{
274-
mExpressionLayer = mComposition->atlasComposition().coverageLayer();
275-
if ( mComposition->atlasMode() != QgsComposition::AtlasOff )
276-
{
277-
mExpressionFeature.reset( new QgsFeature( mComposition->atlasComposition().feature() ) );
278-
}
276+
layer = mComposition->atlasComposition().coverageLayer();
279277
}
280278

281279
//setup distance area conversion
282-
if ( mExpressionLayer )
280+
if ( layer )
283281
{
284-
mDistanceArea->setSourceCrs( mExpressionLayer->crs().srsid() );
282+
mDistanceArea->setSourceCrs( layer->crs().srsid() );
285283
}
286284
else
287285
{
@@ -300,7 +298,16 @@ QString QgsComposerLabel::displayText() const
300298
replaceDateText( displayText );
301299
QMap<QString, QVariant> subs = mSubstitutions;
302300
subs[ "$page" ] = QVariant(( int )mComposition->itemPageNumber( this ) + 1 );
303-
return QgsExpression::replaceExpressionText( displayText, mExpressionFeature.data(), mExpressionLayer, &subs, mDistanceArea );
301+
302+
QScopedPointer<QgsExpressionContext> context( createExpressionContext() );
303+
//overwrite layer/feature if they have been set via setExpressionContext
304+
//TODO remove when setExpressionContext is removed
305+
if ( mExpressionFeature.data() )
306+
context->setFeature( *mExpressionFeature.data() );
307+
if ( mExpressionLayer )
308+
context->setFields( mExpressionLayer->fields() );
309+
310+
return QgsExpression::replaceExpressionText( displayText, context.data(), &subs, mDistanceArea );
304311
}
305312

306313
void QgsComposerLabel::replaceDateText( QString& text ) const

‎src/core/qgsexpressioncontext.cpp

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#include "qgsproject.h"
2323
#include "qgssymbollayerv2utils.h"
2424
#include "qgsgeometry.h"
25+
#include "qgscomposition.h"
26+
#include "qgscomposeritem.h"
27+
#include "qgsatlascomposition.h"
2528
#include <QSettings>
2629
#include <QDir>
2730

@@ -586,6 +589,167 @@ void QgsExpressionContextUtils::setLayerVariables( QgsMapLayer* layer, const Qgs
586589
layer->setCustomProperty( "variableValues", variableValues );
587590
}
588591

592+
QgsExpressionContextScope *QgsExpressionContextUtils::compositionScope( const QgsComposition *composition )
593+
{
594+
QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Composition" ) );
595+
if ( !composition )
596+
return scope;
597+
598+
//add variables defined in composition properties
599+
QStringList variableNames = composition->customProperty( "variableNames" ).toStringList();
600+
QStringList variableValues = composition->customProperty( "variableValues" ).toStringList();
601+
602+
int varIndex = 0;
603+
foreach ( QString variableName, variableNames )
604+
{
605+
if ( varIndex >= variableValues.length() )
606+
{
607+
break;
608+
}
609+
610+
QVariant varValue = variableValues.at( varIndex );
611+
varIndex++;
612+
scope->setVariable( variableName, varValue );
613+
}
614+
615+
//add known composition context variables
616+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "composer_numpages", composition->numPages(), true ) );
617+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "composer_page_height", composition->paperHeight(), true ) );
618+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "composer_page_width", composition->paperWidth(), true ) );
619+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "composer_dpi", composition->printResolution(), true ) );
620+
621+
return scope;
622+
}
623+
624+
void QgsExpressionContextUtils::setCompositionVariable( QgsComposition* composition, const QString& name, const QVariant& value )
625+
{
626+
if ( !composition )
627+
return;
628+
629+
//write variable to composition
630+
QStringList variableNames = composition->customProperty( "variableNames" ).toStringList();
631+
QStringList variableValues = composition->customProperty( "variableValues" ).toStringList();
632+
633+
variableNames << name;
634+
variableValues << value.toString();
635+
636+
composition->setCustomProperty( "variableNames", variableNames );
637+
composition->setCustomProperty( "variableValues", variableValues );
638+
}
639+
640+
void QgsExpressionContextUtils::setCompositionVariables( QgsComposition* composition, const QgsStringMap variables )
641+
{
642+
if ( !composition )
643+
return;
644+
645+
QStringList variableNames;
646+
QStringList variableValues;
647+
648+
Q_FOREACH ( QString variable, variables.keys() )
649+
{
650+
variableNames << variable;
651+
variableValues << variables.value( variable );
652+
}
653+
654+
composition->setCustomProperty( "variableNames", variableNames );
655+
composition->setCustomProperty( "variableValues", variableValues );
656+
}
657+
658+
QgsExpressionContextScope* QgsExpressionContextUtils::atlasScope( const QgsAtlasComposition* atlas )
659+
{
660+
QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Atlas" ) );
661+
if ( !atlas )
662+
return scope;
663+
664+
//add known atlas variables
665+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_numpages", atlas->numFeatures(), true ) );
666+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_page", atlas->currentFeatureNumber() + 1, true ) );
667+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_filename", atlas->currentFilename(), true ) );
668+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_pagename", atlas->currentPageName(), true ) );
669+
670+
if ( atlas->enabled() && atlas->coverageLayer() )
671+
{
672+
scope->setFields( atlas->coverageLayer()->fields() );
673+
}
674+
675+
if ( atlas->enabled() )
676+
{
677+
QgsFeature atlasFeature = atlas->feature();
678+
scope->setFeature( atlasFeature );
679+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_featureid", atlasFeature.id(), true ) );
680+
}
681+
682+
return scope;
683+
}
684+
685+
QgsExpressionContextScope *QgsExpressionContextUtils::composerItemScope( const QgsComposerItem *composerItem )
686+
{
687+
QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Composer Item" ) );
688+
if ( !composerItem )
689+
return scope;
690+
691+
//add variables defined in composer item properties
692+
QStringList variableNames = composerItem->customProperty( "variableNames" ).toStringList();
693+
QStringList variableValues = composerItem->customProperty( "variableValues" ).toStringList();
694+
695+
int varIndex = 0;
696+
foreach ( QString variableName, variableNames )
697+
{
698+
if ( varIndex >= variableValues.length() )
699+
{
700+
break;
701+
}
702+
703+
QVariant varValue = variableValues.at( varIndex );
704+
varIndex++;
705+
scope->setVariable( variableName, varValue );
706+
}
707+
708+
//add known composer item context variables
709+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "item_id", composerItem->id(), true ) );
710+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "item_uuid", composerItem->uuid(), true ) );
711+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "item_left", composerItem->sceneBoundingRect().left(), true ) );
712+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "item_top", composerItem->sceneBoundingRect().top(), true ) );
713+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "item_width", composerItem->sceneBoundingRect().width(), true ) );
714+
scope->addVariable( QgsExpressionContextScope::StaticVariable( "item_height", composerItem->sceneBoundingRect().height(), true ) );
715+
716+
return scope;
717+
}
718+
719+
void QgsExpressionContextUtils::setComposerItemVariable( QgsComposerItem* composerItem, const QString& name, const QVariant& value )
720+
{
721+
if ( !composerItem )
722+
return;
723+
724+
//write variable to composer item
725+
QStringList variableNames = composerItem->customProperty( "variableNames" ).toStringList();
726+
QStringList variableValues = composerItem->customProperty( "variableValues" ).toStringList();
727+
728+
variableNames << name;
729+
variableValues << value.toString();
730+
731+
composerItem->setCustomProperty( "variableNames", variableNames );
732+
composerItem->setCustomProperty( "variableValues", variableValues );
733+
}
734+
735+
void QgsExpressionContextUtils::setComposerItemVariables( QgsComposerItem* composerItem, const QgsStringMap variables )
736+
{
737+
if ( !composerItem )
738+
return;
739+
740+
QStringList variableNames;
741+
QStringList variableValues;
742+
743+
Q_FOREACH ( QString variable, variables.keys() )
744+
{
745+
variableNames << variable;
746+
variableValues << variables.value( variable );
747+
}
748+
749+
composerItem->setCustomProperty( "variableNames", variableNames );
750+
composerItem->setCustomProperty( "variableValues", variableValues );
751+
}
752+
589753
QgsExpressionContext QgsExpressionContextUtils::createFeatureBasedContext( const QgsFeature &feature, const QgsFields &fields )
590754
{
591755
QgsExpressionContextScope* scope = new QgsExpressionContextScope();

‎src/core/qgsexpressioncontext.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424

2525
class QgsExpression;
2626
class QgsMapLayer;
27+
class QgsComposition;
28+
class QgsComposerItem;
29+
class QgsAtlasComposition;
2730

2831
/** \ingroup core
2932
* \class QgsScopedExpressionFunction
@@ -430,6 +433,62 @@ class CORE_EXPORT QgsExpressionContextUtils
430433
*/
431434
static void setLayerVariables( QgsMapLayer* layer, const QgsStringMap variables );
432435

436+
/** Creates a new scope which contains variables and functions relating to a QgsComposition.
437+
* For instance, number of pages and page sizes.
438+
* @param composition source composition
439+
*/
440+
static QgsExpressionContextScope* compositionScope( const QgsComposition *composition );
441+
442+
/** Sets a composition context variable. This variable will be contained within scopes retrieved via
443+
* compositionScope().
444+
* @param composition target composition
445+
* @param name variable name
446+
* @param value variable value
447+
* @see setCompositionVariables()
448+
* @see compositionScope()
449+
*/
450+
static void setCompositionVariable( QgsComposition* composition, const QString& name, const QVariant& value );
451+
452+
/** Sets all composition context variables. Existing composition variables will be removed and replaced
453+
* with the variables specified.
454+
* @param composition target composition
455+
* @param variables new set of layer variables
456+
* @see setCompositionVariable()
457+
* @see compositionScope()
458+
*/
459+
static void setCompositionVariables( QgsComposition* composition, const QgsStringMap variables );
460+
461+
/** Creates a new scope which contains variables and functions relating to a QgsAtlasComposition.
462+
* For instance, current page name and number.
463+
* @param atlas source atlas
464+
*/
465+
static QgsExpressionContextScope* atlasScope( const QgsAtlasComposition* atlas );
466+
467+
/** Creates a new scope which contains variables and functions relating to a QgsComposerItem.
468+
* For instance, item size and position.
469+
* @param composerItem source composer item
470+
*/
471+
static QgsExpressionContextScope* composerItemScope( const QgsComposerItem *composerItem );
472+
473+
/** Sets a composer item context variable. This variable will be contained within scopes retrieved via
474+
* composerItemScope().
475+
* @param composerItem target composer item
476+
* @param name variable name
477+
* @param value variable value
478+
* @see setComposerItemVariables()
479+
* @see composerItemScope()
480+
*/
481+
static void setComposerItemVariable( QgsComposerItem* composerItem, const QString& name, const QVariant& value );
482+
483+
/** Sets all composition context variables. Existing compositoin variables will be removed and replaced
484+
* with the variables specified.
485+
* @param composerItem target composer item
486+
* @param variables new set of layer variables
487+
* @see setComposerItemVariable()
488+
* @see composerItemScope()
489+
*/
490+
static void setComposerItemVariables( QgsComposerItem* composerItem, const QgsStringMap variables );
491+
433492
/** Helper function for creating an expression context which contains just a feature and fields
434493
* collection. Generally this method should not be used as the created context does not include
435494
* standard scopes such as the global and project scopes.

‎src/ui/qgscomposeritemwidgetbase.ui

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,25 @@
703703
</layout>
704704
</widget>
705705
</item>
706+
<item>
707+
<widget class="QgsCollapsibleGroupBox" name="groupBox_3">
708+
<property name="title">
709+
<string>Variables</string>
710+
</property>
711+
<layout class="QVBoxLayout" name="verticalLayout_4">
712+
<item>
713+
<widget class="QgsVariableEditorWidget" name="mVariableEditor" native="true">
714+
<property name="minimumSize">
715+
<size>
716+
<width>0</width>
717+
<height>200</height>
718+
</size>
719+
</property>
720+
</widget>
721+
</item>
722+
</layout>
723+
</widget>
724+
</item>
706725
<item>
707726
<spacer name="verticalSpacer">
708727
<property name="orientation">
@@ -759,6 +778,18 @@
759778
<extends>QComboBox</extends>
760779
<header>qgsblendmodecombobox.h</header>
761780
</customwidget>
781+
<customwidget>
782+
<class>QgsCollapsibleGroupBox</class>
783+
<extends>QGroupBox</extends>
784+
<header>qgscollapsiblegroupbox.h</header>
785+
<container>1</container>
786+
</customwidget>
787+
<customwidget>
788+
<class>QgsVariableEditorWidget</class>
789+
<extends>QWidget</extends>
790+
<header location="global">qgsvariableeditorwidget.h</header>
791+
<container>1</container>
792+
</customwidget>
762793
</customwidgets>
763794
<tabstops>
764795
<tabstop>mGeneralOptionsGroupBox</tabstop>

‎src/ui/qgscompositionwidgetbase.ui

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,16 @@
2323
<property name="spacing">
2424
<number>0</number>
2525
</property>
26-
<property name="margin">
26+
<property name="leftMargin">
27+
<number>0</number>
28+
</property>
29+
<property name="topMargin">
30+
<number>0</number>
31+
</property>
32+
<property name="rightMargin">
33+
<number>0</number>
34+
</property>
35+
<property name="bottomMargin">
2736
<number>0</number>
2837
</property>
2938
<item>
@@ -50,9 +59,9 @@
5059
<property name="geometry">
5160
<rect>
5261
<x>0</x>
53-
<y>0</y>
62+
<y>-337</y>
5463
<width>327</width>
55-
<height>586</height>
64+
<height>841</height>
5665
</rect>
5766
</property>
5867
<layout class="QVBoxLayout" name="verticalLayout_2">
@@ -137,7 +146,7 @@
137146
<property name="maximum">
138147
<double>99999.000000000000000</double>
139148
</property>
140-
<property name="showClearButton">
149+
<property name="showClearButton" stdset="0">
141150
<bool>false</bool>
142151
</property>
143152
</widget>
@@ -180,7 +189,7 @@
180189
<property name="maximum">
181190
<double>99999.000000000000000</double>
182191
</property>
183-
<property name="showClearButton">
192+
<property name="showClearButton" stdset="0">
184193
<bool>false</bool>
185194
</property>
186195
</widget>
@@ -234,7 +243,7 @@
234243
<property name="minimum">
235244
<number>1</number>
236245
</property>
237-
<property name="showClearButton">
246+
<property name="showClearButton" stdset="0">
238247
<bool>false</bool>
239248
</property>
240249
</widget>
@@ -317,7 +326,7 @@
317326
<property name="maximum">
318327
<number>3000</number>
319328
</property>
320-
<property name="showClearButton">
329+
<property name="showClearButton" stdset="0">
321330
<bool>false</bool>
322331
</property>
323332
</widget>
@@ -406,7 +415,7 @@
406415
<property name="maximum">
407416
<double>9999.000000000000000</double>
408417
</property>
409-
<property name="showClearButton">
418+
<property name="showClearButton" stdset="0">
410419
<bool>false</bool>
411420
</property>
412421
</widget>
@@ -466,14 +475,33 @@
466475
<property name="maximum">
467476
<number>200</number>
468477
</property>
469-
<property name="showClearButton">
478+
<property name="showClearButton" stdset="0">
470479
<bool>false</bool>
471480
</property>
472481
</widget>
473482
</item>
474483
</layout>
475484
</widget>
476485
</item>
486+
<item>
487+
<widget class="QgsCollapsibleGroupBox" name="groupBox_2">
488+
<property name="title">
489+
<string>Variables</string>
490+
</property>
491+
<layout class="QVBoxLayout" name="verticalLayout_4">
492+
<item>
493+
<widget class="QgsVariableEditorWidget" name="mVariableEditor" native="true">
494+
<property name="minimumSize">
495+
<size>
496+
<width>0</width>
497+
<height>200</height>
498+
</size>
499+
</property>
500+
</widget>
501+
</item>
502+
</layout>
503+
</widget>
504+
</item>
477505
<item>
478506
<spacer name="verticalSpacer">
479507
<property name="orientation">
@@ -495,6 +523,18 @@
495523
</widget>
496524
<layoutdefault spacing="6" margin="11"/>
497525
<customwidgets>
526+
<customwidget>
527+
<class>QgsCollapsibleGroupBox</class>
528+
<extends>QGroupBox</extends>
529+
<header>qgscollapsiblegroupbox.h</header>
530+
<container>1</container>
531+
</customwidget>
532+
<customwidget>
533+
<class>QgsVariableEditorWidget</class>
534+
<extends>QWidget</extends>
535+
<header location="global">qgsvariableeditorwidget.h</header>
536+
<container>1</container>
537+
</customwidget>
498538
<customwidget>
499539
<class>QgsDataDefinedButton</class>
500540
<extends>QToolButton</extends>

0 commit comments

Comments
 (0)
Please sign in to comment.