Skip to content

Commit c9251c5

Browse files
committedOct 19, 2016
Avoid creating multiple render contexts when calculating legend
node size Partial fix for qgis slowdown when using layer with large number of legend nodes
1 parent cf60049 commit c9251c5

File tree

6 files changed

+66
-12
lines changed

6 files changed

+66
-12
lines changed
 

‎python/core/layertree/qgslayertreemodel.sip

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class QgsLayerTreeModel : QAbstractItemModel
166166
//! Get hints about map view - to be used in legend nodes. Arguments that are not null will receive values.
167167
//! If there are no valid map view data (from previous call to setLegendMapViewData()), returned values are zeros.
168168
//! @note added in 2.6
169-
void legendMapViewData( double *mapUnitsPerPixel /Out/, int *dpi /Out/, double *scale /Out/ );
169+
void legendMapViewData( double *mapUnitsPerPixel /Out/, int *dpi /Out/, double *scale /Out/ ) const;
170170

171171
//! Get map of map layer style overrides (key: layer ID, value: style name) where a different style should be used instead of the current one
172172
//! @note added in 2.10

‎python/core/layertree/qgslayertreemodellegendnode.sip

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,23 @@ class QgsSymbolLegendNode : QgsLayerTreeModelLegendNode
141141
//! @note added in 2.10
142142
QSize iconSize() const;
143143

144-
//! Get the minimum icon size to prevent cropping
145-
//! @note added in 2.10
144+
/**
145+
* Calculates the minimum icon size to prevent cropping. When evaluating
146+
* the size for multiple icons it is more efficient to create a single
147+
* render context in advance and use the variant which accepts a QgsRenderContext
148+
* argument.
149+
* @note added in 2.10
150+
*/
146151
QSize minimumIconSize() const;
147152

