Skip to content

Commit 43bcc0c

Browse files
committed
Finish porting composer to expression contexts
1 parent 5cb874c commit 43bcc0c

20 files changed

+189
-84
lines changed

python/core/composer/qgscomposerhtml.sip

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,15 +185,16 @@ class QgsComposerHtml: QgsComposerMultiFrame
185185
/** Reloads the html source from the url and redraws the item.
186186
* @param useCache set to true to use a cached copy of remote html
187187
* content
188+
* @param context expression context for evaluating data defined urls and expressions in html
188189
* @see setUrl
189190
* @see url
190191
*/
191-
void loadHtml( const bool useCache = false );
192+
void loadHtml( const bool useCache = false, const QgsExpressionContext* context = 0 );
192193

193194
/** Recalculates the frame sizes for the current viewport dimensions*/
194195
void recalculateFrameSizes();
195196
void refreshExpressionContext();
196197

197-
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties );
198+
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext* context = 0 );
198199

199200
};

python/core/composer/qgscomposeritem.sip

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -658,9 +658,10 @@ class QgsComposerItem : QgsComposerObject, QGraphicsRectItem
658658
* @param property data defined property to refresh. If property is set to
659659
* QgsComposerItem::AllProperties then all data defined properties for the item will be
660660
* refreshed.
661+
* @param context expression context for evaluating data defined expressions
661662
* @note this method was added in version 2.5
662663
*/
663-
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties );
664+
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext* context = 0 );
664665

665666
protected:
666667

@@ -767,11 +768,12 @@ class QgsComposerItem : QgsComposerObject, QGraphicsRectItem
767768
* @param resizeOnly set to true if the item is only being resized. If true then
768769
* the position of the returned rect will be adjusted to account for the item's
769770
* position mode
771+
* @param context expression context for evaluating data defined expressions
770772
* @returns bounding box rectangle for item after data defined size and position have been
771773
* set and position mode has been accounted for
772774
* @note added in QGIS 2.5
773775
*/
774-
QRectF evalItemRect( const QRectF &newRect, const bool resizeOnly = false );
776+
QRectF evalItemRect( const QRectF &newRect, const bool resizeOnly = false, const QgsExpressionContext* context = 0 );
775777

776778
/** Returns whether the item should be drawn in the current context
777779
* @returns true if item should be drawn

python/core/composer/qgscomposermap.sip

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ class QgsComposerMap : QgsComposerItem
777777
/** @deprecated use QgsComposerMapOverview::overviewExtentChanged instead*/
778778
void overviewExtentChanged();
779779

780-
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties );
780+
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext* context = 0 );
781781

782782
protected slots:
783783

python/core/composer/qgscomposerobject.sip

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,20 +145,22 @@ class QgsComposerObject : QObject
145145
* @param property data defined property to refresh. If property is set to
146146
* QgsComposerItem::AllProperties then all data defined properties for the item will be
147147
* refreshed.
148+
* @context expression context for evaluating data defined expressions
148149
* @note this method was added in version 2.5
149150
*/
150-
virtual void refreshDataDefinedProperty( const DataDefinedProperty property = AllProperties );
151-
151+
virtual void refreshDataDefinedProperty( const DataDefinedProperty property = AllProperties, const QgsExpressionContext* context = 0 );
152152

153153
protected:
154154

155155
/** Evaluate a data defined property and return the calculated value
156156
* @returns true if data defined property could be successfully evaluated
157157
* @param property data defined property to evaluate
158158
* @param expressionValue QVariant for storing the evaluated value
159+
* @param context expression context for evaluating expressions. Must have feature and fields set to current
160+
* atlas feature and coverage layer fields prior to calling this method.
159161
* @note this method was added in version 2.5
160162
*/
161-
bool dataDefinedEvaluate( const QgsComposerObject::DataDefinedProperty property, QVariant &expressionValue ) const;
163+
bool dataDefinedEvaluate( const QgsComposerObject::DataDefinedProperty property, QVariant &expressionValue, const QgsExpressionContext& context = QgsExpressionContext() ) const;
162164

163165
signals:
164166
/** Emitted when the item changes. Signifies that the item widgets must update the

python/core/composer/qgscomposerpicture.sip

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,11 @@ class QgsComposerPicture: QgsComposerItem
246246

247247
/** Recalculates the source image (if using an expression for picture's source)
248248
* and reloads and redraws the picture.
249+
* @param context expression context for evaluating data defined picture sources
249250
* @note added in 2.3
250251
*/
251-
void refreshPicture();
252-
252+
void refreshPicture( const QgsExpressionContext* context = 0 );
253+
253254
/** Prepares the picture's source expression after it is altered or the compositions
254255
* atlas coverage layer changes.
255256
* @note added in 2.3
@@ -262,7 +263,7 @@ class QgsComposerPicture: QgsComposerItem
262263
*/
263264
void recalculateSize();
264265

