QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
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 
18 #include "qgslayoutlegendwidget.h"
19 #include "qgslayoutitemlegend.h"
21 #include "qgslayoutitemwidget.h"
22 #include "qgslayoutitemmap.h"
23 #include "qgslayout.h"
24 #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 "qgsproject.h"
35 #include "qgsrenderer.h"
36 #include "qgsvectorlayer.h"
37 #include "qgslayoutatlas.h"
38 #include "qgslayoutitemlegend.h"
40 #include "qgsunittypes.h"
43 
44 #include <QMenu>
45 #include <QMessageBox>
46 #include <QInputDialog>
47 
48 Q_GUI_EXPORT extern int qt_defaultDpiX();
49 
50 static int _unfilteredLegendNodeIndex( QgsLayerTreeModelLegendNode *legendNode )
51 {
52  return legendNode->model()->layerOriginalLegendNodes( legendNode->layerNode() ).indexOf( legendNode );
53 }
54 
55 static int _originalLegendNodeIndex( QgsLayerTreeModelLegendNode *legendNode )
56 {
57  // figure out index of the legend node as it comes out of the map layer legend.
58  // first legend nodes may be reordered, output of that is available in layerOriginalLegendNodes().
59  // next the nodes may be further filtered (by scale, map content etc).
60  // so here we go in reverse order: 1. find index before filtering, 2. find index before reorder
61  int unfilteredNodeIndex = _unfilteredLegendNodeIndex( legendNode );
62  QList<int> order = QgsMapLayerLegendUtils::legendNodeOrder( legendNode->layerNode() );
63  return ( unfilteredNodeIndex >= 0 && unfilteredNodeIndex < order.count() ? order[unfilteredNodeIndex] : -1 );
64 }
65 
66 
68  : QgsLayoutItemBaseWidget( nullptr, legend )
69  , mLegend( legend )
70  , mMapCanvas( mapCanvas )
71 {
72  Q_ASSERT( mLegend );
73 
74  setupUi( this );
75  connect( mWrapCharLineEdit, &QLineEdit::textChanged, this, &QgsLayoutLegendWidget::mWrapCharLineEdit_textChanged );
76  connect( mTitleLineEdit, &QLineEdit::textChanged, this, &QgsLayoutLegendWidget::mTitleLineEdit_textChanged );
77  connect( mTitleAlignCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::titleAlignmentChanged );
78  connect( mGroupAlignCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::groupAlignmentChanged );
79  connect( mSubgroupAlignCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::subgroupAlignmentChanged );
80  connect( mItemAlignCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::itemAlignmentChanged );
81  connect( mColumnCountSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mColumnCountSpinBox_valueChanged );
82  connect( mSplitLayerCheckBox, &QCheckBox::toggled, this, &QgsLayoutLegendWidget::mSplitLayerCheckBox_toggled );
83  connect( mEqualColumnWidthCheckBox, &QCheckBox::toggled, this, &QgsLayoutLegendWidget::mEqualColumnWidthCheckBox_toggled );
84  connect( mSymbolWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mSymbolWidthSpinBox_valueChanged );
85  connect( mSymbolHeightSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mSymbolHeightSpinBox_valueChanged );
86  connect( mWmsLegendWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mWmsLegendWidthSpinBox_valueChanged );
87  connect( mWmsLegendHeightSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mWmsLegendHeightSpinBox_valueChanged );
88  connect( mTitleSpaceBottomSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mTitleSpaceBottomSpinBox_valueChanged );
89  connect( mGroupSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mGroupSpaceSpinBox_valueChanged );
90  connect( mSpaceBelowGroupHeadingSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::spaceBelowGroupHeadingChanged );
91  connect( mLayerSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mLayerSpaceSpinBox_valueChanged );
92  connect( mSpaceBelowSubgroupHeadingSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::spaceBelowSubGroupHeadingChanged );
93  connect( mSymbolSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mSymbolSpaceSpinBox_valueChanged );
94  connect( mIconLabelSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mIconLabelSpaceSpinBox_valueChanged );
95  connect( mFontColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutLegendWidget::mFontColorButton_colorChanged );
96  connect( mBoxSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mBoxSpaceSpinBox_valueChanged );
97  connect( mColumnSpaceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mColumnSpaceSpinBox_valueChanged );
98  connect( mLineSpacingSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mLineSpacingSpinBox_valueChanged );
99  connect( mCheckBoxAutoUpdate, &QCheckBox::stateChanged, this, &QgsLayoutLegendWidget::mCheckBoxAutoUpdate_stateChanged );
100  connect( mCheckboxResizeContents, &QCheckBox::toggled, this, &QgsLayoutLegendWidget::mCheckboxResizeContents_toggled );
101  connect( mRasterStrokeGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutLegendWidget::mRasterStrokeGroupBox_toggled );
102  connect( mRasterStrokeWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mRasterStrokeWidthSpinBox_valueChanged );
103  connect( mRasterStrokeColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutLegendWidget::mRasterStrokeColorButton_colorChanged );
104  connect( mMoveDownToolButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mMoveDownToolButton_clicked );
105  connect( mMoveUpToolButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mMoveUpToolButton_clicked );
106  connect( mRemoveToolButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mRemoveToolButton_clicked );
107  connect( mAddToolButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mAddToolButton_clicked );
108  connect( mEditPushButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mEditPushButton_clicked );
109  connect( mCountToolButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mCountToolButton_clicked );
110  connect( mExpressionFilterButton, &QgsLegendFilterButton::toggled, this, &QgsLayoutLegendWidget::mExpressionFilterButton_toggled );
111  connect( mLayerExpressionButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mLayerExpressionButton_clicked );
112  connect( mFilterByMapCheckBox, &QCheckBox::toggled, this, &QgsLayoutLegendWidget::mFilterByMapCheckBox_toggled );
113  connect( mUpdateAllPushButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mUpdateAllPushButton_clicked );
114  connect( mAddGroupToolButton, &QToolButton::clicked, this, &QgsLayoutLegendWidget::mAddGroupToolButton_clicked );
115  connect( mFilterLegendByAtlasCheckBox, &QCheckBox::toggled, this, &QgsLayoutLegendWidget::mFilterLegendByAtlasCheckBox_toggled );
116  connect( mItemTreeView, &QgsLayerTreeView::doubleClicked, this, &QgsLayoutLegendWidget::mItemTreeView_doubleClicked );
117  setPanelTitle( tr( "Legend Properties" ) );
118 
119  mTitleFontButton->setMode( QgsFontButton::ModeQFont );
120  mGroupFontButton->setMode( QgsFontButton::ModeQFont );
121  mLayerFontButton->setMode( QgsFontButton::ModeQFont );
122  mItemFontButton->setMode( QgsFontButton::ModeQFont );
123 
124  mTitleAlignCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
125  mGroupAlignCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
126  mSubgroupAlignCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
127  mItemAlignCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
128 
129  mArrangementCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignRight );
130  connect( mArrangementCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::arrangementChanged );
131  mArrangementCombo->customizeAlignmentDisplay( Qt::AlignLeft, tr( "Symbols on Left" ), QgsApplication::getThemeIcon( QStringLiteral( "/mIconArrangeSymbolsLeft.svg" ) ) );
132  mArrangementCombo->customizeAlignmentDisplay( Qt::AlignRight, tr( "Symbols on Right" ), QgsApplication::getThemeIcon( QStringLiteral( "/mIconArrangeSymbolsRight.svg" ) ) );
133 
134  mSpaceBelowGroupHeadingSpinBox->setClearValue( 0 );
135  mSpaceBelowSubgroupHeadingSpinBox->setClearValue( 0 );
136 
137  // setup icons
138  mAddToolButton->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
139  mEditPushButton->setIcon( QIcon( QgsApplication::iconPath( "symbologyEdit.svg" ) ) );
140  mRemoveToolButton->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
141  mMoveUpToolButton->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowUp.svg" ) ) );
142  mMoveDownToolButton->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowDown.svg" ) ) );
143  mCountToolButton->setIcon( QIcon( QgsApplication::iconPath( "mActionSum.svg" ) ) );
144  mLayerExpressionButton->setIcon( QIcon( QgsApplication::iconPath( "mIconExpression.svg" ) ) );
145 
146  mMoveDownToolButton->setIconSize( QgsGuiUtils::iconSize( true ) );
147  mMoveUpToolButton->setIconSize( QgsGuiUtils::iconSize( true ) );
148  mAddGroupToolButton->setIconSize( QgsGuiUtils::iconSize( true ) );
149  mAddToolButton->setIconSize( QgsGuiUtils::iconSize( true ) );
150  mRemoveToolButton->setIconSize( QgsGuiUtils::iconSize( true ) );
151  mEditPushButton->setIconSize( QgsGuiUtils::iconSize( true ) );
152  mCountToolButton->setIconSize( QgsGuiUtils::iconSize( true ) );
153  mExpressionFilterButton->setIconSize( QgsGuiUtils::iconSize( true ) );
154  mLayerExpressionButton->setIconSize( QgsGuiUtils::iconSize( true ) );
155 
156  mFontColorButton->setColorDialogTitle( tr( "Select Font Color" ) );
157  mFontColorButton->setContext( QStringLiteral( "composer" ) );
158 
159  mRasterStrokeColorButton->setColorDialogTitle( tr( "Select Stroke Color" ) );
160  mRasterStrokeColorButton->setAllowOpacity( true );
161  mRasterStrokeColorButton->setContext( QStringLiteral( "composer " ) );
162 
163  mMapComboBox->setCurrentLayout( legend->layout() );
164  mMapComboBox->setItemType( QgsLayoutItemRegistry::LayoutMap );
165  connect( mMapComboBox, &QgsLayoutItemComboBox::itemChanged, this, &QgsLayoutLegendWidget::composerMapChanged );
166 
167  //add widget for general composer item properties
168  mItemPropertiesWidget = new QgsLayoutItemPropertiesWidget( this, legend );
169  mainLayout->addWidget( mItemPropertiesWidget );
170 
171  mItemTreeView->setHeaderHidden( true );
172 
173  mItemTreeView->setModel( legend->model() );
174  mItemTreeView->setMenuProvider( new QgsLayoutLegendMenuProvider( mItemTreeView, this ) );
175  setLegendMapViewData();
176  connect( legend, &QgsLayoutObject::changed, this, &QgsLayoutLegendWidget::setGuiElements );
177 
178  // connect atlas state to the filter legend by atlas checkbox
179  if ( layoutAtlas() )
180  {
181  connect( layoutAtlas(), &QgsLayoutAtlas::toggled, this, &QgsLayoutLegendWidget::updateFilterLegendByAtlasButton );
182  }
183  connect( &legend->layout()->reportContext(), &QgsLayoutReportContext::layerChanged, this, &QgsLayoutLegendWidget::updateFilterLegendByAtlasButton );
184 
187 
188  setGuiElements();
189 
190  connect( mItemTreeView->selectionModel(), &QItemSelectionModel::currentChanged,
191  this, &QgsLayoutLegendWidget::selectedChanged );
192  connect( mTitleFontButton, &QgsFontButton::changed, this, &QgsLayoutLegendWidget::titleFontChanged );
193  connect( mGroupFontButton, &QgsFontButton::changed, this, &QgsLayoutLegendWidget::groupFontChanged );
194  connect( mLayerFontButton, &QgsFontButton::changed, this, &QgsLayoutLegendWidget::layerFontChanged );
195  connect( mItemFontButton, &QgsFontButton::changed, this, &QgsLayoutLegendWidget::itemFontChanged );
196 }
197 
199 {
200  if ( mItemPropertiesWidget )
201  mItemPropertiesWidget->setMasterLayout( masterLayout );
202 }
203 
204 void QgsLayoutLegendWidget::setGuiElements()
205 {
206  if ( !mLegend )
207  {
208  return;
209  }
210 
211  blockAllSignals( true );
212  mTitleLineEdit->setText( mLegend->title() );
213  whileBlocking( mTitleAlignCombo )->setCurrentAlignment( mLegend->titleAlignment() );
214  whileBlocking( mGroupAlignCombo )->setCurrentAlignment( mLegend->style( QgsLegendStyle::Group ).alignment() );
215  whileBlocking( mSubgroupAlignCombo )->setCurrentAlignment( mLegend->style( QgsLegendStyle::Subgroup ).alignment() );
216  whileBlocking( mItemAlignCombo )->setCurrentAlignment( mLegend->style( QgsLegendStyle::SymbolLabel ).alignment() );
217  whileBlocking( mArrangementCombo )->setCurrentAlignment( mLegend->symbolAlignment() );
218  mFilterByMapCheckBox->setChecked( mLegend->legendFilterByMapEnabled() );
219  mColumnCountSpinBox->setValue( mLegend->columnCount() );
220  mSplitLayerCheckBox->setChecked( mLegend->splitLayer() );
221  mEqualColumnWidthCheckBox->setChecked( mLegend->equalColumnWidth() );
222  mSymbolWidthSpinBox->setValue( mLegend->symbolWidth() );
223  mSymbolHeightSpinBox->setValue( mLegend->symbolHeight() );
224  mWmsLegendWidthSpinBox->setValue( mLegend->wmsLegendWidth() );
225  mWmsLegendHeightSpinBox->setValue( mLegend->wmsLegendHeight() );
226  mTitleSpaceBottomSpinBox->setValue( mLegend->style( QgsLegendStyle::Title ).margin( QgsLegendStyle::Bottom ) );
227  mGroupSpaceSpinBox->setValue( mLegend->style( QgsLegendStyle::Group ).margin( QgsLegendStyle::Top ) );
228  mSpaceBelowGroupHeadingSpinBox->setValue( mLegend->style( QgsLegendStyle::Group ).margin( QgsLegendStyle::Bottom ) );
229  mLayerSpaceSpinBox->setValue( mLegend->style( QgsLegendStyle::Subgroup ).margin( QgsLegendStyle::Top ) );
230  mSpaceBelowSubgroupHeadingSpinBox->setValue( mLegend->style( QgsLegendStyle::Subgroup ).margin( QgsLegendStyle::Bottom ) );
231  // We keep Symbol and SymbolLabel Top in sync for now
232  mSymbolSpaceSpinBox->setValue( mLegend->style( QgsLegendStyle::Symbol ).margin( QgsLegendStyle::Top ) );
233  mIconLabelSpaceSpinBox->setValue( mLegend->style( QgsLegendStyle::SymbolLabel ).margin( QgsLegendStyle::Left ) );
234  mBoxSpaceSpinBox->setValue( mLegend->boxSpace() );
235  mColumnSpaceSpinBox->setValue( mLegend->columnSpace() );
236  mLineSpacingSpinBox->setValue( mLegend->lineSpacing() );
237 
238  mRasterStrokeGroupBox->setChecked( mLegend->drawRasterStroke() );
239  mRasterStrokeWidthSpinBox->setValue( mLegend->rasterStrokeWidth() );
240  mRasterStrokeColorButton->setColor( mLegend->rasterStrokeColor() );
241 
242  mCheckBoxAutoUpdate->setChecked( mLegend->autoUpdateModel() );
243 
244  mCheckboxResizeContents->setChecked( mLegend->resizeToContents() );
245  mFilterLegendByAtlasCheckBox->setChecked( mLegend->legendFilterOutAtlas() );
246  mWrapCharLineEdit->setText( mLegend->wrapString() );
247 
248  QgsLayoutItemMap *map = mLegend->linkedMap();
249  mMapComboBox->setItem( map );
250  mFontColorButton->setColor( mLegend->fontColor() );
251  mTitleFontButton->setCurrentFont( mLegend->style( QgsLegendStyle::Title ).font() );
252  mGroupFontButton->setCurrentFont( mLegend->style( QgsLegendStyle::Group ).font() );
253  mLayerFontButton->setCurrentFont( mLegend->style( QgsLegendStyle::Subgroup ).font() );
254  mItemFontButton->setCurrentFont( mLegend->style( QgsLegendStyle::SymbolLabel ).font() );
255 
256  blockAllSignals( false );
257 
258  mCheckBoxAutoUpdate_stateChanged( mLegend->autoUpdateModel() ? Qt::Checked : Qt::Unchecked );
259  updateDataDefinedButton( mLegendTitleDDBtn );
260  updateDataDefinedButton( mColumnsDDBtn );
261 }
262 
263 void QgsLayoutLegendWidget::mWrapCharLineEdit_textChanged( const QString &text )
264 {
265  if ( mLegend )
266  {
267  mLegend->beginCommand( tr( "Change Legend Wrap" ) );
268  mLegend->setWrapString( text );
269  mLegend->adjustBoxSize();
270  mLegend->update();
271  mLegend->endCommand();
272  }
273 }
274 
275 void QgsLayoutLegendWidget::mTitleLineEdit_textChanged( const QString &text )
276 {
277  if ( mLegend )
278  {
279  mLegend->beginCommand( tr( "Change Legend Title" ), QgsLayoutItem::UndoLegendText );
280  mLegend->setTitle( text );
281  mLegend->adjustBoxSize();
282  mLegend->update();
283  mLegend->endCommand();
284  }
285 }
286 
287 void QgsLayoutLegendWidget::titleAlignmentChanged()
288 {
289  if ( mLegend )
290  {
291  Qt::AlignmentFlag alignment = static_cast< Qt::AlignmentFlag >( static_cast< int >( mTitleAlignCombo->currentAlignment() & Qt::AlignHorizontal_Mask ) );
292  mLegend->beginCommand( tr( "Change Title Alignment" ) );
293  mLegend->setTitleAlignment( alignment );
294  mLegend->update();
295  mLegend->endCommand();
296  }
297 }
298 
299 void QgsLayoutLegendWidget::groupAlignmentChanged()
300 {
301  if ( mLegend )
302  {
303  mLegend->beginCommand( tr( "Change Group Alignment" ) );
304  mLegend->rstyle( QgsLegendStyle::Group ).setAlignment( mGroupAlignCombo->currentAlignment() );
305  mLegend->update();
306  mLegend->endCommand();
307  }
308 }
309 
310 void QgsLayoutLegendWidget::subgroupAlignmentChanged()
311 {
312  if ( mLegend )
313  {
314  mLegend->beginCommand( tr( "Change Subgroup Alignment" ) );
315  mLegend->rstyle( QgsLegendStyle::Subgroup ).setAlignment( mSubgroupAlignCombo->currentAlignment() );
316  mLegend->update();
317  mLegend->endCommand();
318  }
319 }
320 
321 void QgsLayoutLegendWidget::itemAlignmentChanged()
322 {
323  if ( mLegend )
324  {
325  mLegend->beginCommand( tr( "Change Item Alignment" ) );
326  mLegend->rstyle( QgsLegendStyle::SymbolLabel ).setAlignment( mItemAlignCombo->currentAlignment() );
327  mLegend->update();
328  mLegend->endCommand();
329  }
330 }
331 
332 void QgsLayoutLegendWidget::arrangementChanged()
333 {
334  if ( mLegend )
335  {
336  Qt::AlignmentFlag alignment = static_cast< Qt::AlignmentFlag >( static_cast< int >( mArrangementCombo->currentAlignment() & Qt::AlignHorizontal_Mask ) );
337  mLegend->beginCommand( tr( "Change Legend Arrangement" ) );
338  mLegend->setSymbolAlignment( alignment );
339  mLegend->update();
340  mLegend->endCommand();
341  }
342 }
343 
344 void QgsLayoutLegendWidget::mColumnCountSpinBox_valueChanged( int c )
345 {
346  if ( mLegend )
347  {
348  mLegend->beginCommand( tr( "Change Column Count" ), QgsLayoutItem::UndoLegendColumnCount );
349  mLegend->setColumnCount( c );
350  mLegend->adjustBoxSize();
351  mLegend->update();
352  mLegend->endCommand();
353  }
354  mSplitLayerCheckBox->setEnabled( c > 1 );
355  mEqualColumnWidthCheckBox->setEnabled( c > 1 );
356 }
357 
358 void QgsLayoutLegendWidget::mSplitLayerCheckBox_toggled( bool checked )
359 {
360  if ( mLegend )
361  {
362  mLegend->beginCommand( tr( "Split Legend Layers" ) );
363  mLegend->setSplitLayer( checked );
364  mLegend->adjustBoxSize();
365  mLegend->update();
366  mLegend->endCommand();
367  }
368 }
369 
370 void QgsLayoutLegendWidget::mEqualColumnWidthCheckBox_toggled( bool checked )
371 {
372  if ( mLegend )
373  {
374  mLegend->beginCommand( tr( "Legend Column Width" ) );
375  mLegend->setEqualColumnWidth( checked );
376  mLegend->adjustBoxSize();
377  mLegend->update();
378  mLegend->endCommand();
379  }
380 }
381 
382 void QgsLayoutLegendWidget::mSymbolWidthSpinBox_valueChanged( double d )
383 {
384  if ( mLegend )
385  {
386  mLegend->beginCommand( tr( "Resize Symbol Width" ), QgsLayoutItem::UndoLegendSymbolWidth );
387  mLegend->setSymbolWidth( d );
388  mLegend->adjustBoxSize();
389  mLegend->update();
390  mLegend->endCommand();
391  }
392 }
393 
394 void QgsLayoutLegendWidget::mSymbolHeightSpinBox_valueChanged( double d )
395 {
396  if ( mLegend )
397  {
398  mLegend->beginCommand( tr( "Resize Symbol Height" ), QgsLayoutItem::UndoLegendSymbolHeight );
399  mLegend->setSymbolHeight( d );
400  mLegend->adjustBoxSize();
401  mLegend->update();
402  mLegend->endCommand();
403  }
404 }
405 
406 void QgsLayoutLegendWidget::mWmsLegendWidthSpinBox_valueChanged( double d )
407 {
408  if ( mLegend )
409  {
410  mLegend->beginCommand( tr( "Resize WMS Width" ), QgsLayoutItem::UndoLegendWmsLegendWidth );
411  mLegend->setWmsLegendWidth( d );
412  mLegend->adjustBoxSize();
413  mLegend->update();
414  mLegend->endCommand();
415  }
416 }
417 
418 void QgsLayoutLegendWidget::mWmsLegendHeightSpinBox_valueChanged( double d )
419 {
420  if ( mLegend )
421  {
422  mLegend->beginCommand( tr( "Resize WMS Height" ), QgsLayoutItem::UndoLegendWmsLegendHeight );
423  mLegend->setWmsLegendHeight( d );
424  mLegend->adjustBoxSize();
425  mLegend->update();
426  mLegend->endCommand();
427  }
428 }
429 
430 void QgsLayoutLegendWidget::mTitleSpaceBottomSpinBox_valueChanged( double d )
431 {
432  if ( mLegend )
433  {
434  mLegend->beginCommand( tr( "Change Title Space" ), QgsLayoutItem::UndoLegendTitleSpaceBottom );
435  mLegend->rstyle( QgsLegendStyle::Title ).setMargin( QgsLegendStyle::Bottom, d );
436  mLegend->adjustBoxSize();
437  mLegend->update();
438  mLegend->endCommand();
439  }
440 }
441 
442 void QgsLayoutLegendWidget::mGroupSpaceSpinBox_valueChanged( double d )
443 {
444  if ( mLegend )
445  {
446  mLegend->beginCommand( tr( "Change Group Space" ), QgsLayoutItem::UndoLegendGroupSpace );
447  mLegend->rstyle( QgsLegendStyle::Group ).setMargin( QgsLegendStyle::Top, d );
448  mLegend->adjustBoxSize();
449  mLegend->update();
450  mLegend->endCommand();
451  }
452 }
453 
454 void QgsLayoutLegendWidget::spaceBelowGroupHeadingChanged( double space )
455 {
456  if ( mLegend )
457  {
458  mLegend->beginCommand( tr( "Change Group Space" ), QgsLayoutItem::UndoLegendGroupSpace );
459  mLegend->rstyle( QgsLegendStyle::Group ).setMargin( QgsLegendStyle::Bottom, space );
460  mLegend->adjustBoxSize();
461  mLegend->update();
462  mLegend->endCommand();
463  }
464 }
465 
466 void QgsLayoutLegendWidget::mLayerSpaceSpinBox_valueChanged( double d )
467 {
468  if ( mLegend )
469  {
470  mLegend->beginCommand( tr( "Change Subgroup Space" ), QgsLayoutItem::UndoLegendLayerSpace );
471  mLegend->rstyle( QgsLegendStyle::Subgroup ).setMargin( QgsLegendStyle::Top, d );
472  mLegend->adjustBoxSize();
473  mLegend->update();
474  mLegend->endCommand();
475  }
476 }
477 
478 void QgsLayoutLegendWidget::mSymbolSpaceSpinBox_valueChanged( double d )
479 {
480  if ( mLegend )
481  {
482  mLegend->beginCommand( tr( "Change Symbol Space" ), QgsLayoutItem::UndoLegendSymbolSpace );
483  // We keep Symbol and SymbolLabel Top in sync for now
484  mLegend->rstyle( QgsLegendStyle::Symbol ).setMargin( QgsLegendStyle::Top, d );
485  mLegend->rstyle( QgsLegendStyle::SymbolLabel ).setMargin( QgsLegendStyle::Top, d );
486  mLegend->adjustBoxSize();
487  mLegend->update();
488  mLegend->endCommand();
489  }
490 }
491 
492 void QgsLayoutLegendWidget::mIconLabelSpaceSpinBox_valueChanged( double d )
493 {
494  if ( mLegend )
495  {
496  mLegend->beginCommand( tr( "Change Label Space" ), QgsLayoutItem::UndoLegendIconSymbolSpace );
497  mLegend->rstyle( QgsLegendStyle::SymbolLabel ).setMargin( QgsLegendStyle::Left, d );
498  mLegend->adjustBoxSize();
499  mLegend->update();
500  mLegend->endCommand();
501  }
502 }
503 
504 void QgsLayoutLegendWidget::titleFontChanged()
505 {
506  if ( mLegend )
507  {
508  mLegend->beginCommand( tr( "Change Title Font" ), QgsLayoutItem::UndoLegendTitleFont );
509  mLegend->setStyleFont( QgsLegendStyle::Title, mTitleFontButton->currentFont() );
510  mLegend->adjustBoxSize();
511  mLegend->update();
512  mLegend->endCommand();
513  }
514 }
515 
516 void QgsLayoutLegendWidget::groupFontChanged()
517 {
518  if ( mLegend )
519  {
520  mLegend->beginCommand( tr( "Change Group Font" ), QgsLayoutItem::UndoLegendGroupFont );
521  mLegend->setStyleFont( QgsLegendStyle::Group, mGroupFontButton->currentFont() );
522  mLegend->adjustBoxSize();
523  mLegend->update();
524  mLegend->endCommand();
525  }
526 }
527 
528 void QgsLayoutLegendWidget::layerFontChanged()
529 {
530  if ( mLegend )
531  {
532  mLegend->beginCommand( tr( "Change Layer Font" ), QgsLayoutItem::UndoLegendLayerFont );
533  mLegend->setStyleFont( QgsLegendStyle::Subgroup, mLayerFontButton->currentFont() );
534  mLegend->adjustBoxSize();
535  mLegend->update();
536  mLegend->endCommand();
537  }
538 }
539 
540 void QgsLayoutLegendWidget::itemFontChanged()
541 {
542  if ( mLegend )
543  {
544  mLegend->beginCommand( tr( "Change Item Font" ), QgsLayoutItem::UndoLegendItemFont );
545  mLegend->setStyleFont( QgsLegendStyle::SymbolLabel, mItemFontButton->currentFont() );
546  mLegend->adjustBoxSize();
547  mLegend->update();
548  mLegend->endCommand();
549  }
550 }
551 
552 void QgsLayoutLegendWidget::spaceBelowSubGroupHeadingChanged( double space )
553 {
554  if ( mLegend )
555  {
556  mLegend->beginCommand( tr( "Change Subgroup Space" ), QgsLayoutItem::UndoLegendLayerSpace );
557  mLegend->rstyle( QgsLegendStyle::Subgroup ).setMargin( QgsLegendStyle::Bottom, space );
558  mLegend->adjustBoxSize();
559  mLegend->update();
560  mLegend->endCommand();
561  }
562 }
563 
564 void QgsLayoutLegendWidget::mFontColorButton_colorChanged( const QColor &newFontColor )
565 {
566  if ( !mLegend )
567  {
568  return;
569  }
570 
571  mLegend->beginCommand( tr( "Change Font Color" ), QgsLayoutItem::UndoLegendFontColor );
572  mLegend->setFontColor( newFontColor );
573  mLegend->update();
574  mLegend->endCommand();
575 }
576 
577 void QgsLayoutLegendWidget::mBoxSpaceSpinBox_valueChanged( double d )
578 {
579  if ( mLegend )
580  {
581  mLegend->beginCommand( tr( "Change Box Space" ), QgsLayoutItem::UndoLegendBoxSpace );
582  mLegend->setBoxSpace( d );
583  mLegend->adjustBoxSize();
584  mLegend->update();
585  mLegend->endCommand();
586  }
587 }
588 
589 void QgsLayoutLegendWidget::mColumnSpaceSpinBox_valueChanged( double d )
590 {
591  if ( mLegend )
592  {
593  mLegend->beginCommand( tr( "Change Column Space" ), QgsLayoutItem::UndoLegendColumnSpace );
594  mLegend->setColumnSpace( d );
595  mLegend->adjustBoxSize();
596  mLegend->update();
597  mLegend->endCommand();
598  }
599 }
600 
601 void QgsLayoutLegendWidget::mLineSpacingSpinBox_valueChanged( double d )
602 {
603  if ( mLegend )
604  {
605  mLegend->beginCommand( tr( "Change Line Space" ), QgsLayoutItem::UndoLegendLineSpacing );
606  mLegend->setLineSpacing( d );
607  mLegend->adjustBoxSize();
608  mLegend->update();
609  mLegend->endCommand();
610  }
611 }
612 
613 static void _moveLegendNode( QgsLayerTreeLayer *nodeLayer, int legendNodeIndex, int offset )
614 {
615  QList<int> order = QgsMapLayerLegendUtils::legendNodeOrder( nodeLayer );
616 
617  if ( legendNodeIndex < 0 || legendNodeIndex >= order.count() )
618  return;
619  if ( legendNodeIndex + offset < 0 || legendNodeIndex + offset >= order.count() )
620  return;
621 
622  int id = order.takeAt( legendNodeIndex );
623  order.insert( legendNodeIndex + offset, id );
624 
625  QgsMapLayerLegendUtils::setLegendNodeOrder( nodeLayer, order );
626 }
627 
628 
629 void QgsLayoutLegendWidget::mMoveDownToolButton_clicked()
630 {
631  if ( !mLegend )
632  {
633  return;
634  }
635 
636  QModelIndex index = mItemTreeView->selectionModel()->currentIndex();
637  QModelIndex parentIndex = index.parent();
638  if ( !index.isValid() || index.row() == mItemTreeView->model()->rowCount( parentIndex ) - 1 )
639  return;
640 
641  QgsLayerTreeNode *node = mItemTreeView->layerTreeModel()->index2node( index );
642  QgsLayerTreeModelLegendNode *legendNode = mItemTreeView->layerTreeModel()->index2legendNode( index );
643  if ( !node && !legendNode )
644  return;
645 
646  mLegend->beginCommand( tr( "Moved Legend Item Down" ) );
647 
648  if ( node )
649  {
650  QgsLayerTreeGroup *parentGroup = QgsLayerTree::toGroup( node->parent() );
651  parentGroup->insertChildNode( index.row() + 2, node->clone() );
652  parentGroup->removeChildNode( node );
653  }
654  else // legend node
655  {
656  _moveLegendNode( legendNode->layerNode(), _unfilteredLegendNodeIndex( legendNode ), 1 );
657  mItemTreeView->layerTreeModel()->refreshLayerLegend( legendNode->layerNode() );
658  }
659 
660  mItemTreeView->setCurrentIndex( mItemTreeView->layerTreeModel()->index( index.row() + 1, 0, parentIndex ) );
661 
662  mLegend->update();
663  mLegend->endCommand();
664 }
665 
666 void QgsLayoutLegendWidget::mMoveUpToolButton_clicked()
667 {
668  if ( !mLegend )
669  {
670  return;
671  }
672 
673  QModelIndex index = mItemTreeView->selectionModel()->currentIndex();
674  QModelIndex parentIndex = index.parent();
675  if ( !index.isValid() || index.row() == 0 )
676  return;
677 
678  QgsLayerTreeNode *node = mItemTreeView->layerTreeModel()->index2node( index );
679  QgsLayerTreeModelLegendNode *legendNode = mItemTreeView->layerTreeModel()->index2legendNode( index );
680  if ( !node && !legendNode )
681  return;
682 
683  mLegend->beginCommand( tr( "Move Legend Item Up" ) );
684 
685  if ( node )
686  {
687  QgsLayerTreeGroup *parentGroup = QgsLayerTree::toGroup( node->parent() );
688  parentGroup->insertChildNode( index.row() - 1, node->clone() );
689  parentGroup->removeChildNode( node );
690  }
691  else // legend node
692  {
693  _moveLegendNode( legendNode->layerNode(), _unfilteredLegendNodeIndex( legendNode ), -1 );
694  mItemTreeView->layerTreeModel()->refreshLayerLegend( legendNode->layerNode() );
695  }
696 
697  mItemTreeView->setCurrentIndex( mItemTreeView->layerTreeModel()->index( index.row() - 1, 0, parentIndex ) );
698 
699  mLegend->update();
700  mLegend->endCommand();
701 }
702 
703 void QgsLayoutLegendWidget::mCheckBoxAutoUpdate_stateChanged( int state )
704 {
705  mLegend->beginCommand( tr( "Change Auto Update" ) );
706 
707  mLegend->setAutoUpdateModel( state == Qt::Checked );
708 
709  mLegend->updateFilterByMap();
710  mLegend->endCommand();
711 
712  // do not allow editing of model if auto update is on - we would modify project's layer tree
713  QList<QWidget *> widgets;
714  widgets << mMoveDownToolButton << mMoveUpToolButton << mRemoveToolButton << mAddToolButton
715  << mEditPushButton << mCountToolButton << mUpdateAllPushButton << mAddGroupToolButton
716  << mExpressionFilterButton;
717  for ( QWidget *w : qgis::as_const( widgets ) )
718  w->setEnabled( state != Qt::Checked );
719 
720  if ( state == Qt::Unchecked )
721  {
722  // update widgets state based on current selection
723  selectedChanged( QModelIndex(), QModelIndex() );
724  }
725 }
726 
727 void QgsLayoutLegendWidget::composerMapChanged( QgsLayoutItem *item )
728 {
729  if ( !mLegend )
730  {
731  return;
732  }
733 
734  QgsLayout *layout = mLegend->layout();
735  if ( !layout )
736  {
737  return;
738  }
739 
740  QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( item );
741  if ( map )
742  {
743  mLegend->beginCommand( tr( "Change Legend Map" ) );
744  mLegend->setLinkedMap( map );
745  mLegend->updateFilterByMap();
746  mLegend->endCommand();
747 
748  setLegendMapViewData();
749  }
750 }
751 
752 void QgsLayoutLegendWidget::mCheckboxResizeContents_toggled( bool checked )
753 {
754  if ( !mLegend )
755  {
756  return;
757  }
758 
759  mLegend->beginCommand( tr( "Resize Legend to Contents" ) );
760  mLegend->setResizeToContents( checked );
761  if ( checked )
762  mLegend->adjustBoxSize();
763  mLegend->updateFilterByMap();
764  mLegend->endCommand();
765 }
766 
767 void QgsLayoutLegendWidget::mRasterStrokeGroupBox_toggled( bool state )
768 {
769  if ( !mLegend )
770  {
771  return;
772  }
773 
774  mLegend->beginCommand( tr( "Change Legend Borders" ) );
775  mLegend->setDrawRasterStroke( state );
776  mLegend->adjustBoxSize();
777  mLegend->update();
778  mLegend->endCommand();
779 }
780 
781 void QgsLayoutLegendWidget::mRasterStrokeWidthSpinBox_valueChanged( double d )
782 {
783  if ( !mLegend )
784  {
785  return;
786  }
787 
788  mLegend->beginCommand( tr( "Resize Legend Borders" ), QgsLayoutItem::UndoLegendRasterStrokeWidth );
789  mLegend->setRasterStrokeWidth( d );
790  mLegend->adjustBoxSize();
791  mLegend->update();
792  mLegend->endCommand();
793 }
794 
795 void QgsLayoutLegendWidget::mRasterStrokeColorButton_colorChanged( const QColor &newColor )
796 {
797  if ( !mLegend )
798  {
799  return;
800  }
801 
802  mLegend->beginCommand( tr( "Change Legend Border Color" ), QgsLayoutItem::UndoLegendRasterStrokeColor );
803  mLegend->setRasterStrokeColor( newColor );
804  mLegend->update();
805  mLegend->endCommand();
806 }
807 
808 void QgsLayoutLegendWidget::mAddToolButton_clicked()
809 {
810  if ( !mLegend )
811  {
812  return;
813  }
814 
815  QList< QgsMapLayer * > visibleLayers;
816  if ( mLegend->linkedMap() )
817  {
818  visibleLayers = mLegend->linkedMap()->layersToRender();
819  }
820  if ( visibleLayers.isEmpty() )
821  {
822  // just use current canvas layers as visible layers
823  visibleLayers = mMapCanvas->layers();
824  }
825 
826  QgsLayoutLegendLayersDialog addDialog( this );
827  addDialog.setVisibleLayers( visibleLayers );
828  if ( addDialog.exec() == QDialog::Accepted )
829  {
830  const QList<QgsMapLayer *> layers = addDialog.selectedLayers();
831  if ( !layers.empty() )
832  {
833  mLegend->beginCommand( tr( "Add Legend Item(s)" ) );
834  for ( QgsMapLayer *layer : layers )
835  {
836  mLegend->model()->rootGroup()->addLayer( layer );
837  }
838  mLegend->updateLegend();
839  mLegend->endCommand();
840  }
841  }
842 }
843 
844 void QgsLayoutLegendWidget::mRemoveToolButton_clicked()
845 {
846  if ( !mLegend )
847  {
848  return;
849  }
850 
851  QItemSelectionModel *selectionModel = mItemTreeView->selectionModel();
852  if ( !selectionModel )
853  {
854  return;
855  }
856 
857  mLegend->beginCommand( tr( "Remove Legend Item" ) );
858 
859  QList<QPersistentModelIndex> indexes;
860  const auto constSelectedIndexes = selectionModel->selectedIndexes();
861  for ( const QModelIndex &index : constSelectedIndexes )
862  indexes << index;
863 
864  // first try to remove legend nodes
865  QHash<QgsLayerTreeLayer *, QList<int> > nodesWithRemoval;
866  for ( const QPersistentModelIndex &index : qgis::as_const( indexes ) )
867  {
868  if ( QgsLayerTreeModelLegendNode *legendNode = mItemTreeView->layerTreeModel()->index2legendNode( index ) )
869  {
870  QgsLayerTreeLayer *nodeLayer = legendNode->layerNode();
871  nodesWithRemoval[nodeLayer].append( _unfilteredLegendNodeIndex( legendNode ) );
872  }
873  }
874  for ( auto it = nodesWithRemoval.constBegin(); it != nodesWithRemoval.constEnd(); ++it )
875  {
876  QList<int> toDelete = it.value();
877  std::sort( toDelete.begin(), toDelete.end(), std::greater<int>() );
878  QList<int> order = QgsMapLayerLegendUtils::legendNodeOrder( it.key() );
879 
880  const auto constToDelete = toDelete;
881  for ( int i : constToDelete )
882  {
883  if ( i >= 0 && i < order.count() )
884  order.removeAt( i );
885  }
886 
888  mItemTreeView->layerTreeModel()->refreshLayerLegend( it.key() );
889  }
890 
891  // then remove layer tree nodes
892  for ( const QPersistentModelIndex &index : qgis::as_const( indexes ) )
893  {
894  if ( index.isValid() && mItemTreeView->layerTreeModel()->index2node( index ) )
895  mLegend->model()->removeRow( index.row(), index.parent() );
896  }
897 
898  mLegend->updateLegend();
899  mLegend->endCommand();
900 }
901 
902 void QgsLayoutLegendWidget::mEditPushButton_clicked()
903 {
904  if ( !mLegend )
905  {
906  return;
907  }
908 
909  QModelIndex idx = mItemTreeView->selectionModel()->currentIndex();
910  mItemTreeView_doubleClicked( idx );
911 }
912 
914 {
915  if ( !mLegend )
916  {
917  return;
918  }
919 
920  //get current item
921  QModelIndex currentIndex = mItemTreeView->currentIndex();
922  if ( !currentIndex.isValid() )
923  {
924  return;
925  }
926 
927  QgsLayerTreeLayer *nodeLayer = nullptr;
928  if ( QgsLayerTreeNode *node = mItemTreeView->layerTreeModel()->index2node( currentIndex ) )
929  {
930  if ( QgsLayerTree::isLayer( node ) )
931  nodeLayer = QgsLayerTree::toLayer( node );
932  }
933  if ( QgsLayerTreeModelLegendNode *legendNode = mItemTreeView->layerTreeModel()->index2legendNode( currentIndex ) )
934  {
935  nodeLayer = legendNode->layerNode();
936  }
937 
938  if ( !nodeLayer )
939  return;
940 
941  mLegend->beginCommand( tr( "Update Legend" ) );
942 
943  const auto constCustomProperties = nodeLayer->customProperties();
944  for ( const QString &key : constCustomProperties )
945  {
946  if ( key.startsWith( QLatin1String( "legend/" ) ) )
947  nodeLayer->removeCustomProperty( key );
948  }
949 
950  mItemTreeView->layerTreeModel()->refreshLayerLegend( nodeLayer );
951 
952  mLegend->updateLegend();
953  mLegend->endCommand();
954 }
955 
956 void QgsLayoutLegendWidget::mCountToolButton_clicked( bool checked )
957 {
958  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
959  if ( !mLegend )
960  {
961  return;
962  }
963 
964  //get current item
965  QModelIndex currentIndex = mItemTreeView->currentIndex();
966  if ( !currentIndex.isValid() )
967  {
968  return;
969  }
970 
971  QgsLayerTreeNode *currentNode = mItemTreeView->currentNode();
972  if ( !QgsLayerTree::isLayer( currentNode ) )
973  return;
974 
975  mLegend->beginCommand( tr( "Update Legend" ) );
976  currentNode->setCustomProperty( QStringLiteral( "showFeatureCount" ), checked ? 1 : 0 );
977  mLegend->updateFilterByMap();
978  mLegend->adjustBoxSize();
979  mLegend->endCommand();
980 }
981 
982 void QgsLayoutLegendWidget::mFilterByMapCheckBox_toggled( bool checked )
983 {
984  mLegend->beginCommand( tr( "Update Legend" ) );
985  mLegend->setLegendFilterByMapEnabled( checked );
986  mLegend->adjustBoxSize();
987  mLegend->update();
988  mLegend->endCommand();
989 }
990 
991 void QgsLayoutLegendWidget::mExpressionFilterButton_toggled( bool checked )
992 {
993  if ( !mLegend )
994  {
995  return;
996  }
997 
998  //get current item
999  QModelIndex currentIndex = mItemTreeView->currentIndex();
1000  if ( !currentIndex.isValid() )
1001  {
1002  return;
1003  }
1004 
1005  QgsLayerTreeNode *currentNode = mItemTreeView->currentNode();
1006  if ( !QgsLayerTree::isLayer( currentNode ) )
1007  return;
1008 
1009  QgsLayerTreeUtils::setLegendFilterByExpression( *qobject_cast<QgsLayerTreeLayer *>( currentNode ),
1010  mExpressionFilterButton->expressionText(),
1011  checked );
1012 
1013  mLegend->beginCommand( tr( "Update Legend" ) );
1014  mLegend->updateFilterByMap();
1015  mLegend->adjustBoxSize();
1016  mLegend->endCommand();
1017 }
1018 
1019 void QgsLayoutLegendWidget::mLayerExpressionButton_clicked()
1020 {
1021  if ( !mLegend )
1022  {
1023  return;
1024  }
1025 
1026  QModelIndex currentIndex = mItemTreeView->currentIndex();
1027  if ( !currentIndex.isValid() )
1028  return;
1029 
1030  QgsLayerTreeNode *currentNode = mItemTreeView->currentNode();
1031  if ( !QgsLayerTree::isLayer( currentNode ) )
1032  return;
1033 
1034  QgsLayerTreeLayer *layerNode = qobject_cast<QgsLayerTreeLayer *>( currentNode );
1035  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerNode->layer() );
1036 
1037  if ( !vl )
1038  return;
1039 
1040  QString currentExpression;
1041  if ( layerNode->labelExpression().isEmpty() )
1042  currentExpression = QStringLiteral( "@symbol_label" );
1043  else
1044  currentExpression = layerNode->labelExpression();
1045  QgsExpressionContext legendContext = mLegend->createExpressionContext();
1046  legendContext.appendScope( vl->createExpressionContextScope() );
1047 
1048  QgsExpressionContextScope *symbolLegendScope = new QgsExpressionContextScope( tr( "Symbol scope" ) );
1049 
1050  QgsFeatureRenderer *r = vl->renderer();
1051 
1052  QStringList highlighted;
1053  if ( r )
1054  {
1055  const QgsLegendSymbolList legendSymbols = r->legendSymbolItems();
1056 
1057  if ( !legendSymbols.empty() )
1058  {
1059  QgsSymbolLegendNode legendNode( layerNode, legendSymbols.first() );
1060 
1061  symbolLegendScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_label" ), legendNode.symbolLabel().remove( QStringLiteral( "[%" ) ).remove( QStringLiteral( "%]" ) ), true ) );
1062  symbolLegendScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_id" ), legendSymbols.first().ruleKey(), true ) );
1063  highlighted << QStringLiteral( "symbol_label" ) << QStringLiteral( "symbol_id" );
1064  if ( vl )
1065  {
1066  symbolLegendScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_count" ), QVariant::fromValue( vl->featureCount( legendSymbols.first().ruleKey() ) ), true ) );
1067  highlighted << QStringLiteral( "symbol_count" );
1068  }
1069  }
1070  }
1071 
1072  legendContext.appendScope( symbolLegendScope );
1073 
1074  legendContext.setHighlightedVariables( highlighted );
1075 
1076  QgsExpressionBuilderDialog expressiondialog( vl, currentExpression, nullptr, QStringLiteral( "generic" ), legendContext );
1077  if ( expressiondialog.exec() )
1078  layerNode->setLabelExpression( expressiondialog.expressionText() );
1079 
1080  mLegend->beginCommand( tr( "Update Legend" ) );
1081  mLegend->updateLegend();
1082  mLegend->adjustBoxSize();
1083  mLegend->endCommand();
1084 }
1085 
1086 void QgsLayoutLegendWidget::mUpdateAllPushButton_clicked()
1087 {
1088  updateLegend();
1089 }
1090 
1091 void QgsLayoutLegendWidget::mAddGroupToolButton_clicked()
1092 {
1093  if ( mLegend )
1094  {
1095  mLegend->beginCommand( tr( "Add Legend Group" ) );
1096  mLegend->model()->rootGroup()->addGroup( tr( "Group" ) );
1097  mLegend->updateLegend();
1098  mLegend->endCommand();
1099  }
1100 }
1101 
1102 void QgsLayoutLegendWidget::mFilterLegendByAtlasCheckBox_toggled( bool toggled )
1103 {
1104  Q_UNUSED( toggled )
1105  if ( mLegend )
1106  {
1107  mLegend->setLegendFilterOutAtlas( toggled );
1108  // force update of legend when in preview mode
1109  mLegend->refresh();
1110  }
1111 }
1112 
1114 {
1115  if ( mLegend )
1116  {
1117  mLegend->beginCommand( tr( "Update Legend" ) );
1118 
1119  // this will reset the model completely, losing any changes
1120  mLegend->setAutoUpdateModel( true );
1121  mLegend->setAutoUpdateModel( false );
1122  mLegend->updateFilterByMap();
1123  mLegend->endCommand();
1124  }
1125 }
1126 
1127 void QgsLayoutLegendWidget::setReportTypeString( const QString &string )
1128 {
1129  mFilterLegendByAtlasCheckBox->setText( tr( "Only show items inside current %1 feature" ).arg( string ) );
1130  mFilterLegendByAtlasCheckBox->setToolTip( tr( "Filter out legend elements that lie outside the current %1 feature." ).arg( string ) );
1131 }
1132 
1134 {
1135  if ( item->type() != QgsLayoutItemRegistry::LayoutLegend )
1136  return false;
1137 
1138  if ( mLegend )
1139  {
1140  disconnect( mLegend, &QgsLayoutObject::changed, this, &QgsLayoutLegendWidget::setGuiElements );
1141  }
1142 
1143  mLegend = qobject_cast< QgsLayoutItemLegend * >( item );
1144  mItemPropertiesWidget->setItem( mLegend );
1145 
1146  if ( mLegend )
1147  {
1148  mItemTreeView->setModel( mLegend->model() );
1149  connect( mLegend, &QgsLayoutObject::changed, this, &QgsLayoutLegendWidget::setGuiElements );
1150  }
1151 
1152  setGuiElements();
1153 
1154  return true;
1155 }
1156 
1157 void QgsLayoutLegendWidget::blockAllSignals( bool b )
1158 {
1159  mTitleLineEdit->blockSignals( b );
1160  mTitleAlignCombo->blockSignals( b );
1161  mItemTreeView->blockSignals( b );
1162  mCheckBoxAutoUpdate->blockSignals( b );
1163  mMapComboBox->blockSignals( b );
1164  mFilterByMapCheckBox->blockSignals( b );
1165  mColumnCountSpinBox->blockSignals( b );
1166  mSplitLayerCheckBox->blockSignals( b );
1167  mEqualColumnWidthCheckBox->blockSignals( b );
1168  mSymbolWidthSpinBox->blockSignals( b );
1169  mSymbolHeightSpinBox->blockSignals( b );
1170  mGroupSpaceSpinBox->blockSignals( b );
1171  mLayerSpaceSpinBox->blockSignals( b );
1172  mSymbolSpaceSpinBox->blockSignals( b );
1173  mIconLabelSpaceSpinBox->blockSignals( b );
1174  mBoxSpaceSpinBox->blockSignals( b );
1175  mColumnSpaceSpinBox->blockSignals( b );
1176  mFontColorButton->blockSignals( b );
1177  mRasterStrokeGroupBox->blockSignals( b );
1178  mRasterStrokeColorButton->blockSignals( b );
1179  mRasterStrokeWidthSpinBox->blockSignals( b );
1180  mWmsLegendWidthSpinBox->blockSignals( b );
1181  mWmsLegendHeightSpinBox->blockSignals( b );
1182  mCheckboxResizeContents->blockSignals( b );
1183  mTitleSpaceBottomSpinBox->blockSignals( b );
1184  mFilterLegendByAtlasCheckBox->blockSignals( b );
1185  mTitleFontButton->blockSignals( b );
1186  mGroupFontButton->blockSignals( b );
1187  mLayerFontButton->blockSignals( b );
1188  mItemFontButton->blockSignals( b );
1189  mWrapCharLineEdit->blockSignals( b );
1190 }
1191 
1192 void QgsLayoutLegendWidget::selectedChanged( const QModelIndex &current, const QModelIndex &previous )
1193 {
1194  Q_UNUSED( current )
1195  Q_UNUSED( previous )
1196 
1197  mLayerExpressionButton->setEnabled( false );
1198 
1199  if ( mLegend && mLegend->autoUpdateModel() )
1200  {
1201  QgsLayerTreeNode *currentNode = mItemTreeView->currentNode();
1202  if ( !QgsLayerTree::isLayer( currentNode ) )
1203  return;
1204 
1205  QgsLayerTreeLayer *currentLayerNode = QgsLayerTree::toLayer( currentNode );
1206  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( currentLayerNode->layer() );
1207  if ( !vl )
1208  return;
1209 
1210  mLayerExpressionButton->setEnabled( true );
1211  return;
1212  }
1213 
1214  mCountToolButton->setChecked( false );
1215  mCountToolButton->setEnabled( false );
1216 
1217 
1218  mExpressionFilterButton->blockSignals( true );
1219  mExpressionFilterButton->setChecked( false );
1220  mExpressionFilterButton->setEnabled( false );
1221  mExpressionFilterButton->blockSignals( false );
1222 
1223  QgsLayerTreeNode *currentNode = mItemTreeView->currentNode();
1224  if ( !QgsLayerTree::isLayer( currentNode ) )
1225  return;
1226 
1227  QgsLayerTreeLayer *currentLayerNode = QgsLayerTree::toLayer( currentNode );
1228  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( currentLayerNode->layer() );
1229  if ( !vl )
1230  return;
1231 
1232  mCountToolButton->setChecked( currentNode->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toInt() );
1233  mCountToolButton->setEnabled( true );
1234  mLayerExpressionButton->setEnabled( true );
1235 
1236  bool exprEnabled;
1237  QString expr = QgsLayerTreeUtils::legendFilterByExpression( *qobject_cast<QgsLayerTreeLayer *>( currentNode ), &exprEnabled );
1238  mExpressionFilterButton->blockSignals( true );
1239  mExpressionFilterButton->setExpressionText( expr );
1240  mExpressionFilterButton->setVectorLayer( vl );
1241  mExpressionFilterButton->setEnabled( true );
1242  mExpressionFilterButton->setChecked( exprEnabled );
1243  mExpressionFilterButton->blockSignals( false );
1244 }
1245 
1247 {
1248  QAction *a = qobject_cast<QAction *>( sender() );
1249  if ( !a || !mItemTreeView->currentNode() )
1250  return;
1251 
1252  QgsLegendRenderer::setNodeLegendStyle( mItemTreeView->currentNode(), static_cast< QgsLegendStyle::Style >( a->data().toInt() ) );
1253  mLegend->updateFilterByMap();
1254 }
1255 
1256 void QgsLayoutLegendWidget::setLegendMapViewData()
1257 {
1258  if ( mLegend->linkedMap() )
1259  {
1260  int dpi = qt_defaultDpiX();
1262  measurementConverter.setDpi( dpi );
1263  double mapWidth = measurementConverter.convert( mLegend->linkedMap()->sizeWithUnits(), QgsUnitTypes::LayoutPixels ).width();
1264  double mapHeight = measurementConverter.convert( mLegend->linkedMap()->sizeWithUnits(), QgsUnitTypes::LayoutPixels ).height();
1265  double mapUnitsPerPixelX = mLegend->linkedMap()->extent().width() / mapWidth;
1266  double mapUnitsPerPixelY = mLegend->linkedMap()->extent().height() / mapHeight;
1267  mLegend->model()->setLegendMapViewData( ( mapUnitsPerPixelX > mapUnitsPerPixelY ? mapUnitsPerPixelX : mapUnitsPerPixelY ), dpi, mLegend->linkedMap()->scale() );
1268  }
1269 }
1270 
1271 void QgsLayoutLegendWidget::updateFilterLegendByAtlasButton()
1272 {
1273  if ( QgsLayoutAtlas *atlas = layoutAtlas() )
1274  {
1275  mFilterLegendByAtlasCheckBox->setEnabled( atlas->enabled() && mLegend->layout()->reportContext().layer() && mLegend->layout()->reportContext().layer()->geometryType() == QgsWkbTypes::PolygonGeometry );
1276  }
1277 }
1278 
1279 void QgsLayoutLegendWidget::mItemTreeView_doubleClicked( const QModelIndex &idx )
1280 {
1281  if ( !mLegend || !idx.isValid() )
1282  {
1283  return;
1284  }
1285 
1286  QgsLayerTreeModel *model = mItemTreeView->layerTreeModel();
1287  QgsLayerTreeNode *currentNode = model->index2node( idx );
1288  QgsLayerTreeModelLegendNode *legendNode = model->index2legendNode( idx );
1289  QString currentText;
1290 
1291  if ( QgsLayerTree::isGroup( currentNode ) )
1292  {
1293  currentText = QgsLayerTree::toGroup( currentNode )->name();
1294  }
1295  else if ( QgsLayerTree::isLayer( currentNode ) )
1296  {
1297  currentText = QgsLayerTree::toLayer( currentNode )->name();
1298  QVariant v = currentNode->customProperty( QStringLiteral( "legend/title-label" ) );
1299  if ( !v.isNull() )
1300  currentText = v.toString();
1301  }
1302  else if ( legendNode )
1303  {
1304  currentText = legendNode->data( Qt::EditRole ).toString();
1305  }
1306 
1307  bool ok;
1308  QString newText = QInputDialog::getText( this, tr( "Legend Item Properties" ), tr( "Item text" ),
1309  QLineEdit::Normal, currentText, &ok );
1310  if ( !ok || newText == currentText )
1311  return;
1312 
1313  mLegend->beginCommand( tr( "Edit Legend Item" ) );
1314 
1315  if ( QgsLayerTree::isGroup( currentNode ) )
1316  {
1317  QgsLayerTree::toGroup( currentNode )->setName( newText );
1318  }
1319  else if ( QgsLayerTree::isLayer( currentNode ) )
1320  {
1321  currentNode->setCustomProperty( QStringLiteral( "legend/title-label" ), newText );
1322 
1323  // force update of label of the legend node with embedded icon (a bit clumsy i know)
1324  if ( QgsLayerTreeModelLegendNode *embeddedNode = model->legendNodeEmbeddedInParent( QgsLayerTree::toLayer( currentNode ) ) )
1325  embeddedNode->setUserLabel( QString() );
1326  }
1327  else if ( legendNode )
1328  {
1329  int originalIndex = _originalLegendNodeIndex( legendNode );
1330  QgsMapLayerLegendUtils::setLegendNodeUserLabel( legendNode->layerNode(), originalIndex, newText );
1331  model->refreshLayerLegend( legendNode->layerNode() );
1332  }
1333 
1334  mLegend->adjustBoxSize();
1335  mLegend->updateFilterByMap();
1336  mLegend->endCommand();
1337 }
1338 
1339 
1340 //
1341 // QgsComposerLegendMenuProvider
1342 //
1343 
1345  : mView( view )
1346  , mWidget( w )
1347 {}
1348 
1350 {
1351  if ( !mView->currentNode() )
1352  return nullptr;
1353 
1354  if ( mWidget->legend()->autoUpdateModel() )
1355  return nullptr; // no editing allowed
1356 
1357  QMenu *menu = new QMenu();
1358 
1360  {
1361  menu->addAction( QObject::tr( "Reset to Defaults" ), mWidget, &QgsLayoutLegendWidget::resetLayerNodeToDefaults );
1362  menu->addSeparator();
1363  }
1364 
1366 
1367  QList<QgsLegendStyle::Style> lst;
1369  for ( QgsLegendStyle::Style style : qgis::as_const( lst ) )
1370  {
1371  QAction *action = menu->addAction( QgsLegendStyle::styleLabel( style ), mWidget, &QgsLayoutLegendWidget::setCurrentNodeStyleFromAction );
1372  action->setCheckable( true );
1373  action->setChecked( currentStyle == style );
1374  action->setData( static_cast< int >( style ) );
1375  }
1376 
1377  return menu;
1378 }
static void setNodeLegendStyle(QgsLayerTreeNode *node, QgsLegendStyle::Style style)
Sets the style of a node.
Layer tree group node serves as a container for layers and further groups.
virtual QgsLegendSymbolList legendSymbolItems() const
Returns a list of symbology items for the legend.
Single variable definition for use within a QgsExpressionContextScope.
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:75
Base class for all map layer types.
Definition: qgsmaplayer.h:79
The QgsLayerTreeView class extends QTreeView and provides some additional functionality when working ...
static void setLegendNodeOrder(QgsLayerTreeLayer *nodeLayer, const QList< int > &order)
QString labelExpression() const
Returns the expression member of the LayerTreeNode.
QList< QgsLegendSymbolItem > QgsLegendSymbolList
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:43
QgsLegendModel * model()
Returns the legend model.
QList< QgsMapLayer * > layers() const
Returns the list of layers shown within the map canvas.
Base class for graphical items within a QgsLayout.
int type() const override
Returns a unique graphics item type identifier.
QList< QgsLayerTreeModelLegendNode * > layerOriginalLegendNodes(QgsLayerTreeLayer *nodeLayer)
Returns original (unfiltered) list of legend nodes attached to a particular layer node...
static void setLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex, const QString &newLabel)
QgsLayoutMeasurement convert(QgsLayoutMeasurement measurement, QgsUnitTypes::LayoutUnit targetUnits) const
Converts a measurement from one unit to another.
virtual QgsLayerTreeNode * clone() const =0
Create a copy of the node. Returns new instance.
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Definition: qgslayertree.h:64
QgsLayerTreeModelLegendNode * legendNodeEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const
Returns legend node that may be embedded in parent (i.e.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
static QList< int > legendNodeOrder(QgsLayerTreeLayer *nodeLayer)
A widget for controlling the common properties of layout items (e.g.
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
QgsLayerTreeLayer * layerNode() const
Returns pointer to the parent layer node.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void removeChildNode(QgsLayerTreeNode *node)
Remove a child node from this group.
void resetLayerNodeToDefaults()
Reset a layer node to the default settings.
void setDpi(const double dpi)
Sets the dots per inch (dpi) for the measurement converter.
void toggled(bool)
Emitted when atlas is enabled or disabled.
void updateDataDefinedButton(QgsPropertyOverrideButton *button)
Updates a previously registered data defined button to reflect the item&#39;s current properties...
QList< QgsMapLayer *> selectedLayers() const
Returns the list of selected layers.
QStringList customProperties() const
Returns list of keys stored in custom properties.
void updateLegend()
Updates the legend layers and groups.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:75
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
QgsLayoutLegendMenuProvider(QgsLayerTreeView *view, QgsLayoutLegendWidget *w)
constructor
void registerDataDefinedButton(QgsPropertyOverrideButton *button, QgsLayoutObject::DataDefinedProperty property)
Registers a data defined button, setting up its initial value, connections and description.
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
The QgsLayerTreeModel class is model implementation for Qt item views framework.
static QgsLegendStyle::Style nodeLegendStyle(QgsLayerTreeNode *node, QgsLayerTreeModel *model)
Returns the style for the given node, within the specified model.
A widget for setting properties relating to a layout legend.
Layout graphical items for displaying a map.
QString name() const override
Returns the layer&#39;s name.
const QgsLayout * layout() const
Returns the layout the object is attached to.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
A dialog to add new layers to the legend.
static QgsLayerTreeModelLegendNode * index2legendNode(const QModelIndex &index)
Returns legend node for given index.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsLayerTreeNode * parent()
Gets pointer to the parent. If parent is nullptr, the node is a root node.
QgsLayerTreeModel * model() const
Returns pointer to model owning this legend node.
Class used to render QgsLayout as an atlas, by iterating over the features from an associated vector ...
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...
void setName(const QString &n) override
Sets the group&#39;s name.
Symbol icon (excluding label)
bool setNewItem(QgsLayoutItem *item) override
Attempts to update the widget to show the properties for the specified item.
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:53
This class is a base class for nodes in a layer tree.
void changed()
Emitted when the widget&#39;s text format settings are changed.
Legend subgroup title.
void layerChanged(QgsVectorLayer *layer)
Emitted when the context&#39;s layer is changed.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void removeCustomProperty(const QString &key)
Remove a custom property from layer. Properties are stored in a map and saved in project file...
QgsLayoutAtlas * layoutAtlas() const
Returns the atlas for the layout (if available)
QgsLayerTreeModelLegendNode * legendNode(const QString &rule, QgsLayerTreeModel &model)
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:49
static QString styleLabel(Style s)
Returns a translated string representing a style component, for use in UI.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window&#39;s toolbar icons.
void itemChanged(QgsLayoutItem *item)
Emitted whenever the currently selected item changes.
Style
Component of legends which can be styled.
QgsLayerTreeModel * layerTreeModel() const
Gets access to the model casted to QgsLayerTreeModel.
void refreshLayerLegend(QgsLayerTreeLayer *nodeLayer)
Force a refresh of legend nodes of a layer node.
QgsMapLayer * layer() const
Returns the map layer associated with this node.
void setVisibleLayers(const QList< QgsMapLayer *> &layers)
Sets a list of visible layers, to use for filtering within the dialog.
QgsLayoutReportContext & reportContext()
Returns a reference to the layout&#39;s report context, which stores information relating to the current ...
Definition: qgslayout.cpp:368
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
QgsLayoutItemLegend * legend()
Returns the legend item associated to this widget.
Special style, item is hidden including margins around.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:262
void setMasterLayout(QgsMasterLayoutInterface *masterLayout) override
Sets the master layout associated with the item.
static void setLegendFilterByExpression(QgsLayerTreeLayer &layer, const QString &expr, bool enabled=true)
Sets the expression filter of a legend layer.
void insertChildNode(int index, QgsLayerTreeNode *node)
Insert existing node at specified position.
QgsLayoutLegendWidget(QgsLayoutItemLegend *legend, QgsMapCanvas *mapCanvas)
constructor
A base class for property widgets for layout items.
QgsLayerTreeNode * index2node(const QModelIndex &index) const
Returns layer tree node for given index.
QMenu * createContextMenu() override
Returns a newly created menu instance (or nullptr on error)
This class provides a method of converting QgsLayoutMeasurements from one unit to another...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
bool autoUpdateModel() const
Returns whether the legend content should auto update to reflect changes in the project&#39;s layer tree...
virtual QVariant data(int role) const =0
Returns data associated with the item. Must be implemented in derived class.
void setCurrentNodeStyleFromAction()
Sets the current node style from the data of the action which invokes this slot.
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
void changed()
Emitted when the alignment is changed.
void setItem(QgsLayoutItem *item)
Sets the layout item.
void setHighlightedVariables(const QStringList &variableNames)
Sets the list of variable names within the context intended to be highlighted to the user...
void setLabelExpression(const QString &expression)
set the expression to evaluate
Configure font settings for use with QFont objects.
Definition: qgsfontbutton.h:59
QString name() const override
Returns the group&#39;s name.
A layout item subclass for map legends.
Symbol label (excluding icon)
Interface for master layout type objects, such as print layouts and reports.
Layout legend menu provider.
void changed()
Emitted when the object&#39;s properties change.
void setReportTypeString(const QString &string) override
Sets the string to use to describe the current report type (e.g.
Represents a vector layer which manages a vector based data sets.
Q_GUI_EXPORT int qt_defaultDpiX()
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
QgsLayoutLegendWidget * mWidget
A generic dialog for building expression strings.
static QString legendFilterByExpression(const QgsLayerTreeLayer &layer, bool *enabled=nullptr)
Returns the expression filter of a legend layer.
Legend group title.
void setMasterLayout(QgsMasterLayoutInterface *masterLayout)
Sets the master layout associated with the item.
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...
Layer tree node points to a map layer.
QgsLayerTreeNode * currentNode() const
Gets current node. May be nullptr.