153+
/**
154+
* Calculates the minimum icon size to prevent cropping. When evaluating
155+
* the size for multiple icons it is more efficient to create a single
156+
* render context in advance and call this method instead of minimumIconSize().
157+
* @note added in QGIS 2.18
158+
*/
159+
QSize minimumIconSize( QgsRenderContext &context ) const;
160+
148161
/** Returns the symbol used by the legend node.
149162
* @see setSymbol()
150163
* @note added in QGIS 2.14

‎src/core/layertree/qgslayertreemodel.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ void QgsLayerTreeModel::setLegendMapViewData( double mapUnitsPerPixel, int dpi,
663663
refreshScaleBasedLayers();
664664
}
665665

666-
void QgsLayerTreeModel::legendMapViewData( double* mapUnitsPerPixel, int* dpi, double* scale )
666+
void QgsLayerTreeModel::legendMapViewData( double* mapUnitsPerPixel, int* dpi, double* scale ) const
667667
{
668668
if ( mapUnitsPerPixel ) *mapUnitsPerPixel = mLegendMapViewMupp;
669669
if ( dpi ) *dpi = mLegendMapViewDpi;
@@ -1269,6 +1269,22 @@ void QgsLayerTreeModel::tryBuildLegendTree( LayerLegendData& data )
12691269
}
12701270
}
12711271

1272+
QgsRenderContext* QgsLayerTreeModel::createTemporaryRenderContext() const
1273+
{
1274+
double scale = 0.0;
1275+
double mupp = 0.0;
1276+
int dpi = 0;
1277+
legendMapViewData( &mupp, &dpi, &scale );
1278+
bool validData = !qgsDoubleNear( mupp, 0.0 ) && dpi != 0 && !qgsDoubleNear( scale, 0.0 );
1279+
1280+
// setup temporary render context
1281+
QScopedPointer<QgsRenderContext> context( new QgsRenderContext );
1282+
context->setScaleFactor( dpi / 25.4 );
1283+
context->setRendererScale( scale );
1284+
context->setMapToPixel( QgsMapToPixel( mupp ) );
1285+
return validData ? context.take() : nullptr;
1286+
}
1287+
12721288

12731289
QgsLayerTreeModelLegendNode* QgsLayerTreeModel::index2legendNode( const QModelIndex& index )
12741290
{
@@ -1470,6 +1486,8 @@ void QgsLayerTreeModel::invalidateLegendMapBasedData()
14701486
// we do that here because for symbols with size defined in map units
14711487
// the symbol sizes changes depends on the zoom level
14721488

1489+
QScopedPointer<QgsRenderContext> context( createTemporaryRenderContext() );
1490+
14731491
Q_FOREACH ( const LayerLegendData& data, mLegend )
14741492
{
14751493
QList<QgsSymbolLegendNode*> symbolNodes;
@@ -1479,7 +1497,7 @@ void QgsLayerTreeModel::invalidateLegendMapBasedData()
14791497
QgsSymbolLegendNode* n = dynamic_cast<QgsSymbolLegendNode*>( legendNode );
14801498
if ( n )
14811499
{
1482-
const QSize sz( n->minimumIconSize() );
1500+
const QSize sz( n->minimumIconSize( *context ) );
14831501
const QString parentKey( n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString() );
14841502
widthMax[parentKey] = qMax( sz.width(), widthMax.contains( parentKey ) ? widthMax[parentKey] : 0 );
14851503
n->setIconSize( sz );

‎src/core/layertree/qgslayertreemodel.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class QgsMapHitTest;
3131
class QgsMapLayer;
3232
class QgsMapSettings;
3333
class QgsExpression;
34+
class QgsRenderContext;
3435

3536
/** \ingroup core
3637
* The QgsLayerTreeModel class is model implementation for Qt item views framework.
@@ -191,7 +192,7 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
191192
//! Get hints about map view - to be used in legend nodes. Arguments that are not null will receive values.
192193
//! If there are no valid map view data (from previous call to setLegendMapViewData()), returned values are zeros.
193194
//! @note added in 2.6
194-
void legendMapViewData( double *mapUnitsPerPixel, int *dpi, double *scale );
195+
void legendMapViewData( double *mapUnitsPerPixel, int *dpi, double *scale ) const;
195196

196197
//! Get map of map layer style overrides (key: layer ID, value: style name) where a different style should be used instead of the current one
197198
//! @note added in 2.10
@@ -328,6 +329,11 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
328329
int mLegendMapViewDpi;
329330
double mLegendMapViewScale;
330331
QTimer mDeferLegendInvalidationTimer;
332+
333+
private:
334+
335+
//! Returns a temporary render context
336+
QgsRenderContext* createTemporaryRenderContext() const;
331337
};
332338

333339
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsLayerTreeModel::Flags )

‎src/core/layertree/qgslayertreemodellegendnode.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,23 +157,27 @@ Qt::ItemFlags QgsSymbolLegendNode::flags() const
157157

158158

159159
QSize QgsSymbolLegendNode::minimumIconSize() const
160+
{
161+
QScopedPointer<QgsRenderContext> context( createTemporaryRenderContext() );
162+
return minimumIconSize( *context );
163+
}
164+
165+
QSize QgsSymbolLegendNode::minimumIconSize( QgsRenderContext& context ) const
160166
{
161167
QSize minSz( 16, 16 );
162168
if ( mItem.symbol() && mItem.symbol()->type() == QgsSymbol::Marker )
163169
{
164-
QScopedPointer<QgsRenderContext> context( createTemporaryRenderContext() );
165170
minSz = QgsImageOperation::nonTransparentImageRect(
166171
QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), QSize( 512, 512 ),
167-
context.data() ).toImage(),
172+
&context ).toImage(),
168173
minSz,
169174
true ).size();
170175
}
171176
else if ( mItem.symbol() && mItem.symbol()->type() == QgsSymbol::Line )
172177
{
173-
QScopedPointer<QgsRenderContext> context( createTemporaryRenderContext() );
174178
minSz = QgsImageOperation::nonTransparentImageRect(
175179
QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), QSize( minSz.width(), 512 ),
176-
context.data() ).toImage(),
180+
&context ).toImage(),
177181
minSz,
178182
true ).size();
179183
}

‎src/core/layertree/qgslayertreemodellegendnode.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,23 @@ class CORE_EXPORT QgsSymbolLegendNode : public QgsLayerTreeModelLegendNode
171171
//! @note added in 2.10
172172
QSize iconSize() const { return mIconSize; }
173173

174-
//! Get the minimum icon size to prevent cropping
175-
//! @note added in 2.10
174+
/**
175+
* Calculates the minimum icon size to prevent cropping. When evaluating
176+
* the size for multiple icons it is more efficient to create a single
177+
* render context in advance and use the variant which accepts a QgsRenderContext
178+
* argument.
179+
* @note added in 2.10
180+
*/
176181
QSize minimumIconSize() const;
177182

183+
/**
184+
* Calculates the minimum icon size to prevent cropping. When evaluating
185+
* the size for multiple icons it is more efficient to create a single
186+
* render context in advance and call this method instead of minimumIconSize().
187+
* @note added in QGIS 2.18
188+
*/
189+
QSize minimumIconSize( QgsRenderContext &context ) const;
190+
178191
/** Returns the symbol used by the legend node.
179192
* @see setSymbol()
180193
* @note added in QGIS 2.14

0 commit comments

Comments
 (0)
Please sign in to comment.