QGIS API Documentation 3.29.0-Master (d0a9f12494)
qgslayoutlegendwidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayoutlegendwidget.cpp
3 -------------------------
4 begin : October 2017
5 copyright : (C) 2017 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19#include "qgslayoutitemlegend.h"
21#include "qgslayoutitemwidget.h"
22#include "qgslayoutitemmap.h"
23#include "qgsguiutils.h"
25
26#include "qgsapplication.h"
27#include "qgslayertree.h"
28#include "qgslayertreeutils.h"
29#include "qgslayertreemodel.h"
31#include "qgslegendrenderer.h"
32#include "qgsmapcanvas.h"
33#include "qgsmaplayerlegend.h"
34#include "qgsrenderer.h"
35#include "qgsvectorlayer.h"
36#include "qgslayoutatlas.h"
37#include "qgslayoutitemlegend.h"
39#include "qgsunittypes.h"
43#include "qgssymbol.h"
44
45#include <QMenu>
46#include <QMessageBox>
47#include <QInputDialog>
48
50
51Q_GUI_EXPORT extern int qt_defaultDpiX();
52
53static int _unfilteredLegendNodeIndex( QgsLayerTreeModelLegendNode *legendNode )
54{
56}
57
58static int _originalLegendNodeIndex( QgsLayerTreeModelLegendNode *legendNode )
59{
60 // figure out index of the legend node as it comes out of the map layer legend.
61 // first legend nodes may be reordered, output of that is available in layerOriginalLegendNodes().
62 // next the nodes may be further filtered (by scale, map content etc).
63 // so here we go in reverse order: 1. find index before filtering, 2. find index before reorder
64 int unfilteredNodeIndex = _unfilteredLegendNodeIndex( legendNode );
66 return ( unfilteredNodeIndex >= 0 && unfilteredNodeIndex < order.count() ? order[unfilteredNodeIndex] : -1 );
67}
68
69
70QgsLayoutLegendWidget::QgsLayoutLegendWidget( QgsLayoutItemLegend *legend, QgsMapCanvas *mapCanvas )
71 : QgsLayoutItemBaseWidget( nullptr, legend )
72 , mLegend( legend )
73 , mMapCanvas( mapCanvas )
74{
75 Q_ASSERT( mLegend );
76
77 setupUi( this );
78 connect( mWrapCharLineEdit, &QLineEdit::textChanged, this, &QgsLayoutLegendWidget::mWrapCharLineEdit_textChanged );
79 connect( mTitleLineEdit, &QLineEdit::textChanged, this, &QgsLayoutLegendWidget::mTitleLineEdit_textChanged );
80 connect( mTitleAlignCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::titleAlignmentChanged );
81 connect( mGroupAlignCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::groupAlignmentChanged );
82 connect( mSubgroupAlignCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::subgroupAlignmentChanged );
83 connect( mItemAlignCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::itemAlignmentChanged );
84 connect( mColumnCountSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mColumnCountSpinBox_valueChanged );
85 connect( mSplitLayerCheckBox, &QCheckBox::toggled, this, &QgsLayoutLegendWidget::mSplitLayerCheckBox_toggled );
86 connect( mEqualColumnWidthCheckBox, &QCheckBox::toggled, this, &QgsLayoutLegendWidget::mEqualColumnWidthCheckBox_toggled );
87 connect( mSymbolWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mSymbolWidthSpinBox_valueChanged );
88 connect( mSymbolHeightSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mSymbolHeightSpinBox_valueChanged );
89 connect( mMaxSymbolSizeSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mMaxSymbolSizeSpinBox_valueChanged );
90 connect( mMinSymbolSizeSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mMinSymbolSizeSpinBox_valueChanged );
91 connect( mWmsLegendWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mWmsLegendWidthSpinBox_valueChanged );
92 connect( mWmsLegendHeightSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mWmsLegendHeightSpinBox_valueChanged );
93 connect( mTitleSpaceBottomSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mTitleSpaceBottomSpinBox_valueChanged );
94 connect( mGroupSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mGroupSpaceSpinBox_valueChanged );
95 connect( mGroupIndentSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mGroupIndentSpinBox_valueChanged );
96 connect( mSubgroupIndentSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mSubgroupIndentSpinBox_valueChanged );
97 connect( mSpaceBelowGroupHeadingSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::spaceBelowGroupHeadingChanged );
98 connect( mGroupSideSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::spaceGroupSideChanged );
99 connect( mLayerSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mLayerSpaceSpinBox_valueChanged );
100 connect( mSpaceBelowSubgroupHeadingSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::spaceBelowSubGroupHeadingChanged );
101 connect( mSubgroupSideSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::spaceSubGroupSideChanged );
102 connect( mSymbolSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mSymbolSpaceSpinBox_valueChanged );
103 connect( mSymbolSideSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::spaceSymbolSideChanged );
104 connect( mIconLabelSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mIconLabelSpaceSpinBox_valueChanged );
105 connect( mBoxSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mBoxSpaceSpinBox_valueChanged );
106 connect( mColumnSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mColumnSpaceSpinBox_valueChanged );
107 connect( mCheckBoxAutoUpdate, &QCheckBox::stateChanged, this, [ = ]( int state ) { mCheckBoxAutoUpdate_stateChanged( state ); } );
108 connect( mCheckboxResizeContents, &QCheckBox::toggled, this, &QgsLayoutLegendWidget::mCheckboxResizeContents_toggled );
109 connect( mRasterStrokeGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutLegendWidget::mRasterStrokeGroupBox_toggled );
110 connect( mRasterStrokeWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mRasterStrokeWidthSpinBox_valueChanged );
111 connect( mRasterStrokeColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutLegendWidget::mRasterStrokeColorButton_colorChanged );
112 connect( mMoveDownToolButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mMoveDownToolButton_clicked );
113 connect( mMoveUpToolButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mMoveUpToolButton_clicked );
114 connect( mRemoveToolButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mRemoveToolButton_clicked );
115 connect( mAddToolButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mAddToolButton_clicked );
116 connect( mEditPushButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mEditPushButton_clicked );
117 connect( mCountToolButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mCountToolButton_clicked );
118 connect( mExpressionFilterButton, &QgsLegendFilterButton::toggled, this, &QgsLayoutLegendWidget::mExpressionFilterButton_toggled );
119 connect( mLayerExpressionButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mLayerExpressionButton_clicked );
120 connect( mFilterByMapCheckBox, &QCheckBox::toggled, this, &QgsLayoutLegendWidget::mFilterByMapCheckBox_toggled );
121 connect( mUpdateAllPushButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mUpdateAllPushButton_clicked );
122 connect( mAddGroupToolButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mAddGroupToolButton_clicked );
123 connect( mFilterLegendByAtlasCheckBox, &QCheckBox::toggled, this, &QgsLayoutLegendWidget::mFilterLegendByAtlasCheckBox_toggled );
124 connect( mItemTreeView, &QgsLayerTreeView::doubleClicked, this, &QgsLayoutLegendWidget::mItemTreeView_doubleClicked );
125 setPanelTitle( tr( "Legend Properties" ) );
126
127 mTitleFontButton->setMode( QgsFontButton::ModeTextRenderer );
128 mGroupFontButton->setMode( QgsFontButton::ModeTextRenderer );
129 mLayerFontButton->setMode( QgsFontButton::ModeTextRenderer );
130 mItemFontButton->setMode( QgsFontButton::ModeTextRenderer );
131
132 mTitleAlignCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
133 mGroupAlignCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
134 mSubgroupAlignCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
135 mItemAlignCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
136
137 mArrangementCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignRight );
138 connect( mArrangementCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::arrangementChanged );
139 mArrangementCombo->customizeAlignmentDisplay( Qt::AlignLeft, tr( "Symbols on Left" ), QgsApplication::getThemeIcon( QStringLiteral( "/mIconArrangeSymbolsLeft.svg" ) ) );
140 mArrangementCombo->customizeAlignmentDisplay( Qt::AlignRight, tr( "Symbols on Right" ), QgsApplication::getThemeIcon( QStringLiteral( "/mIconArrangeSymbolsRight.svg" ) ) );
141
142 mSpaceBelowGroupHeadingSpinBox->setClearValue( 0 );
143 mGroupSideSpinBox->setClearValue( 0 );
144 mSpaceBelowSubgroupHeadingSpinBox->setClearValue( 0 );
145 mSubgroupSideSpinBox->setClearValue( 0 );
146 mSymbolSideSpaceSpinBox->setClearValue( 0 );
147
148 // setup icons
149 mAddToolButton->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
150 mEditPushButton->setIcon( QIcon( QgsApplication::iconPath( "symbologyEdit.svg" ) ) );
151 mRemoveToolButton->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
152 mMoveUpToolButton->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowUp.svg" ) ) );
153 mMoveDownToolButton->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowDown.svg" ) ) );
154 mCountToolButton->setIcon( QIcon( QgsApplication::iconPath( "mActionSum.svg" ) ) );
155 mLayerExpressionButton->setIcon( QIcon( QgsApplication::iconPath( "mIconExpression.svg" ) ) );
156
157 mMoveDownToolButton->setIconSize( QgsGuiUtils::iconSize( true ) );
158 mMoveUpToolButton->setIconSize( QgsGuiUtils::iconSize( true ) );
159 mAddGroupToolButton->setIconSize( QgsGuiUtils::iconSize( true ) );
160 mAddToolButton->setIconSize( QgsGuiUtils::iconSize( true ) );
161 mRemoveToolButton->setIconSize( QgsGuiUtils::iconSize( true ) );
162 mEditPushButton->setIconSize( QgsGuiUtils::iconSize( true ) );
163 mCountToolButton->setIconSize( QgsGuiUtils::iconSize( true ) );
164 mExpressionFilterButton->setIconSize( QgsGuiUtils::iconSize( true ) );
165 mLayerExpressionButton->setIconSize( QgsGuiUtils::iconSize( true ) );
166
167 mRasterStrokeColorButton->setColorDialogTitle( tr( "Select Stroke Color" ) );
168 mRasterStrokeColorButton->setAllowOpacity( true );
169 mRasterStrokeColorButton->setContext( QStringLiteral( "composer " ) );
170
171 mMapComboBox->setCurrentLayout( legend->layout() );
172 mMapComboBox->setItemType( QgsLayoutItemRegistry::LayoutMap );
173 connect( mMapComboBox, &QgsLayoutItemComboBox::itemChanged, this, &QgsLayoutLegendWidget::composerMapChanged );
174
175 //add widget for general composer item properties
176 mItemPropertiesWidget = new QgsLayoutItemPropertiesWidget( this, legend );
177 mainLayout->addWidget( mItemPropertiesWidget );
178
179 mItemTreeView->setHeaderHidden( true );
180
181 mItemTreeView->setModel( legend->model() );
182 mItemTreeView->setMenuProvider( new QgsLayoutLegendMenuProvider( mItemTreeView, this ) );
183 setLegendMapViewData();
184 connect( legend, &QgsLayoutObject::changed, this, &QgsLayoutLegendWidget::setGuiElements );
185
186 // connect atlas state to the filter legend by atlas checkbox
187 if ( layoutAtlas() )
188 {
189 connect( layoutAtlas(), &QgsLayoutAtlas::toggled, this, &QgsLayoutLegendWidget::updateFilterLegendByAtlasButton );
190 }
191 connect( &legend->layout()->reportContext(), &QgsLayoutReportContext::layerChanged, this, &QgsLayoutLegendWidget::updateFilterLegendByAtlasButton );
192
193 mTitleFontButton->registerExpressionContextGenerator( this );
194 mGroupFontButton->registerExpressionContextGenerator( this );
195 mLayerFontButton->registerExpressionContextGenerator( this );
196 mItemFontButton->registerExpressionContextGenerator( this );
197
198 mTitleFontButton->setLayer( coverageLayer() );
199 mGroupFontButton->setLayer( coverageLayer() );
200 mLayerFontButton->setLayer( coverageLayer() );
201 mItemFontButton->setLayer( coverageLayer() );
202 if ( mLegend->layout() )
203 {
204 connect( &mLegend->layout()->reportContext(), &QgsLayoutReportContext::layerChanged, mTitleFontButton, &QgsFontButton::setLayer );
205 connect( &mLegend->layout()->reportContext(), &QgsLayoutReportContext::layerChanged, mGroupFontButton, &QgsFontButton::setLayer );
206 connect( &mLegend->layout()->reportContext(), &QgsLayoutReportContext::layerChanged, mLayerFontButton, &QgsFontButton::setLayer );
207 connect( &mLegend->layout()->reportContext(), &QgsLayoutReportContext::layerChanged, mItemFontButton, &QgsFontButton::setLayer );
208 }
209
210 registerDataDefinedButton( mLegendTitleDDBtn, QgsLayoutObject::LegendTitle );
211 registerDataDefinedButton( mColumnsDDBtn, QgsLayoutObject::LegendColumnCount );
212
213 setGuiElements();
214
215 connect( mItemTreeView->selectionModel(), &QItemSelectionModel::currentChanged,
216 this, &QgsLayoutLegendWidget::selectedChanged );
217 connect( mTitleFontButton, &QgsFontButton::changed, this, &QgsLayoutLegendWidget::titleFontChanged );
218 connect( mGroupFontButton, &QgsFontButton::changed, this, &QgsLayoutLegendWidget::groupFontChanged );
219 connect( mLayerFontButton, &QgsFontButton::changed, this, &QgsLayoutLegendWidget::layerFontChanged );
220 connect( mItemFontButton, &QgsFontButton::changed, this, &QgsLayoutLegendWidget::itemFontChanged );
221}
222
223void QgsLayoutLegendWidget::setMasterLayout( QgsMasterLayoutInterface *masterLayout )
224{
225 if ( mItemPropertiesWidget )
226 mItemPropertiesWidget->setMasterLayout( masterLayout );
227}
228
229void QgsLayoutLegendWidget::setDesignerInterface( QgsLayoutDesignerInterface *iface )
230{
232 mTitleFontButton->setMessageBar( iface->messageBar() );
233 mGroupFontButton->setMessageBar( iface->messageBar() );
234 mLayerFontButton->setMessageBar( iface->messageBar() );
235 mItemFontButton->setMessageBar( iface->messageBar() );
236}
237
238void QgsLayoutLegendWidget::setGuiElements()
239{
240 if ( !mLegend )
241 {
242 return;
243 }
244
245 blockAllSignals( true );
246 mTitleLineEdit->setText( mLegend->title() );
247 whileBlocking( mTitleAlignCombo )->setCurrentAlignment( mLegend->titleAlignment() );
248 whileBlocking( mGroupAlignCombo )->setCurrentAlignment( mLegend->style( QgsLegendStyle::Group ).alignment() );
249 whileBlocking( mSubgroupAlignCombo )->setCurrentAlignment( mLegend->style( QgsLegendStyle::Subgroup ).alignment() );
250 whileBlocking( mItemAlignCombo )->setCurrentAlignment( mLegend->style( QgsLegendStyle::SymbolLabel ).alignment() );
251 whileBlocking( mArrangementCombo )->setCurrentAlignment( mLegend->symbolAlignment() );
252 mFilterByMapCheckBox->setChecked( mLegend->legendFilterByMapEnabled() );
253 mColumnCountSpinBox->setValue( mLegend->columnCount() );
254 mSplitLayerCheckBox->setChecked( mLegend->splitLayer() );
255 mEqualColumnWidthCheckBox->setChecked( mLegend->equalColumnWidth() );
256 mSymbolWidthSpinBox->setValue( mLegend->symbolWidth() );
257 mSymbolHeightSpinBox->setValue( mLegend->symbolHeight() );
258 mMaxSymbolSizeSpinBox->setValue( mLegend->maximumSymbolSize() );
259 mMinSymbolSizeSpinBox->setValue( mLegend->minimumSymbolSize() );
260 mWmsLegendWidthSpinBox->setValue( mLegend->wmsLegendWidth() );
261 mWmsLegendHeightSpinBox->setValue( mLegend->wmsLegendHeight() );
262 mTitleSpaceBottomSpinBox->setValue( mLegend->style( QgsLegendStyle::Title ).margin( QgsLegendStyle::Bottom ) );
263 mGroupSpaceSpinBox->setValue( mLegend->style( QgsLegendStyle::Group ).margin( QgsLegendStyle::Top ) );
264 mGroupIndentSpinBox->setValue( mLegend->style( QgsLegendStyle::Group ).indent() );
265 mSubgroupIndentSpinBox->setValue( mLegend->style( QgsLegendStyle::Subgroup ).indent() );
266 mGroupSideSpinBox->setValue( mLegend->style( QgsLegendStyle::Group ).margin( QgsLegendStyle::Left ) );
267 mSpaceBelowGroupHeadingSpinBox->setValue( mLegend->style( QgsLegendStyle::Group ).margin( QgsLegendStyle::Bottom ) );
268 mLayerSpaceSpinBox->setValue( mLegend->style( QgsLegendStyle::Subgroup ).margin( QgsLegendStyle::Top ) );
269 mSpaceBelowSubgroupHeadingSpinBox->setValue( mLegend->style( QgsLegendStyle::Subgroup ).margin( QgsLegendStyle::Bottom ) );
270 mSubgroupSideSpinBox->setValue( mLegend->style( QgsLegendStyle::Subgroup ).margin( QgsLegendStyle::Left ) );
271 // We keep Symbol and SymbolLabel Top in sync for now
272 mSymbolSpaceSpinBox->setValue( mLegend->style( QgsLegendStyle::Symbol ).margin( QgsLegendStyle::Top ) );
273 mIconLabelSpaceSpinBox->setValue( mLegend->style( QgsLegendStyle::SymbolLabel ).margin( QgsLegendStyle::Left ) );
274 mSymbolSideSpaceSpinBox->setValue( mLegend->style( QgsLegendStyle::Symbol ).margin( QgsLegendStyle::Left ) );
275 mBoxSpaceSpinBox->setValue( mLegend->boxSpace() );
276 mColumnSpaceSpinBox->setValue( mLegend->columnSpace() );
277
278 mRasterStrokeGroupBox->setChecked( mLegend->drawRasterStroke() );
279 mRasterStrokeWidthSpinBox->setValue( mLegend->rasterStrokeWidth() );
280 mRasterStrokeColorButton->setColor( mLegend->rasterStrokeColor() );
281
282 mCheckBoxAutoUpdate->setChecked( mLegend->autoUpdateModel() );
283
284 mCheckboxResizeContents->setChecked( mLegend->resizeToContents() );
285 mFilterLegendByAtlasCheckBox->setChecked( mLegend->legendFilterOutAtlas() );
286 mWrapCharLineEdit->setText( mLegend->wrapString() );
287
288 QgsLayoutItemMap *map = mLegend->linkedMap();
289 mMapComboBox->setItem( map );
290 mTitleFontButton->setTextFormat( mLegend->style( QgsLegendStyle::Title ).textFormat() );
291 mGroupFontButton->setTextFormat( mLegend->style( QgsLegendStyle::Group ).textFormat() );
292 mLayerFontButton->setTextFormat( mLegend->style( QgsLegendStyle::Subgroup ).textFormat() );
293 mItemFontButton->setTextFormat( mLegend->style( QgsLegendStyle::SymbolLabel ).textFormat() );
294
295 blockAllSignals( false );
296
297 mCheckBoxAutoUpdate_stateChanged( mLegend->autoUpdateModel() ? Qt::Checked : Qt::Unchecked, false );
298 updateDataDefinedButton( mLegendTitleDDBtn );
299 updateDataDefinedButton( mColumnsDDBtn );
300}
301
302void QgsLayoutLegendWidget::mWrapCharLineEdit_textChanged( const QString &text )
303{
304 if ( mLegend )
305 {
306 mLegend->beginCommand( tr( "Change Legend Wrap" ) );
307 mLegend->setWrapString( text );
308 mLegend->adjustBoxSize();
309 mLegend->update();
310 mLegend->endCommand();
311 }
312}
313
314void QgsLayoutLegendWidget::mTitleLineEdit_textChanged( const QString &text )
315{
316 if ( mLegend )
317 {
318 mLegend->beginCommand( tr( "Change Legend Title" ), QgsLayoutItem::UndoLegendText );
319 mLegend->setTitle( text );
320 mLegend->adjustBoxSize();
321 mLegend->update();
322 mLegend->endCommand();
323 }
324}
325
326void QgsLayoutLegendWidget::titleAlignmentChanged()
327{
328 if ( mLegend )
329 {
330 Qt::AlignmentFlag alignment = static_cast< Qt::AlignmentFlag >( static_cast< int >( mTitleAlignCombo->currentAlignment() & Qt::AlignHorizontal_Mask ) );
331 mLegend->beginCommand( tr( "Change Title Alignment" ) );
332 mLegend->setTitleAlignment( alignment );
333 mLegend->update();
334 mLegend->endCommand();
335 }
336}
337
338void QgsLayoutLegendWidget::groupAlignmentChanged()
339{
340 if ( mLegend )
341 {
342 mLegend->beginCommand( tr( "Change Group Alignment" ) );
343 mLegend->rstyle( QgsLegendStyle::Group ).setAlignment( mGroupAlignCombo->currentAlignment() );
344 mLegend->update();
345 mLegend->endCommand();
346 }
347}
348
349void QgsLayoutLegendWidget::subgroupAlignmentChanged()
350{
351 if ( mLegend )
352 {
353 mLegend->beginCommand( tr( "Change Subgroup Alignment" ) );
354 mLegend->rstyle( QgsLegendStyle::Subgroup ).setAlignment( mSubgroupAlignCombo->currentAlignment() );
355 mLegend->update();
356 mLegend->endCommand();
357 }
358}
359
360void QgsLayoutLegendWidget::itemAlignmentChanged()
361{
362 if ( mLegend )
363 {
364 mLegend->beginCommand( tr( "Change Item Alignment" ) );
365 mLegend->rstyle( QgsLegendStyle::SymbolLabel ).setAlignment( mItemAlignCombo->currentAlignment() );
366 mLegend->update();
367 mLegend->endCommand();
368 }
369}
370
371void QgsLayoutLegendWidget::arrangementChanged()
372{
373 if ( mLegend )
374 {
375 Qt::AlignmentFlag alignment = static_cast< Qt::AlignmentFlag >( static_cast< int >( mArrangementCombo->currentAlignment() & Qt::AlignHorizontal_Mask ) );
376 mLegend->beginCommand( tr( "Change Legend Arrangement" ) );
377 mLegend->setSymbolAlignment( alignment );
378 mLegend->update();
379 mLegend->endCommand();
380 }
381}
382
383void QgsLayoutLegendWidget::mColumnCountSpinBox_valueChanged( int c )
384{
385 if ( mLegend )
386 {
387 mLegend->beginCommand( tr( "Change Column Count" ), QgsLayoutItem::UndoLegendColumnCount );
388 mLegend->setColumnCount( c );
389 mLegend->adjustBoxSize();
390 mLegend->update();
391 mLegend->endCommand();
392 }
393 mSplitLayerCheckBox->setEnabled( c > 1 );
394 mEqualColumnWidthCheckBox->setEnabled( c > 1 );
395}
396
397void QgsLayoutLegendWidget::mSplitLayerCheckBox_toggled( bool checked )
398{
399 if ( mLegend )
400 {
401 mLegend->beginCommand( tr( "Split Legend Layers" ) );
402 mLegend->setSplitLayer( checked );
403 mLegend->adjustBoxSize();
404 mLegend->update();
405 mLegend->endCommand();
406 }
407}
408
409void QgsLayoutLegendWidget::mEqualColumnWidthCheckBox_toggled( bool checked )
410{
411 if ( mLegend )
412 {
413 mLegend->beginCommand( tr( "Legend Column Width" ) );
414 mLegend->setEqualColumnWidth( checked );
415 mLegend->adjustBoxSize();
416 mLegend->update();
417 mLegend->endCommand();
418 }
419}
420
421void QgsLayoutLegendWidget::mSymbolWidthSpinBox_valueChanged( double d )
422{
423 if ( mLegend )
424 {
425 mLegend->beginCommand( tr( "Resize Symbol Width" ), QgsLayoutItem::UndoLegendSymbolWidth );
426 mLegend->setSymbolWidth( d );
427 mLegend->adjustBoxSize();
428 mLegend->update();
429 mLegend->endCommand();
430 }
431}
432
433void QgsLayoutLegendWidget::mMaxSymbolSizeSpinBox_valueChanged( double d )
434{
435 if ( mLegend )
436 {
437 mLegend->beginCommand( tr( "Change Legend Maximum Symbol Size" ), QgsLayoutItem::UndoLegendMaxSymbolSize );
438 mLegend->setMaximumSymbolSize( d );
439 mLegend->adjustBoxSize();
440 mLegend->update();
441 mLegend->endCommand();
442 }
443}
444
445void QgsLayoutLegendWidget::mMinSymbolSizeSpinBox_valueChanged( double d )
446{
447 if ( mLegend )
448 {
449 mLegend->beginCommand( tr( "Change Legend Minimum Symbol Size" ), QgsLayoutItem::UndoLegendMinSymbolSize );
450 mLegend->setMinimumSymbolSize( d );
451 mLegend->adjustBoxSize();
452 mLegend->update();
453 mLegend->endCommand();
454 }
455}
456
457void QgsLayoutLegendWidget::mSymbolHeightSpinBox_valueChanged( double d )
458{
459 if ( mLegend )
460 {
461 mLegend->beginCommand( tr( "Resize Symbol Height" ), QgsLayoutItem::UndoLegendSymbolHeight );
462 mLegend->setSymbolHeight( d );
463 mLegend->adjustBoxSize();
464 mLegend->update();
465 mLegend->endCommand();
466 }
467}
468
469void QgsLayoutLegendWidget::mWmsLegendWidthSpinBox_valueChanged( double d )
470{
471 if ( mLegend )
472 {
473 mLegend->beginCommand( tr( "Resize WMS Width" ), QgsLayoutItem::UndoLegendWmsLegendWidth );
474 mLegend->setWmsLegendWidth( d );
475 mLegend->adjustBoxSize();
476 mLegend->update();
477 mLegend->endCommand();
478 }
479}
480
481void QgsLayoutLegendWidget::mWmsLegendHeightSpinBox_valueChanged( double d )
482{
483 if ( mLegend )
484 {
485 mLegend->beginCommand( tr( "Resize WMS Height" ), QgsLayoutItem::UndoLegendWmsLegendHeight );
486 mLegend->setWmsLegendHeight( d );
487 mLegend->adjustBoxSize();
488 mLegend->update();
489 mLegend->endCommand();
490 }
491}
492
493void QgsLayoutLegendWidget::mTitleSpaceBottomSpinBox_valueChanged( double d )
494{
495 if ( mLegend )
496 {
497 mLegend->beginCommand( tr( "Change Title Space" ), QgsLayoutItem::UndoLegendTitleSpaceBottom );
498 mLegend->rstyle( QgsLegendStyle::Title ).setMargin( QgsLegendStyle::Bottom, d );
499 mLegend->adjustBoxSize();
500 mLegend->update();
501 mLegend->endCommand();
502 }
503}
504
505void QgsLayoutLegendWidget::mGroupSpaceSpinBox_valueChanged( double d )
506{
507 if ( mLegend )
508 {
509 mLegend->beginCommand( tr( "Change Group Space" ), QgsLayoutItem::UndoLegendGroupSpace );
510 mLegend->rstyle( QgsLegendStyle::Group ).setMargin( QgsLegendStyle::Top, d );
511 mLegend->adjustBoxSize();
512 mLegend->update();
513 mLegend->endCommand();
514 }
515}
516
517void QgsLayoutLegendWidget::mGroupIndentSpinBox_valueChanged( double d )
518{
519 if ( mLegend )
520 {
521 mLegend->beginCommand( tr( "Change Group Indent" ), QgsLayoutItem::UndoLegendGroupIndent );
522 mLegend->rstyle( QgsLegendStyle::Group ).setIndent( d );
523 mLegend->adjustBoxSize();
524 mLegend->update();
525 mLegend->endCommand();
526 }
527}
528
529void QgsLayoutLegendWidget::mSubgroupIndentSpinBox_valueChanged( double d )
530{
531 if ( mLegend )
532 {
533 mLegend->beginCommand( tr( "Change Subgroup Indent" ), QgsLayoutItem::UndoLegendSubgroupIndent );
534 mLegend->rstyle( QgsLegendStyle::Subgroup ).setIndent( d );
535 mLegend->adjustBoxSize();
536 mLegend->update();
537 mLegend->endCommand();
538 }
539}
540
541void QgsLayoutLegendWidget::spaceBelowGroupHeadingChanged( double space )
542{
543 if ( mLegend )
544 {
545 mLegend->beginCommand( tr( "Change Group Space" ), QgsLayoutItem::UndoLegendGroupSpace );
546 mLegend->rstyle( QgsLegendStyle::Group ).setMargin( QgsLegendStyle::Bottom, space );
547 mLegend->adjustBoxSize();
548 mLegend->update();
549 mLegend->endCommand();
550 }
551}
552
553void QgsLayoutLegendWidget::spaceGroupSideChanged( double space )
554{
555 if ( mLegend )
556 {
557 mLegend->beginCommand( tr( "Change Side of Group Space" ), QgsLayoutItem::UndoLegendGroupSpace );
558 mLegend->rstyle( QgsLegendStyle::Group ).setMargin( QgsLegendStyle::Left, space );
559 mLegend->adjustBoxSize();
560 mLegend->update();
561 mLegend->endCommand();
562 }
563}
564
565void QgsLayoutLegendWidget::spaceSubGroupSideChanged( double space )
566{
567 if ( mLegend )
568 {
569 mLegend->beginCommand( tr( "Change Side of Subgroup Space" ), QgsLayoutItem::UndoLegendLayerSpace );
570 mLegend->rstyle( QgsLegendStyle::Subgroup ).setMargin( QgsLegendStyle::Left, space );
571 mLegend->adjustBoxSize();
572 mLegend->update();
573 mLegend->endCommand();
574 }
575}
576
577void QgsLayoutLegendWidget::spaceSymbolSideChanged( double space )
578{
579 if ( mLegend )
580 {
581 mLegend->beginCommand( tr( "Change Side of Symbol Space" ), QgsLayoutItem::UndoLegendSymbolSpace );
582 mLegend->rstyle( QgsLegendStyle::Symbol ).setMargin( QgsLegendStyle::Left, space );
583 mLegend->adjustBoxSize();
584 mLegend->update();
585 mLegend->endCommand();
586 }
587}
588
589void QgsLayoutLegendWidget::mLayerSpaceSpinBox_valueChanged( double d )
590{
591 if ( mLegend )
592 {
593 mLegend->beginCommand( tr( "Change Subgroup Space" ), QgsLayoutItem::UndoLegendLayerSpace );
594 mLegend->rstyle( QgsLegendStyle::Subgroup ).setMargin( QgsLegendStyle::Top, d );
595 mLegend->adjustBoxSize();
596 mLegend->update();
597 mLegend->endCommand();
598 }
599}
600
601void QgsLayoutLegendWidget::mSymbolSpaceSpinBox_valueChanged( double d )
602{
603 if ( mLegend )
604 {
605 mLegend->beginCommand( tr( "Change Symbol Space" ), QgsLayoutItem::UndoLegendSymbolSpace );
606 // We keep Symbol and SymbolLabel Top in sync for now
607 mLegend->rstyle( QgsLegendStyle::Symbol ).setMargin( QgsLegendStyle::Top, d );
608 mLegend->rstyle( QgsLegendStyle::SymbolLabel ).setMargin( QgsLegendStyle::Top, d );
609 mLegend->adjustBoxSize();
610 mLegend->update();
611 mLegend->endCommand();
612 }
613}
614
615void QgsLayoutLegendWidget::mIconLabelSpaceSpinBox_valueChanged( double d )
616{
617 if ( mLegend )
618 {
619 mLegend->beginCommand( tr( "Change Label Space" ), QgsLayoutItem::UndoLegendIconSymbolSpace );
620 mLegend->rstyle( QgsLegendStyle::SymbolLabel ).setMargin( QgsLegendStyle::Left, d );
621 mLegend->adjustBoxSize();
622 mLegend->update();
623 mLegend->endCommand();
624 }
625}
626
627void QgsLayoutLegendWidget::titleFontChanged()
628{
629 if ( mLegend )
630 {
631 mLegend->beginCommand( tr( "Change Title Font" ), QgsLayoutItem::UndoLegendTitleFont );
632 mLegend->rstyle( QgsLegendStyle::Title ).setTextFormat( mTitleFontButton->textFormat() );
633 mLegend->adjustBoxSize();
634 mLegend->update();
635 mLegend->endCommand();
636 }
637}
638
639void QgsLayoutLegendWidget::groupFontChanged()
640{
641 if ( mLegend )
642 {
643 mLegend->beginCommand( tr( "Change Group Font" ), QgsLayoutItem::UndoLegendGroupFont );
644 mLegend->rstyle( QgsLegendStyle::Group ).setTextFormat( mGroupFontButton->textFormat() );
645 mLegend->adjustBoxSize();
646 mLegend->update();
647 mLegend->endCommand();
648 }
649}
650
651void QgsLayoutLegendWidget::layerFontChanged()
652{
653 if ( mLegend )
654 {
655 mLegend->beginCommand( tr( "Change Layer Font" ), QgsLayoutItem::UndoLegendLayerFont );
656 mLegend->rstyle( QgsLegendStyle::Subgroup ).setTextFormat( mLayerFontButton->textFormat() );
657 mLegend->adjustBoxSize();
658 mLegend->update();
659 mLegend->endCommand();
660 }
661}
662
663void QgsLayoutLegendWidget::itemFontChanged()
664{
665 if ( mLegend )
666 {
667 mLegend->beginCommand( tr( "Change Item Font" ), QgsLayoutItem::UndoLegendItemFont );
668 mLegend->rstyle( QgsLegendStyle::SymbolLabel ).setTextFormat( mItemFontButton->textFormat() );
669 mLegend->adjustBoxSize();
670 mLegend->update();
671 mLegend->endCommand();
672 }
673}
674
675void QgsLayoutLegendWidget::spaceBelowSubGroupHeadingChanged( double space )
676{
677 if ( mLegend )
678 {
679 mLegend->beginCommand( tr( "Change Subgroup Space" ), QgsLayoutItem::UndoLegendLayerSpace );
680 mLegend->rstyle( QgsLegendStyle::Subgroup ).setMargin( QgsLegendStyle::Bottom, space );
681 mLegend->adjustBoxSize();
682 mLegend->update();
683 mLegend->endCommand();
684 }
685}
686
687void QgsLayoutLegendWidget::mBoxSpaceSpinBox_valueChanged( double d )
688{
689 if ( mLegend )
690 {
691 mLegend->beginCommand( tr( "Change Box Space" ), QgsLayoutItem::UndoLegendBoxSpace );
692 mLegend->setBoxSpace( d );
693 mLegend->adjustBoxSize();
694 mLegend->update();
695 mLegend->endCommand();
696 }
697}
698
699void QgsLayoutLegendWidget::mColumnSpaceSpinBox_valueChanged( double d )
700{
701 if ( mLegend )
702 {
703 mLegend->beginCommand( tr( "Change Column Space" ), QgsLayoutItem::UndoLegendColumnSpace );
704 mLegend->setColumnSpace( d );
705 mLegend->adjustBoxSize();
706 mLegend->update();
707 mLegend->endCommand();
708 }
709}
710
711static void _moveLegendNode( QgsLayerTreeLayer *nodeLayer, int legendNodeIndex, int offset )
712{
713 QList<int> order = QgsMapLayerLegendUtils::legendNodeOrder( nodeLayer );
714
715 if ( legendNodeIndex < 0 || legendNodeIndex >= order.count() )
716 return;
717 if ( legendNodeIndex + offset < 0 || legendNodeIndex + offset >= order.count() )
718 return;
719
720 int id = order.takeAt( legendNodeIndex );
721 order.insert( legendNodeIndex + offset, id );
722
724}
725
726
727void QgsLayoutLegendWidget::mMoveDownToolButton_clicked()
728{
729 if ( !mLegend )
730 {
731 return;
732 }
733
734 const QModelIndex index = mItemTreeView->selectionModel()->currentIndex();
735 const QModelIndex sourceIndex = mItemTreeView->proxyModel()->mapToSource( index );
736 const QModelIndex parentIndex = sourceIndex.parent();
737 if ( !sourceIndex.isValid() || sourceIndex.row() == mItemTreeView->layerTreeModel()->rowCount( parentIndex ) - 1 )
738 return;
739
740 QgsLayerTreeNode *node = mItemTreeView->index2node( index );
741 QgsLayerTreeModelLegendNode *legendNode = mItemTreeView->index2legendNode( index );
742 if ( !node && !legendNode )
743 return;
744
745 mLegend->beginCommand( tr( "Moved Legend Item Down" ) );
746
747 if ( node )
748 {
749 QgsLayerTreeGroup *parentGroup = QgsLayerTree::toGroup( node->parent() );
750 parentGroup->insertChildNode( sourceIndex.row() + 2, node->clone() );
751 parentGroup->removeChildNode( node );
752 }
753 else // legend node
754 {
755 _moveLegendNode( legendNode->layerNode(), _unfilteredLegendNodeIndex( legendNode ), 1 );
756 mItemTreeView->layerTreeModel()->refreshLayerLegend( legendNode->layerNode() );
757 }
758
759 mItemTreeView->setCurrentIndex( mItemTreeView->proxyModel()->mapFromSource( mItemTreeView->layerTreeModel()->index( sourceIndex.row() + 1, 0, parentIndex ) ) );
760
761 mLegend->update();
762 mLegend->endCommand();
763}
764
765void QgsLayoutLegendWidget::mMoveUpToolButton_clicked()
766{
767 if ( !mLegend )
768 {
769 return;
770 }
771
772 const QModelIndex index = mItemTreeView->selectionModel()->currentIndex();
773 const QModelIndex sourceIndex = mItemTreeView->proxyModel()->mapToSource( index );
774 const QModelIndex parentIndex = sourceIndex.parent();
775 if ( !sourceIndex.isValid() || sourceIndex.row() == 0 )
776 return;
777
778 QgsLayerTreeNode *node = mItemTreeView->index2node( index );
779 QgsLayerTreeModelLegendNode *legendNode = mItemTreeView->index2legendNode( index );
780 if ( !node && !legendNode )
781 return;
782
783 mLegend->beginCommand( tr( "Move Legend Item Up" ) );
784
785 if ( node )
786 {
787 QgsLayerTreeGroup *parentGroup = QgsLayerTree::toGroup( node->parent() );
788 parentGroup->insertChildNode( sourceIndex.row() - 1, node->clone() );
789 parentGroup->removeChildNode( node );
790 }
791 else // legend node
792 {
793 _moveLegendNode( legendNode->layerNode(), _unfilteredLegendNodeIndex( legendNode ), -1 );
794 mItemTreeView->layerTreeModel()->refreshLayerLegend( legendNode->layerNode() );
795 }
796
797 mItemTreeView->setCurrentIndex( mItemTreeView->proxyModel()->mapFromSource( mItemTreeView->layerTreeModel()->index( sourceIndex.row() - 1, 0, parentIndex ) ) );
798
799 mLegend->update();
800 mLegend->endCommand();
801}
802
803void QgsLayoutLegendWidget::mCheckBoxAutoUpdate_stateChanged( int state, bool userTriggered )
804{
805 if ( userTriggered )
806 {
807 mLegend->beginCommand( tr( "Change Auto Update" ) );
808
809 mLegend->setAutoUpdateModel( state == Qt::Checked );
810 mLegend->update();
811 mLegend->endCommand();
812 }
813
814 // do not allow editing of model if auto update is on - we would modify project's layer tree
815 QList<QWidget *> widgets;
816 widgets << mMoveDownToolButton << mMoveUpToolButton << mRemoveToolButton << mAddToolButton
817 << mEditPushButton << mCountToolButton << mUpdateAllPushButton << mAddGroupToolButton
818 << mExpressionFilterButton;
819 for ( QWidget *w : std::as_const( widgets ) )
820 w->setEnabled( state != Qt::Checked );
821
822 if ( state == Qt::Unchecked )
823 {
824 // update widgets state based on current selection
825 selectedChanged( QModelIndex(), QModelIndex() );
826 }
827}
828
829void QgsLayoutLegendWidget::composerMapChanged( QgsLayoutItem *item )
830{
831 if ( !mLegend )
832 {
833 return;
834 }
835
836 QgsLayout *layout = mLegend->layout();
837 if ( !layout )
838 {
839 return;
840 }
841
842 QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( item );
843 if ( map )
844 {
845 mLegend->beginCommand( tr( "Change Legend Map" ) );
846 mLegend->setLinkedMap( map );
847 mLegend->update();
848 mLegend->endCommand();
849
850 setLegendMapViewData();
851 }
852}
853
854void QgsLayoutLegendWidget::mCheckboxResizeContents_toggled( bool checked )
855{
856 if ( !mLegend )
857 {
858 return;
859 }
860
861 mLegend->beginCommand( tr( "Resize Legend to Contents" ) );
862 mLegend->setResizeToContents( checked );
863 if ( checked )
864 mLegend->adjustBoxSize();
865 mLegend->update();
866 mLegend->endCommand();
867}
868
869void QgsLayoutLegendWidget::mRasterStrokeGroupBox_toggled( bool state )
870{
871 if ( !mLegend )
872 {
873 return;
874 }
875
876 mLegend->beginCommand( tr( "Change Legend Borders" ) );
877 mLegend->setDrawRasterStroke( state );
878 mLegend->adjustBoxSize();
879 mLegend->update();
880 mLegend->endCommand();
881}
882
883void QgsLayoutLegendWidget::mRasterStrokeWidthSpinBox_valueChanged( double d )
884{
885 if ( !mLegend )
886 {
887 return;
888 }
889
890 mLegend->beginCommand( tr( "Resize Legend Borders" ), QgsLayoutItem::UndoLegendRasterStrokeWidth );
891 mLegend->setRasterStrokeWidth( d );
892 mLegend->adjustBoxSize();
893 mLegend->update();
894 mLegend->endCommand();
895}
896
897void QgsLayoutLegendWidget::mRasterStrokeColorButton_colorChanged( const QColor &newColor )
898{
899 if ( !mLegend )
900 {
901 return;
902 }
903
904 mLegend->beginCommand( tr( "Change Legend Border Color" ), QgsLayoutItem::UndoLegendRasterStrokeColor );
905 mLegend->setRasterStrokeColor( newColor );
906 mLegend->update();
907 mLegend->endCommand();
908}
909
910void QgsLayoutLegendWidget::mAddToolButton_clicked()
911{
912 if ( !mLegend )
913 {
914 return;
915 }
916
917 QList< QgsMapLayer * > visibleLayers;
918 if ( mLegend->linkedMap() )
919 {
920 visibleLayers = mLegend->linkedMap()->layersToRender();
921 }
922 if ( visibleLayers.isEmpty() )
923 {
924 // just use current canvas layers as visible layers
925 visibleLayers = mMapCanvas->layers( true );
926 }
927
928 QgsLayoutLegendLayersDialog addDialog( this );
929 addDialog.setVisibleLayers( visibleLayers );
930 if ( addDialog.exec() == QDialog::Accepted )
931 {
932 const QList<QgsMapLayer *> layers = addDialog.selectedLayers();
933 if ( !layers.empty() )
934 {
935 mLegend->beginCommand( tr( "Add Legend Item(s)" ) );
936 for ( QgsMapLayer *layer : layers )
937 {
938 mLegend->model()->rootGroup()->addLayer( layer );
939 }
940 mLegend->updateLegend();
941 mLegend->update();
942 mLegend->endCommand();
943 }
944 }
945}
946
947void QgsLayoutLegendWidget::mRemoveToolButton_clicked()
948{
949 if ( !mLegend )
950 {
951 return;
952 }
953
954 QItemSelectionModel *selectionModel = mItemTreeView->selectionModel();
955 if ( !selectionModel )
956 {
957 return;
958 }
959
960 mLegend->beginCommand( tr( "Remove Legend Item" ) );
961
962 QList<QPersistentModelIndex> proxyIndexes;
963 const QModelIndexList viewSelection = selectionModel->selectedIndexes();
964 for ( const QModelIndex &index : viewSelection )
965 proxyIndexes << index;
966
967 // first try to remove legend nodes
968 QHash<QgsLayerTreeLayer *, QList<int> > nodesWithRemoval;
969 for ( const QPersistentModelIndex &proxyIndex : std::as_const( proxyIndexes ) )
970 {
971 if ( QgsLayerTreeModelLegendNode *legendNode = mItemTreeView->index2legendNode( proxyIndex ) )
972 {
973 QgsLayerTreeLayer *nodeLayer = legendNode->layerNode();
974 nodesWithRemoval[nodeLayer].append( _unfilteredLegendNodeIndex( legendNode ) );
975 }
976 }
977 for ( auto it = nodesWithRemoval.constBegin(); it != nodesWithRemoval.constEnd(); ++it )
978 {
979 QList<int> toDelete = it.value();
980 std::sort( toDelete.begin(), toDelete.end(), std::greater<int>() );
981 QList<int> order = QgsMapLayerLegendUtils::legendNodeOrder( it.key() );
982
983 for ( int i : std::as_const( toDelete ) )
984 {
985 if ( i >= 0 && i < order.count() )
986 order.removeAt( i );
987 }
988
990 mItemTreeView->layerTreeModel()->refreshLayerLegend( it.key() );
991 }
992
993 // then remove layer tree nodes
994 for ( const QPersistentModelIndex &proxyIndex : std::as_const( proxyIndexes ) )
995 {
996 if ( proxyIndex.isValid() && mItemTreeView->index2node( proxyIndex ) )
997 {
998 const QModelIndex sourceIndex = mItemTreeView->proxyModel()->mapToSource( proxyIndex );
999 mLegend->model()->removeRow( sourceIndex.row(), sourceIndex.parent() );
1000 }
1001 }
1002
1003 mLegend->updateLegend();
1004 mLegend->update();
1005 mLegend->endCommand();
1006}
1007
1008void QgsLayoutLegendWidget::mEditPushButton_clicked()
1009{
1010 if ( !mLegend )
1011 {
1012 return;
1013 }
1014
1015 QModelIndex idx = mItemTreeView->selectionModel()->currentIndex();
1016 mItemTreeView_doubleClicked( idx );
1017}
1018
1019void QgsLayoutLegendWidget::resetLayerNodeToDefaults()
1020{
1021 if ( !mLegend )
1022 {
1023 return;
1024 }
1025
1026 //get current item
1027 QModelIndex currentIndex = mItemTreeView->currentIndex();
1028 if ( !currentIndex.isValid() )
1029 {
1030 return;
1031 }
1032
1033 QgsLayerTreeLayer *nodeLayer = nullptr;
1034 if ( QgsLayerTreeNode *node = mItemTreeView->index2node( currentIndex ) )
1035 {
1036 if ( QgsLayerTree::isLayer( node ) )
1037 nodeLayer = QgsLayerTree::toLayer( node );
1038 }
1039 if ( QgsLayerTreeModelLegendNode *legendNode = mItemTreeView->index2legendNode( currentIndex ) )
1040 {
1041 nodeLayer = legendNode->layerNode();
1042 }
1043
1044 if ( !nodeLayer )
1045 return;
1046
1047 mLegend->beginCommand( tr( "Update Legend" ) );
1048
1049 const auto constCustomProperties = nodeLayer->customProperties();
1050 for ( const QString &key : constCustomProperties )
1051 {
1052 if ( key.startsWith( QLatin1String( "legend/" ) ) )
1053 nodeLayer->removeCustomProperty( key );
1054 }
1055
1056 nodeLayer->setPatchShape( QgsLegendPatchShape() );
1057 nodeLayer->setPatchSize( QSizeF() );
1058
1059 mItemTreeView->layerTreeModel()->refreshLayerLegend( nodeLayer );
1060
1061 mLegend->updateLegend();
1062 mLegend->update();
1063 mLegend->endCommand();
1064}
1065
1066void QgsLayoutLegendWidget::mCountToolButton_clicked( bool checked )
1067{
1068 if ( !mLegend )
1069 {
1070 return;
1071 }
1072
1073 const QList< QModelIndex > selectedIndexes = mItemTreeView->selectionModel()->selectedIndexes();
1074 if ( selectedIndexes.empty() )
1075 return;
1076
1077 mLegend->beginCommand( tr( "Update Legend" ) );
1078 for ( const QModelIndex &index : selectedIndexes )
1079 {
1080 QgsLayerTreeNode *currentNode = mItemTreeView->index2node( index );
1081 if ( !QgsLayerTree::isLayer( currentNode ) )
1082 continue;
1083
1084 currentNode->setCustomProperty( QStringLiteral( "showFeatureCount" ), checked ? 1 : 0 );
1085 }
1086 mLegend->updateFilterByMap();
1087 mLegend->adjustBoxSize();
1088 mLegend->endCommand();
1089}
1090
1091void QgsLayoutLegendWidget::mFilterByMapCheckBox_toggled( bool checked )
1092{
1093 mLegend->beginCommand( tr( "Update Legend" ) );
1094 mLegend->setLegendFilterByMapEnabled( checked );
1095 mLegend->adjustBoxSize();
1096 mLegend->update();
1097 mLegend->endCommand();
1098}
1099
1100void QgsLayoutLegendWidget::mExpressionFilterButton_toggled( bool checked )
1101{
1102 if ( !mLegend )
1103 {
1104 return;
1105 }
1106
1107 //get current item
1108 QModelIndex currentIndex = mItemTreeView->currentIndex();
1109 if ( !currentIndex.isValid() )
1110 {
1111 return;
1112 }
1113
1114 QgsLayerTreeNode *currentNode = mItemTreeView->currentNode();
1115 if ( !QgsLayerTree::isLayer( currentNode ) )
1116 return;
1117
1118 QgsLayerTreeUtils::setLegendFilterByExpression( *qobject_cast<QgsLayerTreeLayer *>( currentNode ),
1119 mExpressionFilterButton->expressionText(),
1120 checked );
1121
1122 mLegend->beginCommand( tr( "Update Legend" ) );
1123 mLegend->updateFilterByMap();
1124 mLegend->adjustBoxSize();
1125 mLegend->endCommand();
1126}
1127
1128void QgsLayoutLegendWidget::mLayerExpressionButton_clicked()
1129{
1130 if ( !mLegend )
1131 {
1132 return;
1133 }
1134
1135 QModelIndex currentIndex = mItemTreeView->currentIndex();
1136 if ( !currentIndex.isValid() )
1137 return;
1138
1139 QgsLayerTreeNode *currentNode = mItemTreeView->currentNode();
1140 if ( !QgsLayerTree::isLayer( currentNode ) )
1141 return;
1142
1143 QgsLayerTreeLayer *layerNode = qobject_cast<QgsLayerTreeLayer *>( currentNode );
1144 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerNode->layer() );
1145
1146 if ( !vl )
1147 return;
1148
1149 QString currentExpression;
1150 if ( layerNode->labelExpression().isEmpty() )
1151 currentExpression = QStringLiteral( "@symbol_label" );
1152 else
1153 currentExpression = layerNode->labelExpression();
1154 QgsExpressionContext legendContext = mLegend->createExpressionContext();
1155 legendContext.appendScope( vl->createExpressionContextScope() );
1156
1157 QgsExpressionContextScope *symbolLegendScope = new QgsExpressionContextScope( tr( "Symbol scope" ) );
1158
1159 QgsFeatureRenderer *r = vl->renderer();
1160
1161 QStringList highlighted;
1162 if ( r )
1163 {
1164 const QgsLegendSymbolList legendSymbols = r->legendSymbolItems();
1165
1166 if ( !legendSymbols.empty() )
1167 {
1168 QgsSymbolLegendNode legendNode( layerNode, legendSymbols.first() );
1169
1170 symbolLegendScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_label" ), legendNode.symbolLabel().remove( QStringLiteral( "[%" ) ).remove( QStringLiteral( "%]" ) ), true ) );
1171 symbolLegendScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_id" ), legendSymbols.first().ruleKey(), true ) );
1172 highlighted << QStringLiteral( "symbol_label" ) << QStringLiteral( "symbol_id" );
1173 symbolLegendScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_count" ), QVariant::fromValue( vl->featureCount( legendSymbols.first().ruleKey() ) ), true ) );
1174 highlighted << QStringLiteral( "symbol_count" );
1175 }
1176 }
1177
1178 legendContext.appendScope( symbolLegendScope );
1179
1180 legendContext.setHighlightedVariables( highlighted );
1181
1182 QgsExpressionBuilderDialog expressiondialog( vl, currentExpression, nullptr, QStringLiteral( "generic" ), legendContext );
1183 if ( expressiondialog.exec() )
1184 layerNode->setLabelExpression( expressiondialog.expressionText() );
1185
1186 mLegend->beginCommand( tr( "Update Legend" ) );
1187 mLegend->refresh();
1188 mLegend->adjustBoxSize();
1189 mLegend->endCommand();
1190}
1191
1192void QgsLayoutLegendWidget::mUpdateAllPushButton_clicked()
1193{
1194 updateLegend();
1195}
1196
1197void QgsLayoutLegendWidget::mAddGroupToolButton_clicked()
1198{
1199 if ( mLegend )
1200 {
1201 mLegend->beginCommand( tr( "Add Legend Group" ) );
1202 mLegend->model()->rootGroup()->addGroup( tr( "Group" ) );
1203 mLegend->updateLegend();
1204 mLegend->update();
1205 mLegend->endCommand();
1206 }
1207}
1208
1209void QgsLayoutLegendWidget::mFilterLegendByAtlasCheckBox_toggled( bool toggled )
1210{
1211 Q_UNUSED( toggled )
1212 if ( mLegend )
1213 {
1214 mLegend->setLegendFilterOutAtlas( toggled );
1215 // force update of legend when in preview mode
1216 mLegend->refresh();
1217 }
1218}
1219
1220void QgsLayoutLegendWidget::updateLegend()
1221{
1222 if ( mLegend )
1223 {
1224 mLegend->beginCommand( tr( "Update Legend" ) );
1225
1226 // this will reset the model completely, losing any changes
1227 mLegend->setAutoUpdateModel( true );
1228 mLegend->setAutoUpdateModel( false );
1229 mLegend->update();
1230 mLegend->endCommand();
1231 }
1232}
1233
1234void QgsLayoutLegendWidget::setReportTypeString( const QString &string )
1235{
1236 mFilterLegendByAtlasCheckBox->setText( tr( "Only show items inside current %1 feature" ).arg( string ) );
1237 mFilterLegendByAtlasCheckBox->setToolTip( tr( "Filter out legend elements that lie outside the current %1 feature." ).arg( string ) );
1238}
1239
1240QgsExpressionContext QgsLayoutLegendWidget::createExpressionContext() const
1241{
1242 QgsExpressionContext context = mLegend->createExpressionContext();
1243 return context;
1244}
1245
1246bool QgsLayoutLegendWidget::setNewItem( QgsLayoutItem *item )
1247{
1249 return false;
1250
1251 if ( mLegend )
1252 {
1253 disconnect( mLegend, &QgsLayoutObject::changed, this, &QgsLayoutLegendWidget::setGuiElements );
1254 }
1255
1256 mLegend = qobject_cast< QgsLayoutItemLegend * >( item );
1257 mItemPropertiesWidget->setItem( mLegend );
1258
1259 if ( mLegend )
1260 {
1261 mItemTreeView->setModel( mLegend->model() );
1262 connect( mLegend, &QgsLayoutObject::changed, this, &QgsLayoutLegendWidget::setGuiElements );
1263 }
1264
1265 setGuiElements();
1266
1267 return true;
1268}
1269
1270void QgsLayoutLegendWidget::blockAllSignals( bool b )
1271{
1272 mTitleLineEdit->blockSignals( b );
1273 mTitleAlignCombo->blockSignals( b );
1274 mItemTreeView->blockSignals( b );
1275 mCheckBoxAutoUpdate->blockSignals( b );
1276 mMapComboBox->blockSignals( b );
1277 mFilterByMapCheckBox->blockSignals( b );
1278 mColumnCountSpinBox->blockSignals( b );
1279 mSplitLayerCheckBox->blockSignals( b );
1280 mEqualColumnWidthCheckBox->blockSignals( b );
1281 mSymbolWidthSpinBox->blockSignals( b );
1282 mSymbolHeightSpinBox->blockSignals( b );
1283 mMaxSymbolSizeSpinBox->blockSignals( b );
1284 mMinSymbolSizeSpinBox->blockSignals( b );
1285 mGroupSpaceSpinBox->blockSignals( b );
1286 mGroupIndentSpinBox->blockSignals( b );
1287 mSubgroupIndentSpinBox->blockSignals( b );
1288 mSpaceBelowGroupHeadingSpinBox->blockSignals( b );
1289 mGroupSideSpinBox->blockSignals( b );
1290 mSpaceBelowSubgroupHeadingSpinBox->blockSignals( b );
1291 mSubgroupSideSpinBox->blockSignals( b );
1292 mLayerSpaceSpinBox->blockSignals( b );
1293 mSymbolSpaceSpinBox->blockSignals( b );
1294 mSymbolSideSpaceSpinBox->blockSignals( b );
1295 mIconLabelSpaceSpinBox->blockSignals( b );
1296 mBoxSpaceSpinBox->blockSignals( b );
1297 mColumnSpaceSpinBox->blockSignals( b );
1298 mRasterStrokeGroupBox->blockSignals( b );
1299 mRasterStrokeColorButton->blockSignals( b );
1300 mRasterStrokeWidthSpinBox->blockSignals( b );
1301 mWmsLegendWidthSpinBox->blockSignals( b );
1302 mWmsLegendHeightSpinBox->blockSignals( b );
1303 mCheckboxResizeContents->blockSignals( b );
1304 mTitleSpaceBottomSpinBox->blockSignals( b );
1305 mFilterLegendByAtlasCheckBox->blockSignals( b );
1306 mTitleFontButton->blockSignals( b );
1307 mGroupFontButton->blockSignals( b );
1308 mLayerFontButton->blockSignals( b );
1309 mItemFontButton->blockSignals( b );
1310 mWrapCharLineEdit->blockSignals( b );
1311}
1312
1313void QgsLayoutLegendWidget::selectedChanged( const QModelIndex &current, const QModelIndex &previous )
1314{
1315 Q_UNUSED( current )
1316 Q_UNUSED( previous )
1317
1318 mLayerExpressionButton->setEnabled( false );
1319
1320 if ( mLegend && mLegend->autoUpdateModel() )
1321 {
1322 QgsLayerTreeNode *currentNode = mItemTreeView->currentNode();
1323 if ( !QgsLayerTree::isLayer( currentNode ) )
1324 return;
1325
1326 QgsLayerTreeLayer *currentLayerNode = QgsLayerTree::toLayer( currentNode );
1327 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( currentLayerNode->layer() );
1328 if ( !vl )
1329 return;
1330
1331 mLayerExpressionButton->setEnabled( true );
1332 return;
1333 }
1334
1335 mCountToolButton->setChecked( false );
1336 mCountToolButton->setEnabled( false );
1337
1338
1339 mExpressionFilterButton->blockSignals( true );
1340 mExpressionFilterButton->setChecked( false );
1341 mExpressionFilterButton->setEnabled( false );
1342 mExpressionFilterButton->blockSignals( false );
1343
1344 QgsLayerTreeNode *currentNode = mItemTreeView->currentNode();
1345 if ( !QgsLayerTree::isLayer( currentNode ) )
1346 return;
1347
1348 QgsLayerTreeLayer *currentLayerNode = QgsLayerTree::toLayer( currentNode );
1349 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( currentLayerNode->layer() );
1350 if ( !vl )
1351 return;
1352
1353 mCountToolButton->setChecked( currentNode->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toInt() );
1354 mCountToolButton->setEnabled( true );
1355 mLayerExpressionButton->setEnabled( true );
1356
1357 bool exprEnabled;
1358 QString expr = QgsLayerTreeUtils::legendFilterByExpression( *qobject_cast<QgsLayerTreeLayer *>( currentNode ), &exprEnabled );
1359 mExpressionFilterButton->blockSignals( true );
1360 mExpressionFilterButton->setExpressionText( expr );
1361 mExpressionFilterButton->setVectorLayer( vl );
1362 mExpressionFilterButton->setEnabled( true );
1363 mExpressionFilterButton->setChecked( exprEnabled );
1364 mExpressionFilterButton->blockSignals( false );
1365}
1366
1367void QgsLayoutLegendWidget::setCurrentNodeStyleFromAction()
1368{
1369 QAction *a = qobject_cast<QAction *>( sender() );
1370 if ( !a || !mItemTreeView->currentNode() )
1371 return;
1372
1373 QgsLegendRenderer::setNodeLegendStyle( mItemTreeView->currentNode(), static_cast< QgsLegendStyle::Style >( a->data().toInt() ) );
1374 mLegend->update();
1375}
1376
1377void QgsLayoutLegendWidget::setLegendMapViewData()
1378{
1379 if ( mLegend->linkedMap() )
1380 {
1381 int dpi = qt_defaultDpiX();
1383 measurementConverter.setDpi( dpi );
1384 double mapWidth = measurementConverter.convert( mLegend->linkedMap()->sizeWithUnits(), QgsUnitTypes::LayoutPixels ).width();
1385 double mapHeight = measurementConverter.convert( mLegend->linkedMap()->sizeWithUnits(), QgsUnitTypes::LayoutPixels ).height();
1386 double mapUnitsPerPixelX = mLegend->linkedMap()->extent().width() / mapWidth;
1387 double mapUnitsPerPixelY = mLegend->linkedMap()->extent().height() / mapHeight;
1388 mLegend->model()->setLegendMapViewData( ( mapUnitsPerPixelX > mapUnitsPerPixelY ? mapUnitsPerPixelX : mapUnitsPerPixelY ), dpi, mLegend->linkedMap()->scale() );
1389 }
1390}
1391
1392void QgsLayoutLegendWidget::updateFilterLegendByAtlasButton()
1393{
1394 if ( QgsLayoutAtlas *atlas = layoutAtlas() )
1395 {
1396 mFilterLegendByAtlasCheckBox->setEnabled( atlas->enabled() && mLegend->layout()->reportContext().layer() && mLegend->layout()->reportContext().layer()->geometryType() == QgsWkbTypes::PolygonGeometry );
1397 }
1398}
1399
1400void QgsLayoutLegendWidget::mItemTreeView_doubleClicked( const QModelIndex &idx )
1401{
1402 if ( !mLegend || !idx.isValid() )
1403 {
1404 return;
1405 }
1406
1407 if ( mLegend->autoUpdateModel() )
1408 return;
1409
1410 QgsLayerTreeNode *currentNode = mItemTreeView->index2node( idx );
1411 QgsLayerTreeModelLegendNode *legendNode = mItemTreeView->index2legendNode( idx );
1412
1413 int originalIndex = -1;
1414 if ( legendNode )
1415 {
1416 originalIndex = _originalLegendNodeIndex( legendNode );
1417 currentNode = legendNode->layerNode();
1418 }
1419
1420 QgsLayoutLegendNodeWidget *widget = new QgsLayoutLegendNodeWidget( mLegend, currentNode, legendNode, originalIndex );
1421 openPanel( widget );
1422}
1423
1424
1425//
1426// QgsComposerLegendMenuProvider
1427//
1428
1429QgsLayoutLegendMenuProvider::QgsLayoutLegendMenuProvider( QgsLayerTreeView *view, QgsLayoutLegendWidget *w )
1430 : mView( view )
1431 , mWidget( w )
1432{}
1433
1434QMenu *QgsLayoutLegendMenuProvider::createContextMenu()
1435{
1436 if ( !mView->currentNode() )
1437 return nullptr;
1438
1439 if ( mWidget->legend()->autoUpdateModel() )
1440 return nullptr; // no editing allowed
1441
1442 QMenu *menu = new QMenu();
1443
1444 if ( QgsLayerTree::isLayer( mView->currentNode() ) )
1445 {
1446 menu->addAction( QObject::tr( "Reset to Defaults" ), mWidget, &QgsLayoutLegendWidget::resetLayerNodeToDefaults );
1447 menu->addSeparator();
1448 }
1449
1450 QgsLegendStyle::Style currentStyle = QgsLegendRenderer::nodeLegendStyle( mView->currentNode(), mView->layerTreeModel() );
1451
1452 QList<QgsLegendStyle::Style> lst;
1454 for ( QgsLegendStyle::Style style : std::as_const( lst ) )
1455 {
1456 QAction *action = menu->addAction( QgsLegendStyle::styleLabel( style ), mWidget, &QgsLayoutLegendWidget::setCurrentNodeStyleFromAction );
1457 action->setCheckable( true );
1458 action->setChecked( currentStyle == style );
1459 action->setData( static_cast< int >( style ) );
1460 }
1461
1462 return menu;
1463}
1464
1465//
1466// QgsLayoutLegendNodeWidget
1467//
1468QgsLayoutLegendNodeWidget::QgsLayoutLegendNodeWidget( QgsLayoutItemLegend *legend, QgsLayerTreeNode *node, QgsLayerTreeModelLegendNode *legendNode, int originalLegendNodeIndex, QWidget *parent )
1469 : QgsPanelWidget( parent )
1470 , mLegend( legend )
1471 , mNode( node )
1472 , mLayer( qobject_cast< QgsLayerTreeLayer* >( node ) )
1473 , mLegendNode( legendNode )
1474 , mOriginalLegendNodeIndex( originalLegendNodeIndex )
1475{
1476 setupUi( this );
1477 setPanelTitle( tr( "Legend Item Properties" ) );
1478
1479 // auto close panel if layer removed
1480 connect( node, &QObject::destroyed, this, &QgsPanelWidget::acceptPanel );
1481
1482 mColumnSplitBehaviorComboBox->addItem( tr( "Follow Legend Default" ), QgsLayerTreeLayer::UseDefaultLegendSetting );
1483 mColumnSplitBehaviorComboBox->addItem( tr( "Allow Splitting Over Columns" ), QgsLayerTreeLayer::AllowSplittingLegendNodesOverMultipleColumns );
1484 mColumnSplitBehaviorComboBox->addItem( tr( "Prevent Splitting Over Columns" ), QgsLayerTreeLayer::PreventSplittingLegendNodesOverMultipleColumns );
1485
1486 QString currentLabel;
1487 if ( mLegendNode )
1488 {
1489 currentLabel = mLegendNode->data( Qt::EditRole ).toString();
1490 mColumnBreakBeforeCheckBox->setChecked( mLegendNode->columnBreak() );
1491 }
1492 else if ( mLayer )
1493 {
1494 currentLabel = mLayer->name();
1495 QVariant v = mLayer->customProperty( QStringLiteral( "legend/title-label" ) );
1496 if ( !QgsVariantUtils::isNull( v ) )
1497 currentLabel = v.toString();
1498 mColumnBreakBeforeCheckBox->setChecked( mLayer->customProperty( QStringLiteral( "legend/column-break" ) ).toInt() );
1499
1500 mColumnSplitBehaviorComboBox->setCurrentIndex( mColumnSplitBehaviorComboBox->findData( mLayer->legendSplitBehavior() ) );
1501 }
1502 else
1503 {
1504 currentLabel = QgsLayerTree::toGroup( mNode )->name();
1505 mColumnBreakBeforeCheckBox->setChecked( mNode->customProperty( QStringLiteral( "legend/column-break" ) ).toInt() );
1506 }
1507
1508 mWidthSpinBox->setClearValue( 0, tr( "Default" ) );
1509 mHeightSpinBox->setClearValue( 0, tr( "Default" ) );
1510 mWidthSpinBox->setVisible( mLegendNode || mLayer );
1511 mHeightSpinBox->setVisible( mLegendNode || mLayer );
1512 mPatchGroup->setVisible( mLegendNode || mLayer );
1513 mPatchWidthLabel->setVisible( mLegendNode || mLayer );
1514 mPatchHeightLabel->setVisible( mLegendNode || mLayer );
1515 mCustomSymbolCheckBox->setVisible( mLegendNode || mLegend->model()->legendNodeEmbeddedInParent( mLayer ) );
1516 mColumnSplitLabel->setVisible( mLayer && !mLegendNode );
1517 mColumnSplitBehaviorComboBox->setVisible( mLayer && !mLegendNode );
1518 if ( mLegendNode )
1519 {
1520 mWidthSpinBox->setValue( mLegendNode->userPatchSize().width() );
1521 mHeightSpinBox->setValue( mLegendNode->userPatchSize().height() );
1522 }
1523 else if ( mLayer )
1524 {
1525 mWidthSpinBox->setValue( mLayer->patchSize().width() );
1526 mHeightSpinBox->setValue( mLayer->patchSize().height() );
1527 }
1528
1529 mCustomSymbolCheckBox->setChecked( false );
1530
1531 QgsLegendPatchShape patchShape;
1532 if ( QgsSymbolLegendNode *symbolLegendNode = dynamic_cast< QgsSymbolLegendNode * >( mLegendNode ) )
1533 {
1534 patchShape = symbolLegendNode->patchShape();
1535
1536 std::unique_ptr< QgsSymbol > customSymbol( symbolLegendNode->customSymbol() ? symbolLegendNode->customSymbol()->clone() : nullptr );
1537 mCustomSymbolCheckBox->setChecked( customSymbol.get() );
1538 if ( customSymbol )
1539 {
1540 mPatchShapeButton->setPreviewSymbol( customSymbol->clone() );
1541 mCustomSymbolButton->setSymbolType( customSymbol->type() );
1542 mCustomSymbolButton->setSymbol( customSymbol.release() );
1543 }
1544 else if ( symbolLegendNode->symbol() )
1545 {
1546 mPatchShapeButton->setPreviewSymbol( symbolLegendNode->symbol()->clone() );
1547 mCustomSymbolButton->setSymbolType( symbolLegendNode->symbol()->type() );
1548 mCustomSymbolButton->setSymbol( symbolLegendNode->symbol()->clone() );
1549 }
1550 }
1551 else if ( !mLegendNode && mLayer )
1552 {
1553 patchShape = mLayer->patchShape();
1554 if ( QgsSymbolLegendNode *symbolLegendNode = dynamic_cast< QgsSymbolLegendNode * >( mLegend->model()->legendNodeEmbeddedInParent( mLayer ) ) )
1555 {
1556 if ( QgsSymbol *customSymbol = symbolLegendNode->customSymbol() )
1557 {
1558 mCustomSymbolCheckBox->setChecked( true );
1559 mPatchShapeButton->setPreviewSymbol( customSymbol->clone() );
1560 mCustomSymbolButton->setSymbolType( customSymbol->type() );
1561 mCustomSymbolButton->setSymbol( customSymbol->clone() );
1562 }
1563 else
1564 {
1565 mPatchShapeButton->setPreviewSymbol( symbolLegendNode->symbol()->clone() );
1566 mCustomSymbolButton->setSymbolType( symbolLegendNode->symbol()->type() );
1567 mCustomSymbolButton->setSymbol( symbolLegendNode->symbol()->clone() );
1568 }
1569 }
1570 }
1571
1572 if ( mLayer && mLayer->layer() && mLayer->layer()->type() == QgsMapLayerType::VectorLayer )
1573 {
1574 switch ( qobject_cast< QgsVectorLayer * >( mLayer->layer() )->geometryType() )
1575 {
1577 mPatchShapeButton->setSymbolType( Qgis::SymbolType::Fill );
1578 break;
1579
1581 mPatchShapeButton->setSymbolType( Qgis::SymbolType::Line );
1582 break;
1583
1585 mPatchShapeButton->setSymbolType( Qgis::SymbolType::Marker );
1586 break;
1587
1588 default:
1589 mPatchShapeLabel->hide();
1590 mPatchShapeButton->hide();
1591 break;
1592 }
1593 if ( !patchShape.isNull() )
1594 mPatchShapeButton->setShape( patchShape );
1595
1596 }
1597 else if ( QgsSymbolLegendNode *symbolLegendNode = dynamic_cast< QgsSymbolLegendNode * >( mLegendNode ) )
1598 {
1599 if ( symbolLegendNode->symbol() )
1600 {
1601 mPatchShapeButton->setSymbolType( symbolLegendNode->symbol()->type() );
1602 }
1603 else
1604 {
1605 mPatchShapeLabel->hide();
1606 mPatchShapeButton->hide();
1607 }
1608 }
1609 else
1610 {
1611 mPatchShapeLabel->hide();
1612 mPatchShapeButton->hide();
1613 }
1614
1615 if ( QgsColorRampLegendNode *colorRampNode = dynamic_cast< QgsColorRampLegendNode * >( mLegendNode ) )
1616 {
1617 mLabelGroup->hide();
1618 mColorRampLegendWidget->setSettings( colorRampNode->settings() );
1619 }
1620 else
1621 {
1622 mColorRampLegendWidget->hide();
1623 }
1624
1625 if ( mLegendNode )
1626 {
1627 switch ( static_cast< QgsLayerTreeModelLegendNode::NodeTypes >( mLegendNode->data( QgsLayerTreeModelLegendNode::NodeTypeRole ).toInt() ) )
1628 {
1635 mCustomSymbolCheckBox->hide();
1636 break;
1637
1640 break;
1641 }
1642 }
1643
1644 mLabelEdit->setPlainText( currentLabel );
1645 connect( mLabelEdit, &QPlainTextEdit::textChanged, this, &QgsLayoutLegendNodeWidget::labelChanged );
1646 connect( mPatchShapeButton, &QgsLegendPatchShapeButton::changed, this, &QgsLayoutLegendNodeWidget::patchChanged );
1647 connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsLayoutLegendNodeWidget::insertExpression );
1648
1649 connect( mWidthSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendNodeWidget::sizeChanged );
1650 connect( mHeightSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendNodeWidget::sizeChanged );
1651
1652 connect( mCustomSymbolCheckBox, &QGroupBox::toggled, this, &QgsLayoutLegendNodeWidget::customSymbolChanged );
1653 connect( mCustomSymbolButton, &QgsSymbolButton::changed, this, &QgsLayoutLegendNodeWidget::customSymbolChanged );
1654
1655 connect( mColumnBreakBeforeCheckBox, &QCheckBox::toggled, this, &QgsLayoutLegendNodeWidget::columnBreakToggled );
1656
1657 connect( mColumnSplitBehaviorComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsLayoutLegendNodeWidget::columnSplitChanged );
1658
1659 connect( mColorRampLegendWidget, &QgsColorRampLegendNodeWidget::widgetChanged, this, &QgsLayoutLegendNodeWidget::colorRampLegendChanged );
1660
1661 connectChildPanel( mColorRampLegendWidget );
1662}
1663
1664void QgsLayoutLegendNodeWidget::setDockMode( bool dockMode )
1665{
1666 mColorRampLegendWidget->setDockMode( dockMode );
1667 QgsPanelWidget::setDockMode( dockMode );
1668}
1669
1670void QgsLayoutLegendNodeWidget::labelChanged()
1671{
1672 mLegend->beginCommand( tr( "Edit Legend Item" ), QgsLayoutItem::UndoLegendText );
1673
1674 const QString label = mLabelEdit->toPlainText();
1675 if ( QgsLayerTree::isGroup( mNode ) )
1676 {
1677 QgsLayerTree::toGroup( mNode )->setName( label );
1678 }
1679 else if ( mLegendNode )
1680 {
1681 QgsMapLayerLegendUtils::setLegendNodeUserLabel( mLayer, mOriginalLegendNodeIndex, label );
1682 mLegend->model()->refreshLayerLegend( mLayer );
1683 }
1684 else if ( mLayer )
1685 {
1686 mLayer->setCustomProperty( QStringLiteral( "legend/title-label" ), label );
1687
1688 // force update of label of the legend node with embedded icon (a bit clumsy i know)
1689 if ( QgsLayerTreeModelLegendNode *embeddedNode = mLegend->model()->legendNodeEmbeddedInParent( mLayer ) )
1690 embeddedNode->setUserLabel( QString() );
1691 }
1692
1693 mLegend->adjustBoxSize();
1694 mLegend->update();
1695 mLegend->endCommand();
1696}
1697
1698void QgsLayoutLegendNodeWidget::patchChanged()
1699{
1700 mLegend->beginCommand( tr( "Edit Legend Item" ) );
1701
1702 QgsLegendPatchShape shape = mPatchShapeButton->shape();
1703 if ( mLegendNode )
1704 {
1705 QgsMapLayerLegendUtils::setLegendNodePatchShape( mLayer, mOriginalLegendNodeIndex, shape );
1706 mLegend->model()->refreshLayerLegend( mLayer );
1707 }
1708 else if ( mLayer )
1709 {
1710 mLayer->setPatchShape( shape );
1711 const QList<QgsLayerTreeModelLegendNode *> layerLegendNodes = mLegend->model()->layerLegendNodes( mLayer, false );
1712 for ( QgsLayerTreeModelLegendNode *node : layerLegendNodes )
1713 {
1714 QgsMapLayerLegendUtils::setLegendNodePatchShape( mLayer, _originalLegendNodeIndex( node ), shape );
1715 }
1716 mLegend->model()->refreshLayerLegend( mLayer );
1717 }
1718
1719 mLegend->adjustBoxSize();
1720 mLegend->update();
1721 mLegend->endCommand();
1722}
1723
1724void QgsLayoutLegendNodeWidget::insertExpression()
1725{
1726 if ( !mLegend )
1727 return;
1728
1729 QString selText = mLabelEdit->textCursor().selectedText();
1730
1731 // html editor replaces newlines with Paragraph Separator characters - see https://github.com/qgis/QGIS/issues/27568
1732 selText = selText.replace( QChar( 0x2029 ), QChar( '\n' ) );
1733
1734 // edit the selected expression if there's one
1735 if ( selText.startsWith( QLatin1String( "[%" ) ) && selText.endsWith( QLatin1String( "%]" ) ) )
1736 selText = selText.mid( 2, selText.size() - 4 );
1737
1738 // use the atlas coverage layer, if any
1739 QgsVectorLayer *layer = mLegend->layout() ? mLegend->layout()->reportContext().layer() : nullptr;
1740
1741 QgsExpressionContext context = mLegend->createExpressionContext();
1742
1743 if ( mLayer && mLayer->layer() )
1744 {
1745 context.appendScope( QgsExpressionContextUtils::layerScope( mLayer->layer() ) );
1746 }
1747
1748 context.setHighlightedVariables( QStringList() << QStringLiteral( "legend_title" )
1749 << QStringLiteral( "legend_column_count" )
1750 << QStringLiteral( "legend_split_layers" )
1751 << QStringLiteral( "legend_wrap_string" )
1752 << QStringLiteral( "legend_filter_by_map" )
1753 << QStringLiteral( "legend_filter_out_atlas" ) );
1754
1755 QgsExpressionBuilderDialog exprDlg( layer, selText, this, QStringLiteral( "generic" ), context );
1756
1757 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
1758 if ( exprDlg.exec() == QDialog::Accepted )
1759 {
1760 QString expression = exprDlg.expressionText();
1761 if ( !expression.isEmpty() )
1762 {
1763 mLegend->beginCommand( tr( "Insert expression" ) );
1764 mLabelEdit->insertPlainText( "[%" + expression + "%]" );
1765 mLegend->endCommand();
1766 }
1767 }
1768}
1769
1770void QgsLayoutLegendNodeWidget::sizeChanged( double )
1771{
1772 mLegend->beginCommand( tr( "Edit Legend Item" ) );
1773 const QSizeF size = QSizeF( mWidthSpinBox->value(), mHeightSpinBox->value() );
1774
1775 if ( mLegendNode )
1776 {
1777 QgsMapLayerLegendUtils::setLegendNodeSymbolSize( mLayer, mOriginalLegendNodeIndex, size );
1778 mLegend->model()->refreshLayerLegend( mLayer );
1779 }
1780 else if ( mLayer )
1781 {
1782 mLayer->setPatchSize( size );
1783 const QList<QgsLayerTreeModelLegendNode *> layerLegendNodes = mLegend->model()->layerLegendNodes( mLayer, false );
1784 for ( QgsLayerTreeModelLegendNode *node : layerLegendNodes )
1785 {
1786 QgsMapLayerLegendUtils::setLegendNodeSymbolSize( mLayer, _originalLegendNodeIndex( node ), size );
1787 }
1788 mLegend->model()->refreshLayerLegend( mLayer );
1789 }
1790
1791 mLegend->adjustBoxSize();
1792 mLegend->update();
1793 mLegend->endCommand();
1794}
1795
1796void QgsLayoutLegendNodeWidget::customSymbolChanged()
1797{
1798 mLegend->beginCommand( tr( "Edit Legend Item" ) );
1799
1800 if ( mCustomSymbolCheckBox->isChecked() )
1801 {
1802 if ( mLegendNode )
1803 {
1804 QgsMapLayerLegendUtils::setLegendNodeCustomSymbol( mLayer, mOriginalLegendNodeIndex, mCustomSymbolButton->symbol() );
1805 mLegend->model()->refreshLayerLegend( mLayer );
1806 }
1807 else if ( mLayer )
1808 {
1809 const QList<QgsLayerTreeModelLegendNode *> layerLegendNodes = mLegend->model()->layerLegendNodes( mLayer, false );
1810 for ( QgsLayerTreeModelLegendNode *node : layerLegendNodes )
1811 {
1812 QgsMapLayerLegendUtils::setLegendNodeCustomSymbol( mLayer, _originalLegendNodeIndex( node ), mCustomSymbolButton->symbol() );
1813 }
1814 mLegend->model()->refreshLayerLegend( mLayer );
1815 }
1816 }
1817 else
1818 {
1819 if ( mLegendNode )
1820 {
1821 QgsMapLayerLegendUtils::setLegendNodeCustomSymbol( mLayer, mOriginalLegendNodeIndex, nullptr );
1822 mLegend->model()->refreshLayerLegend( mLayer );
1823 }
1824 else if ( mLayer )
1825 {
1826 const QList<QgsLayerTreeModelLegendNode *> layerLegendNodes = mLegend->model()->layerLegendNodes( mLayer, false );
1827 for ( QgsLayerTreeModelLegendNode *node : layerLegendNodes )
1828 {
1829 QgsMapLayerLegendUtils::setLegendNodeCustomSymbol( mLayer, _originalLegendNodeIndex( node ), nullptr );
1830 }
1831 mLegend->model()->refreshLayerLegend( mLayer );
1832 }
1833 }
1834
1835 mLegend->adjustBoxSize();
1836 mLegend->update();
1837 mLegend->endCommand();
1838}
1839
1840void QgsLayoutLegendNodeWidget::colorRampLegendChanged()
1841{
1842 mLegend->beginCommand( tr( "Edit Legend Item" ) );
1843
1844 QgsColorRampLegendNodeSettings settings = mColorRampLegendWidget->settings();
1845 QgsMapLayerLegendUtils::setLegendNodeColorRampSettings( mLayer, mOriginalLegendNodeIndex, &settings );
1846 mLegend->model()->refreshLayerLegend( mLayer );
1847
1848 mLegend->adjustBoxSize();
1849 mLegend->update();
1850 mLegend->endCommand();
1851}
1852
1853void QgsLayoutLegendNodeWidget::columnBreakToggled( bool checked )
1854{
1855 mLegend->beginCommand( tr( "Edit Legend Columns" ) );
1856
1857 if ( mLegendNode )
1858 {
1859 QgsMapLayerLegendUtils::setLegendNodeColumnBreak( mLayer, mOriginalLegendNodeIndex, checked );
1860 mLegend->model()->refreshLayerLegend( mLayer );
1861 }
1862 else if ( mLayer )
1863 {
1864 mLayer->setCustomProperty( QStringLiteral( "legend/column-break" ), QString( checked ? '1' : '0' ) );
1865 }
1866 else if ( mNode )
1867 {
1868 mNode->setCustomProperty( QStringLiteral( "legend/column-break" ), QString( checked ? '1' : '0' ) );
1869 }
1870
1871 mLegend->adjustBoxSize();
1872 mLegend->update();
1873 mLegend->endCommand();
1874}
1875
1876void QgsLayoutLegendNodeWidget::columnSplitChanged()
1877{
1878 mLegend->beginCommand( tr( "Edit Legend Columns" ) );
1879
1880 if ( mLayer && !mLegendNode )
1881 {
1882 mLayer->setLegendSplitBehavior( static_cast< QgsLayerTreeLayer::LegendNodesSplitBehavior >( mColumnSplitBehaviorComboBox->currentData().toInt() ) );
1883 }
1884
1885 mLegend->adjustBoxSize();
1886 mLegend->update();
1887 mLegend->endCommand();
1888}
1889
@ Marker
Marker symbol.
@ Line
Line symbol.
@ Fill
Fill symbol.
void changed()
Emitted when the alignment is changed.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
Settings for a color ramp legend node.
A legend node which renders a color ramp.
A generic dialog for building expression strings.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setHighlightedVariables(const QStringList &variableNames)
Sets the list of variable names within the context intended to be highlighted to the user.
virtual QgsLegendSymbolList legendSymbolItems() const
Returns a list of symbology items for the legend.
@ ModeTextRenderer
Configure font settings for use with QgsTextRenderer.
Definition: qgsfontbutton.h:62
void setLayer(QgsVectorLayer *layer)
Sets a layer to associate with the widget.
void changed()
Emitted when the widget's text format settings are changed.
Layer tree group node serves as a container for layers and further groups.
void insertChildNode(int index, QgsLayerTreeNode *node)
Insert existing node at specified position.
void setName(const QString &n) override
Sets the group's name.
void removeChildNode(QgsLayerTreeNode *node)
Remove a child node from this group.
QString name() const override
Returns the group's name.
Layer tree node points to a map layer.
void setPatchSize(QSizeF size)
Sets the user (overridden) size for the legend node.
QString labelExpression() const
Returns the expression member of the LayerTreeNode.
LegendNodesSplitBehavior
Legend node column split behavior.
@ AllowSplittingLegendNodesOverMultipleColumns
Allow splitting node's legend nodes across multiple columns.
@ PreventSplittingLegendNodesOverMultipleColumns
Prevent splitting node's legend nodes across multiple columns.
@ UseDefaultLegendSetting
Inherit default legend column splitting setting.
void setLabelExpression(const QString &expression)
set the expression to evaluate
void setPatchShape(const QgsLegendPatchShape &shape)
Sets the symbol patch shape to use when rendering the legend node symbol.
QgsMapLayer * layer() const
Returns the map layer associated with this node.
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
@ SimpleLegend
Simple label with icon legend node type.
@ RasterSymbolLegend
Raster symbol legend node type.
@ ImageLegend
Raster image legend node type.
@ DataDefinedSizeLegend
Marker symbol legend node type.
@ EmbeddedWidget
Embedded widget placeholder node type.
@ ColorRampLegend
Color ramp legend (since QGIS 3.18)
@ SymbolLegend
Vector symbol legend node type.
@ NodeTypeRole
Type of node. Added in 3.16.
QgsLayerTreeModel * model() const
Returns pointer to model owning this legend node.
QgsLayerTreeLayer * layerNode() const
Returns pointer to the parent layer node.
QgsLayerTreeModelLegendNode * legendNodeEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const
Returns legend node that may be embedded in parent (i.e.
QList< QgsLayerTreeModelLegendNode * > layerOriginalLegendNodes(QgsLayerTreeLayer *nodeLayer)
Returns original (unfiltered) list of legend nodes attached to a particular layer node.
This class is a base class for nodes in a layer tree.
void setCustomProperty(const QString &key, const QVariant &value)
Sets a custom property for the node. Properties are stored in a map and saved in project file.
void removeCustomProperty(const QString &key)
Remove a custom property from layer. Properties are stored in a map and saved in project file.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer. Properties are stored in a map and saved in project file.
QgsLayerTreeNode * parent()
Gets pointer to the parent. If parent is nullptr, the node is a root node.
QStringList customProperties() const
Returns list of keys stored in custom properties.
virtual QgsLayerTreeNode * clone() const =0
Create a copy of the node. Returns new instance.
static void setLegendFilterByExpression(QgsLayerTreeLayer &layer, const QString &expr, bool enabled=true)
Sets the expression filter of a legend layer.
static QString legendFilterByExpression(const QgsLayerTreeLayer &layer, bool *enabled=nullptr)
Returns the expression filter of a legend layer.
The QgsLayerTreeView class extends QTreeView and provides some additional functionality when working ...
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:75
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:53
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:43
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Definition: qgslayertree.h:64
Class used to render QgsLayout as an atlas, by iterating over the features from an associated vector ...
void toggled(bool)
Emitted when atlas is enabled or disabled.
A common interface for layout designer dialogs and widgets.
virtual QgsMessageBar * messageBar()=0
Returns the designer's message bar.
A base class for property widgets for layout items.
virtual void setDesignerInterface(QgsLayoutDesignerInterface *iface)
Sets the the layout designer interface in which the widget is being shown.
void itemChanged(QgsLayoutItem *item)
Emitted whenever the currently selected item changes.
A layout item subclass for map legends.
QgsLegendModel * model()
Returns the legend model.
Layout graphical items for displaying a map.
A widget for controlling the common properties of layout items (e.g.
Base class for graphical items within a QgsLayout.
@ UndoLegendMinSymbolSize
Legend minimum symbol size.
@ UndoLegendTitleSpaceBottom
Legend title space.
@ UndoLegendIconSymbolSpace
Legend icon symbol space.
@ UndoLegendLayerFont
Legend layer font.
@ UndoLegendBoxSpace
Legend box space.
@ UndoLegendRasterStrokeColor
Legend raster stroke color.
@ UndoLegendTitleFont
Legend title font.
@ UndoLegendItemFont
Legend item font.
@ UndoLegendWmsLegendWidth
Legend WMS width.
@ UndoLegendLayerSpace
Legend layer spacing.
@ UndoLegendColumnSpace
Legend column space.
@ UndoLegendMaxSymbolSize
Legend maximum symbol size.
@ UndoLegendSymbolSpace
Legend symbol spacing.
@ UndoLegendSymbolWidth
Legend symbol width.
@ UndoLegendColumnCount
Legend column count.
@ UndoLegendSymbolHeight
Legend symbol height.
@ UndoLegendGroupSpace
Legend group spacing.
@ UndoLegendSubgroupIndent
Legend subgroup indent.
@ UndoLegendRasterStrokeWidth
Legend raster stroke width.
@ UndoLegendGroupIndent
Legend group indent.
@ UndoLegendText
Legend text.
@ UndoLegendWmsLegendHeight
Legend WMS height.
@ UndoLegendGroupFont
Legend group font.
int type() const override
Returns a unique graphics item type identifier.
A dialog to add new layers to the legend.
This class provides a method of converting QgsLayoutMeasurements from one unit to another.
QgsLayoutMeasurement convert(QgsLayoutMeasurement measurement, QgsUnitTypes::LayoutUnit targetUnits) const
Converts a measurement from one unit to another.
void setDpi(const double dpi)
Sets the dots per inch (dpi) for the measurement converter.
const QgsLayout * layout() const
Returns the layout the object is attached to.
void changed()
Emitted when the object's properties change.
@ LegendTitle
Legend title.
@ LegendColumnCount
Legend column count.
void layerChanged(QgsVectorLayer *layer)
Emitted when the context's layer is changed.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:52
QgsLayoutReportContext & reportContext()
Returns a reference to the layout's report context, which stores information relating to the current ...
Definition: qgslayout.cpp:373
void changed()
Emitted when the shape's settings are changed.
Represents a patch shape for use in map legends.
void setSymbolType(Qgis::SymbolType type)
Sets the symbol type associated with this patch.
bool isNull() const
Returns true if the patch shape is a null QgsLegendPatchShape, which indicates that the default legen...
static void setNodeLegendStyle(QgsLayerTreeNode *node, QgsLegendStyle::Style style)
Sets the style of a node.
static QgsLegendStyle::Style nodeLegendStyle(QgsLayerTreeNode *node, QgsLayerTreeModel *model)
Returns the style for the given node, within the specified model.
static QString styleLabel(Style s)
Returns a translated string representing a style component, for use in UI.
@ Left
Left side.
@ Bottom
Bottom side.
@ Top
Top side.
Style
Component of legends which can be styled.
@ Group
Legend group title.
@ Symbol
Symbol icon (excluding label)
@ Subgroup
Legend subgroup title.
@ Title
Legend title.
@ Hidden
Special style, item is hidden including margins around.
@ SymbolLabel
Symbol label (excluding icon)
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:90
static void setLegendNodeOrder(QgsLayerTreeLayer *nodeLayer, const QList< int > &order)
static void setLegendNodeColorRampSettings(QgsLayerTreeLayer *nodeLayer, int originalIndex, const QgsColorRampLegendNodeSettings *settings)
Sets a custom legend color ramp settings for the legend node belonging to nodeLayer at the specified ...
static void setLegendNodeCustomSymbol(QgsLayerTreeLayer *nodeLayer, int originalIndex, const QgsSymbol *symbol)
Sets a custom legend symbol for the legend node belonging to nodeLayer at the specified originalIndex...
static void setLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex, const QString &newLabel)
static void setLegendNodeSymbolSize(QgsLayerTreeLayer *nodeLayer, int originalIndex, QSizeF size)
Sets the legend symbol size for the legend node belonging to nodeLayer at the specified originalIndex...
static void setLegendNodeColumnBreak(QgsLayerTreeLayer *nodeLayer, int originalIndex, bool columnBreakBeforeNode)
Sets whether a forced column break should occur before the node.
static void setLegendNodePatchShape(QgsLayerTreeLayer *nodeLayer, int originalIndex, const QgsLegendPatchShape &shape)
Sets the legend patch shape for the legend node belonging to nodeLayer at the specified originalIndex...
static QList< int > legendNodeOrder(QgsLayerTreeLayer *nodeLayer)
Base class for all map layer types.
Definition: qgsmaplayer.h:73
Interface for master layout type objects, such as print layouts and reports.
Base class for any widget that can be shown as a inline panel.
void widgetChanged()
Emitted when the widget state changes.
void acceptPanel()
Accept the panel.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
void changed()
Emitted when the symbol's settings are changed.
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:93
@ LayoutPixels
Pixels.
Definition: qgsunittypes.h:190
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based data sets.
QgsExpressionContextScope * createExpressionContextScope() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
@ VectorLayer
Vector layer.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
QgsLayerTreeModelLegendNode * legendNode(const QString &rule, QgsLayerTreeModel &model)
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:3053
QList< QgsLegendSymbolItem > QgsLegendSymbolList
Q_GUI_EXPORT int qt_defaultDpiX()
Single variable definition for use within a QgsExpressionContextScope.