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