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