265-
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties );
266+
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext *context = 0 );
266267

267268
signals:
268269
/** Is emitted on picture rotation change*/

python/core/composer/qgscomposition.sip

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,9 +673,10 @@ class QgsComposition : QGraphicsScene
673673
* @param property data defined property to refresh. If property is set to
674674
* QgsComposerItem::AllProperties then all data defined properties for the composition will be
675675
* refreshed.
676+
* @param context expression context for evaluating data defined expressions
676677
* @note this method was added in version 2.5
677678
*/
678-
void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties );
679+
void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext* context = 0 );
679680

680681
protected:
681682
void init();

src/core/composer/qgscomposerattributetable.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,9 @@ bool QgsComposerAttributeTable::getFeatureAttributes( QList<QgsAttributeMap> &at
375375
return false;
376376
}
377377

378+
QScopedPointer< QgsExpressionContext > context( createExpressionContext() );
379+
context->setFields( mVectorLayer->fields() );
380+
378381
attributeMaps.clear();
379382

380383
//prepare filter expression
@@ -421,10 +424,11 @@ bool QgsComposerAttributeTable::getFeatureAttributes( QList<QgsAttributeMap> &at
421424

422425
while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures )
423426
{
427+
context->setFeature( f );
424428
//check feature against filter
425429
if ( activeFilter && !filterExpression.isNull() )
426430
{
427-
QVariant result = filterExpression->evaluate( &f, mVectorLayer->fields() );
431+
QVariant result = filterExpression->evaluate( context.data() );
428432
// skip this feature if the filter evaluation is false
429433
if ( !result.toBool() )
430434
{
@@ -447,9 +451,9 @@ bool QgsComposerAttributeTable::getFeatureAttributes( QList<QgsAttributeMap> &at
447451
{
448452
// Lets assume it's an expression
449453
QgsExpression* expression = new QgsExpression(( *columnIt )->attribute() );
450-
expression->setCurrentRowNumber( counter + 1 );
451-
expression->prepare( mVectorLayer->fields() );
452-
QVariant value = expression->evaluate( f );
454+
context->lastScope()->setVariable( QString( "_rownum_" ), counter + 1 );
455+
expression->prepare( context.data() );
456+
QVariant value = expression->evaluate( context.data() );
453457
attributeMaps.last().insert( i, value.toString() );
454458
}
455459

src/core/composer/qgscomposerattributetablev2.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,9 @@ bool QgsComposerAttributeTableV2::getTableContents( QgsComposerTableContents &co
451451
return false;
452452
}
453453

454+
QScopedPointer< QgsExpressionContext > context( createExpressionContext() );
455+
context->setFields( layer->fields() );
456+
454457
//prepare filter expression
455458
QScopedPointer<QgsExpression> filterExpression;
456459
bool activeFilter = false;
@@ -511,10 +514,11 @@ bool QgsComposerAttributeTableV2::getTableContents( QgsComposerTableContents &co
511514

512515
while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures )
513516
{
517+
context->setFeature( f );
514518
//check feature against filter
515519
if ( activeFilter && !filterExpression.isNull() )
516520
{
517-
QVariant result = filterExpression->evaluate( &f, layer->fields() );
521+
QVariant result = filterExpression->evaluate( context.data() );
518522
// skip this feature if the filter evaluation is false
519523
if ( !result.toBool() )
520524
{
@@ -551,9 +555,9 @@ bool QgsComposerAttributeTableV2::getTableContents( QgsComposerTableContents &co
551555
{
552556
// Lets assume it's an expression
553557
QgsExpression* expression = new QgsExpression(( *columnIt )->attribute() );
554-
expression->setCurrentRowNumber( counter + 1 );
555-
expression->prepare( layer->fields() );
556-
QVariant value = expression->evaluate( f );
558+
context->lastScope()->setVariable( QString( "_rownum_" ), counter + 1 );
559+
expression->prepare( context.data() );
560+
QVariant value = expression->evaluate( context.data() );
557561
currentRow << value;
558562
}
559563
}

src/core/composer/qgscomposerhtml.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,21 @@ void QgsComposerHtml::setEvaluateExpressions( bool evaluateExpressions )
122122
emit changed();
123123
}
124124

125-
void QgsComposerHtml::loadHtml( const bool useCache )
125+
void QgsComposerHtml::loadHtml( const bool useCache, const QgsExpressionContext *context )
126126
{
127127
if ( !mWebPage )
128128
{
129129
return;
130130
}
131131

132+
const QgsExpressionContext* evalContext = context;
133+
QScopedPointer< QgsExpressionContext > scopedContext;
134+
if ( !evalContext )
135+
{
136+
scopedContext.reset( createExpressionContext() );
137+
evalContext = scopedContext.data();
138+
}
139+
132140
QString loadedHtml;
133141
switch ( mContentMode )
134142
{
@@ -139,7 +147,7 @@ void QgsComposerHtml::loadHtml( const bool useCache )
139147

140148
//data defined url set?
141149
QVariant exprVal;
142-
if ( dataDefinedEvaluate( QgsComposerObject::SourceUrl, exprVal ) )
150+
if ( dataDefinedEvaluate( QgsComposerObject::SourceUrl, exprVal, *evalContext ) )
143151
{
144152
currentUrl = exprVal.toString().trimmed();;
145153
QgsDebugMsg( QString( "exprVal Source Url:%1" ).arg( currentUrl ) );
@@ -168,7 +176,7 @@ void QgsComposerHtml::loadHtml( const bool useCache )
168176
//evaluate expressions
169177
if ( mEvaluateExpressions )
170178
{
171-
loadedHtml = QgsExpression::replaceExpressionText( loadedHtml, &mExpressionFeature, mExpressionLayer, 0, mDistanceArea );
179+
loadedHtml = QgsExpression::replaceExpressionText( loadedHtml, evalContext, 0, mDistanceArea );
172180
}
173181

174182
mLoaded = false;
@@ -552,12 +560,20 @@ void QgsComposerHtml::refreshExpressionContext()
552560
loadHtml( true );
553561
}
554562

555-
void QgsComposerHtml::refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property )
563+
void QgsComposerHtml::refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property, const QgsExpressionContext* context )
556564
{
565+
const QgsExpressionContext* evalContext = context;
566+
QScopedPointer< QgsExpressionContext > scopedContext;
567+
if ( !evalContext )
568+
{
569+
scopedContext.reset( createExpressionContext() );
570+
evalContext = scopedContext.data();
571+
}
572+
557573
//updates data defined properties and redraws item to match
558574
if ( property == QgsComposerObject::SourceUrl || property == QgsComposerObject::AllProperties )
559575
{
560-
loadHtml( true );
576+
loadHtml( true, evalContext );
561577
}
562-
QgsComposerObject::refreshDataDefinedProperty( property );
578+
QgsComposerObject::refreshDataDefinedProperty( property, context );
563579
}

src/core/composer/qgscomposerhtml.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,16 +210,17 @@ class CORE_EXPORT QgsComposerHtml: public QgsComposerMultiFrame
210210
/** Reloads the html source from the url and redraws the item.
211211
* @param useCache set to true to use a cached copy of remote html
212212
* content
213+
* @param context expression context for evaluating data defined urls and expressions in html
213214
* @see setUrl
214215
* @see url
215216
*/
216-
void loadHtml( const bool useCache = false );
217+
void loadHtml( const bool useCache = false, const QgsExpressionContext* context = 0 );
217218

218219
/** Recalculates the frame sizes for the current viewport dimensions*/
219220
void recalculateFrameSizes() override;
220221
void refreshExpressionContext();
221222

222-
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties ) override;
223+
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext* context = 0 ) override;
223224

224225
private slots:
225226
void frameLoaded( bool ok = true );

src/core/composer/qgscomposeritem.cpp

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -897,16 +897,17 @@ void QgsComposerItem::setBlendMode( const QPainter::CompositionMode blendMode )
897897
{
898898
mBlendMode = blendMode;
899899
// Update the composer effect to use the new blend mode
900-
refreshBlendMode();
900+
QScopedPointer< QgsExpressionContext > context( createExpressionContext() );
901+
refreshBlendMode( *context.data() );
901902
}
902903

903-
void QgsComposerItem::refreshBlendMode()
904+
void QgsComposerItem::refreshBlendMode( const QgsExpressionContext& context )
904905
{
905906
QPainter::CompositionMode blendMode = mBlendMode;
906907

907908
//data defined blend mode set?
908909
QVariant exprVal;
909-
if ( dataDefinedEvaluate( QgsComposerObject::BlendMode, exprVal ) && !exprVal.isNull() )
910+
if ( dataDefinedEvaluate( QgsComposerObject::BlendMode, exprVal, context ) && !exprVal.isNull() )
910911
{
911912
QString blendstr = exprVal.toString().trimmed();
912913
QPainter::CompositionMode blendModeD = QgsSymbolLayerV2Utils::decodeBlendMode( blendstr );
@@ -922,16 +923,17 @@ void QgsComposerItem::refreshBlendMode()
922923
void QgsComposerItem::setTransparency( const int transparency )
923924
{
924925
mTransparency = transparency;
925-
refreshTransparency( true );
926+
QScopedPointer< QgsExpressionContext > context( createExpressionContext() );
927+
refreshTransparency( true, *context.data() );
926928
}
927929

928-
void QgsComposerItem::refreshTransparency( const bool updateItem )
930+
void QgsComposerItem::refreshTransparency( const bool updateItem, const QgsExpressionContext& context )
929931
{
930932
int transparency = mTransparency;
931933

932934
//data defined transparency set?
933935
QVariant exprVal;
934-
if ( dataDefinedEvaluate( QgsComposerObject::Transparency, exprVal ) )
936+
if ( dataDefinedEvaluate( QgsComposerObject::Transparency, exprVal, context ) )
935937
{
936938
bool ok;
937939
int transparencyD = exprVal.toInt( &ok );
@@ -1072,16 +1074,17 @@ void QgsComposerItem::setItemRotation( const double r, const bool adjustPosition
10721074
mItemRotation = r;
10731075
}
10741076

1075-
refreshRotation( true, adjustPosition );
1077+
QScopedPointer< QgsExpressionContext > context( createExpressionContext() );
1078+
refreshRotation( true, adjustPosition, *context.data() );
10761079
}
10771080

1078-
void QgsComposerItem::refreshRotation( const bool updateItem, const bool adjustPosition )
1081+
void QgsComposerItem::refreshRotation( const bool updateItem, const bool adjustPosition, const QgsExpressionContext& context )
10791082
{
10801083
double rotation = mItemRotation;
10811084

10821085
//data defined rotation set?
10831086
QVariant exprVal;
1084-
if ( dataDefinedEvaluate( QgsComposerObject::ItemRotation, exprVal ) )
1087+
if ( dataDefinedEvaluate( QgsComposerObject::ItemRotation, exprVal, context ) )
10851088
{
10861089
bool ok;
10871090
double rotD = exprVal.toDouble( &ok );
@@ -1355,38 +1358,48 @@ void QgsComposerItem::repaint()
13551358
updateItem();
13561359
}
13571360

1358-
void QgsComposerItem::refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property )
1361+
void QgsComposerItem::refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property, const QgsExpressionContext *context )
13591362
{
1363+
//maintain 2.10 API
1364+
//TODO QGIS 3.0 - remove this
1365+
const QgsExpressionContext* evalContext = context;
1366+
QScopedPointer< QgsExpressionContext > scopedContext;
1367+
if ( !evalContext )
1368+
{
1369+
scopedContext.reset( createExpressionContext() );
1370+
evalContext = scopedContext.data();
1371+
}
1372+
13601373
//update data defined properties and redraw item to match
13611374
if ( property == QgsComposerObject::PositionX || property == QgsComposerObject::PositionY ||
13621375
property == QgsComposerObject::ItemWidth || property == QgsComposerObject::ItemHeight ||
13631376
property == QgsComposerObject::AllProperties )
13641377
{
13651378
QRectF beforeRect = QRectF( pos().x(), pos().y(), rect().width(), rect().height() );
1366-
QRectF evaluatedRect = evalItemRect( beforeRect );
1379+
QRectF evaluatedRect = evalItemRect( beforeRect, false, evalContext );
13671380
if ( evaluatedRect != beforeRect )
13681381
{
13691382
setSceneRect( evaluatedRect );
13701383
}
13711384
}
13721385
if ( property == QgsComposerObject::ItemRotation || property == QgsComposerObject::AllProperties )
13731386
{
1374-
refreshRotation( false, true );
1387+
refreshRotation( false, true, *evalContext );
13751388
}
13761389
if ( property == QgsComposerObject::Transparency || property == QgsComposerObject::AllProperties )
13771390
{
1378-
refreshTransparency( false );
1391+
refreshTransparency( false, *evalContext );
13791392
}
13801393
if ( property == QgsComposerObject::BlendMode || property == QgsComposerObject::AllProperties )
13811394
{
1382-
refreshBlendMode();
1395+
refreshBlendMode( *evalContext );
13831396
}
13841397
if ( property == QgsComposerObject::ExcludeFromExports || property == QgsComposerObject::AllProperties )
13851398
{
13861399
bool exclude = mExcludeFromExports;
13871400
//data defined exclude from exports set?
13881401
QVariant exprVal;
1389-
if ( dataDefinedEvaluate( QgsComposerObject::ExcludeFromExports, exprVal ) && !exprVal.isNull() )
1402+
if ( dataDefinedEvaluate( QgsComposerObject::ExcludeFromExports, exprVal, *evalContext ) && !exprVal.isNull() )
13901403
{
13911404
exclude = exprVal.toBool();
13921405
}

0 commit comments

Comments
 (0)