From e005d8d308ee49b64240778825090e853f1c4891 Mon Sep 17 00:00:00 2001 From: Matthias Kuhn Date: Sat, 19 Sep 2020 22:41:47 +0200 Subject: [PATCH 1/2] Recalculate layout when legend item size changes Fixes https://github.com/qgis/QGIS/issues/38881 --- .../qgslayertreemodellegendnode.sip.in | 7 +++++ src/core/layertree/qgslayertreemodel.cpp | 12 ++++++++ src/core/layertree/qgslayertreemodel.h | 3 ++ .../layertree/qgslayertreemodellegendnode.cpp | 10 +++++++ .../layertree/qgslayertreemodellegendnode.h | 9 +++++- src/gui/layertree/qgslayertreeview.cpp | 28 +++++++++++++++---- src/gui/layertree/qgslayertreeview.h | 2 ++ 7 files changed, 64 insertions(+), 7 deletions(-) diff --git a/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in b/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in index dba949e2155f..3564d4f6cedc 100644 --- a/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in +++ b/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in @@ -207,6 +207,13 @@ Draws label on the right side of the item void dataChanged(); %Docstring Emitted on internal data change so the layer tree model can forward the signal to views +%End + + void sizeChanged(); +%Docstring +Emitted when the size of this node changes. + +.. versionadded:: 3.16 %End protected: diff --git a/src/core/layertree/qgslayertreemodel.cpp b/src/core/layertree/qgslayertreemodel.cpp index e59672988465..540970f7b8b4 100644 --- a/src/core/layertree/qgslayertreemodel.cpp +++ b/src/core/layertree/qgslayertreemodel.cpp @@ -868,6 +868,17 @@ void QgsLayerTreeModel::legendNodeDataChanged() emit dataChanged( index, index ); } +void QgsLayerTreeModel::legendNodeSizeChanged() +{ + QgsLayerTreeModelLegendNode *legendNode = qobject_cast( sender() ); + if ( !legendNode ) + return; + + QModelIndex index = legendNode2index( legendNode ); + if ( index.isValid() ) + emit dataChanged( index, index, QVector { Qt::SizeHintRole } ); +} + void QgsLayerTreeModel::connectToLayer( QgsLayerTreeLayer *nodeLayer ) { @@ -1293,6 +1304,7 @@ void QgsLayerTreeModel::addLegendToLayer( QgsLayerTreeLayer *nodeL ) { n->setParent( this ); connect( n, &QgsLayerTreeModelLegendNode::dataChanged, this, &QgsLayerTreeModel::legendNodeDataChanged ); + connect( n, &QgsLayerTreeModelLegendNode::sizeChanged, this, &QgsLayerTreeModel::legendNodeSizeChanged ); } // See if we have an embedded node - if we do, we will not use it among active nodes. diff --git a/src/core/layertree/qgslayertreemodel.h b/src/core/layertree/qgslayertreemodel.h index 385bb6dc43b3..668c075d9797 100644 --- a/src/core/layertree/qgslayertreemodel.h +++ b/src/core/layertree/qgslayertreemodel.h @@ -452,6 +452,9 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel double mLegendMapViewScale; QTimer mDeferLegendInvalidationTimer; + private slots: + void legendNodeSizeChanged(); + private: //! Returns a temporary render context diff --git a/src/core/layertree/qgslayertreemodellegendnode.cpp b/src/core/layertree/qgslayertreemodellegendnode.cpp index 5e373e556bdc..dd5eeba7194b 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.cpp +++ b/src/core/layertree/qgslayertreemodellegendnode.cpp @@ -68,6 +68,15 @@ QSizeF QgsLayerTreeModelLegendNode::userPatchSize() const return mUserSize; } +void QgsLayerTreeModelLegendNode::setUserPatchSize( QSizeF size ) +{ + if ( mUserSize == size ) + return; + + mUserSize = size; + emit sizeChanged(); +} + QgsLayerTreeModelLegendNode::ItemMetrics QgsLayerTreeModelLegendNode::draw( const QgsLegendSettings &settings, ItemContext *ctx ) { QFont symbolLabelFont = settings.style( QgsLegendStyle::SymbolLabel ).font(); @@ -1146,6 +1155,7 @@ void QgsWmsLegendNode::getLegendGraphicFinished( const QImage &image ) if ( image != mImage ) { mImage = image; + setUserPatchSize( mImage.size() ); emit dataChanged(); } mValid = true; // only if not null I guess diff --git a/src/core/layertree/qgslayertreemodellegendnode.h b/src/core/layertree/qgslayertreemodellegendnode.h index 574bade41e72..4078272a83b9 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.h +++ b/src/core/layertree/qgslayertreemodellegendnode.h @@ -107,7 +107,7 @@ class CORE_EXPORT QgsLayerTreeModelLegendNode : public QObject * \see userPatchSize() * \since QGIS 3.14 */ - virtual void setUserPatchSize( QSizeF size ) { mUserSize = size; } + virtual void setUserPatchSize( QSizeF size ); /** * Sets whether a forced column break should occur before the node. @@ -255,6 +255,13 @@ class CORE_EXPORT QgsLayerTreeModelLegendNode : public QObject //! Emitted on internal data change so the layer tree model can forward the signal to views void dataChanged(); + /** + * Emitted when the size of this node changes. + * + * \since QGIS 3.16 + */ + void sizeChanged(); + protected: //! Construct the node with pointer to its parent layer node explicit QgsLayerTreeModelLegendNode( QgsLayerTreeLayer *nodeL, QObject *parent SIP_TRANSFERTHIS = nullptr ); diff --git a/src/gui/layertree/qgslayertreeview.cpp b/src/gui/layertree/qgslayertreeview.cpp index ce85562a76ea..af009c051cee 100644 --- a/src/gui/layertree/qgslayertreeview.cpp +++ b/src/gui/layertree/qgslayertreeview.cpp @@ -76,28 +76,31 @@ QgsLayerTreeView::~QgsLayerTreeView() void QgsLayerTreeView::setModel( QAbstractItemModel *model ) { - if ( !qobject_cast( model ) ) + QgsLayerTreeModel *layerTreeModel = qobject_cast( model ); + if ( !layerTreeModel ) return; connect( model, &QAbstractItemModel::rowsInserted, this, &QgsLayerTreeView::modelRowsInserted ); connect( model, &QAbstractItemModel::rowsRemoved, this, &QgsLayerTreeView::modelRowsRemoved ); if ( mMessageBar ) - connect( layerTreeModel(), &QgsLayerTreeModel::messageEmitted, + connect( layerTreeModel, &QgsLayerTreeModel::messageEmitted, [ = ]( const QString & message, Qgis::MessageLevel level = Qgis::Info, int duration = 5 ) {mMessageBar->pushMessage( message, level, duration );} ); QTreeView::setModel( model ); - connect( layerTreeModel()->rootGroup(), &QgsLayerTreeNode::expandedChanged, this, &QgsLayerTreeView::onExpandedChanged ); - connect( layerTreeModel()->rootGroup(), &QgsLayerTreeNode::customPropertyChanged, this, &QgsLayerTreeView::onCustomPropertyChanged ); + connect( layerTreeModel->rootGroup(), &QgsLayerTreeNode::expandedChanged, this, &QgsLayerTreeView::onExpandedChanged ); + connect( layerTreeModel->rootGroup(), &QgsLayerTreeNode::customPropertyChanged, this, &QgsLayerTreeView::onCustomPropertyChanged ); connect( selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsLayerTreeView::onCurrentChanged ); - connect( layerTreeModel(), &QAbstractItemModel::modelReset, this, &QgsLayerTreeView::onModelReset ); + connect( layerTreeModel, &QAbstractItemModel::modelReset, this, &QgsLayerTreeView::onModelReset ); - updateExpandedStateFromNode( layerTreeModel()->rootGroup() ); + connect( layerTreeModel, &QgsLayerTreeModel::dataChanged, this, &QgsLayerTreeView::onDataChanged ); + + updateExpandedStateFromNode( layerTreeModel->rootGroup() ); } QgsLayerTreeModel *QgsLayerTreeView::layerTreeModel() const @@ -586,3 +589,16 @@ void QgsLayerTreeView::onHorizontalScroll( int value ) Q_UNUSED( value ) viewport()->update(); } + +void QgsLayerTreeView::onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles ) +{ + Q_UNUSED( topLeft ) + Q_UNUSED( bottomRight ) + + // If an item is resized asynchroneously (e.g. wms legend) + // The items below will need to be shifted vertically. + // This doesn't happen automatically, unless the viewport update is triggered. + + if ( roles.contains( Qt::SizeHintRole ) ) + viewport()->update(); +} diff --git a/src/gui/layertree/qgslayertreeview.h b/src/gui/layertree/qgslayertreeview.h index 34d96901fbf5..5b55dee639d4 100644 --- a/src/gui/layertree/qgslayertreeview.h +++ b/src/gui/layertree/qgslayertreeview.h @@ -248,6 +248,8 @@ class GUI_EXPORT QgsLayerTreeView : public QTreeView //! Handles updating the viewport to avoid flicker void onHorizontalScroll( int value ); + void onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles ); + protected: //! helper class with default actions. Lazily initialized. QgsLayerTreeViewDefaultActions *mDefaultActions = nullptr; From ebb8f8d2000eac35570f236a97cf8037f311db32 Mon Sep 17 00:00:00 2001 From: Matthias Kuhn Date: Sun, 20 Sep 2020 00:16:33 +0200 Subject: [PATCH 2/2] Fix typo --- src/gui/layertree/qgslayertreeview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/layertree/qgslayertreeview.cpp b/src/gui/layertree/qgslayertreeview.cpp index af009c051cee..f64551a5b6f5 100644 --- a/src/gui/layertree/qgslayertreeview.cpp +++ b/src/gui/layertree/qgslayertreeview.cpp @@ -595,7 +595,7 @@ void QgsLayerTreeView::onDataChanged( const QModelIndex &topLeft, const QModelIn Q_UNUSED( topLeft ) Q_UNUSED( bottomRight ) - // If an item is resized asynchroneously (e.g. wms legend) + // If an item is resized asynchronously (e.g. wms legend) // The items below will need to be shifted vertically. // This doesn't happen automatically, unless the viewport update is triggered.