Recalculate layout when legend item size changes

Fixes https://github.com/qgis/QGIS/issues/38881
This commit is contained in:
Matthias Kuhn 2020-09-19 22:41:47 +02:00 committed by Nyall Dawson
parent 673d6727ee
commit 2eaf5e6d29
7 changed files with 64 additions and 7 deletions

View File

@ -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:

View File

@ -868,6 +868,17 @@ void QgsLayerTreeModel::legendNodeDataChanged()
emit dataChanged( index, index );
}
void QgsLayerTreeModel::legendNodeSizeChanged()
{
QgsLayerTreeModelLegendNode *legendNode = qobject_cast<QgsLayerTreeModelLegendNode *>( sender() );
if ( !legendNode )
return;
QModelIndex index = legendNode2index( legendNode );
if ( index.isValid() )
emit dataChanged( index, index, QVector<int> { 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.

View File

@ -458,6 +458,9 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
double mLegendMapViewScale;
QTimer mDeferLegendInvalidationTimer;
private slots:
void legendNodeSizeChanged();
private:
//! Returns a temporary render context

View File

@ -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

View File

@ -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 );

View File

@ -76,28 +76,31 @@ QgsLayerTreeView::~QgsLayerTreeView()
void QgsLayerTreeView::setModel( QAbstractItemModel *model )
{
if ( !qobject_cast<QgsLayerTreeModel *>( model ) )
QgsLayerTreeModel *layerTreeModel = qobject_cast<QgsLayerTreeModel *>( 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<int> &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();
}

View File

@ -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<int> &roles );
protected:
//! helper class with default actions. Lazily initialized.
QgsLayerTreeViewDefaultActions *mDefaultActions = nullptr;