From 673d6727ee0b99ea2ff0bd8df498134706341a00 Mon Sep 17 00:00:00 2001 From: Matthias Kuhn Date: Sun, 20 Sep 2020 13:18:16 +0200 Subject: [PATCH] Improve legend performance Only recalculate the position of the icons for affected legend nodes. Avoids brute forcing over complex legends as soon as something is changed. Fixes #38890 --- .../layertree/qgslayertreemodel.sip.in | 1 + src/core/layertree/qgslayertreemodel.cpp | 19 ++++++++++++------- src/core/layertree/qgslayertreemodel.h | 6 ++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/python/core/auto_generated/layertree/qgslayertreemodel.sip.in b/python/core/auto_generated/layertree/qgslayertreemodel.sip.in index 641ef6cf394..41434334cd6 100644 --- a/python/core/auto_generated/layertree/qgslayertreemodel.sip.in +++ b/python/core/auto_generated/layertree/qgslayertreemodel.sip.in @@ -415,6 +415,7 @@ Filter nodes from QgsMapLayerLegend according to the current filtering rules + }; QFlags operator|(QgsLayerTreeModel::Flag f1, QFlags f2); diff --git a/src/core/layertree/qgslayertreemodel.cpp b/src/core/layertree/qgslayertreemodel.cpp index e5967298846..e3080652608 100644 --- a/src/core/layertree/qgslayertreemodel.cpp +++ b/src/core/layertree/qgslayertreemodel.cpp @@ -1318,7 +1318,8 @@ void QgsLayerTreeModel::addLegendToLayer( QgsLayerTreeLayer *nodeL ) int count = legendTree ? legendTree->children[nullptr].count() : filteredLstNew.count(); - if ( !filteredLstNew.isEmpty() ) beginInsertRows( node2index( nodeL ), 0, count - 1 ); + if ( !filteredLstNew.isEmpty() ) + beginInsertRows( node2index( nodeL ), 0, count - 1 ); LayerLegendData data; data.originalNodes = lstNew; @@ -1328,10 +1329,12 @@ void QgsLayerTreeModel::addLegendToLayer( QgsLayerTreeLayer *nodeL ) mLegend[nodeL] = data; - if ( !filteredLstNew.isEmpty() ) endInsertRows(); + if ( !filteredLstNew.isEmpty() ) + endInsertRows(); // invalidate map based data even if the data is not map-based to make sure // the symbol sizes are computed at least once + mInvalidatedNodes.insert( nodeL ); legendInvalidateMapBasedData(); } @@ -1575,7 +1578,7 @@ void QgsLayerTreeModel::legendInvalidateMapBasedData() if ( !testFlag( DeferredLegendInvalidation ) ) invalidateLegendMapBasedData(); else - mDeferLegendInvalidationTimer.start( 1000 ); + mDeferLegendInvalidationTimer.start( 10 ); } void QgsLayerTreeModel::invalidateLegendMapBasedData() @@ -1583,15 +1586,17 @@ void QgsLayerTreeModel::invalidateLegendMapBasedData() // we have varying icon sizes, and we want icon to be centered and // text to be left aligned, so we have to compute the max width of icons // - // we do that for nodes who share a common parent + // we do that for nodes which share a common parent // // we do that here because for symbols with size defined in map units // the symbol sizes changes depends on the zoom level std::unique_ptr context( createTemporaryRenderContext() ); - for ( const LayerLegendData &data : qgis::as_const( mLegend ) ) + for ( QgsLayerTreeLayer *layerNode : qgis::as_const( mInvalidatedNodes ) ) { + const LayerLegendData &data = mLegend.value( layerNode ); + QList symbolNodes; QMap widthMax; for ( QgsLayerTreeModelLegendNode *legendNode : qgis::as_const( data.originalNodes ) ) @@ -1606,8 +1611,7 @@ void QgsLayerTreeModel::invalidateLegendMapBasedData() symbolNodes.append( n ); } } - const auto constSymbolNodes = symbolNodes; - for ( QgsSymbolLegendNode *n : constSymbolNodes ) + for ( QgsSymbolLegendNode *n : qgis::as_const( symbolNodes ) ) { const QString parentKey( n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString() ); Q_ASSERT( widthMax[parentKey] > 0 ); @@ -1618,6 +1622,7 @@ void QgsLayerTreeModel::invalidateLegendMapBasedData() legendNode->invalidateMapBasedData(); } + mInvalidatedNodes.clear(); } // Legend nodes routines - end diff --git a/src/core/layertree/qgslayertreemodel.h b/src/core/layertree/qgslayertreemodel.h index 385bb6dc43b..2d68c6efe2b 100644 --- a/src/core/layertree/qgslayertreemodel.h +++ b/src/core/layertree/qgslayertreemodel.h @@ -435,6 +435,12 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel //! Per layer data about layer's legend nodes QHash mLegend; + /** + * Keep track of layer nodes for which the legend + * size needs to be recalculated + */ + QSet mInvalidatedNodes; + QFont mFontLayer; QFont mFontGroup;