Skip to content
Permalink
Browse files

[feature][layouts] Expose control over layer legend splitting behavio…

…r on a layer-by-layer basis

This allows users to manually override the legend's default setting for "split layers"
on a layer-by-layer basis, by double clicking a layer in the layout legend panel
and choosing whether that layer:
- follows the default legend setting for splitting
- can ALWAYS be split over multiple columns (regardless of the legend's setting)
or
- can NEVER be split over multiple columns (regardless of the legend's setting)

Sponsored by SLYR
  • Loading branch information
nyalldawson committed May 6, 2020
1 parent 0d5ea7d commit 1e0b890dc17617a7a8f4f256a9e286d8bbe2020f
@@ -177,6 +177,35 @@ symbol width or height from :py:class:`QgsLegendSettings`.

.. seealso:: :py:func:`patchSize`

.. versionadded:: 3.14
%End

enum LegendNodesSplitBehavior
{
UseDefaultLegendSetting,
AllowSplittingLegendNodesOverMultipleColumns,
PreventSplittingLegendNodesOverMultipleColumns,
};

LegendNodesSplitBehavior legendSplitBehavior() const;
%Docstring
Returns the column split behavior for the node.

This value controls how legend nodes belonging the to layer may be split over multiple columns in legends.

.. seealso:: :py:func:`setLegendSplitBehavior`

.. versionadded:: 3.14
%End

void setLegendSplitBehavior( LegendNodesSplitBehavior behavior );
%Docstring
Sets the column split ``behavior`` for the node.

This value controls how legend nodes belonging the to layer may be split over multiple columns in legends.

.. seealso:: :py:func:`legendSplitBehavior`

.. versionadded:: 3.14
%End

@@ -42,6 +42,7 @@ QgsLayerTreeLayer::QgsLayerTreeLayer( const QgsLayerTreeLayer &other )
, mLayerName( other.mLayerName )
, mPatchShape( other.mPatchShape )
, mPatchSize( other.mPatchSize )
, mSplitBehavior( other.mSplitBehavior )
{
attachToLayer();
}
@@ -134,6 +135,8 @@ QgsLayerTreeLayer *QgsLayerTreeLayer::readXml( QDomElement &element, const QgsRe

nodeLayer->setPatchSize( QgsSymbolLayerUtils::decodeSize( element.attribute( QStringLiteral( "patch_size" ) ) ) );

nodeLayer->setLegendSplitBehavior( static_cast< LegendNodesSplitBehavior >( element.attribute( QStringLiteral( "legend_split_behavior" ), QStringLiteral( "0" ) ).toInt() ) );

return nodeLayer;
}

@@ -170,6 +173,8 @@ void QgsLayerTreeLayer::writeXml( QDomElement &parentElement, const QgsReadWrite
}
elem.setAttribute( QStringLiteral( "patch_size" ), QgsSymbolLayerUtils::encodeSize( mPatchSize ) );

elem.setAttribute( QStringLiteral( "legend_split_behavior" ), mSplitBehavior );

writeCommonXml( elem );

parentElement.appendChild( elem );
@@ -181,6 +181,38 @@ class CORE_EXPORT QgsLayerTreeLayer : public QgsLayerTreeNode
*/
void setPatchSize( QSizeF size ) { mPatchSize = size; }

/**
* Legend node column split behavior.
*
* \since QGIS 3.14
*/
enum LegendNodesSplitBehavior
{
UseDefaultLegendSetting, //!< Inherit default legend column splitting setting
AllowSplittingLegendNodesOverMultipleColumns, //!< Allow splitting node's legend nodes across multiple columns
PreventSplittingLegendNodesOverMultipleColumns, //!< Prevent splitting node's legend nodes across multiple columns
};

/**
* Returns the column split behavior for the node.
*
* This value controls how legend nodes belonging the to layer may be split over multiple columns in legends.
*
* \see setLegendSplitBehavior()
* \since QGIS 3.14
*/
LegendNodesSplitBehavior legendSplitBehavior() const { return mSplitBehavior; }

/**
* Sets the column split \a behavior for the node.
*
* This value controls how legend nodes belonging the to layer may be split over multiple columns in legends.
*
* \see legendSplitBehavior()
* \since QGIS 3.14
*/
void setLegendSplitBehavior( LegendNodesSplitBehavior behavior ) { mSplitBehavior = behavior; }

signals:

/**
@@ -233,6 +265,7 @@ class CORE_EXPORT QgsLayerTreeLayer : public QgsLayerTreeNode

QgsLegendPatchShape mPatchShape;
QSizeF mPatchSize;
LegendNodesSplitBehavior mSplitBehavior = UseDefaultLegendSetting;
};


@@ -151,7 +151,7 @@ QSizeF QgsLegendRenderer::paintAndDetermineSize( QgsRenderContext &context )
// to send the full render context so that an expression context is available during the size calculation
QgsScopedRenderContextPainterSwap noPainter( context, nullptr );

QList<LegendComponentGroup> componentGroups = createComponentGroupList( rootGroup, mSettings.splitLayer(), context );
QList<LegendComponentGroup> componentGroups = createComponentGroupList( rootGroup, context );

const int columnCount = setColumns( componentGroups );

@@ -265,7 +265,7 @@ void QgsLegendRenderer::widthAndOffsetForTitleText( const Qt::AlignmentFlag hali
}
}

QList<QgsLegendRenderer::LegendComponentGroup> QgsLegendRenderer::createComponentGroupList( QgsLayerTreeGroup *parentGroup, bool splitLayer, QgsRenderContext &context )
QList<QgsLegendRenderer::LegendComponentGroup> QgsLegendRenderer::createComponentGroupList( QgsLayerTreeGroup *parentGroup, QgsRenderContext &context )
{
QList<LegendComponentGroup> componentGroups;

@@ -280,7 +280,7 @@ QList<QgsLegendRenderer::LegendComponentGroup> QgsLegendRenderer::createComponen
QgsLayerTreeGroup *nodeGroup = QgsLayerTree::toGroup( node );

// Group subitems
QList<LegendComponentGroup> subgroups = createComponentGroupList( nodeGroup, splitLayer, context );
QList<LegendComponentGroup> subgroups = createComponentGroupList( nodeGroup, context );
bool hasSubItems = !subgroups.empty();

if ( nodeLegendStyle( nodeGroup ) != QgsLegendStyle::Hidden )
@@ -323,6 +323,20 @@ QList<QgsLegendRenderer::LegendComponentGroup> QgsLegendRenderer::createComponen
{
QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );

bool allowColumnSplit = false;
switch ( nodeLayer->legendSplitBehavior() )
{
case QgsLayerTreeLayer::UseDefaultLegendSetting:
allowColumnSplit = mSettings.splitLayer();
break;
case QgsLayerTreeLayer::AllowSplittingLegendNodesOverMultipleColumns:
allowColumnSplit = true;
break;
case QgsLayerTreeLayer::PreventSplittingLegendNodesOverMultipleColumns:
allowColumnSplit = false;
break;
}

LegendComponentGroup group;
group.placeColumnBreakBeforeGroup = nodeLayer->customProperty( QStringLiteral( "legend/column-break" ) ).toInt();

@@ -357,7 +371,7 @@ QList<QgsLegendRenderer::LegendComponentGroup> QgsLegendRenderer::createComponen

const bool forceBreak = legendNode->columnBreak();

if ( !mSettings.splitLayer() || j == 0 )
if ( !allowColumnSplit || j == 0 )
{
if ( forceBreak )
{
@@ -215,7 +215,7 @@ class CORE_EXPORT QgsLegendRenderer
* Returns a list of component groups for the specified \a parentGroup, respecting the current layer's
* splitting settings.
*/
QList<LegendComponentGroup> createComponentGroupList( QgsLayerTreeGroup *parentGroup, bool splitLayer, QgsRenderContext &context );
QList<LegendComponentGroup> createComponentGroupList( QgsLayerTreeGroup *parentGroup, QgsRenderContext &context );

/**
* Divides a list of component groups into columns, and sets the column index for each group in the list.
@@ -1423,6 +1423,10 @@ QgsLayoutLegendNodeWidget::QgsLayoutLegendNodeWidget( QgsLayoutItemLegend *legen
// auto close panel if layer removed
connect( node, &QObject::destroyed, this, &QgsPanelWidget::acceptPanel );

mColumnSplitBehaviorComboBox->addItem( tr( "Follow Legend Default" ), QgsLayerTreeLayer::UseDefaultLegendSetting );
mColumnSplitBehaviorComboBox->addItem( tr( "Allow Splitting Over Columns" ), QgsLayerTreeLayer::AllowSplittingLegendNodesOverMultipleColumns );
mColumnSplitBehaviorComboBox->addItem( tr( "Prevent Splitting Over Columns" ), QgsLayerTreeLayer::PreventSplittingLegendNodesOverMultipleColumns );

QString currentLabel;
if ( mLegendNode )
{
@@ -1436,6 +1440,8 @@ QgsLayoutLegendNodeWidget::QgsLayoutLegendNodeWidget( QgsLayoutItemLegend *legen
if ( !v.isNull() )
currentLabel = v.toString();
mColumnBreakBeforeCheckBox->setChecked( mLayer->customProperty( QStringLiteral( "legend/column-break" ) ).toInt() );

mColumnSplitBehaviorComboBox->setCurrentIndex( mColumnSplitBehaviorComboBox->findData( mLayer->legendSplitBehavior() ) );
}
else
{
@@ -1447,9 +1453,12 @@ QgsLayoutLegendNodeWidget::QgsLayoutLegendNodeWidget( QgsLayoutItemLegend *legen
mHeightSpinBox->setClearValue( 0, tr( "Default" ) );
mWidthSpinBox->setVisible( mLegendNode || mLayer );
mHeightSpinBox->setVisible( mLegendNode || mLayer );
mPatchGroup->setVisible( mLegendNode || mLayer );
mPatchWidthLabel->setVisible( mLegendNode || mLayer );
mPatchHeightLabel->setVisible( mLegendNode || mLayer );
mCustomSymbolCheckBox->setVisible( mLegendNode || mLegend->model()->legendNodeEmbeddedInParent( mLayer ) );
mColumnSplitLabel->setVisible( mLayer && !mLegendNode );
mColumnSplitBehaviorComboBox->setVisible( mLayer && !mLegendNode );
if ( mLegendNode )
{
mWidthSpinBox->setValue( mLegendNode->userPatchSize().width() );
@@ -1547,6 +1556,8 @@ QgsLayoutLegendNodeWidget::QgsLayoutLegendNodeWidget( QgsLayoutItemLegend *legen
connect( mCustomSymbolButton, &QgsSymbolButton::changed, this, &QgsLayoutLegendNodeWidget::customSymbolChanged );

connect( mColumnBreakBeforeCheckBox, &QCheckBox::toggled, this, &QgsLayoutLegendNodeWidget::columnBreakToggled );

connect( mColumnSplitBehaviorComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLayoutLegendNodeWidget::columnSplitChanged );
}

void QgsLayoutLegendNodeWidget::labelChanged()
@@ -1742,4 +1753,18 @@ void QgsLayoutLegendNodeWidget::columnBreakToggled( bool checked )
mLegend->endCommand();
}

void QgsLayoutLegendNodeWidget::columnSplitChanged()
{
mLegend->beginCommand( tr( "Edit Legend Columns" ) );

if ( mLayer && !mLegendNode )
{
mLayer->setLegendSplitBehavior( static_cast< QgsLayerTreeLayer::LegendNodesSplitBehavior >( mColumnSplitBehaviorComboBox->currentData().toInt() ) );
}

mLegend->adjustBoxSize();
mLegend->updateFilterByMap();
mLegend->endCommand();
}

///@endcond
@@ -196,6 +196,7 @@ class GUI_EXPORT QgsLayoutLegendNodeWidget: public QgsPanelWidget, private Ui::Q
void sizeChanged( double );
void customSymbolChanged();
void columnBreakToggled( bool checked );
void columnSplitChanged();

private:

0 comments on commit 1e0b890

Please sign in to comment.
You can’t perform that action at this time.